aboutsummaryrefslogtreecommitdiff
path: root/hw/intc/arm_gicv3_cpuif.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/intc/arm_gicv3_cpuif.c')
-rw-r--r--hw/intc/arm_gicv3_cpuif.c506
1 files changed, 376 insertions, 130 deletions
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 3fe5de8ad7..67d8fd07b7 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -1,5 +1,5 @@
/*
- * ARM Generic Interrupt Controller v3
+ * ARM Generic Interrupt Controller v3 (emulation)
*
* Copyright (c) 2016 Linaro Limited
* Written by Peter Maydell
@@ -20,14 +20,15 @@
#include "gicv3_internal.h"
#include "hw/irq.h"
#include "cpu.h"
+#include "target/arm/cpregs.h"
+#include "sysemu/tcg.h"
+#include "sysemu/qtest.h"
-void gicv3_set_gicv3state(CPUState *cpu, GICv3CPUState *s)
-{
- ARMCPU *arm_cpu = ARM_CPU(cpu);
- CPUARMState *env = &arm_cpu->env;
-
- env->gicv3state = (void *)s;
-};
+/*
+ * Special case return value from hppvi_index(); must be larger than
+ * the architecturally maximum possible list register index (which is 15)
+ */
+#define HPPVI_INDEX_VLPI 16
static GICv3CPUState *icc_cs_from_env(CPUARMState *env)
{
@@ -50,6 +51,14 @@ static inline int icv_min_vbpr(GICv3CPUState *cs)
return 7 - cs->vprebits;
}
+static inline int ich_num_aprs(GICv3CPUState *cs)
+{
+ /* Return the number of virtual APR registers (1, 2, or 4) */
+ int aprmax = 1 << (cs->vprebits - 5);
+ assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
+ return aprmax;
+}
+
/* Simple accessor functions for LR fields */
static uint32_t ich_lr_vintid(uint64_t lr)
{
@@ -137,7 +146,7 @@ static uint32_t icv_fullprio_mask(GICv3CPUState *cs)
* with the group priority, whose mask depends on the value of VBPR
* for the interrupt group.)
*/
- return ~0U << (8 - cs->vpribits);
+ return (~0U << (8 - cs->vpribits)) & 0xff;
}
static int ich_highest_active_virt_prio(GICv3CPUState *cs)
@@ -146,9 +155,7 @@ static int ich_highest_active_virt_prio(GICv3CPUState *cs)
* in the ICH Active Priority Registers.
*/
int i;
- int aprmax = 1 << (cs->vprebits - 5);
-
- assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
+ int aprmax = ich_num_aprs(cs);
for (i = 0; i < aprmax; i++) {
uint32_t apr = cs->ich_apr[GICV3_G0][i] |
@@ -165,10 +172,18 @@ static int ich_highest_active_virt_prio(GICv3CPUState *cs)
static int hppvi_index(GICv3CPUState *cs)
{
- /* Return the list register index of the highest priority pending
+ /*
+ * Return the list register index of the highest priority pending
* virtual interrupt, as per the HighestPriorityVirtualInterrupt
* pseudocode. If no pending virtual interrupts, return -1.
+ * If the highest priority pending virtual interrupt is a vLPI,
+ * return HPPVI_INDEX_VLPI.
+ * (The pseudocode handles checking whether the vLPI is higher
+ * priority than the highest priority list register at every
+ * callsite of HighestPriorityVirtualInterrupt; we check it here.)
*/
+ ARMCPU *cpu = ARM_CPU(cs->cpu);
+ CPUARMState *env = &cpu->env;
int idx = -1;
int i;
/* Note that a list register entry with a priority of 0xff will
@@ -210,6 +225,23 @@ static int hppvi_index(GICv3CPUState *cs)
}
}
+ /*
+ * "no pending vLPI" is indicated with prio = 0xff, which always
+ * fails the priority check here. vLPIs are only considered
+ * when we are in Non-Secure state.
+ */
+ if (cs->hppvlpi.prio < prio && !arm_is_secure(env)) {
+ if (cs->hppvlpi.grp == GICV3_G0) {
+ if (cs->ich_vmcr_el2 & ICH_VMCR_EL2_VENG0) {
+ return HPPVI_INDEX_VLPI;
+ }
+ } else {
+ if (cs->ich_vmcr_el2 & ICH_VMCR_EL2_VENG1) {
+ return HPPVI_INDEX_VLPI;
+ }
+ }
+ }
+
return idx;
}
@@ -297,6 +329,47 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr)
return false;
}
+static bool icv_hppvlpi_can_preempt(GICv3CPUState *cs)
+{
+ /*
+ * Return true if we can signal the highest priority pending vLPI.
+ * We can assume we're Non-secure because hppvi_index() already
+ * tested for that.
+ */
+ uint32_t mask, rprio, vpmr;
+
+ if (!(cs->ich_hcr_el2 & ICH_HCR_EL2_EN)) {
+ /* Virtual interface disabled */
+ return false;
+ }
+
+ vpmr = extract64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VPMR_SHIFT,
+ ICH_VMCR_EL2_VPMR_LENGTH);
+
+ if (cs->hppvlpi.prio >= vpmr) {
+ /* Priority mask masks this interrupt */
+ return false;
+ }
+
+ rprio = ich_highest_active_virt_prio(cs);
+ if (rprio == 0xff) {
+ /* No running interrupt so we can preempt */
+ return true;
+ }
+
+ mask = icv_gprio_mask(cs, cs->hppvlpi.grp);
+
+ /*
+ * We only preempt a running interrupt if the pending interrupt's
+ * group priority is sufficient (the subpriorities are not considered).
+ */
+ if ((cs->hppvlpi.prio & mask) < (rprio & mask)) {
+ return true;
+ }
+
+ return false;
+}
+
static uint32_t eoi_maintenance_interrupt_state(GICv3CPUState *cs,
uint32_t *misr)
{
@@ -351,7 +424,8 @@ static uint32_t maintenance_interrupt_state(GICv3CPUState *cs)
/* Scan list registers and fill in the U, NP and EOI bits */
eoi_maintenance_interrupt_state(cs, &value);
- if (cs->ich_hcr_el2 & (ICH_HCR_EL2_LRENPIE | ICH_HCR_EL2_EOICOUNT_MASK)) {
+ if ((cs->ich_hcr_el2 & ICH_HCR_EL2_LRENPIE) &&
+ (cs->ich_hcr_el2 & ICH_HCR_EL2_EOICOUNT_MASK)) {
value |= ICH_MISR_EL2_LRENP;
}
@@ -377,9 +451,55 @@ static uint32_t maintenance_interrupt_state(GICv3CPUState *cs)
return value;
}
+void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs)
+{
+ /*
+ * Tell the CPU about any pending virtual interrupts.
+ * This should only be called for changes that affect the
+ * vIRQ and vFIQ status and do not change the maintenance
+ * interrupt status. This means that unlike gicv3_cpuif_virt_update()
+ * this function won't recursively call back into the GIC code.
+ * The main use of this is when the redistributor has changed the
+ * highest priority pending virtual LPI.
+ */
+ int idx;
+ int irqlevel = 0;
+ int fiqlevel = 0;
+
+ idx = hppvi_index(cs);
+ trace_gicv3_cpuif_virt_update(gicv3_redist_affid(cs), idx,
+ cs->hppvlpi.irq, cs->hppvlpi.grp,
+ cs->hppvlpi.prio);
+ if (idx == HPPVI_INDEX_VLPI) {
+ if (icv_hppvlpi_can_preempt(cs)) {
+ if (cs->hppvlpi.grp == GICV3_G0) {
+ fiqlevel = 1;
+ } else {
+ irqlevel = 1;
+ }
+ }
+ } else if (idx >= 0) {
+ uint64_t lr = cs->ich_lr_el2[idx];
+
+ if (icv_hppi_can_preempt(cs, lr)) {
+ /* Virtual interrupts are simple: G0 are always FIQ, and G1 IRQ */
+ if (lr & ICH_LR_EL2_GROUP) {
+ irqlevel = 1;
+ } else {
+ fiqlevel = 1;
+ }
+ }
+ }
+
+ trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel, irqlevel);
+ qemu_set_irq(cs->parent_vfiq, fiqlevel);
+ qemu_set_irq(cs->parent_virq, irqlevel);
+}
+
static void gicv3_cpuif_virt_update(GICv3CPUState *cs)
{
- /* Tell the CPU about any pending virtual interrupts or
+ /*
+ * Tell the CPU about any pending virtual interrupts or
* maintenance interrupts, following a change to the state
* of the CPU interface relevant to virtual interrupts.
*
@@ -396,37 +516,17 @@ static void gicv3_cpuif_virt_update(GICv3CPUState *cs)
* naturally as a result of there being no architectural
* linkage between the physical and virtual GIC logic.
*/
- int idx;
- int irqlevel = 0;
- int fiqlevel = 0;
- int maintlevel = 0;
ARMCPU *cpu = ARM_CPU(cs->cpu);
+ int maintlevel = 0;
- idx = hppvi_index(cs);
- trace_gicv3_cpuif_virt_update(gicv3_redist_affid(cs), idx);
- if (idx >= 0) {
- uint64_t lr = cs->ich_lr_el2[idx];
-
- if (icv_hppi_can_preempt(cs, lr)) {
- /* Virtual interrupts are simple: G0 are always FIQ, and G1 IRQ */
- if (lr & ICH_LR_EL2_GROUP) {
- irqlevel = 1;
- } else {
- fiqlevel = 1;
- }
- }
- }
+ gicv3_cpuif_virt_irq_fiq_update(cs);
if ((cs->ich_hcr_el2 & ICH_HCR_EL2_EN) &&
maintenance_interrupt_state(cs) != 0) {
maintlevel = 1;
}
- trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel,
- irqlevel, maintlevel);
-
- qemu_set_irq(cs->parent_vfiq, fiqlevel);
- qemu_set_irq(cs->parent_virq, irqlevel);
+ trace_gicv3_cpuif_virt_set_maint_irq(gicv3_redist_affid(cs), maintlevel);
qemu_set_irq(cpu->gicv3_maintenance_interrupt, maintlevel);
}
@@ -452,7 +552,7 @@ static void icv_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
- gicv3_cpuif_virt_update(cs);
+ gicv3_cpuif_virt_irq_fiq_update(cs);
return;
}
@@ -497,7 +597,7 @@ static void icv_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri,
write_vbpr(cs, grp, value);
- gicv3_cpuif_virt_update(cs);
+ gicv3_cpuif_virt_irq_fiq_update(cs);
}
static uint64_t icv_pmr_read(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -524,7 +624,7 @@ static void icv_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri,
cs->ich_vmcr_el2 = deposit64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VPMR_SHIFT,
ICH_VMCR_EL2_VPMR_LENGTH, value);
- gicv3_cpuif_virt_update(cs);
+ gicv3_cpuif_virt_irq_fiq_update(cs);
}
static uint64_t icv_igrpen_read(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -565,7 +665,7 @@ static uint64_t icv_ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
* should match the ones reported in ich_vtr_read().
*/
value = ICC_CTLR_EL1_A3V | (1 << ICC_CTLR_EL1_IDBITS_SHIFT) |
- (7 << ICC_CTLR_EL1_PRIBITS_SHIFT);
+ ((cs->vpribits - 1) << ICC_CTLR_EL1_PRIBITS_SHIFT);
if (cs->ich_vmcr_el2 & ICH_VMCR_EL2_VEOIM) {
value |= ICC_CTLR_EL1_EOIMODE;
@@ -591,7 +691,7 @@ static void icv_ctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
cs->ich_vmcr_el2 = deposit64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VEOIM_SHIFT,
1, value & ICC_CTLR_EL1_EOIMODE ? 1 : 0);
- gicv3_cpuif_virt_update(cs);
+ gicv3_cpuif_virt_irq_fiq_update(cs);
}
static uint64_t icv_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -610,7 +710,11 @@ static uint64_t icv_hppir_read(CPUARMState *env, const ARMCPRegInfo *ri)
int idx = hppvi_index(cs);
uint64_t value = INTID_SPURIOUS;
- if (idx >= 0) {
+ if (idx == HPPVI_INDEX_VLPI) {
+ if (cs->hppvlpi.grp == grp) {
+ value = cs->hppvlpi.irq;
+ }
+ } else if (idx >= 0) {
uint64_t lr = cs->ich_lr_el2[idx];
int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
@@ -619,7 +723,8 @@ static uint64_t icv_hppir_read(CPUARMState *env, const ARMCPRegInfo *ri)
}
}
- trace_gicv3_icv_hppir_read(grp, gicv3_redist_affid(cs), value);
+ trace_gicv3_icv_hppir_read(ri->crm == 8 ? 0 : 1,
+ gicv3_redist_affid(cs), value);
return value;
}
@@ -640,6 +745,18 @@ static void icv_activate_irq(GICv3CPUState *cs, int idx, int grp)
cs->ich_apr[grp][regno] |= (1 << regbit);
}
+static void icv_activate_vlpi(GICv3CPUState *cs)
+{
+ uint32_t mask = icv_gprio_mask(cs, cs->hppvlpi.grp);
+ int prio = cs->hppvlpi.prio & mask;
+ int aprbit = prio >> (8 - cs->vprebits);
+ int regno = aprbit / 32;
+ int regbit = aprbit % 32;
+
+ cs->ich_apr[cs->hppvlpi.grp][regno] |= (1 << regbit);
+ gicv3_redist_vlpi_pending(cs, cs->hppvlpi.irq, 0);
+}
+
static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
GICv3CPUState *cs = icc_cs_from_env(env);
@@ -647,13 +764,18 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
int idx = hppvi_index(cs);
uint64_t intid = INTID_SPURIOUS;
- if (idx >= 0) {
+ if (idx == HPPVI_INDEX_VLPI) {
+ if (cs->hppvlpi.grp == grp && icv_hppvlpi_can_preempt(cs)) {
+ intid = cs->hppvlpi.irq;
+ icv_activate_vlpi(cs);
+ }
+ } else if (idx >= 0) {
uint64_t lr = cs->ich_lr_el2[idx];
int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
if (thisgrp == grp && icv_hppi_can_preempt(cs, lr)) {
intid = ich_lr_vintid(lr);
- if (intid < INTID_SECURE) {
+ if (!gicv3_intid_is_special(intid)) {
icv_activate_irq(cs, idx, grp);
} else {
/* Interrupt goes from Pending to Invalid */
@@ -673,6 +795,36 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
return intid;
}
+static uint32_t icc_fullprio_mask(GICv3CPUState *cs)
+{
+ /*
+ * Return a mask word which clears the unimplemented priority bits
+ * from a priority value for a physical interrupt. (Not to be confused
+ * with the group priority, whose mask depends on the value of BPR
+ * for the interrupt group.)
+ */
+ return (~0U << (8 - cs->pribits)) & 0xff;
+}
+
+static inline int icc_min_bpr(GICv3CPUState *cs)
+{
+ /* The minimum BPR for the physical interface. */
+ return 7 - cs->prebits;
+}
+
+static inline int icc_min_bpr_ns(GICv3CPUState *cs)
+{
+ return icc_min_bpr(cs) + 1;
+}
+
+static inline int icc_num_aprs(GICv3CPUState *cs)
+{
+ /* Return the number of APR registers (1, 2, or 4) */
+ int aprmax = 1 << MAX(cs->prebits - 5, 0);
+ assert(aprmax <= ARRAY_SIZE(cs->icc_apr[0]));
+ return aprmax;
+}
+
static int icc_highest_active_prio(GICv3CPUState *cs)
{
/* Calculate the current running priority based on the set bits
@@ -680,14 +832,14 @@ static int icc_highest_active_prio(GICv3CPUState *cs)
*/
int i;
- for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) {
+ for (i = 0; i < icc_num_aprs(cs); i++) {
uint32_t apr = cs->icc_apr[GICV3_G0][i] |
cs->icc_apr[GICV3_G1][i] | cs->icc_apr[GICV3_G1NS][i];
if (!apr) {
continue;
}
- return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1);
+ return (i * 32 + ctz32(apr)) << (icc_min_bpr(cs) + 1);
}
/* No current active interrupts: return idle priority */
return 0xff;
@@ -782,7 +934,7 @@ void gicv3_cpuif_update(GICv3CPUState *cs)
ARMCPU *cpu = ARM_CPU(cs->cpu);
CPUARMState *env = &cpu->env;
- g_assert(qemu_mutex_iothread_locked());
+ g_assert(bql_locked());
trace_gicv3_cpuif_update(gicv3_redist_affid(cs), cs->hppi.irq,
cs->hppi.grp, cs->hppi.prio);
@@ -866,8 +1018,6 @@ static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri,
trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value);
- value &= 0xff;
-
if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env) &&
(env->cp15.scr_el3 & SCR_FIQ)) {
/* NS access and Group 0 is inaccessible to NS: return the
@@ -879,6 +1029,7 @@ static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri,
}
value = (value >> 1) | 0x80;
}
+ value &= icc_fullprio_mask(cs);
cs->icc_pmr_el1 = value;
gicv3_cpuif_update(cs);
}
@@ -890,7 +1041,7 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq)
*/
uint32_t mask = icc_gprio_mask(cs, cs->hppi.grp);
int prio = cs->hppi.prio & mask;
- int aprbit = prio >> 1;
+ int aprbit = prio >> (8 - cs->prebits);
int regno = aprbit / 32;
int regbit = aprbit % 32;
@@ -916,7 +1067,7 @@ static uint64_t icc_hppir0_value(GICv3CPUState *cs, CPUARMState *env)
*/
bool irq_is_secure;
- if (cs->hppi.prio == 0xff) {
+ if (icc_no_enabled_hppi(cs)) {
return INTID_SPURIOUS;
}
@@ -953,7 +1104,7 @@ static uint64_t icc_hppir1_value(GICv3CPUState *cs, CPUARMState *env)
*/
bool irq_is_secure;
- if (cs->hppi.prio == 0xff) {
+ if (icc_no_enabled_hppi(cs)) {
return INTID_SPURIOUS;
}
@@ -997,7 +1148,7 @@ static uint64_t icc_iar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
intid = icc_hppir0_value(cs, env);
}
- if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) {
+ if (!gicv3_intid_is_special(intid)) {
icc_activate_irq(cs, intid);
}
@@ -1020,7 +1171,7 @@ static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
intid = icc_hppir1_value(cs, env);
}
- if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) {
+ if (!gicv3_intid_is_special(intid)) {
icc_activate_irq(cs, intid);
}
@@ -1048,7 +1199,7 @@ static void icc_drop_prio(GICv3CPUState *cs, int grp)
*/
int i;
- for (i = 0; i < ARRAY_SIZE(cs->icc_apr[grp]); i++) {
+ for (i = 0; i < icc_num_aprs(cs); i++) {
uint64_t *papr = &cs->icc_apr[grp][i];
if (!*papr) {
@@ -1189,9 +1340,7 @@ static int icv_drop_prio(GICv3CPUState *cs)
* 32 bits are actually relevant.
*/
int i;
- int aprmax = 1 << (cs->vprebits - 5);
-
- assert(aprmax <= ARRAY_SIZE(cs->ich_apr[0]));
+ int aprmax = ich_num_aprs(cs);
for (i = 0; i < aprmax; i++) {
uint64_t *papr0 = &cs->ich_apr[GICV3_G0][i];
@@ -1265,8 +1414,7 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
trace_gicv3_icv_eoir_write(ri->crm == 8 ? 0 : 1,
gicv3_redist_affid(cs), value);
- if (irq >= GICV3_MAXIRQ) {
- /* Also catches special interrupt numbers and LPIs */
+ if (gicv3_intid_is_special(irq)) {
return;
}
@@ -1286,16 +1434,25 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
idx = icv_find_active(cs, irq);
if (idx < 0) {
- /* No valid list register corresponding to EOI ID */
- icv_increment_eoicount(cs);
+ /*
+ * No valid list register corresponding to EOI ID; if this is a vLPI
+ * not in the list regs then do nothing; otherwise increment EOI count
+ */
+ if (irq < GICV3_LPI_INTID_START) {
+ icv_increment_eoicount(cs);
+ }
} else {
uint64_t lr = cs->ich_lr_el2[idx];
int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
int lr_gprio = ich_lr_prio(lr) & icv_gprio_mask(cs, grp);
if (thisgrp == grp && lr_gprio == dropprio) {
- if (!icv_eoi_split(env, cs)) {
- /* Priority drop and deactivate not split: deactivate irq now */
+ if (!icv_eoi_split(env, cs) || irq >= GICV3_LPI_INTID_START) {
+ /*
+ * Priority drop and deactivate not split: deactivate irq now.
+ * LPIs always get their active state cleared immediately
+ * because no separate deactivate is expected.
+ */
icv_deactivate_irq(cs, idx);
}
}
@@ -1477,7 +1634,7 @@ static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri,
return;
}
- minval = (grp == GICV3_G1NS) ? GIC_MIN_BPR_NS : GIC_MIN_BPR;
+ minval = (grp == GICV3_G1NS) ? icc_min_bpr_ns(cs) : icc_min_bpr(cs);
if (value < minval) {
value = minval;
}
@@ -1900,7 +2057,7 @@ static void icc_ctlr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri,
cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_CBPR;
}
- /* The only bit stored in icc_ctlr_el3 which is writeable is EOIMODE_EL3: */
+ /* The only bit stored in icc_ctlr_el3 which is writable is EOIMODE_EL3: */
mask = ICC_CTLR_EL3_EOIMODE_EL3;
cs->icc_ctlr_el3 &= ~mask;
@@ -2058,19 +2215,19 @@ static void icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
cs->icc_ctlr_el1[GICV3_S] = ICC_CTLR_EL1_A3V |
(1 << ICC_CTLR_EL1_IDBITS_SHIFT) |
- (7 << ICC_CTLR_EL1_PRIBITS_SHIFT);
+ ((cs->pribits - 1) << ICC_CTLR_EL1_PRIBITS_SHIFT);
cs->icc_ctlr_el1[GICV3_NS] = ICC_CTLR_EL1_A3V |
(1 << ICC_CTLR_EL1_IDBITS_SHIFT) |
- (7 << ICC_CTLR_EL1_PRIBITS_SHIFT);
+ ((cs->pribits - 1) << ICC_CTLR_EL1_PRIBITS_SHIFT);
cs->icc_pmr_el1 = 0;
- cs->icc_bpr[GICV3_G0] = GIC_MIN_BPR;
- cs->icc_bpr[GICV3_G1] = GIC_MIN_BPR;
- cs->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR_NS;
+ cs->icc_bpr[GICV3_G0] = icc_min_bpr(cs);
+ cs->icc_bpr[GICV3_G1] = icc_min_bpr(cs);
+ cs->icc_bpr[GICV3_G1NS] = icc_min_bpr_ns(cs);
memset(cs->icc_apr, 0, sizeof(cs->icc_apr));
memset(cs->icc_igrpen, 0, sizeof(cs->icc_igrpen));
cs->icc_ctlr_el3 = ICC_CTLR_EL3_NDS | ICC_CTLR_EL3_A3V |
(1 << ICC_CTLR_EL3_IDBITS_SHIFT) |
- (7 << ICC_CTLR_EL3_PRIBITS_SHIFT);
+ ((cs->pribits - 1) << ICC_CTLR_EL3_PRIBITS_SHIFT);
memset(cs->ich_apr, 0, sizeof(cs->ich_apr));
cs->ich_hcr_el2 = 0;
@@ -2125,27 +2282,6 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
.readfn = icc_ap_read,
.writefn = icc_ap_write,
},
- { .name = "ICC_AP0R1_EL1", .state = ARM_CP_STATE_BOTH,
- .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 5,
- .type = ARM_CP_IO | ARM_CP_NO_RAW,
- .access = PL1_RW, .accessfn = gicv3_fiq_access,
- .readfn = icc_ap_read,
- .writefn = icc_ap_write,
- },
- { .name = "ICC_AP0R2_EL1", .state = ARM_CP_STATE_BOTH,
- .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 6,
- .type = ARM_CP_IO | ARM_CP_NO_RAW,
- .access = PL1_RW, .accessfn = gicv3_fiq_access,
- .readfn = icc_ap_read,
- .writefn = icc_ap_write,
- },
- { .name = "ICC_AP0R3_EL1", .state = ARM_CP_STATE_BOTH,
- .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 7,
- .type = ARM_CP_IO | ARM_CP_NO_RAW,
- .access = PL1_RW, .accessfn = gicv3_fiq_access,
- .readfn = icc_ap_read,
- .writefn = icc_ap_write,
- },
/* All the ICC_AP1R*_EL1 registers are banked */
{ .name = "ICC_AP1R0_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 0,
@@ -2154,27 +2290,6 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
.readfn = icc_ap_read,
.writefn = icc_ap_write,
},
- { .name = "ICC_AP1R1_EL1", .state = ARM_CP_STATE_BOTH,
- .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 1,
- .type = ARM_CP_IO | ARM_CP_NO_RAW,
- .access = PL1_RW, .accessfn = gicv3_irq_access,
- .readfn = icc_ap_read,
- .writefn = icc_ap_write,
- },
- { .name = "ICC_AP1R2_EL1", .state = ARM_CP_STATE_BOTH,
- .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 2,
- .type = ARM_CP_IO | ARM_CP_NO_RAW,
- .access = PL1_RW, .accessfn = gicv3_irq_access,
- .readfn = icc_ap_read,
- .writefn = icc_ap_write,
- },
- { .name = "ICC_AP1R3_EL1", .state = ARM_CP_STATE_BOTH,
- .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 3,
- .type = ARM_CP_IO | ARM_CP_NO_RAW,
- .access = PL1_RW, .accessfn = gicv3_irq_access,
- .readfn = icc_ap_read,
- .writefn = icc_ap_write,
- },
{ .name = "ICC_DIR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 1,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
@@ -2272,6 +2387,7 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 6,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
.access = PL1_RW, .accessfn = gicv3_fiq_access,
+ .fgt = FGT_ICC_IGRPENN_EL1,
.readfn = icc_igrpen_read,
.writefn = icc_igrpen_write,
},
@@ -2280,6 +2396,7 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 7,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
.access = PL1_RW, .accessfn = gicv3_irq_access,
+ .fgt = FGT_ICC_IGRPENN_EL1,
.readfn = icc_igrpen_read,
.writefn = icc_igrpen_write,
},
@@ -2315,7 +2432,54 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
.readfn = icc_igrpen1_el3_read,
.writefn = icc_igrpen1_el3_write,
},
- REGINFO_SENTINEL
+};
+
+static const ARMCPRegInfo gicv3_cpuif_icc_apxr1_reginfo[] = {
+ { .name = "ICC_AP0R1_EL1", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 5,
+ .type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .access = PL1_RW, .accessfn = gicv3_fiq_access,
+ .readfn = icc_ap_read,
+ .writefn = icc_ap_write,
+ },
+ { .name = "ICC_AP1R1_EL1", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 1,
+ .type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .access = PL1_RW, .accessfn = gicv3_irq_access,
+ .readfn = icc_ap_read,
+ .writefn = icc_ap_write,
+ },
+};
+
+static const ARMCPRegInfo gicv3_cpuif_icc_apxr23_reginfo[] = {
+ { .name = "ICC_AP0R2_EL1", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 6,
+ .type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .access = PL1_RW, .accessfn = gicv3_fiq_access,
+ .readfn = icc_ap_read,
+ .writefn = icc_ap_write,
+ },
+ { .name = "ICC_AP0R3_EL1", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 7,
+ .type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .access = PL1_RW, .accessfn = gicv3_fiq_access,
+ .readfn = icc_ap_read,
+ .writefn = icc_ap_write,
+ },
+ { .name = "ICC_AP1R2_EL1", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 2,
+ .type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .access = PL1_RW, .accessfn = gicv3_irq_access,
+ .readfn = icc_ap_read,
+ .writefn = icc_ap_write,
+ },
+ { .name = "ICC_AP1R3_EL1", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 3,
+ .type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .access = PL1_RW, .accessfn = gicv3_irq_access,
+ .readfn = icc_ap_read,
+ .writefn = icc_ap_write,
+ },
};
static uint64_t ich_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -2340,7 +2504,7 @@ static void ich_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
trace_gicv3_ich_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value);
cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
- gicv3_cpuif_virt_update(cs);
+ gicv3_cpuif_virt_irq_fiq_update(cs);
}
static uint64_t ich_hcr_read(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -2466,11 +2630,15 @@ static uint64_t ich_vtr_read(CPUARMState *env, const ARMCPRegInfo *ri)
uint64_t value;
value = ((cs->num_list_regs - 1) << ICH_VTR_EL2_LISTREGS_SHIFT)
- | ICH_VTR_EL2_TDS | ICH_VTR_EL2_NV4 | ICH_VTR_EL2_A3V
+ | ICH_VTR_EL2_TDS | ICH_VTR_EL2_A3V
| (1 << ICH_VTR_EL2_IDBITS_SHIFT)
| ((cs->vprebits - 1) << ICH_VTR_EL2_PREBITS_SHIFT)
| ((cs->vpribits - 1) << ICH_VTR_EL2_PRIBITS_SHIFT);
+ if (cs->gic->revision < 4) {
+ value |= ICH_VTR_EL2_NV4;
+ }
+
trace_gicv3_ich_vtr_read(gicv3_redist_affid(cs), value);
return value;
}
@@ -2516,6 +2684,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
{ .name = "ICH_AP0R0_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 0,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x480,
.access = PL2_RW,
.readfn = ich_ap_read,
.writefn = ich_ap_write,
@@ -2523,6 +2692,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
{ .name = "ICH_AP1R0_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 0,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x4a0,
.access = PL2_RW,
.readfn = ich_ap_read,
.writefn = ich_ap_write,
@@ -2530,6 +2700,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
{ .name = "ICH_HCR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 0,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x4c0,
.access = PL2_RW,
.readfn = ich_hcr_read,
.writefn = ich_hcr_write,
@@ -2561,17 +2732,18 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
{ .name = "ICH_VMCR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 7,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x4c8,
.access = PL2_RW,
.readfn = ich_vmcr_read,
.writefn = ich_vmcr_write,
},
- REGINFO_SENTINEL
};
static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = {
{ .name = "ICH_AP0R1_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 1,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x488,
.access = PL2_RW,
.readfn = ich_ap_read,
.writefn = ich_ap_write,
@@ -2579,17 +2751,18 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = {
{ .name = "ICH_AP1R1_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 1,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x4a8,
.access = PL2_RW,
.readfn = ich_ap_read,
.writefn = ich_ap_write,
},
- REGINFO_SENTINEL
};
static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
{ .name = "ICH_AP0R2_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 2,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x490,
.access = PL2_RW,
.readfn = ich_ap_read,
.writefn = ich_ap_write,
@@ -2597,6 +2770,7 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
{ .name = "ICH_AP0R3_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 3,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x498,
.access = PL2_RW,
.readfn = ich_ap_read,
.writefn = ich_ap_write,
@@ -2604,6 +2778,7 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
{ .name = "ICH_AP1R2_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 2,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x4b0,
.access = PL2_RW,
.readfn = ich_ap_read,
.writefn = ich_ap_write,
@@ -2611,11 +2786,11 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
{ .name = "ICH_AP1R3_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 3,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x4b8,
.access = PL2_RW,
.readfn = ich_ap_read,
.writefn = ich_ap_write,
},
- REGINFO_SENTINEL
};
static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque)
@@ -2623,6 +2798,12 @@ static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque)
GICv3CPUState *cs = opaque;
gicv3_cpuif_update(cs);
+ /*
+ * Because vLPIs are only pending in NonSecure state,
+ * an EL change can change the VIRQ/VFIQ status (but
+ * cannot affect the maintenance interrupt state)
+ */
+ gicv3_cpuif_virt_irq_fiq_update(cs);
}
void gicv3_init_cpuif(GICv3State *s)
@@ -2636,21 +2817,76 @@ void gicv3_init_cpuif(GICv3State *s)
ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
GICv3CPUState *cs = &s->cpu[i];
+ /*
+ * If the CPU doesn't define a GICv3 configuration, probably because
+ * in real hardware it doesn't have one, then we use default values
+ * matching the one used by most Arm CPUs. This applies to:
+ * cpu->gic_num_lrs
+ * cpu->gic_vpribits
+ * cpu->gic_vprebits
+ * cpu->gic_pribits
+ */
+
/* Note that we can't just use the GICv3CPUState as an opaque pointer
* in define_arm_cp_regs_with_opaque(), because when we're called back
* it might be with code translated by CPU 0 but run by CPU 1, in
* which case we'd get the wrong value.
* So instead we define the regs with no ri->opaque info, and
* get back to the GICv3CPUState from the CPUARMState.
+ *
+ * These CP regs callbacks can be called from either TCG or HVF code.
*/
define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
- if (arm_feature(&cpu->env, ARM_FEATURE_EL2)
- && cpu->gic_num_lrs) {
+
+ /*
+ * The CPU implementation specifies the number of supported
+ * bits of physical priority. For backwards compatibility
+ * of migration, we have a compat property that forces use
+ * of 8 priority bits regardless of what the CPU really has.
+ */
+ if (s->force_8bit_prio) {
+ cs->pribits = 8;
+ } else {
+ cs->pribits = cpu->gic_pribits ?: 5;
+ }
+
+ /*
+ * The GICv3 has separate ID register fields for virtual priority
+ * and preemption bit values, but only a single ID register field
+ * for the physical priority bits. The preemption bit count is
+ * always the same as the priority bit count, except that 8 bits
+ * of priority means 7 preemption bits. We precalculate the
+ * preemption bits because it simplifies the code and makes the
+ * parallels between the virtual and physical bits of the GIC
+ * a bit clearer.
+ */
+ cs->prebits = cs->pribits;
+ if (cs->prebits == 8) {
+ cs->prebits--;
+ }
+ /*
+ * Check that CPU code defining pribits didn't violate
+ * architectural constraints our implementation relies on.
+ */
+ g_assert(cs->pribits >= 4 && cs->pribits <= 8);
+
+ /*
+ * gicv3_cpuif_reginfo[] defines ICC_AP*R0_EL1; add definitions
+ * for ICC_AP*R{1,2,3}_EL1 if the prebits value requires them.
+ */
+ if (cs->prebits >= 6) {
+ define_arm_cp_regs(cpu, gicv3_cpuif_icc_apxr1_reginfo);
+ }
+ if (cs->prebits == 7) {
+ define_arm_cp_regs(cpu, gicv3_cpuif_icc_apxr23_reginfo);
+ }
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) {
int j;
- cs->num_list_regs = cpu->gic_num_lrs;
- cs->vpribits = cpu->gic_vpribits;
- cs->vprebits = cpu->gic_vprebits;
+ cs->num_list_regs = cpu->gic_num_lrs ?: 4;
+ cs->vpribits = cpu->gic_vpribits ?: 5;
+ cs->vprebits = cpu->gic_vprebits ?: 5;
/* Check against architectural constraints: getting these
* wrong would be a bug in the CPU code defining these,
@@ -2672,6 +2908,7 @@ void gicv3_init_cpuif(GICv3State *s)
.opc0 = 3, .opc1 = 4, .crn = 12,
.crm = 12 + (j >> 3), .opc2 = j & 7,
.type = ARM_CP_IO | ARM_CP_NO_RAW,
+ .nv2_redirect_offset = 0x400 + 8 * j,
.access = PL2_RW,
.readfn = ich_lr_read,
.writefn = ich_lr_write,
@@ -2684,7 +2921,6 @@ void gicv3_init_cpuif(GICv3State *s)
.readfn = ich_lr_read,
.writefn = ich_lr_write,
},
- REGINFO_SENTINEL
};
define_arm_cp_regs(cpu, lr_regset);
}
@@ -2695,6 +2931,16 @@ void gicv3_init_cpuif(GICv3State *s)
define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo);
}
}
- arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs);
+ if (tcg_enabled() || qtest_enabled()) {
+ /*
+ * We can only trap EL changes with TCG. However the GIC interrupt
+ * state only changes on EL changes involving EL2 or EL3, so for
+ * the non-TCG case this is OK, as EL2 and EL3 can't exist.
+ */
+ arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs);
+ } else {
+ assert(!arm_feature(&cpu->env, ARM_FEATURE_EL2));
+ assert(!arm_feature(&cpu->env, ARM_FEATURE_EL3));
+ }
}
}