[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Minios-devel] [UNIKRAFT RFC PATCH 1/2] Implement gic-v2 library for Arm



From: Jianyong Wu <Jianyong.Wu@xxxxxxx>

This library has implemented basic GICv2 functions. We don't support
GICv2M and security extension in this library.

Signed-off-by: Wei Chen <wei.chen@xxxxxxx>
Signed-off-by: Jianyong Wu <jianyong.wu@xxxxxxx>
---
 plat/common/arm/gic-v2.c         | 447 +++++++++++++++++++++++++++++++
 plat/common/include/arm/gic-v2.h | 380 ++++++++++++++++++++++++++
 plat/common/include/irq.h        |  15 ++
 plat/kvm/Makefile.uk             |   2 +
 plat/kvm/arm/setup.c             |  55 ++--
 5 files changed, 877 insertions(+), 22 deletions(-)
 create mode 100644 plat/common/arm/gic-v2.c
 create mode 100644 plat/common/include/arm/gic-v2.h

diff --git a/plat/common/arm/gic-v2.c b/plat/common/arm/gic-v2.c
new file mode 100644
index 0000000..98a7688
--- /dev/null
+++ b/plat/common/arm/gic-v2.c
@@ -0,0 +1,447 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Wei Chen <Wei.Chen@xxxxxxx>
+ *          Jianyong Wu <Jianyong.Wu@xxxxxxx>
+ *
+ * Copyright (c) 2018, Arm Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+#include <string.h>
+#include <libfdt.h>
+#include <uk/essentials.h>
+#include <uk/print.h>
+#include <uk/assert.h>
+#include <uk/bitops.h>
+#include <uk/asm.h>
+#include <irq.h>
+#include <arm/cpu.h>
+#include <arm/gic-v2.h>
+
+static void *gic_dist_addr, *gic_cpuif_addr;
+static uint64_t gic_dist_size, gic_cpuif_size;
+
+#define GIC_DIST_REG(r)        (gic_dist_addr + (r))
+#define GIC_CPU_REG(r) (gic_cpuif_addr + (r))
+
+static char *gic_device_list[] = {
+       "arm,cortex-a15-gic",
+       "arm,cortex-a7-gic",
+       "arm,cortex-a9-gic",
+       "arm,gic-400",
+       "arm,eb11mp-gic",
+       "arm,pl390",
+       "arm,arm1176jzf-devchip-gic",
+       "arm,arm11mp-gic",
+       "arm,tc11mp-gic",
+       "brcm,brahma-b15-gic",
+       "nvidia,tegra210-agic",
+       "qcom,msm-8660-qgic",
+       "qcom,msm-qgic2",
+};
+
+/* inline functions to access GICC & GICD registers */
+static inline void write_gicd8(uint64_t offset, uint8_t val)
+{
+       ioreg_write8(GIC_DIST_REG(offset), val);
+}
+
+static inline void write_gicd32(uint64_t offset, uint32_t val)
+{
+       ioreg_write32(GIC_DIST_REG(offset), val);
+}
+
+static inline uint32_t read_gicd32(uint64_t offset)
+{
+       return ioreg_read32(GIC_DIST_REG(offset));
+}
+
+static inline void write_gicc32(uint64_t offset, uint32_t val)
+{
+        ioreg_write32(GIC_CPU_REG(offset), val);
+}
+
+static inline uint32_t read_gicc32(uint64_t offset)
+{
+       return ioreg_read32(GIC_CPU_REG(offset));
+}
+
+/*
+ * Functions of GIC CPU interface
+ */
+
+/* Enable GIC cpu interface */
+static void gic_enable_cpuif(void)
+{
+       /* just set bit 0 to 1 to enable cpu interface */
+       write_gicc32(GICC_CTLR, GICC_CTLR_ENABLE);
+}
+
+/* Set priority threshold for processor */
+static void gic_set_threshold_priority(uint32_t threshold_prio)
+{
+       /* GICC_PMR allocate 1 byte for each irq */
+       if (threshold_prio > GICC_PMR_PRIO_MAX)
+               UK_CRASH("Possible priority from 0 to 255, input: %d\n",
+                       threshold_prio);
+       write_gicc32(GICC_PMR, threshold_prio);
+}
+
+/*
+ * Acknowledging irq equals reading GICC_IAR also
+ * get the interrupt ID as the side effect.
+ */
+uint32_t gic_ack_irq(void)
+{
+       return read_gicc32(GICC_IAR);
+}
+
+/*
+ * write to GICC_EOIR to inform cpu interface completation
+ * of interrupt processing. If GICC_CTLR.EOImode sets to 1
+ * this func just gets priority drop.
+ */
+void gic_eoi_irq(uint32_t irq)
+{
+       write_gicc32(GICC_EOIR, irq);
+}
+
+/* Functions of GIC Distributor */
+
+/*
+ * @sgintid denotes the sgi ID;
+ * @targetfilter : this term is TargetListFilter
+ * 0 denotes forwarding interrupt to cpu specified in the
+ * target list; 1 denotes forwarding interrupt to cpu execpt the
+ * processor that request the intrrupt; 2 denotes forwarding the
+ * interrupt only to the cpu that requtest the interrupt.
+ * @targetlist is bitmask, which bit 1 denotes forwarding to and only low 8
+ * bit is in use.
+ */
+static void gic_sgi_gen(uint32_t sgintid, uint8_t targetfilter,
+                       uint8_t targetlist)
+{
+       uint32_t val;
+
+       /* Only INTID 0-15 allocated to sgi */
+       if (sgintid > GICD_SGI_MAX_INITID)
+               UK_CRASH("Only INTID 0-15 allocated to sgi\n");
+
+       /* Set SGI tagetfileter field */
+       val = (targetfilter & GICD_SGI_FILTER_MASK) << GICD_SGI_FILTER_SHIFT;
+
+       /* Set SGI targetlist field */
+       val |= (targetlist & GICD_SGI_TARGET_MASK) << GICD_SGI_TARGET_SHIFT;
+
+       /* Set SGI INITID field */
+       val |= sgintid;
+
+       /* Generate SGI */
+       write_gicd32(GICD_SGIR, val);
+}
+
+/*
+ * Forward the SIG to the CPU interfaces specified in the
+ * targetlist. Targetlist is a 8-bit bitmap for 0~7 CPU.
+ */
+void gic_sgi_gen_to_list(uint32_t sgintid, uint8_t targetlist)
+{
+       gic_sgi_gen(sgintid, GICD_SGI_FILTER_TO_LIST, targetlist);
+}
+
+/*
+ * Forward the SGI to all CPU interfaces except that of the
+ * processor that requested the interrupt.
+ */
+void gic_sgi_gen_to_others(uint32_t sgintid)
+{
+       gic_sgi_gen(sgintid, GICD_SGI_FILTER_TO_OTHERS, 0);
+}
+
+/*
+ * Forward the SGI only to the CPU interface of the processor
+ * that requested the interrupt.
+ */
+void gic_sgi_gen_to_self(uint32_t sgintid)
+{
+       gic_sgi_gen(sgintid, GICD_SGI_FILTER_TO_SELF, 0);
+}
+
+/*
+ * set target cpu for irq in distributor,
+ * @target: bitmask value, bit 1 indicates target to
+ * corresponding cpu interface
+ */
+void gic_set_irq_target(uint32_t irq, uint8_t target)
+{
+       write_gicd8(GICD_ITARGETSR(irq), target);
+}
+
+/* set priority for irq in distributor */
+void gic_set_irq_prio(uint32_t irq, uint8_t priority)
+{
+       write_gicd8(GICD_IPRIORITYR(irq), priority);
+}
+
+/*
+ * Enable an irq in distributor, each irq occupies one bit
+ * to configure in corresponding registor
+ */
+void gic_enable_irq(uint32_t irq)
+{
+       write_gicd32(GICD_ISENABLER(irq),
+               UK_BIT(irq % GICD_I_PER_ISENABLERn));
+}
+
+/*
+ * Disable an irq in distributor, one bit reserved for an irq
+ * to configure in corresponding register
+ */
+void gic_disable_irq(uint32_t irq)
+{
+       write_gicd32(GICD_ICENABLER(irq),
+               UK_BIT(irq % GICD_I_PER_ICENABLERn));
+}
+
+/* Enable distributor */
+static void gic_enable_dist(void)
+{
+       /* just set bit 0 to 1 to enable distributor */
+       write_gicd32(GICD_CTLR, read_gicd32(GICD_CTLR) | GICD_CTLR_ENABLE);
+}
+
+/* disable distributor */
+static void gic_disable_dist(void)
+{
+       /* just clear bit 0 to 0 to enable distributor */
+       write_gicd32(GICD_CTLR, read_gicd32(GICD_CTLR) & (~GICD_CTLR_ENABLE));
+}
+
+/*
+ * inspect that if an irq is in pending state, every bit
+ * holds the state value for the corresponding irq
+ */
+int gic_is_irq_pending(uint32_t irq)
+{
+       return !! (read_gicd32(GICD_ICPENDR(irq)) &
+               UK_BIT(irq % GICD_I_PER_ICPENDRn));
+}
+
+/*
+ * inspect that if an irq is in active state,
+ * every bit holds the value for an irq
+ */
+int gic_is_irq_active(uint32_t irq)
+{
+       return !! (read_gicd32(GICD_ISACTIVER(irq)) &
+               UK_BIT(irq % GICD_I_PER_ISACTIVERn));
+}
+
+/* Config intrrupt trigger type and polarity */
+void gic_set_irq_type(uint32_t irq, int trigger, int polarity)
+{
+       uint32_t val, mask, oldmask;
+
+       if ((trigger >= UK_IRQ_TRIGGER_MAX) ||
+               (polarity >= UK_IRQ_POLARITY_MAX))
+               return;
+
+       val = read_gicd32(GICD_ICFGR(irq));
+       mask = oldmask = (val >> ((irq % GICD_I_PER_ICFGRn) * 2)) &
+                       GICD_ICFGR_MASK;
+
+       if (trigger == UK_IRQ_TRIGGER_LEVEL) {
+               mask &= ~GICD_ICFGR_TRIG_MASK;
+               mask |= GICD_ICFGR_TRIG_LVL;
+       } else if (trigger == UK_IRQ_TRIGGER_EDGE) {
+               mask &= ~GICD_ICFGR_TRIG_MASK;
+               mask |= GICD_ICFGR_TRIG_EDGE;
+       }
+
+       if (polarity == UK_IRQ_POLARITY_LOW) {
+               mask &= ~GICD_ICFGR_POL_MASK;
+               mask |= GICD_ICFGR_POL_LOW;
+       } else if (polarity == UK_IRQ_POLARITY_HIGH) {
+               mask &= ~GICD_ICFGR_POL_MASK;
+               mask |= GICD_ICFGR_POL_HIGH;
+       }
+
+       /* Check if nothing changed */
+       if (mask == oldmask)
+               return;
+
+       /* Update new interrupt type */
+       val &= (~(GICD_ICFGR_MASK << (irq % GICD_I_PER_ICFGRn) * 2));
+       val |= (mask << (irq % GICD_I_PER_ICFGRn) * 2);
+       write_gicd32(GICD_ICFGR(irq), val);
+}
+
+static void gic_init_dist(void)
+{
+       uint32_t val, cpuif_number, irq_number;
+       uint32_t i;
+
+       /* Turn down distributor */
+       gic_disable_dist();
+
+       /* Get GIC CPU interface */
+       val = read_gicd32(GICD_TYPER);
+       cpuif_number = GICD_TYPER_CPUI_NUM(val);
+       if (cpuif_number > GIC_MAX_CPUIF)
+               cpuif_number = GIC_MAX_CPUIF;
+       uk_printd(DLVL_INFO, "GICv2 Max CPU interface:%d\n", cpuif_number);
+
+       /* Get the maximum number of interrupts that the GIC supports */
+       irq_number = GICD_TYPER_LINE_NUM(val);
+       if (irq_number > GIC_MAX_IRQ)
+               irq_number = GIC_MAX_IRQ;
+       uk_printd(DLVL_INFO, "GICv2 Max interrupt lines:%d\n", irq_number);
+       /*
+        * Set all SPI interrupts targets to all CPU.
+        */
+       for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_ITARGETSRn)
+               write_gicd32(GICD_ITARGETSR(i), GICD_ITARGETSR_DEF);
+
+       /*
+        * Set all SPI interrupts type to be polarity low level triggered
+        */
+       for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_ICFGRn)
+               write_gicd32(GICD_ICFGR(i), GICD_ICFGR_DEF_TYPE);
+
+       /*
+        * Set all SPI priority to a default value.
+        */
+       for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_IPRIORITYn)
+               write_gicd32(GICD_IPRIORITYR(i), GICD_IPRIORITY_DEF);
+
+       /*
+        * Deactivate and disable all SPIs.
+        */
+       for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_ICACTIVERn) {
+               write_gicd32(GICD_ICACTIVER(i), GICD_DEF_ICACTIVERn);
+               write_gicd32(GICD_ICENABLER(i), GICD_DEF_ICENABLERn);
+       }
+
+       /* turn on distributor */
+       gic_enable_dist();
+}
+
+static void gic_init_cpuif(void)
+{
+       uint32_t i;
+       /* set priority mask to the lowest priority to let all irq visible to 
cpu interface */
+       gic_set_threshold_priority(GICC_PMR_PRIO_MAX);
+
+       /* set PPI and SGI to polarity low level triggered */
+       for (i = 0; i < GIC_SPI_BASE; i += GICD_I_PER_ICFGRn)
+               write_gicd32(GICD_ICFGR(i), GICD_ICFGR_DEF_TYPE);
+
+       /* set PPI and SGI to a default value */
+       for (i = 0; i < GIC_SPI_BASE; i += GICD_I_PER_IPRIORITYn)
+               write_gicd32(GICD_IPRIORITYR(i), GICD_IPRIORITY_DEF);
+        /*
+        * Deactivate and disable all PPIs.
+        */
+        for (i = 0; i < GICD_SGI_MAX_INITID; i += GICD_I_PER_ICACTIVERn) {
+               write_gicd32(GICD_ICACTIVER(i), GICD_DEF_ICACTIVERn);
+               write_gicd32(GICD_ICENABLER(i), GICD_DEF_PPI_ICENABLERn);
+                                                               }
+       /* Deactivate and enable all SGIs */
+       for (i = 0; i < GIC_PPI_BASE; i += GICD_I_PER_ICACTIVERn)
+       {
+               write_gicd32(GICD_ICACTIVER(i), GICD_DEF_ICACTIVERn);
+               write_gicd32(GICD_ISENABLER(i), GICD_DEF_SGI_ISENABLERn);
+       }
+
+       /* enable cpu interface */
+       gic_enable_cpuif();
+}
+
+int _dtb_init_gic(void *dtb)
+{
+       uint32_t idx;
+       int fdt_gic, naddr, nsize, prop_len, prop_min_len;
+       const uint64_t *regs;
+
+       uk_printd(DLVL_INFO, "Probing GICv2...\n");
+       /* Currently, we only support 1 GIC per system */
+       for (idx = 0;
+               idx < sizeof(gic_device_list) / sizeof(gic_device_list[0]);
+               idx++) {
+               fdt_gic = fdt_node_offset_by_compatible(dtb, -1,
+                               gic_device_list[idx]);
+                if (fdt_gic >= 0)
+                        break;
+       }
+
+       if (fdt_gic < 0)
+               UK_CRASH("No valid GIC device find\n");
+
+       naddr = fdt_address_cells(dtb, fdt_gic);
+       if (naddr < 0 || naddr >= FDT_MAX_NCELLS)
+               UK_CRASH("Could not find proper address cells!\n");
+
+       nsize = fdt_size_cells(dtb, fdt_gic);
+       if (nsize < 0 || nsize >= FDT_MAX_NCELLS)
+               UK_CRASH("Could not find proper size cells!\n");
+
+        regs = fdt_getprop(dtb, fdt_gic, "reg", &prop_len);
+
+       /*
+        * The property must contain at least the start address and size
+        * of distributor and cpu interface
+        */
+       prop_min_len = (int)sizeof(fdt32_t) * (naddr + nsize) * 2;
+       if (regs == NULL || prop_len < prop_min_len)
+               UK_CRASH("Bad 'reg' property: %p %d\n", regs, prop_len);
+
+       /*
+        * From:
+        * 
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
+        * We know that the first region is the GIC distributor register
+        * base and size. The 2nd region is the GIC cpu interface register
+        * base and size.
+        */
+       gic_dist_addr = (void *)fdt64_to_cpu(regs[0]);
+       gic_dist_size = fdt64_to_cpu(regs[1]);
+       gic_cpuif_addr = (void *)fdt64_to_cpu(regs[2]);
+       gic_cpuif_size = fdt64_to_cpu(regs[3]);
+
+       uk_printd(DLVL_INFO, "Found GICv2 on:\n");
+       uk_printd(DLVL_INFO, "\tCPU interface address: %p\n", gic_cpuif_addr);
+       uk_printd(DLVL_INFO, "\tDistributor address: %p\n", gic_dist_addr);
+
+
+       /* Initialize GICv2 distributor */
+       gic_init_dist();
+
+       /* Initialize GICv2 CPU interface */
+       gic_init_cpuif();
+
+       return 0;
+}
diff --git a/plat/common/include/arm/gic-v2.h b/plat/common/include/arm/gic-v2.h
new file mode 100644
index 0000000..dfee6a8
--- /dev/null
+++ b/plat/common/include/arm/gic-v2.h
@@ -0,0 +1,380 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Wei Chen <Wei.Chen@xxxxxxx>
+ *          Jianyong Wu <Jianyong.Wu@xxxxxxx>
+ *
+ * Copyright (c) 2018, Arm Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+#ifndef __PLAT_CMN_ARM_GIC_H__
+#define __PLAT_CMN_ARM_GIC_H__
+
+/*
+ * Distributor registers. Unikraft only support run on non-secure
+ * so we just describe non-secure registers.
+ */
+
+/*
+ * Distributor Control Register, GICD_CTLR.
+ * Enables the forwarding of pending interrupts from the
+ * Distributor to the CPU interfaces
+ */
+#define GICD_CTLR              0x0000
+#define GICD_CTLR_ENABLE       0x1
+
+/*
+ * Interrupt Controller Type Register, GICD_TYPER.
+ * Provides information about the configuration of the GIC.
+ */
+#define GICD_TYPER             0x0004
+#define        GICD_TYPER_LINE_NUM(r)  ((((r) & 0x1f) + 1) << 5)
+#define        GICD_TYPER_CPUI_NUM(r)  ((((r) >> 5) & 0x3) + 1)
+
+/*
+ * Distributor Implementer Identification Register, GICD_IIDR.
+ * Provides information about the implementer and revision of the Distributor.
+ */
+#define GICD_IIDR              0x0008
+#define        GICD_IIDR_PROD(r)       (((r) >> 24) & 0xff)
+#define GICD_IIDR_VAR(r)       (((r) >> 16) & 0xf)
+#define        GICD_IIDR_REV(r)        (((r) >> 12) & 0xf)
+#define GICD_IIDR_IMPL(r)      ((r) & 0xfff)
+
+/*
+ * Interrupt Group Registers, GICD_IGROUPRn
+ * These registers provide a status bit for each interrupt supported by
+ * the GIC. Each bit controls whether the corresponding interrupt is in
+ * Group 0 or Group 1
+ */
+#define        GICD_IGROUPR(n)         (0x0080 + 4 * ((n) >> 5))
+#define        GICD_I_PER_IGROUPRn     32
+
+/*
+ * Interrupt Set-Enable Registers, GICD_ISENABLERn.
+ * These registers provide a Set-enable bit for each interrupt supported
+ * by the GIC. Writing 1 to a Set-enable bit enables forwarding of the
+ * corresponding interrupt from the Distributor to the CPU interfaces.
+ * Reading a bit identifies whether the interrupt is enabled.
+ */
+#define        GICD_ISENABLER(n)       (0x0100 + 4 * ((n) >> 5))
+#define        GICD_I_PER_ISENABLERn   32
+#define GICD_DEF_SGI_ISENABLERn        0xffff
+
+/*
+ * Interrupt Clear-Enable Registers, GICD_ICENABLERn.
+ * Provide a Clear-enable bit for each interrupt supported by the GIC.
+ * Writing 1 to a Clear-enable bit disables forwarding of the
+ * corresponding interrupt from the Distributor to the CPU interfaces.
+ * Reading a bit identifies whether the interrupt is enabled.
+ */
+#define        GICD_ICENABLER(n)       (0x0180 + 4 * ((n) >> 5))
+#define        GICD_I_PER_ICENABLERn   32
+#define        GICD_DEF_ICENABLERn     0xffffffff
+#define GICD_DEF_PPI_ICENABLERn        0xffff0000
+
+/*
+ * Interrupt Set-Pending Registers, GICD_ISPENDRn.
+ * Provide a Set-pending bit for each interrupt supported by the GIC.
+ * Writing 1 to a Set-pending bit sets the status of the corresponding
+ * peripheral interrupt to pending. Reading a bit identifies whether
+ * the interrupt is pending.
+ */
+#define        GICD_ISPENDR(n)         (0x0200 + 4 * ((n) >> 5))
+#define        GICD_I_PER_ISPENDRn     32
+/*
+ * Interrupt Clear-Pending Registers, GICD_ICPENDRn
+ * Provide a Clear-pending bit for each interrupt supported by the GIC.
+ * Writing 1 to a Clear-pending bit clears the pending state of the
+ * corresponding peripheral interrupt. Reading a bit identifies whether
+ * the interrupt is pending.
+ */
+#define        GICD_ICPENDR(n)         (0x0280 + 4 * ((n) >> 5))
+#define        GICD_I_PER_ICPENDRn     32
+
+/*
+ * Interrupt Set-Active Registers, GICD_ISACTIVERn
+ * Provide a Set-active bit for each interrupt that the GIC supports.
+ * Writing to a Set-active bit Activates the corresponding interrupt.
+ * These registers are used when preserving and restoring GIC state.
+ */
+#define GICD_ISACTIVER(n)      (0x0300 + 4 * ((n) >> 5))
+#define        GICD_I_PER_ISACTIVERn   32
+/*
+ * Interrupt Clear-Active Registers, GICD_ICACTIVERn
+ * Provide a Clear-active bit for each interrupt that the GIC supports.
+ * Writing to a Clear-active bit Deactivates the corresponding interrupt.
+ * These registers are used when preserving and restoring GIC state.
+ */
+#define        GICD_ICACTIVER(n)       (0x0380 + 4 * ((n) >> 5))
+#define        GICD_I_PER_ICACTIVERn   32
+#define        GICD_DEF_ICACTIVERn     0xffffffff
+
+/*
+ * Interrupt ID mask for GICD_ISENABLER, GICD_ICENABLER, GICD_ISPENDR,
+ * GICD_ICPENDR, GICD_ISACTIVER and GICD_ICACTIVER
+ */
+#define        GICD_I_MASK(n)          (1ul << ((n) & 0x1f))
+
+/*
+ * Interrupt Priority Registers, GICD_IPRIORITYRn
+ * Provide an 8-bit priority field for each interrupt supported by the
+ * GIC.
+ *
+ * These registers are byte-accessible, so we define this macro
+ * for byte-access.
+ */
+#define        GICD_IPRIORITYR(n)      (0x0400 + (n))
+#define        GICD_I_PER_IPRIORITYn   4
+#define        GICD_IPRIORITY_DEF      0xa0a0a0a0
+
+/*
+ * Interrupt Processor Targets Registers, GICD_ITARGETSRn
+ * Provide an 8-bit CPU targets field for each interrupt supported by
+ * the GIC.
+ *
+ * These registers are byte-accessible, so we define this macro
+ * for byte-access.
+ */
+#define        GICD_ITARGETSR(n)       (0x0800 + (n))
+#define        GICD_I_PER_ITARGETSRn   4
+#define        GICD_ITARGETSR_DEF      0xffffffff
+
+/*
+ * Interrupt Configuration Registers, GICD_ICFGRn
+ * The GICD_ICFGRs provide a 2-bit Int_config field for each interrupt
+ * supported by the GIC. This field identifies whether the corresponding
+ * interrupt is edge-triggered or level-sensitive.
+ */
+#define        GICD_ICFGR(n)           (0x0C00 + 4 * ((n) >> 4))
+#define        GICD_I_PER_ICFGRn       16
+#define        GICD_ICFGR_DEF_TYPE     0
+#define        GICD_ICFGR_MASK         0x3
+/* First bit is a polarity bit (0 - low, 1 - high) */
+#define        GICD_ICFGR_POL_LOW      (0 << 0)
+#define        GICD_ICFGR_POL_HIGH     (1 << 0)
+#define        GICD_ICFGR_POL_MASK     0x1
+/* Second bit is a trigger bit (0 - level, 1 - edge) */
+#define        GICD_ICFGR_TRIG_LVL     (0 << 1)
+#define        GICD_ICFGR_TRIG_EDGE    (1 << 1)
+#define        GICD_ICFGR_TRIG_MASK    0x2
+
+/*
+ * Software Generated Interrupt Register, GICD_SGIR
+ */
+#define GICD_SGIR              0x0F00
+#define        GICD_SGI_TARGET_SHIFT   16
+#define        GICD_SGI_TARGET_MASK    0xff
+#define        GICD_SGI_FILTER_SHIFT   24
+#define        GICD_SGI_FILTER_MASK    0x3
+#define        GICD_SGI_MAX_INITID     15
+#define GICD_PPI_START
+
+/*
+ * Forward the interrupt to the CPU interfaces specified in the
+ * CPUTargetList field
+ */
+#define        GICD_SGI_FILTER_TO_LIST         0x0
+/*
+ * Forward the interrupt to all CPU interfaces except that of the
+ * processor that requested the interrupt.
+ */
+#define        GICD_SGI_FILTER_TO_OTHERS       0x1
+/*
+ * Forward the interrupt only to the CPU interface of the processor
+ * that requested the interrupt.
+ */
+#define        GICD_SGI_FILTER_TO_SELF         0x2
+
+/*
+ * SGI Clear-Pending Registers, GICD_CPENDSGIRn
+ * Provide a clear-pending bit for each supported SGI and source
+ * processor combination. When a processor writes a 1 to a clear-pending
+ * bit, the pending state of the corresponding SGI for the corresponding
+ * source processor is removed, and no longer targets the processor
+ * performing the write. Writing a 0 has no effect. Reading a bit identifies
+ * whether the SGI is pending, from the corresponding source processor, on
+ * the reading processor.
+ */
+#define GICD_CPENDSGIRn                (0x0F10 + 4 *((n) >> 2))
+#define GICD_I_PER_CPENDSGIRn   4
+
+/*
+ * SGI Set-Pending Registers, GICD_SPENDSGIRn
+ * Provide a set-pending bit for each supported SGI and source processor
+ * combination. When a processor writes a 1 to a set-pending bit, the pending
+ * state is applied to the corresponding SGI for the corresponding source
+ * processor. Writing a 0 has no effect. Reading a bit identifies whether
+ * the SGI is pending, from the corresponding source processor, on the
+ * reading processor.
+ */
+#define GICD_SPENDSGIRn                (0x0F20 + 4 *((n) >> 2))
+#define GICD_I_PER_SPENDSGIRn   4
+
+
+/*
+ * CPU interface registers. Unikraft only support run on non-secure
+ * so we just describe non-secure registers.
+ */
+
+/* CPU Interface Control Register */
+#define GICC_CTLR              0x0000
+#define GICC_CTLR_ENABLE       0x1
+
+/* Interrupt Priority Mask Register */
+#define GICC_PMR               0x0004
+#define GICC_PMR_PRIO_MAX      255
+
+/* Binary Point Register */
+#define GICC_BPR               0x0008
+
+/* Interrupt Acknowledge Register */
+#define GICC_IAR               0x000C
+#define GICC_IAR_INTID_MASK    0x3FF
+#define GICC_IAR_INTID_SPURIOUS        1023
+
+/* End of Interrupt Register */
+#define GICC_EOIR              0x0010
+
+/* Running Priority Register */
+#define GICC_RPR               0x0014
+
+/* Highest Priority Pending Interrupt Register */
+#define GICC_HPPIR             0x0018
+
+/* Aliased Binary Point Register */
+#define GICC_ABPR              0x001C
+
+/* CPU Interface Identification Register */
+#define GICC_IIDR              0x00FC
+
+/* Deactivate Interrupt Register */
+#define GICC_DIR               0x1000
+
+/*
+ * Acknowledging irq equals reading GICC_IAR also
+ * get the intrrupt ID as the side effect.
+ */
+uint32_t gic_ack_irq(void);
+
+/*
+ * write to GICC_EOIR to inform cpu interface completation
+ * of interrupt processing. If GICC_CTLR.EOImode sets to 1
+ * this func just gets priority drop.
+ */
+void gic_eoi_irq(uint32_t irq);
+
+/*
+ * Forward the SIG to the CPU interfaces specified in the
+ * targetlist. Targetlist is a 8-bit bitmap for 0~7 CPU.
+ */
+void gic_sgi_gen_to_list(uint32_t sgintid, uint8_t targetlist);
+
+/*
+ * Forward the SGI to all CPU interfaces except that of the
+ * processor that requested the interrupt.
+ */
+void gic_sgi_gen_to_others(uint32_t sgintid);
+
+/*
+ * Forward the SGI only to the CPU interface of the processor
+ * that requested the interrupt.
+ */
+void gic_sgi_gen_to_self(uint32_t sgintid);
+
+/*
+ * set target cpu for irq in distributor,
+ * @target: bitmask value, bit 1 indicates target to
+ * corresponding cpu interface
+ */
+void gic_set_irq_target(uint32_t irq, uint8_t target);
+
+/* set priority for irq in distributor */
+void gic_set_irq_prio(uint32_t irq, uint8_t priority);
+
+/*
+ * Enable an irq in distributor, each irq occupies one bit
+ * to configure in corresponding registor
+ */
+void gic_enable_irq(uint32_t irq);
+
+/*
+ * Disable an irq in distributor, one bit reserved for an irq
+ * to configure in corresponding register
+ */
+void gic_disable_irq(uint32_t irq);
+
+/*
+ * set pending state for an irq in distributor, one bit
+ * reserved for an irq to configure in corresponding register
+ */
+void gic_set_irq_pending(uint32_t irq);
+
+/*
+ * clear pending state for an irq in distributor, one bit
+ * reserved for an irq to configure in corresponding register
+ */
+void gic_clear_irq_pending(uint32_t irq);
+
+/*
+ * inspect that if an irq is in pending state, every bit
+ * holds the value for the corresponding irq
+ */
+int gic_is_irq_pending(uint32_t irq);
+
+/* set active state for an irq in distributor */
+void gic_set_irq_active(uint32_t irq);
+
+/* clear active state for an irq in distributor */
+void gic_clear_irq_active(uint32_t irq);
+
+/*
+ * inspect that if an irq is in active state,
+ * every bit holds the value for an irq
+ */
+int gic_is_irq_active(uint32_t irq);
+
+/* Config intrrupt trigger type and polarity */
+void gic_set_irq_type(uint32_t irq, int trigger, int polarity);
+
+/* Initialize GICv2 from device tree */
+int _dtb_init_gic(void *dtb);
+
+/* Max CPU interface for GICv2 */
+#define GIC_MAX_CPUIF          8
+
+/* SPI interrupt base ID */
+#define GIC_SPI_BASE           32
+
+/* PPI interrupt base ID */
+#define GIC_PPI_BASE           16
+
+/* Max support interrupt number for GICv2 */
+#define GIC_MAX_IRQ            1020
+
+#endif //__PLAT_CMN_ARM_GICV2_H__
diff --git a/plat/common/include/irq.h b/plat/common/include/irq.h
index edaccfe..c36d004 100644
--- a/plat/common/include/irq.h
+++ b/plat/common/include/irq.h
@@ -43,5 +43,20 @@
 #error "Add irq.h for current architecture."
 #endif
 
