Signed-off-by: Nikhil Devshatwar <
nikh...@ti.com>
---
hypervisor/arch/arm-common/Kbuild | 1 +
hypervisor/arch/arm-common/gic-v3.c | 456 ++++++++++++++++++++++++
hypervisor/arch/arm-common/include/asm/gic_v3.h | 269 ++++++++++++++
hypervisor/arch/arm/Kbuild | 1 -
hypervisor/arch/arm/gic-v3.c | 456 ------------------------
hypervisor/arch/arm/include/asm/gic_v3.h | 269 --------------
6 files changed, 726 insertions(+), 726 deletions(-)
create mode 100644 hypervisor/arch/arm-common/gic-v3.c
create mode 100644 hypervisor/arch/arm-common/include/asm/gic_v3.h
delete mode 100644 hypervisor/arch/arm/gic-v3.c
delete mode 100644 hypervisor/arch/arm/include/asm/gic_v3.h
diff --git a/hypervisor/arch/arm-common/Kbuild b/hypervisor/arch/arm-common/Kbuild
index 7874b9e..779e204 100644
--- a/hypervisor/arch/arm-common/Kbuild
+++ b/hypervisor/arch/arm-common/Kbuild
@@ -16,5 +16,6 @@ ccflags-$(CONFIG_JAILHOUSE_GCOV) += -fprofile-arcs -ftest-coverage
OBJS-y += dbg-write.o lib.o psci.o control.o paging.o mmu_cell.o
OBJS-y += irqchip.o pci.o ivshmem.o uart-pl011.o uart-xuartps.o
OBJS-$(CONFIG_ARM_GIC_V2) += gic-v2.o
+OBJS-$(CONFIG_ARM_GIC_V3) += gic-v3.o
COMMON_OBJECTS = $(addprefix ../arm-common/,$(OBJS-y))
diff --git a/hypervisor/arch/arm-common/gic-v3.c b/hypervisor/arch/arm-common/gic-v3.c
new file mode 100644
index 0000000..2ea947f
--- /dev/null
+++ b/hypervisor/arch/arm-common/gic-v3.c
@@ -0,0 +1,456 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) ARM Limited, 2014
+ *
+ * Authors:
+ * Jean-Philippe Brucker <
jean-phili...@arm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <jailhouse/control.h>
+#include <jailhouse/mmio.h>
+#include <jailhouse/printk.h>
+#include <jailhouse/processor.h>
+#include <jailhouse/types.h>
+#include <asm/control.h>
+#include <asm/gic.h>
+#include <asm/irqchip.h>
+#include <asm/setup.h>
+#include <asm/traps.h>
+
+/*
+ * This implementation assumes that the kernel driver already initialised most
+ * of the GIC.
+ * There is almost no instruction barrier, since IRQs are always disabled in the
+ * hyp, and ERET serves as the context synchronization event.
+ */
+
+static unsigned int gic_num_lr;
+static unsigned int gic_num_priority_bits;
+static u32 gic_version;
+
+static void *gicr_base;
+
+static int gic_init(void)
+{
+ /* TODO: need to validate more? */
+ if (!(mmio_read32(gicd_base + GICD_CTLR) & GICD_CTLR_ARE_NS))
+ return trace_error(-EIO);
+
+ /* Let the per-cpu code access the redistributors */
+ gicr_base = paging_map_device(
+ system_config->platform_info.arm.gicr_base, GICR_SIZE);
+ if (!gicr_base)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void gic_clear_pending_irqs(void)
+{
+ unsigned int n;
+
+ /* Clear list registers. */
+ for (n = 0; n < gic_num_lr; n++)
+ gic_write_lr(n, 0);
+
+ /* Clear active priority bits */
+ if (gic_num_priority_bits >= 5)
+ arm_write_sysreg(ICH_AP1R0_EL2, 0);
+ if (gic_num_priority_bits >= 6)
+ arm_write_sysreg(ICH_AP1R1_EL2, 0);
+ if (gic_num_priority_bits > 6) {
+ arm_write_sysreg(ICH_AP1R2_EL2, 0);
+ arm_write_sysreg(ICH_AP1R3_EL2, 0);
+ }
+}
+
+static void gic_cpu_reset(struct per_cpu *cpu_data)
+{
+ unsigned int mnt_irq = system_config->platform_info.arm.maintenance_irq;
+ void *gicr = cpu_data->gicr_base + GICR_SGI_BASE;
+
+ gic_clear_pending_irqs();
+
+ /* Ensure all IPIs and the maintenance PPI are enabled. */
+ mmio_write32(gicr + GICR_ISENABLER, 0x0000ffff | (1 << mnt_irq));
+
+ /* Disable PPIs, except for the maintenance interrupt. */
+ mmio_write32(gicr + GICR_ICENABLER, 0xffff0000 & ~(1 << mnt_irq));
+
+ /* Deactivate all active PPIs */
+ mmio_write32(gicr + GICR_ICACTIVER, 0xffff0000);
+
+ arm_write_sysreg(ICH_VMCR_EL2, 0);
+}
+
+static int gic_cpu_init(struct per_cpu *cpu_data)
+{
+ unsigned int mnt_irq = system_config->platform_info.arm.maintenance_irq;
+ u64 typer;
+ u32 pidr;
+ u32 cell_icc_ctlr, cell_icc_pmr, cell_icc_igrpen1;
+ u32 ich_vtr;
+ u32 ich_vmcr;
+ void *redist_base = gicr_base;
+
+ /* Find redistributor */
+ do {
+ pidr = mmio_read32(redist_base + GICR_PIDR2);
+ gic_version = GICR_PIDR2_ARCH(pidr);
+ if (gic_version != 3 && gic_version != 4)
+ break;
+
+ typer = mmio_read64(redist_base + GICR_TYPER);
+ if ((typer >> 32) == cpu_data->cpu_id) {
+ cpu_data->gicr_base = redist_base;
+ break;
+ }
+
+ redist_base += gic_version == 4 ? 0x40000 : 0x20000;
+ } while (!(typer & GICR_TYPER_Last));
+
+ if (!cpu_data->gicr_base) {
+ printk("GIC: No redist found for CPU%d\n", cpu_data->cpu_id);
+ return -ENODEV;
+ }
+
+ /* Ensure all IPIs and the maintenance PPI are enabled. */
+ mmio_write32(redist_base + GICR_SGI_BASE + GICR_ISENABLER,
+ 0x0000ffff | (1 << mnt_irq));
+
+ /*
+ * Set EOIMode to 1
+ * This allow to drop the priority of level-triggered interrupts without
+ * deactivating them, and thus ensure that they won't be immediately
+ * re-triggered. (e.g. timer)
+ * They can then be injected into the guest using the LR.HW bit, and
+ * will be deactivated once the guest does an EOI after handling the
+ * interrupt source.
+ */
+ arm_read_sysreg(ICC_CTLR_EL1, cell_icc_ctlr);
+ arm_write_sysreg(ICC_CTLR_EL1, ICC_CTLR_EOImode);
+
+ arm_read_sysreg(ICC_PMR_EL1, cell_icc_pmr);
+ arm_write_sysreg(ICC_PMR_EL1, ICC_PMR_DEFAULT);
+
+ arm_read_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1);
+ arm_write_sysreg(ICC_IGRPEN1_EL1, ICC_IGRPEN1_EN);
+
+ arm_read_sysreg(ICH_VTR_EL2, ich_vtr);
+ gic_num_lr = (ich_vtr & 0xf) + 1;
+ gic_num_priority_bits = (ich_vtr >> 29) + 1;
+
+ /*
+ * Clear pending virtual IRQs in case anything is left from previous
+ * use. Physically pending IRQs will be forwarded to Linux once we
+ * enable interrupts for the hypervisor.
+ */
+ gic_clear_pending_irqs();
+
+ ich_vmcr = (cell_icc_pmr & ICC_PMR_MASK) << ICH_VMCR_VPMR_SHIFT;
+ if (cell_icc_igrpen1 & ICC_IGRPEN1_EN)
+ ich_vmcr |= ICH_VMCR_VENG1;
+ if (cell_icc_ctlr & ICC_CTLR_EOImode)
+ ich_vmcr |= ICH_VMCR_VEOIM;
+ arm_write_sysreg(ICH_VMCR_EL2, ich_vmcr);
+
+ /* After this, the cells access the virtual interface of the GIC. */
+ arm_write_sysreg(ICH_HCR_EL2, ICH_HCR_EN);
+
+ return 0;
+}
+
+static void gic_cpu_shutdown(struct per_cpu *cpu_data)
+{
+ u32 ich_vmcr, icc_ctlr, cell_icc_igrpen1;
+
+ if (!cpu_data->gicr_base)
+ return;
+
+ arm_write_sysreg(ICH_HCR_EL2, 0);
+
+ /* Disable the maintenance interrupt - not used by Linux. */
+ mmio_write32(cpu_data->gicr_base + GICR_SGI_BASE + GICR_ICENABLER,
+ 1 << system_config->platform_info.arm.maintenance_irq);
+
+ /* Restore the root config */
+ arm_read_sysreg(ICH_VMCR_EL2, ich_vmcr);
+
+ if (!(ich_vmcr & ICH_VMCR_VEOIM)) {
+ arm_read_sysreg(ICC_CTLR_EL1, icc_ctlr);
+ icc_ctlr &= ~ICC_CTLR_EOImode;
+ arm_write_sysreg(ICC_CTLR_EL1, icc_ctlr);
+ }
+ if (!(ich_vmcr & ICH_VMCR_VENG1)) {
+ arm_read_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1);
+ cell_icc_igrpen1 &= ~ICC_IGRPEN1_EN;
+ arm_write_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1);
+ }
+}
+
+static void gic_adjust_irq_target(struct cell *cell, u16 irq_id)
+{
+ void *irouter = gicd_base + GICD_IROUTER + irq_id;
+ u32 route = mmio_read32(irouter);
+
+ if (!cell_owns_cpu(cell, route))
+ mmio_write32(irouter, first_cpu(cell->cpu_set));
+}
+
+static enum mmio_result gic_handle_redist_access(void *arg,
+ struct mmio_access *mmio)
+{
+ struct cell *cell = this_cell();
+ unsigned int cpu;
+ unsigned int virt_id;
+ unsigned int redist_size = (gic_version == 4) ? 0x40000 : 0x20000;
+ void *phys_redist = NULL;
+ unsigned long offs;
+
+ /*
+ * The redistributor accessed by the cell is not the one stored in these
+ * cpu_datas, but the one associated to its virtual id. So we first
+ * need to translate the redistributor address.
+ */
+ for_each_cpu(cpu, cell->cpu_set) {
+ virt_id = arm_cpu_phys2virt(cpu);
+ offs = per_cpu(virt_id)->gicr_base - gicr_base;
+ if (mmio->address >= offs &&
+ mmio->address < offs + redist_size) {
+ phys_redist = per_cpu(cpu)->gicr_base;
+ break;
+ }
+ }
+
+ if (phys_redist == NULL)
+ return MMIO_ERROR;
+
+ mmio->address -= offs;
+
+ /* Change the ID register, all other accesses are allowed. */
+ if (!mmio->is_write) {
+ switch (mmio->address) {
+ case GICR_TYPER:
+ if (virt_id == cell->arch.last_virt_id)
+ mmio->value = GICR_TYPER_Last;
+ else
+ mmio->value = 0;
+ /* AArch64 can use a writeq for this register */
+ if (mmio->size == 8)
+ mmio->value |= (u64)virt_id << 32;
+
+ return MMIO_HANDLED;
+ case GICR_TYPER + 4:
+ /* Upper bits contain the affinity */
+ mmio->value = virt_id;
+ return MMIO_HANDLED;
+ }
+ }
+ mmio_perform_access(phys_redist, mmio);
+ return MMIO_HANDLED;
+}
+
+static int gic_cell_init(struct cell *cell)
+{
+ mmio_region_register(cell, system_config->platform_info.arm.gicr_base,
+ GICR_SIZE, gic_handle_redist_access, NULL);
+
+ return 0;
+}
+
+static int gic_send_sgi(struct sgi *sgi)
+{
+ u64 val;
+ u16 targets = sgi->targets;
+
+ if (!is_sgi(sgi->id))
+ return -EINVAL;
+
+ if (sgi->routing_mode == 2)
+ targets = 1 << phys_processor_id();
+
+ val = (u64)sgi->aff3 << ICC_SGIR_AFF3_SHIFT
+ | (u64)sgi->aff2 << ICC_SGIR_AFF2_SHIFT
+ | sgi->aff1 << ICC_SGIR_AFF1_SHIFT
+ | (targets & ICC_SGIR_TARGET_MASK)
+ | (sgi->id & 0xf) << ICC_SGIR_IRQN_SHIFT;
+
+ if (sgi->routing_mode == 1)
+ val |= ICC_SGIR_ROUTING_BIT;
+
+ /*
+ * Ensure the targets see our modifications to their per-cpu
+ * structures.
+ */
+ dsb(ish);
+
+ arm_write_sysreg(ICC_SGI1R_EL1, val);
+ isb();
+
+ return 0;
+}
+
+void gicv3_handle_sgir_write(u64 sgir)
+{
+ struct sgi sgi;
+ unsigned long routing_mode = !!(sgir & ICC_SGIR_ROUTING_BIT);
+
+ /* FIXME: clusters are not supported yet. */
+ sgi.targets = sgir & ICC_SGIR_TARGET_MASK;
+ sgi.routing_mode = routing_mode;
+ sgi.aff1 = sgir >> ICC_SGIR_AFF1_SHIFT & 0xff;
+ sgi.aff2 = sgir >> ICC_SGIR_AFF2_SHIFT & 0xff;
+ sgi.aff3 = sgir >> ICC_SGIR_AFF3_SHIFT & 0xff;
+
sgi.id = sgir >> ICC_SGIR_IRQN_SHIFT & 0xf;
+
+ gic_handle_sgir_write(&sgi, true);
+}
+
+/*
+ * GICv3 uses a 64bit register IROUTER for each IRQ
+ */
+enum mmio_result gic_handle_irq_route(struct mmio_access *mmio,
+ unsigned int irq)
+{
+ struct cell *cell = this_cell();
+ unsigned int cpu;
+
+ /* Ignore aff3 on AArch32 (return 0) */
+ if (mmio->size == 4 && (mmio->address % 8))
+ return MMIO_HANDLED;
+
+ /* SGIs and PPIs are res0 */
+ if (!is_spi(irq))
+ return MMIO_HANDLED;
+
+ /*
+ * Ignore accesses to SPIs that do not belong to the cell. This isn't
+ * forbidden, because the guest driver may simply iterate over all
+ * registers at initialisation
+ */
+ if (!irqchip_irq_in_cell(cell, irq))
+ return MMIO_HANDLED;
+
+ /* Translate the virtual cpu id into the physical one */
+ if (mmio->is_write) {
+ mmio->value = arm_cpu_virt2phys(cell, mmio->value);
+ if (mmio->value == -1) {
+ printk("Attempt to route IRQ%d outside of cell\n", irq);
+ return MMIO_ERROR;
+ }
+ mmio_perform_access(gicd_base, mmio);
+ } else {
+ cpu = mmio_read32(gicd_base + GICD_IROUTER + 8 * irq);
+ mmio->value = arm_cpu_phys2virt(cpu);
+ }
+ return MMIO_HANDLED;
+}
+
+static void gic_eoi_irq(u32 irq_id, bool deactivate)
+{
+ arm_write_sysreg(ICC_EOIR1_EL1, irq_id);
+ if (deactivate)
+ arm_write_sysreg(ICC_DIR_EL1, irq_id);
+}
+
+static int gic_inject_irq(struct per_cpu *cpu_data, u16 irq_id)
+{
+ int i;
+ int free_lr = -1;
+ u32 elsr;
+ u64 lr;
+
+ arm_read_sysreg(ICH_ELSR_EL2, elsr);
+ for (i = 0; i < gic_num_lr; i++) {
+ if ((elsr >> i) & 1) {
+ /* Entry is invalid, candidate for injection */
+ if (free_lr == -1)
+ free_lr = i;
+ continue;
+ }
+
+ /*
+ * Entry is in use, check that it doesn't match the one we want
+ * to inject.
+ */
+ lr = gic_read_lr(i);
+
+ /*
+ * A strict phys->virt id mapping is used for SPIs, so this test
+ * should be sufficient.
+ */
+ if ((u32)lr == irq_id)
+ return -EEXIST;
+ }
+
+ if (free_lr == -1)
+ /* All list registers are in use */
+ return -EBUSY;
+
+ lr = irq_id;
+ /* Only group 1 interrupts */
+ lr |= ICH_LR_GROUP_BIT;
+ lr |= ICH_LR_PENDING;
+ if (!is_sgi(irq_id)) {
+ lr |= ICH_LR_HW_BIT;
+ lr |= (u64)irq_id << ICH_LR_PHYS_ID_SHIFT;
+ }
+
+ gic_write_lr(free_lr, lr);
+
+ return 0;
+}
+
+static void gicv3_enable_maint_irq(bool enable)
+{
+ u32 hcr;
+
+ arm_read_sysreg(ICH_HCR_EL2, hcr);
+ if (enable)
+ hcr |= ICH_HCR_UIE;
+ else
+ hcr &= ~ICH_HCR_UIE;
+ arm_write_sysreg(ICH_HCR_EL2, hcr);
+}
+
+static bool gicv3_has_pending_irqs(void)
+{
+ unsigned int n;
+
+ for (n = 0; n < gic_num_lr; n++)
+ if (gic_read_lr(n) & ICH_LR_PENDING)
+ return true;
+
+ return false;
+}
+
+static enum mmio_result gicv3_handle_irq_target(struct mmio_access *mmio,
+ unsigned int irq)
+{
+ /* ignore writes, we are in affinity routing mode */
+ return MMIO_HANDLED;
+}
+
+unsigned int irqchip_mmio_count_regions(struct cell *cell)
+{
+ return 2;
+}
+
+struct irqchip_ops irqchip = {
+ .init = gic_init,
+ .cpu_init = gic_cpu_init,
+ .cpu_reset = gic_cpu_reset,
+ .cpu_shutdown = gic_cpu_shutdown,
+ .cell_init = gic_cell_init,
+ .adjust_irq_target = gic_adjust_irq_target,
+ .send_sgi = gic_send_sgi,
+ .inject_irq = gic_inject_irq,
+ .enable_maint_irq = gicv3_enable_maint_irq,
+ .has_pending_irqs = gicv3_has_pending_irqs,
+ .eoi_irq = gic_eoi_irq,
+ .handle_irq_target = gicv3_handle_irq_target,
+};
diff --git a/hypervisor/arch/arm-common/include/asm/gic_v3.h b/hypervisor/arch/arm-common/include/asm/gic_v3.h
new file mode 100644
index 0000000..d1b9346
--- /dev/null
+++ b/hypervisor/arch/arm-common/include/asm/gic_v3.h
@@ -0,0 +1,269 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) ARM Limited, 2014
+ *
+ * Authors:
+ * Jean-Philippe Brucker <
jean-phili...@arm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef _JAILHOUSE_ASM_GIC_V3_H
+#define _JAILHOUSE_ASM_GIC_V3_H
+
+#include <asm/sysregs.h>
+
+#define GICD_SIZE 0x10000
+#define GICR_SIZE 0x100000
+
+#define GICD_CIDR0 0xfff0
+#define GICD_CIDR1 0xfff4
+#define GICD_CIDR2 0xfff8
+#define GICD_CIDR3 0xfffc
+
+#define GICD_PIDR0 0xffe0
+#define GICD_PIDR1 0xffe4
+#define GICD_PIDR2 0xffe8
+#define GICD_PIDR3 0xffec
+#define GICD_PIDR4 0xffd0
+#define GICD_PIDR5 0xffd4
+#define GICD_PIDR6 0xffd8
+#define GICD_PIDR7 0xffdc
+
+#define GICR_CTLR GICD_CTLR
+#define GICR_TYPER 0x0008
+#define GICR_WAKER 0x0014
+#define GICR_CIDR0 GICD_CIDR0
+#define GICR_CIDR1 GICD_CIDR1
+#define GICR_CIDR2 GICD_CIDR2
+#define GICR_CIDR3 GICD_CIDR3
+#define GICR_PIDR0 GICD_PIDR0
+#define GICR_PIDR1 GICD_PIDR1
+#define GICR_PIDR2 GICD_PIDR2
+#define GICR_PIDR3 GICD_PIDR3
+#define GICR_PIDR4 GICD_PIDR4
+#define GICR_PIDR5 GICD_PIDR5
+#define GICR_PIDR6 GICD_PIDR6
+#define GICR_PIDR7 GICD_PIDR7
+
+#define GICR_SGI_BASE 0x10000
+#define GICR_IGROUPR GICD_IGROUPR
+#define GICR_ISENABLER GICD_ISENABLER
+#define GICR_ICENABLER GICD_ICENABLER
+#define GICR_ISACTIVER GICD_ISACTIVER
+#define GICR_ICACTIVER GICD_ICACTIVER
+#define GICR_IPRIORITY GICD_IPRIORITY
+
+#define GICR_TYPER_Last (1 << 4)
+#define GICR_PIDR2_ARCH GICD_PIDR2_ARCH
+
+#define ICC_IAR1_EL1 SYSREG_32(0, c12, c12, 0)
+#define ICC_EOIR1_EL1 SYSREG_32(0, c12, c12, 1)
+#define ICC_HPPIR1_EL1 SYSREG_32(0, c12, c12, 2)
+#define ICC_BPR1_EL1 SYSREG_32(0, c12, c12, 3)
+#define ICC_DIR_EL1 SYSREG_32(0, c12, c11, 1)
+#define ICC_PMR_EL1 SYSREG_32(0, c4, c6, 0)
+#define ICC_RPR_EL1 SYSREG_32(0, c12, c11, 3)
+#define ICC_CTLR_EL1 SYSREG_32(0, c12, c12, 4)
+#define ICC_SRE_EL1 SYSREG_32(0, c12, c12, 5)
+#define ICC_SRE_EL2 SYSREG_32(4, c12, c9, 5)
+#define ICC_IGRPEN1_EL1 SYSREG_32(0, c12, c12, 7)
+#define ICC_SGI1R_EL1 SYSREG_64(0, c12)
+#define ICC_AP1R0_EL1 SYSREG_32(0, c12, c9, 0)
+#define ICC_AP1R1_EL1 SYSREG_32(0, c12, c9, 1)
+#define ICC_AP1R2_EL1 SYSREG_32(0, c12, c9, 2)
+#define ICC_AP1R3_EL1 SYSREG_32(0, c12, c9, 3)
+
+#define ICH_HCR_EL2 SYSREG_32(4, c12, c11, 0)
+#define ICH_VTR_EL2 SYSREG_32(4, c12, c11, 1)
+#define ICH_MISR_EL2 SYSREG_32(4, c12, c11, 2)
+#define ICH_EISR_EL2 SYSREG_32(4, c12, c11, 3)
+#define ICH_ELSR_EL2 SYSREG_32(4, c12, c11, 5)
+#define ICH_VMCR_EL2 SYSREG_32(4, c12, c11, 7)
+#define ICH_AP1R0_EL2 SYSREG_32(4, c12, c9, 0)
+#define ICH_AP1R1_EL2 SYSREG_32(4, c12, c9, 1)
+#define ICH_AP1R2_EL2 SYSREG_32(4, c12, c9, 2)
+#define ICH_AP1R3_EL2 SYSREG_32(4, c12, c9, 3)
+
+/* Different on AArch32 and AArch64... */
+#define __ICH_LR0(x) SYSREG_32(4, c12, c12, x)
+#define __ICH_LR8(x) SYSREG_32(4, c12, c13, x)
+#define __ICH_LRC0(x) SYSREG_32(4, c12, c14, x)
+#define __ICH_LRC8(x) SYSREG_32(4, c12, c15, x)
+
+#define ICH_LR0 __ICH_LR0(0)
+#define ICH_LR1 __ICH_LR0(1)
+#define ICH_LR2 __ICH_LR0(2)
+#define ICH_LR3 __ICH_LR0(3)
+#define ICH_LR4 __ICH_LR0(4)
+#define ICH_LR5 __ICH_LR0(5)
+#define ICH_LR6 __ICH_LR0(6)
+#define ICH_LR7 __ICH_LR0(7)
+#define ICH_LR8 __ICH_LR8(0)
+#define ICH_LR9 __ICH_LR8(1)
+#define ICH_LR10 __ICH_LR8(2)
+#define ICH_LR11 __ICH_LR8(3)
+#define ICH_LR12 __ICH_LR8(4)
+#define ICH_LR13 __ICH_LR8(5)
+#define ICH_LR14 __ICH_LR8(6)
+#define ICH_LR15 __ICH_LR8(7)
+#define ICH_LRC0 __ICH_LRC0(0)
+#define ICH_LRC1 __ICH_LRC0(1)
+#define ICH_LRC2 __ICH_LRC0(2)
+#define ICH_LRC3 __ICH_LRC0(3)
+#define ICH_LRC4 __ICH_LRC0(4)
+#define ICH_LRC5 __ICH_LRC0(5)
+#define ICH_LRC6 __ICH_LRC0(6)
+#define ICH_LRC7 __ICH_LRC0(7)
+#define ICH_LRC8 __ICH_LRC8(0)
+#define ICH_LRC9 __ICH_LRC8(1)
+#define ICH_LRC10 __ICH_LRC8(2)
+#define ICH_LRC11 __ICH_LRC8(3)
+#define ICH_LRC12 __ICH_LRC8(4)
+#define ICH_LRC13 __ICH_LRC8(5)
+#define ICH_LRC14 __ICH_LRC8(6)
+#define ICH_LRC15 __ICH_LRC8(7)
+
+#define ICC_CTLR_EOImode 0x2
+#define ICC_PMR_MASK 0xff
+#define ICC_PMR_DEFAULT 0xf0
+#define ICC_IGRPEN1_EN 0x1
+
+#define ICC_SGIR_AFF3_SHIFT 48
+#define ICC_SGIR_AFF2_SHIFT 32
+#define ICC_SGIR_AFF1_SHIFT 16
+#define ICC_SGIR_TARGET_MASK 0xffff
+#define ICC_SGIR_IRQN_SHIFT 24
+#define ICC_SGIR_ROUTING_BIT (1ULL << 40)
+
+#define ICH_HCR_EN (1 << 0)
+#define ICH_HCR_UIE (1 << 1)
+#define ICH_HCR_LRENPIE (1 << 2)
+#define ICH_HCR_NPIE (1 << 3)
+#define ICH_HCR_VGRP0EIE (1 << 4)
+#define ICH_HCR_VGRP0DIE (1 << 5)
+#define ICH_HCR_VGRP1EIE (1 << 6)
+#define ICH_HCR_VGRP1DIE (1 << 7)
+#define ICH_HCR_VARE (1 << 9)
+#define ICH_HCR_TC (1 << 10)
+#define ICH_HCR_TALL0 (1 << 11)
+#define ICH_HCR_TALL1 (1 << 12)
+#define ICH_HCR_TSEI (1 << 13)
+#define ICH_HCR_EOICount (0x1f << 27)
+
+#define ICH_MISR_EOI (1 << 0)
+#define ICH_MISR_U (1 << 1)
+#define ICH_MISR_LRENP (1 << 2)
+#define ICH_MISR_NP (1 << 3)
+#define ICH_MISR_VGRP0E (1 << 4)
+#define ICH_MISR_VGRP0D (1 << 5)
+#define ICH_MISR_VGRP1E (1 << 6)
+#define ICH_MISR_VGRP1D (1 << 7)
+
+#define ICH_VMCR_VENG0 (1 << 0)
+#define ICH_VMCR_VENG1 (1 << 1)
+#define ICH_VMCR_VACKCTL (1 << 2)
+#define ICH_VMCR_VFIQEN (1 << 3)
+#define ICH_VMCR_VCBPR (1 << 4)
+#define ICH_VMCR_VEOIM (1 << 9)
+#define ICH_VMCR_VBPR1_SHIFT 18
+#define ICH_VMCR_VBPR0_SHIFT 21
+#define ICH_VMCR_VPMR_SHIFT 24
+
+/* List registers upper bits */
+#define ICH_LR_INVALID (0x0ULL << 62)
+#define ICH_LR_PENDING (0x1ULL << 62)
+#define ICH_LR_ACTIVE (0x2ULL << 62)
+#define ICH_LR_PENDACTIVE (0x3ULL << 62)
+#define ICH_LR_HW_BIT (0x1ULL << 61)
+#define ICH_LR_GROUP_BIT (0x1ULL << 60)
+#define ICH_LR_PRIORITY_SHIFT 48
+#define ICH_LR_SGI_EOI (0x1ULL << 41)
+#define ICH_LR_PHYS_ID_SHIFT 32
+
+#ifndef __ASSEMBLY__
+
+#include <jailhouse/types.h>
+
+static inline u64 gic_read_lr(unsigned int n)
+{
+ u32 lr, lrc;
+
+ switch (n) {
+#define __READ_LR(n) \
+ case n: \
+ arm_read_sysreg(ICH_LR##n, lr); \
+ arm_read_sysreg(ICH_LRC##n, lrc); \
+ break;
+
+ __READ_LR(0)
+ __READ_LR(1)
+ __READ_LR(2)
+ __READ_LR(3)
+ __READ_LR(4)
+ __READ_LR(5)
+ __READ_LR(6)
+ __READ_LR(7)
+ __READ_LR(8)
+ __READ_LR(9)
+ __READ_LR(10)
+ __READ_LR(11)
+ __READ_LR(12)
+ __READ_LR(13)
+ __READ_LR(14)
+ __READ_LR(15)
+#undef __READ_LR
+
+ default:
+ return (u64)(-1);
+ }
+
+ return (u64)lrc << 32 | lr;
+}
+
+static inline void gic_write_lr(unsigned int n, u64 val)
+{
+ u32 lr = (u32)val;
+ u32 lrc = val >> 32;
+
+ switch (n) {
+#define __WRITE_LR(n) \
+ case n: \
+ arm_write_sysreg(ICH_LR##n, lr); \
+ arm_write_sysreg(ICH_LRC##n, lrc); \
+ break;
+
+ __WRITE_LR(0)
+ __WRITE_LR(1)
+ __WRITE_LR(2)
+ __WRITE_LR(3)
+ __WRITE_LR(4)
+ __WRITE_LR(5)
+ __WRITE_LR(6)
+ __WRITE_LR(7)
+ __WRITE_LR(8)
+ __WRITE_LR(9)
+ __WRITE_LR(10)
+ __WRITE_LR(11)
+ __WRITE_LR(12)
+ __WRITE_LR(13)
+ __WRITE_LR(14)
+ __WRITE_LR(15)
+#undef __WRITE_LR
+ }
+}
+
+static inline u32 gic_read_iar(void)
+{
+ u32 irq_id;
+
+ arm_read_sysreg(ICC_IAR1_EL1, irq_id);
+ return irq_id;
+}
+
+void gicv3_handle_sgir_write(u64 sgir);
+
+#endif /* __ASSEMBLY__ */
+#endif /* _JAILHOUSE_ASM_GIC_V3_H */
diff --git a/hypervisor/arch/arm/Kbuild b/hypervisor/arch/arm/Kbuild
index b996871..04e835c 100644
--- a/hypervisor/arch/arm/Kbuild
+++ b/hypervisor/arch/arm/Kbuild
@@ -26,5 +26,4 @@ obj-y += mmu_hyp.o caches.o mach-stubs.o
# should switch to that for higher granularity, but gcc7 is not even there
CFLAGS_mmu_hyp.o += -fno-profile-arcs -fno-test-coverage
-obj-$(CONFIG_ARM_GIC_V3) += gic-v3.o
obj-$(CONFIG_MACH_VEXPRESS) += mach-vexpress.o
diff --git a/hypervisor/arch/arm/gic-v3.c b/hypervisor/arch/arm/gic-v3.c
deleted file mode 100644
index 2ea947f..0000000
--- a/hypervisor/arch/arm/gic-v3.c
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Jailhouse, a Linux-based partitioning hypervisor
- *
- * Copyright (c) ARM Limited, 2014
- *
- * Authors:
- * Jean-Philippe Brucker <
jean-phili...@arm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-#include <jailhouse/control.h>
-#include <jailhouse/mmio.h>
-#include <jailhouse/printk.h>
-#include <jailhouse/processor.h>
-#include <jailhouse/types.h>
-#include <asm/control.h>
-#include <asm/gic.h>
-#include <asm/irqchip.h>
-#include <asm/setup.h>
-#include <asm/traps.h>
-
-/*
- * This implementation assumes that the kernel driver already initialised most
- * of the GIC.
- * There is almost no instruction barrier, since IRQs are always disabled in the
- * hyp, and ERET serves as the context synchronization event.
- */
-
-static unsigned int gic_num_lr;
-static unsigned int gic_num_priority_bits;
-static u32 gic_version;
-
-static void *gicr_base;
-
-static int gic_init(void)
-{
- /* TODO: need to validate more? */
- if (!(mmio_read32(gicd_base + GICD_CTLR) & GICD_CTLR_ARE_NS))
- return trace_error(-EIO);
-
- /* Let the per-cpu code access the redistributors */
- gicr_base = paging_map_device(
- system_config->platform_info.arm.gicr_base, GICR_SIZE);
- if (!gicr_base)
- return -ENOMEM;
-
- return 0;
-}
-
-static void gic_clear_pending_irqs(void)
-{
- unsigned int n;
-
- /* Clear list registers. */
- for (n = 0; n < gic_num_lr; n++)
- gic_write_lr(n, 0);
-
- /* Clear active priority bits */
- if (gic_num_priority_bits >= 5)
- arm_write_sysreg(ICH_AP1R0_EL2, 0);
- if (gic_num_priority_bits >= 6)
- arm_write_sysreg(ICH_AP1R1_EL2, 0);
- if (gic_num_priority_bits > 6) {
- arm_write_sysreg(ICH_AP1R2_EL2, 0);
- arm_write_sysreg(ICH_AP1R3_EL2, 0);
- }
-}
-
-static void gic_cpu_reset(struct per_cpu *cpu_data)
-{
- unsigned int mnt_irq = system_config->platform_info.arm.maintenance_irq;
- void *gicr = cpu_data->gicr_base + GICR_SGI_BASE;
-
- gic_clear_pending_irqs();
-
- /* Ensure all IPIs and the maintenance PPI are enabled. */
- mmio_write32(gicr + GICR_ISENABLER, 0x0000ffff | (1 << mnt_irq));
-
- /* Disable PPIs, except for the maintenance interrupt. */
- mmio_write32(gicr + GICR_ICENABLER, 0xffff0000 & ~(1 << mnt_irq));
-
- /* Deactivate all active PPIs */
- mmio_write32(gicr + GICR_ICACTIVER, 0xffff0000);
-
- arm_write_sysreg(ICH_VMCR_EL2, 0);
-}
-
-static int gic_cpu_init(struct per_cpu *cpu_data)
-{
- unsigned int mnt_irq = system_config->platform_info.arm.maintenance_irq;
- u64 typer;
- u32 pidr;
- u32 cell_icc_ctlr, cell_icc_pmr, cell_icc_igrpen1;
- u32 ich_vtr;
- u32 ich_vmcr;
- void *redist_base = gicr_base;
-
- /* Find redistributor */
- do {
- pidr = mmio_read32(redist_base + GICR_PIDR2);
- gic_version = GICR_PIDR2_ARCH(pidr);
- if (gic_version != 3 && gic_version != 4)
- break;
-
- typer = mmio_read64(redist_base + GICR_TYPER);
- if ((typer >> 32) == cpu_data->cpu_id) {
- cpu_data->gicr_base = redist_base;
- break;
- }
-
- redist_base += gic_version == 4 ? 0x40000 : 0x20000;
- } while (!(typer & GICR_TYPER_Last));
-
- if (!cpu_data->gicr_base) {
- printk("GIC: No redist found for CPU%d\n", cpu_data->cpu_id);
- return -ENODEV;
- }
-
- /* Ensure all IPIs and the maintenance PPI are enabled. */
- mmio_write32(redist_base + GICR_SGI_BASE + GICR_ISENABLER,
- 0x0000ffff | (1 << mnt_irq));
-
- /*
- * Set EOIMode to 1
- * This allow to drop the priority of level-triggered interrupts without
- * deactivating them, and thus ensure that they won't be immediately
- * re-triggered. (e.g. timer)
- * They can then be injected into the guest using the LR.HW bit, and
- * will be deactivated once the guest does an EOI after handling the
- * interrupt source.
- */
- arm_read_sysreg(ICC_CTLR_EL1, cell_icc_ctlr);
- arm_write_sysreg(ICC_CTLR_EL1, ICC_CTLR_EOImode);
-
- arm_read_sysreg(ICC_PMR_EL1, cell_icc_pmr);
- arm_write_sysreg(ICC_PMR_EL1, ICC_PMR_DEFAULT);
-
- arm_read_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1);
- arm_write_sysreg(ICC_IGRPEN1_EL1, ICC_IGRPEN1_EN);
-
- arm_read_sysreg(ICH_VTR_EL2, ich_vtr);
- gic_num_lr = (ich_vtr & 0xf) + 1;
- gic_num_priority_bits = (ich_vtr >> 29) + 1;
-
- /*
- * Clear pending virtual IRQs in case anything is left from previous
- * use. Physically pending IRQs will be forwarded to Linux once we
- * enable interrupts for the hypervisor.
- */
- gic_clear_pending_irqs();
-
- ich_vmcr = (cell_icc_pmr & ICC_PMR_MASK) << ICH_VMCR_VPMR_SHIFT;
- if (cell_icc_igrpen1 & ICC_IGRPEN1_EN)
- ich_vmcr |= ICH_VMCR_VENG1;
- if (cell_icc_ctlr & ICC_CTLR_EOImode)
- ich_vmcr |= ICH_VMCR_VEOIM;
- arm_write_sysreg(ICH_VMCR_EL2, ich_vmcr);
-
- /* After this, the cells access the virtual interface of the GIC. */
- arm_write_sysreg(ICH_HCR_EL2, ICH_HCR_EN);
-
- return 0;
-}
-
-static void gic_cpu_shutdown(struct per_cpu *cpu_data)
-{
- u32 ich_vmcr, icc_ctlr, cell_icc_igrpen1;
-
- if (!cpu_data->gicr_base)
- return;
-
- arm_write_sysreg(ICH_HCR_EL2, 0);
-
- /* Disable the maintenance interrupt - not used by Linux. */
- mmio_write32(cpu_data->gicr_base + GICR_SGI_BASE + GICR_ICENABLER,
- 1 << system_config->platform_info.arm.maintenance_irq);
-
- /* Restore the root config */
- arm_read_sysreg(ICH_VMCR_EL2, ich_vmcr);
-
- if (!(ich_vmcr & ICH_VMCR_VEOIM)) {
- arm_read_sysreg(ICC_CTLR_EL1, icc_ctlr);
- icc_ctlr &= ~ICC_CTLR_EOImode;
- arm_write_sysreg(ICC_CTLR_EL1, icc_ctlr);
- }
- if (!(ich_vmcr & ICH_VMCR_VENG1)) {
- arm_read_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1);
- cell_icc_igrpen1 &= ~ICC_IGRPEN1_EN;
- arm_write_sysreg(ICC_IGRPEN1_EL1, cell_icc_igrpen1);
- }
-}
-
-static void gic_adjust_irq_target(struct cell *cell, u16 irq_id)
-{
- void *irouter = gicd_base + GICD_IROUTER + irq_id;
- u32 route = mmio_read32(irouter);
-
- if (!cell_owns_cpu(cell, route))
- mmio_write32(irouter, first_cpu(cell->cpu_set));
-}
-
-static enum mmio_result gic_handle_redist_access(void *arg,
- struct mmio_access *mmio)
-{
- struct cell *cell = this_cell();
- unsigned int cpu;
- unsigned int virt_id;
- unsigned int redist_size = (gic_version == 4) ? 0x40000 : 0x20000;
- void *phys_redist = NULL;
- unsigned long offs;
-
- /*
- * The redistributor accessed by the cell is not the one stored in these
- * cpu_datas, but the one associated to its virtual id. So we first
- * need to translate the redistributor address.
- */
- for_each_cpu(cpu, cell->cpu_set) {
- virt_id = arm_cpu_phys2virt(cpu);
- offs = per_cpu(virt_id)->gicr_base - gicr_base;
- if (mmio->address >= offs &&
- mmio->address < offs + redist_size) {
- phys_redist = per_cpu(cpu)->gicr_base;
- break;
- }
- }
-
- if (phys_redist == NULL)
- return MMIO_ERROR;
-
- mmio->address -= offs;
-
- /* Change the ID register, all other accesses are allowed. */
- if (!mmio->is_write) {
- switch (mmio->address) {
- case GICR_TYPER:
- if (virt_id == cell->arch.last_virt_id)
- mmio->value = GICR_TYPER_Last;
- else
- mmio->value = 0;
- /* AArch64 can use a writeq for this register */
- if (mmio->size == 8)
- mmio->value |= (u64)virt_id << 32;
-
- return MMIO_HANDLED;
- case GICR_TYPER + 4:
- /* Upper bits contain the affinity */
- mmio->value = virt_id;
- return MMIO_HANDLED;
- }
- }
- mmio_perform_access(phys_redist, mmio);
- return MMIO_HANDLED;
-}
-
-static int gic_cell_init(struct cell *cell)
-{
- mmio_region_register(cell, system_config->platform_info.arm.gicr_base,
- GICR_SIZE, gic_handle_redist_access, NULL);
-
- return 0;
-}
-
-static int gic_send_sgi(struct sgi *sgi)
-{
- u64 val;
- u16 targets = sgi->targets;
-
- if (!is_sgi(sgi->id))
- return -EINVAL;
-
- if (sgi->routing_mode == 2)
- targets = 1 << phys_processor_id();
-
- val = (u64)sgi->aff3 << ICC_SGIR_AFF3_SHIFT
- | (u64)sgi->aff2 << ICC_SGIR_AFF2_SHIFT
- | sgi->aff1 << ICC_SGIR_AFF1_SHIFT
- | (targets & ICC_SGIR_TARGET_MASK)
- | (sgi->id & 0xf) << ICC_SGIR_IRQN_SHIFT;
-
- if (sgi->routing_mode == 1)
- val |= ICC_SGIR_ROUTING_BIT;
-
- /*
- * Ensure the targets see our modifications to their per-cpu
- * structures.
- */
- dsb(ish);
-
- arm_write_sysreg(ICC_SGI1R_EL1, val);
- isb();
-
- return 0;
-}
-
-void gicv3_handle_sgir_write(u64 sgir)
-{
- struct sgi sgi;
- unsigned long routing_mode = !!(sgir & ICC_SGIR_ROUTING_BIT);
-
- /* FIXME: clusters are not supported yet. */
- sgi.targets = sgir & ICC_SGIR_TARGET_MASK;
- sgi.routing_mode = routing_mode;
- sgi.aff1 = sgir >> ICC_SGIR_AFF1_SHIFT & 0xff;
- sgi.aff2 = sgir >> ICC_SGIR_AFF2_SHIFT & 0xff;
- sgi.aff3 = sgir >> ICC_SGIR_AFF3_SHIFT & 0xff;
-
sgi.id = sgir >> ICC_SGIR_IRQN_SHIFT & 0xf;
-
- gic_handle_sgir_write(&sgi, true);
-}
-
-/*
- * GICv3 uses a 64bit register IROUTER for each IRQ
- */
-enum mmio_result gic_handle_irq_route(struct mmio_access *mmio,
- unsigned int irq)
-{
- struct cell *cell = this_cell();
- unsigned int cpu;
-
- /* Ignore aff3 on AArch32 (return 0) */
- if (mmio->size == 4 && (mmio->address % 8))
- return MMIO_HANDLED;
-
- /* SGIs and PPIs are res0 */
- if (!is_spi(irq))
- return MMIO_HANDLED;
-
- /*
- * Ignore accesses to SPIs that do not belong to the cell. This isn't
- * forbidden, because the guest driver may simply iterate over all
- * registers at initialisation
- */
- if (!irqchip_irq_in_cell(cell, irq))
- return MMIO_HANDLED;
-
- /* Translate the virtual cpu id into the physical one */
- if (mmio->is_write) {
- mmio->value = arm_cpu_virt2phys(cell, mmio->value);
- if (mmio->value == -1) {
- printk("Attempt to route IRQ%d outside of cell\n", irq);
- return MMIO_ERROR;
- }
- mmio_perform_access(gicd_base, mmio);
- } else {
- cpu = mmio_read32(gicd_base + GICD_IROUTER + 8 * irq);
- mmio->value = arm_cpu_phys2virt(cpu);
- }
- return MMIO_HANDLED;
-}
-
-static void gic_eoi_irq(u32 irq_id, bool deactivate)
-{
- arm_write_sysreg(ICC_EOIR1_EL1, irq_id);
- if (deactivate)
- arm_write_sysreg(ICC_DIR_EL1, irq_id);
-}
-
-static int gic_inject_irq(struct per_cpu *cpu_data, u16 irq_id)
-{
- int i;
- int free_lr = -1;
- u32 elsr;
- u64 lr;
-
- arm_read_sysreg(ICH_ELSR_EL2, elsr);
- for (i = 0; i < gic_num_lr; i++) {
- if ((elsr >> i) & 1) {
- /* Entry is invalid, candidate for injection */
- if (free_lr == -1)
- free_lr = i;
- continue;
- }
-
- /*
- * Entry is in use, check that it doesn't match the one we want
- * to inject.
- */
- lr = gic_read_lr(i);
-
- /*
- * A strict phys->virt id mapping is used for SPIs, so this test
- * should be sufficient.
- */
- if ((u32)lr == irq_id)
- return -EEXIST;
- }
-
- if (free_lr == -1)
- /* All list registers are in use */
- return -EBUSY;
-
- lr = irq_id;
- /* Only group 1 interrupts */
- lr |= ICH_LR_GROUP_BIT;
- lr |= ICH_LR_PENDING;
- if (!is_sgi(irq_id)) {
- lr |= ICH_LR_HW_BIT;
- lr |= (u64)irq_id << ICH_LR_PHYS_ID_SHIFT;
- }
-
- gic_write_lr(free_lr, lr);
-
- return 0;
-}
-
-static void gicv3_enable_maint_irq(bool enable)
-{
- u32 hcr;
-
- arm_read_sysreg(ICH_HCR_EL2, hcr);
- if (enable)
- hcr |= ICH_HCR_UIE;
- else
- hcr &= ~ICH_HCR_UIE;
- arm_write_sysreg(ICH_HCR_EL2, hcr);
-}
-
-static bool gicv3_has_pending_irqs(void)
-{
- unsigned int n;
-
- for (n = 0; n < gic_num_lr; n++)
- if (gic_read_lr(n) & ICH_LR_PENDING)
- return true;
-
- return false;
-}
-
-static enum mmio_result gicv3_handle_irq_target(struct mmio_access *mmio,
- unsigned int irq)
-{
- /* ignore writes, we are in affinity routing mode */
- return MMIO_HANDLED;
-}
-
-unsigned int irqchip_mmio_count_regions(struct cell *cell)
-{
- return 2;
-}
-
-struct irqchip_ops irqchip = {
- .init = gic_init,
- .cpu_init = gic_cpu_init,
- .cpu_reset = gic_cpu_reset,
- .cpu_shutdown = gic_cpu_shutdown,
- .cell_init = gic_cell_init,
- .adjust_irq_target = gic_adjust_irq_target,
- .send_sgi = gic_send_sgi,
- .inject_irq = gic_inject_irq,
- .enable_maint_irq = gicv3_enable_maint_irq,
- .has_pending_irqs = gicv3_has_pending_irqs,
- .eoi_irq = gic_eoi_irq,
- .handle_irq_target = gicv3_handle_irq_target,
-};
diff --git a/hypervisor/arch/arm/include/asm/gic_v3.h b/hypervisor/arch/arm/include/asm/gic_v3.h
deleted file mode 100644
index d1b9346..0000000
--- a/hypervisor/arch/arm/include/asm/gic_v3.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Jailhouse, a Linux-based partitioning hypervisor
- *
- * Copyright (c) ARM Limited, 2014
- *
- * Authors:
- * Jean-Philippe Brucker <
jean-phili...@arm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-#ifndef _JAILHOUSE_ASM_GIC_V3_H
-#define _JAILHOUSE_ASM_GIC_V3_H
-
-#include <asm/sysregs.h>
-
-#define GICD_SIZE 0x10000
-#define GICR_SIZE 0x100000
-
-#define GICD_CIDR0 0xfff0
-#define GICD_CIDR1 0xfff4
-#define GICD_CIDR2 0xfff8
-#define GICD_CIDR3 0xfffc
-
-#define GICD_PIDR0 0xffe0
-#define GICD_PIDR1 0xffe4
-#define GICD_PIDR2 0xffe8
-#define GICD_PIDR3 0xffec
-#define GICD_PIDR4 0xffd0
-#define GICD_PIDR5 0xffd4
-#define GICD_PIDR6 0xffd8
-#define GICD_PIDR7 0xffdc
-
-#define GICR_CTLR GICD_CTLR
-#define GICR_TYPER 0x0008
-#define GICR_WAKER 0x0014
-#define GICR_CIDR0 GICD_CIDR0
-#define GICR_CIDR1 GICD_CIDR1
-#define GICR_CIDR2 GICD_CIDR2
-#define GICR_CIDR3 GICD_CIDR3
-#define GICR_PIDR0 GICD_PIDR0
-#define GICR_PIDR1 GICD_PIDR1
-#define GICR_PIDR2 GICD_PIDR2
-#define GICR_PIDR3 GICD_PIDR3
-#define GICR_PIDR4 GICD_PIDR4
-#define GICR_PIDR5 GICD_PIDR5
-#define GICR_PIDR6 GICD_PIDR6
-#define GICR_PIDR7 GICD_PIDR7
-
-#define GICR_SGI_BASE 0x10000
-#define GICR_IGROUPR GICD_IGROUPR
-#define GICR_ISENABLER GICD_ISENABLER
-#define GICR_ICENABLER GICD_ICENABLER
-#define GICR_ISACTIVER GICD_ISACTIVER
-#define GICR_ICACTIVER GICD_ICACTIVER
-#define GICR_IPRIORITY GICD_IPRIORITY
-
-#define GICR_TYPER_Last (1 << 4)
-#define GICR_PIDR2_ARCH GICD_PIDR2_ARCH
-
-#define ICC_IAR1_EL1 SYSREG_32(0, c12, c12, 0)
-#define ICC_EOIR1_EL1 SYSREG_32(0, c12, c12, 1)
-#define ICC_HPPIR1_EL1 SYSREG_32(0, c12, c12, 2)
-#define ICC_BPR1_EL1 SYSREG_32(0, c12, c12, 3)
-#define ICC_DIR_EL1 SYSREG_32(0, c12, c11, 1)
-#define ICC_PMR_EL1 SYSREG_32(0, c4, c6, 0)
-#define ICC_RPR_EL1 SYSREG_32(0, c12, c11, 3)
-#define ICC_CTLR_EL1 SYSREG_32(0, c12, c12, 4)
-#define ICC_SRE_EL1 SYSREG_32(0, c12, c12, 5)
-#define ICC_SRE_EL2 SYSREG_32(4, c12, c9, 5)
-#define ICC_IGRPEN1_EL1 SYSREG_32(0, c12, c12, 7)
-#define ICC_SGI1R_EL1 SYSREG_64(0, c12)
-#define ICC_AP1R0_EL1 SYSREG_32(0, c12, c9, 0)
-#define ICC_AP1R1_EL1 SYSREG_32(0, c12, c9, 1)
-#define ICC_AP1R2_EL1 SYSREG_32(0, c12, c9, 2)
-#define ICC_AP1R3_EL1 SYSREG_32(0, c12, c9, 3)
-
-#define ICH_HCR_EL2 SYSREG_32(4, c12, c11, 0)
-#define ICH_VTR_EL2 SYSREG_32(4, c12, c11, 1)
-#define ICH_MISR_EL2 SYSREG_32(4, c12, c11, 2)
-#define ICH_EISR_EL2 SYSREG_32(4, c12, c11, 3)
-#define ICH_ELSR_EL2 SYSREG_32(4, c12, c11, 5)
-#define ICH_VMCR_EL2 SYSREG_32(4, c12, c11, 7)
-#define ICH_AP1R0_EL2 SYSREG_32(4, c12, c9, 0)
-#define ICH_AP1R1_EL2 SYSREG_32(4, c12, c9, 1)
-#define ICH_AP1R2_EL2 SYSREG_32(4, c12, c9, 2)
-#define ICH_AP1R3_EL2 SYSREG_32(4, c12, c9, 3)
-
-/* Different on AArch32 and AArch64... */
-#define __ICH_LR0(x) SYSREG_32(4, c12, c12, x)
-#define __ICH_LR8(x) SYSREG_32(4, c12, c13, x)
-#define __ICH_LRC0(x) SYSREG_32(4, c12, c14, x)
-#define __ICH_LRC8(x) SYSREG_32(4, c12, c15, x)
-
-#define ICH_LR0 __ICH_LR0(0)
-#define ICH_LR1 __ICH_LR0(1)
-#define ICH_LR2 __ICH_LR0(2)
-#define ICH_LR3 __ICH_LR0(3)
-#define ICH_LR4 __ICH_LR0(4)
-#define ICH_LR5 __ICH_LR0(5)
-#define ICH_LR6 __ICH_LR0(6)
-#define ICH_LR7 __ICH_LR0(7)
-#define ICH_LR8 __ICH_LR8(0)
-#define ICH_LR9 __ICH_LR8(1)
-#define ICH_LR10 __ICH_LR8(2)
-#define ICH_LR11 __ICH_LR8(3)
-#define ICH_LR12 __ICH_LR8(4)
-#define ICH_LR13 __ICH_LR8(5)
-#define ICH_LR14 __ICH_LR8(6)
-#define ICH_LR15 __ICH_LR8(7)
-#define ICH_LRC0 __ICH_LRC0(0)
-#define ICH_LRC1 __ICH_LRC0(1)
-#define ICH_LRC2 __ICH_LRC0(2)
-#define ICH_LRC3 __ICH_LRC0(3)
-#define ICH_LRC4 __ICH_LRC0(4)
-#define ICH_LRC5 __ICH_LRC0(5)
-#define ICH_LRC6 __ICH_LRC0(6)
-#define ICH_LRC7 __ICH_LRC0(7)
-#define ICH_LRC8 __ICH_LRC8(0)
-#define ICH_LRC9 __ICH_LRC8(1)
-#define ICH_LRC10 __ICH_LRC8(2)
-#define ICH_LRC11 __ICH_LRC8(3)
-#define ICH_LRC12 __ICH_LRC8(4)
-#define ICH_LRC13 __ICH_LRC8(5)
-#define ICH_LRC14 __ICH_LRC8(6)
-#define ICH_LRC15 __ICH_LRC8(7)
-
-#define ICC_CTLR_EOImode 0x2
-#define ICC_PMR_MASK 0xff
-#define ICC_PMR_DEFAULT 0xf0
-#define ICC_IGRPEN1_EN 0x1
-
-#define ICC_SGIR_AFF3_SHIFT 48
-#define ICC_SGIR_AFF2_SHIFT 32
-#define ICC_SGIR_AFF1_SHIFT 16
-#define ICC_SGIR_TARGET_MASK 0xffff
-#define ICC_SGIR_IRQN_SHIFT 24
-#define ICC_SGIR_ROUTING_BIT (1ULL << 40)
-
-#define ICH_HCR_EN (1 << 0)
-#define ICH_HCR_UIE (1 << 1)
-#define ICH_HCR_LRENPIE (1 << 2)
-#define ICH_HCR_NPIE (1 << 3)
-#define ICH_HCR_VGRP0EIE (1 << 4)
-#define ICH_HCR_VGRP0DIE (1 << 5)
-#define ICH_HCR_VGRP1EIE (1 << 6)
-#define ICH_HCR_VGRP1DIE (1 << 7)
-#define ICH_HCR_VARE (1 << 9)
-#define ICH_HCR_TC (1 << 10)
-#define ICH_HCR_TALL0 (1 << 11)
-#define ICH_HCR_TALL1 (1 << 12)
-#define ICH_HCR_TSEI (1 << 13)
-#define ICH_HCR_EOICount (0x1f << 27)
-
-#define ICH_MISR_EOI (1 << 0)
-#define ICH_MISR_U (1 << 1)
-#define ICH_MISR_LRENP (1 << 2)
-#define ICH_MISR_NP (1 << 3)
-#define ICH_MISR_VGRP0E (1 << 4)
-#define ICH_MISR_VGRP0D (1 << 5)
-#define ICH_MISR_VGRP1E (1 << 6)
-#define ICH_MISR_VGRP1D (1 << 7)
-
-#define ICH_VMCR_VENG0 (1 << 0)
-#define ICH_VMCR_VENG1 (1 << 1)
-#define ICH_VMCR_VACKCTL (1 << 2)
-#define ICH_VMCR_VFIQEN (1 << 3)
-#define ICH_VMCR_VCBPR (1 << 4)
-#define ICH_VMCR_VEOIM (1 << 9)
-#define ICH_VMCR_VBPR1_SHIFT 18
-#define ICH_VMCR_VBPR0_SHIFT 21
-#define ICH_VMCR_VPMR_SHIFT 24
-
-/* List registers upper bits */
-#define ICH_LR_INVALID (0x0ULL << 62)
-#define ICH_LR_PENDING (0x1ULL << 62)
-#define ICH_LR_ACTIVE (0x2ULL << 62)
-#define ICH_LR_PENDACTIVE (0x3ULL << 62)
-#define ICH_LR_HW_BIT (0x1ULL << 61)
-#define ICH_LR_GROUP_BIT (0x1ULL << 60)
-#define ICH_LR_PRIORITY_SHIFT 48
-#define ICH_LR_SGI_EOI (0x1ULL << 41)
-#define ICH_LR_PHYS_ID_SHIFT 32
-
-#ifndef __ASSEMBLY__
-
-#include <jailhouse/types.h>
-
-static inline u64 gic_read_lr(unsigned int n)
-{
- u32 lr, lrc;
-
- switch (n) {
-#define __READ_LR(n) \
- case n: \
- arm_read_sysreg(ICH_LR##n, lr); \
- arm_read_sysreg(ICH_LRC##n, lrc); \
- break;
-
- __READ_LR(0)
- __READ_LR(1)
- __READ_LR(2)
- __READ_LR(3)
- __READ_LR(4)
- __READ_LR(5)
- __READ_LR(6)
- __READ_LR(7)
- __READ_LR(8)
- __READ_LR(9)
- __READ_LR(10)
- __READ_LR(11)
- __READ_LR(12)
- __READ_LR(13)
- __READ_LR(14)
- __READ_LR(15)
-#undef __READ_LR
-
- default:
- return (u64)(-1);
- }
-
- return (u64)lrc << 32 | lr;
-}
-
-static inline void gic_write_lr(unsigned int n, u64 val)
-{
- u32 lr = (u32)val;
- u32 lrc = val >> 32;
-
- switch (n) {
-#define __WRITE_LR(n) \
- case n: \
- arm_write_sysreg(ICH_LR##n, lr); \
- arm_write_sysreg(ICH_LRC##n, lrc); \
- break;
-
- __WRITE_LR(0)
- __WRITE_LR(1)
- __WRITE_LR(2)
- __WRITE_LR(3)
- __WRITE_LR(4)
- __WRITE_LR(5)
- __WRITE_LR(6)
- __WRITE_LR(7)
- __WRITE_LR(8)
- __WRITE_LR(9)
- __WRITE_LR(10)
- __WRITE_LR(11)
- __WRITE_LR(12)
- __WRITE_LR(13)
- __WRITE_LR(14)
- __WRITE_LR(15)
-#undef __WRITE_LR
- }
-}
-
-static inline u32 gic_read_iar(void)
-{
- u32 irq_id;
-
- arm_read_sysreg(ICC_IAR1_EL1, irq_id);
- return irq_id;
-}
-
-void gicv3_handle_sgir_write(u64 sgir);
-
-#endif /* __ASSEMBLY__ */
-#endif /* _JAILHOUSE_ASM_GIC_V3_H */
--
1.9.1