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

Re: [Minios-devel] [UNIKRAFT PATCHv5 3/6] plat/common: Implement gic-v2 library for Arm



Hello Jianyong Wu,

Please find the comments inline.

Thanks & Regards
Sharan

On 6/28/19 9:09 AM, Jia He wrote:
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>
Signed-off-by: Jia He <justin.he@xxxxxxx>
---
  plat/common/include/irq.h         |  15 ++
  plat/drivers/gic/gic-v2.c         | 409 ++++++++++++++++++++++++++++++
  plat/drivers/include/gic/gic-v2.h | 370 +++++++++++++++++++++++++++
  plat/kvm/Makefile.uk              |   2 +
  4 files changed, 796 insertions(+)
  create mode 100644 plat/drivers/gic/gic-v2.c
  create mode 100644 plat/drivers/include/gic/gic-v2.h

diff --git a/plat/common/include/irq.h b/plat/common/include/irq.h
index a09685d..fac5022 100644
--- a/plat/common/include/irq.h
+++ b/plat/common/include/irq.h
@@ -45,5 +45,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/drivers/gic/gic-v2.c b/plat/drivers/gic/gic-v2.c
new file mode 100644
index 0000000..9321155
--- /dev/null
+++ b/plat/drivers/gic/gic-v2.c
@@ -0,0 +1,409 @@
+/* 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 <kvm/irq.h>
+#include <uk/plat/lcpu.h>
+#include <arm/cpu.h>
+#include <gic/gic-v2.h>
+#include <ofw/fdt.h>
+
+/* 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            __MAX_IRQ
+
+static uint64_t gic_dist_addr, gic_cpuif_addr;
+static uint64_t gic_dist_size, gic_cpuif_size;
+
+#define GIC_DIST_REG(r)        ((void *)(gic_dist_addr + (r)))
+#define GIC_CPU_REG(r) ((void *)(gic_cpuif_addr + (r)))
+
+static const char * const gic_device_list[] = {
+       "arm,cortex-a15-gic",
+       NULL
+};
+
+/* 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 */
+       UK_ASSERT(threshold_prio <= GICC_PMR_PRIO_MAX);
+       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);
+}
+

s/completation/completion