+/* define IRQ trigger types */
+enum uk_irq_trigger {
+       UK_IRQ_TRIGGER_NONE = 0,
+       UK_IRQ_TRIGGER_EDGE = 1,
+       UK_IRQ_TRIGGER_LEVEL = 2,
+       UK_IRQ_TRIGGER_MAX
+};
+
+/* define IRQ trigger polarities */
+enum uk_irq_polarity {
+       UK_IRQ_POLARITY_NONE = 0,
+       UK_IRQ_POLARITY_HIGH = 1,
+       UK_IRQ_POLARITY_LOW = 2,
+       UK_IRQ_POLARITY_MAX
+};
 
 #endif /* __PLAT_CMN_IRQ_H__ */
diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk
index ccc8319..13ef986 100644
--- a/plat/kvm/Makefile.uk
+++ b/plat/kvm/Makefile.uk
@@ -58,7 +58,9 @@ LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += 
$(UK_PLAT_COMMON_BASE)/arm/cpu_native.c
 LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += 
$(UK_PLAT_COMMON_BASE)/arm/cache64.S|common
 LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += 
$(UK_PLAT_COMMON_BASE)/arm/psci_arm64.S|common
 LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += 
$(UK_PLAT_COMMON_BASE)/arm/time.c|common
+LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += 
$(UK_PLAT_COMMON_BASE)/arm/rtc.c|common
 LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += 
