Signed-off-by: Nikhil Devshatwar <[email protected]> --- 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 <[email protected]> + * + * 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 <[email protected]> + * + * 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 <[email protected]> - * - * 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 <[email protected]> - * - * 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 -- You received this message because you are subscribed to the Google Groups "Jailhouse" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