+/*
+ * 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
+ * @targetlist is bitmask value, A bit set to '1' indicated
+ * the interrupt is wired to that CPU.
+ */
+static void gic_sgi_gen(uint32_t sgintid, enum sgi_filter targetfilter,
+                       uint8_t targetlist)
+{
+       uint32_t val;
+
+       /* Only INTID 0-15 allocated to sgi */
+       UK_ASSERT(sgintid <= GICD_SGI_MAX_INITID);
+
+       /* 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);
+}
+


s/SIG/SGI
+/*
+ * Forward the SIG to the CPU interfaces specified in the
+ * targetlist. Targetlist is a 8-bit bitmap for 0~7 CPU.
+ * TODO: this will not work until SMP is supported
+ */
+void gic_sgi_gen_to_list(uint32_t sgintid, uint8_t targetlist)
+{
+       unsigned long irqf;
+
+       /* spin lock here is needed when smp is supported */
+       irqf = ukplat_lcpu_save_irqf();
+       gic_sgi_gen(sgintid, GICD_SGI_FILTER_TO_LIST, targetlist);
+       ukplat_lcpu_restore_irqf(irqf);
+}
+
+/*
+ * Forward the SGI to all CPU interfaces except that of the
+ * processor that requested the interrupt.
+ * TODO: this will not work until SMP is supported
+ */
+void gic_sgi_gen_to_others(uint32_t sgintid)
+{
+       unsigned long irqf;
+
+       /* spin lock here is needed when smp is supported */
+       irqf = ukplat_lcpu_save_irqf();
+       gic_sgi_gen(sgintid, GICD_SGI_FILTER_TO_OTHERS, 0);
+       ukplat_lcpu_restore_irqf(irqf);
+}
+
+/*
+ * 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)
+{
+       if (irq < GIC_SPI_BASE)
+               UK_CRASH("Bad irq number: should not less than %u",
+                       GIC_SPI_BASE);
+
+       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));
+}
+
+/* Config interrupt trigger type */
+void gic_set_irq_type(uint32_t irq, int trigger)
+{
+       uint32_t val, mask, oldmask;
+
+       if (irq < GIC_PPI_BASE)
+               UK_CRASH("Bad irq number: should not less than %u",
+                       GIC_PPI_BASE);
+       if (trigger >= UK_IRQ_TRIGGER_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;
+       }
+
+       /* 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_pr_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_pr_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 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();
+}
+



This function definition assume single CPU which is fine for now. Maybe, we could add TODO stating we need to extend the function cpu interface.
+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);
+


Is this operation valid? From the GIC specification v2 these


register are read only register and PPI register


are implementation defined. Atleast the GICD_ICFGR0 is readonly.
+       /* set PPI and SGI to 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.
+        */
+       write_gicd32(GICD_ICACTIVER(i), GICD_DEF_ICACTIVERn);
+       write_gicd32(GICD_ICENABLER(i), GICD_DEF_PPI_ICENABLERn);
+
+       /* Deactivate and enable all SGIs */
+       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(const void *fdt)
+{
+       int fdt_gic, ret;
+
+       uk_pr_info("Probing GICv2...\n");
+
+       /* Currently, we only support 1 GIC per system */
+       fdt_gic = fdt_node_offset_by_compatible_list(fdt, -1,
+                               gic_device_list);
+       if (fdt_gic < 0)
+               UK_CRASH("Could not find GICv2 Interrupt Controller!\n");
+
+       /* Get device address and size at regs region */
+       ret = fdt_get_address(fdt, fdt_gic, 0,
+                       &gic_dist_addr, &gic_dist_size);
+       if (ret < 0)
+               UK_CRASH("Could not find GICv2 distributor region!\n");
+
+       ret = fdt_get_address(fdt, fdt_gic, 1,
+                       &gic_cpuif_addr, &gic_cpuif_size);
+       if (ret < 0)
+               UK_CRASH("Could not find GICv2 cpuif region!\n");
+
+       uk_pr_info("Found GICv2 on:\n");
+       uk_pr_info("\tDistributor  : 0x%lx - 0x%lx\n",
+               gic_dist_addr, gic_dist_addr + gic_dist_size - 1);
+       uk_pr_info("\tCPU interface: 0x%lx - 0x%lx\n",
+               gic_cpuif_addr, gic_cpuif_addr + gic_cpuif_size - 1);
+
+
+       /* Initialize GICv2 distributor */
+       gic_init_dist();
+
+       /* Initialize GICv2 CPU interface */
+       gic_init_cpuif();
+
+       return 0;
+}
diff --git a/plat/drivers/include/gic/gic-v2.h 
b/plat/drivers/include/gic/gic-v2.h
new file mode 100644
index 0000000..e04542f
--- /dev/null
+++ b/plat/drivers/include/gic/gic-v2.h
@@ -0,0 +1,370 @@
+/* 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     0x80808080
+
+/*
+ * 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
+
+enum sgi_filter {
+/*
+ * Forward the interrupt to the CPU interfaces specified in the
+ * CPUTargetList field
+ */
+       GICD_SGI_FILTER_TO_LIST = 0,
+/*
+ * Forward the interrupt to all CPU interfaces except that of the
+ * processor that requested the interrupt.
+ */
+       GICD_SGI_FILTER_TO_OTHERS,
+/*
+ * Forward the interrupt only to the CPU interface of the processor
+ * that requested the interrupt.
+ */
+       GICD_SGI_FILTER_TO_SELF
+};
+
+/*
+ * 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 interrupt 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 interrupt trigger type */
+void gic_set_irq_type(uint32_t irq, int trigger);
+
+/* Initialize GICv2 from device tree */
+int _dtb_init_gic(const void *fdt);
+
+#endif //__PLAT_CMN_ARM_GICV2_H__
diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk
index 18eaca4..9ece678 100644
--- a/plat/kvm/Makefile.uk
+++ b/plat/kvm/Makefile.uk
@@ -18,6 +18,7 @@ LIBKVMPLAT_ASINCLUDES-y        += -I$(LIBKVMPLAT_BASE)/include
  LIBKVMPLAT_ASINCLUDES-y        += -I$(UK_PLAT_COMMON_BASE)/include
  LIBKVMPLAT_CINCLUDES-y         += -I$(LIBKVMPLAT_BASE)/include
  LIBKVMPLAT_CINCLUDES-y         += -I$(UK_PLAT_COMMON_BASE)/include
+LIBKVMPLAT_CINCLUDES-$(CONFIG_ARCH_ARM_64)         += 
-I$(UK_PLAT_DRIVERS_BASE)/include
LIBKVMPLAT_ASFLAGS += -DKVMPLAT
  LIBKVMPLAT_CFLAGS              += -DKVMPLAT
@@ -66,6 +67,7 @@ LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += 
$(UK_PLAT_COMMON_BASE)/arm/psci_arm64.S
  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/traps.c|common
  LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += 
$(UK_PLAT_DRIVERS_BASE)/ofw/fdt.c|common

Like the fdt driver library, it might be wise to split up this driver from the base kvm platform code. This is similar to what we have with the virtio driver and device tree driver.
+LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += 
$(UK_PLAT_DRIVERS_BASE)/gic/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/pagetable64.S


_______________________________________________
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®.