$(UK_PLAT_COMMON_BASE)/arm/traps.c|common
+LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += 
$(UK_PLAT_COMMON_BASE)/arm/gic-v2.c|common
 LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBKVMPLAT_BASE)/arm/entry64.S
 LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBKVMPLAT_BASE)/arm/exceptions.S
 LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBKVMPLAT_BASE)/arm/pagetable.S
diff --git a/plat/kvm/arm/setup.c b/plat/kvm/arm/setup.c
index 09530bb..30e22bc 100644
--- a/plat/kvm/arm/setup.c
+++ b/plat/kvm/arm/setup.c
@@ -18,18 +18,20 @@
  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
+#include <limits.h>
 #include <libfdt.h>
-#include <kvm/console.h>
+#include <uk/essentials.h>
 #include <uk/assert.h>
+#include <kvm/console.h>
 #include <kvm-arm/mm.h>
 #include <arm/cpu.h>
-#include <uk/arch/limits.h>
+#include <arm/rtc.h>
+#include <arm/gic-v2.h>
 
 void *_libkvmplat_pagetable;
 void *_libkvmplat_heap_start;
 void *_libkvmplat_stack_top;
 void *_libkvmplat_mem_end;
-void *_libkvmplat_dtb;
 
 #define MAX_CMDLINE_SIZE 1024
 static char cmdline[MAX_CMDLINE_SIZE];
@@ -47,7 +49,7 @@ static void _init_dtb(void *dtb_pointer)
                UK_CRASH("Invalid DTB: %s\n", fdt_strerror(ret));
 
        _libkvmplat_dtb = dtb_pointer;
-       uk_pr_info("Found device tree on: %p\n", dtb_pointer);
+       uk_printd(DLVL_INFO, "Found device tree on: %p\n", dtb_pointer);
 }
 
 static void _dtb_get_psci_method(void)
@@ -65,13 +67,13 @@ static void _dtb_get_psci_method(void)
                fdtpsci = fdt_node_offset_by_compatible(_libkvmplat_dtb,
                                                        -1, "arm,psci-0.2");
        if (fdtpsci < 0) {
-               uk_pr_info("No PSCI conduit found in DTB\n");
+               uk_printd(DLVL_INFO, "No PSCI conduit found in DTB\n");
                goto enomethod;
        }
 
        fdtmethod = fdt_getprop(_libkvmplat_dtb, fdtpsci, "method", &len);
        if (!fdtmethod || (len <= 0)) {
-               uk_pr_info("No PSCI method found\n");
+               uk_printd(DLVL_INFO, "No PSCI method found\n");
                goto enomethod;
        }
 
@@ -80,16 +82,16 @@ static void _dtb_get_psci_method(void)
        else if (!strcmp(fdtmethod, "smc"))
                smcc_psci_call = smcc_psci_smc_call;
        else {
-               uk_pr_info("Invalid PSCI conduit method: %s\n",
-                          fdtmethod);
+               uk_printd(DLVL_INFO,
+               "Invalid PSCI conduit method: %s\n", fdtmethod);
                goto enomethod;
        }
 
-       uk_pr_info("PSCI method: %s\n", fdtmethod);
+       uk_printd(DLVL_INFO, "PSCI method: %s\n", fdtmethod);
        return;
 
 enomethod:
-       uk_pr_info("Support PSCI from PSCI-0.2\n");
+       uk_printd(DLVL_INFO, "Support PSCI from PSCI-0.2\n");
        smcc_psci_call = NULL;
 }
 
@@ -104,13 +106,13 @@ static void _init_dtb_mem(void)
 
        /* search for assigned VM memory in DTB */
        if (fdt_num_mem_rsv(_libkvmplat_dtb) != 0)
-               uk_pr_warn("Reserved memory is not supported\n");
+               uk_printd(DLVL_WARN, "Reserved memory is not supported\n");
 
        fdt_mem = fdt_node_offset_by_prop_value(_libkvmplat_dtb, -1,
                                                "device_type",
                                                "memory", sizeof("memory"));
        if (fdt_mem < 0) {
-               uk_pr_warn("No memory found in DTB\n");
+               uk_printd(DLVL_WARN, "No memory found in DTB\n");
                return;
        }
 
@@ -138,7 +140,8 @@ static void _init_dtb_mem(void)
 
        /* If we have more than one memory bank, give a warning messasge */
        if (prop_len > prop_min_len)
-               uk_pr_warn("Currently, we support only one memory bank!\n");
+               uk_printd(DLVL_WARN,
+                       "Currently, we support only one memory bank!\n");
 
        mem_base = fdt64_to_cpu(regs[0]);
        mem_size = fdt64_to_cpu(regs[1]);
@@ -172,17 +175,25 @@ static void _dtb_get_cmdline(char *cmdline, size_t maxlen)
        cmdline[((unsigned int) len - 1) <= (maxlen - 1) ?
                ((unsigned int) len - 1) : (maxlen - 1)] = '\0';
 
-       uk_pr_info("Command line: %s\n", cmdline);
+       uk_printd(DLVL_INFO, "Command line: %s\n", cmdline);
        return;
 
 enocmdl:
-       uk_pr_info("No command line found\n");
+       uk_printd(DLVL_INFO, "No command line found\n");
        strcpy(cmdline, CONFIG_UK_NAME);
 }
 
 static void _libkvmplat_entry2(void *arg __attribute__((unused)))
 {
-       ukplat_entry_argp(NULL, (char *)cmdline, strlen(cmdline));
+       /* After switch to new stack, we start initializing other devices */
+
+       /* Initialize GIC interrupt controller */
+       _dtb_init_gic(_libkvmplat_dtb);
+
+       /* Initialize RTC */
+       _dtb_init_rtc(_libkvmplat_dtb);
+
+       ukplat_entry_argp(NULL, (char *)cmdline, strlen(cmdline));
 }
 
 void _libkvmplat_start(void *dtb_pointer)
@@ -190,7 +201,7 @@ void _libkvmplat_start(void *dtb_pointer)
        _init_dtb(dtb_pointer);
        _libkvmplat_init_console();
 
-       uk_pr_info("Entering from KVM (arm64)...\n");
+       uk_printd(DLVL_INFO, "Entering from KVM (arm64)...\n");
 
        /* Get command line from DTB */
 
@@ -202,15 +213,15 @@ void _libkvmplat_start(void *dtb_pointer)
        /* Initialize memory from DTB */
        _init_dtb_mem();
 
-       uk_pr_info("pagetable start: %p\n", _libkvmplat_pagetable);
-       uk_pr_info("     heap start: %p\n", _libkvmplat_heap_start);
-       uk_pr_info("      stack top: %p\n", _libkvmplat_stack_top);
+       uk_printd(DLVL_INFO, "pagetable start: %p\n", _libkvmplat_pagetable);
+       uk_printd(DLVL_INFO, "     heap start: %p\n", _libkvmplat_heap_start);
+       uk_printd(DLVL_INFO, "      stack top: %p\n", _libkvmplat_stack_top);
 
        /*
         * Switch away from the bootstrap stack as early as possible.
         */
-       uk_pr_info("Switch from bootstrap stack to stack @%p\n",
-                  _libkvmplat_stack_top);
+       uk_printd(DLVL_INFO, "Switch from bootstrap stack to stack @%p\n",
+                               _libkvmplat_stack_top);
 
        _libkvmplat_newstack((uint64_t) _libkvmplat_stack_top,
                                _libkvmplat_entry2, NULL);
-- 
2.17.1


_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.