From 272f75e89088c968c861fef516a4ebc70846dcd5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:52 +0100 Subject: hw/intc/arm_gicv3_cpuif: Handle CPUs that don't specify GICv3 parameters We allow a GICv3 to be connected to any CPU, but we don't do anything to handle the case where the CPU type doesn't in hardware have a GICv3 CPU interface and so the various GIC configuration fields (gic_num_lrs, vprebits, vpribits) are not specified. The current behaviour is that we will add the EL1 CPU interface registers, but will not put in the EL2 CPU interface registers, even if the CPU has EL2, which will leave the GIC in a broken state and probably result in the guest crashing as it tries to set it up. This only affects the virt board when using the cortex-a15 or cortex-a7 CPU types (both 32-bit) with -machine gic-version=3 (or 'max') and -machine virtualization=on. Instead of failing to set up the EL2 registers, if the CPU doesn't define the GIC configuration set it to a reasonable default, matching the standard configuration for most Arm CPUs. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-2-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 9efba79..df2f858 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -2755,6 +2755,15 @@ 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 + */ + /* 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 @@ -2763,13 +2772,12 @@ void gicv3_init_cpuif(GICv3State *s) * get back to the GICv3CPUState from the CPUARMState. */ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); - if (arm_feature(&cpu->env, ARM_FEATURE_EL2) - && cpu->gic_num_lrs) { + 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, -- cgit v1.1 From 9c6f933e71ccfde036d7e19c1ddc2b1a82cc45c0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:53 +0100 Subject: hw/intc/arm_gicv3: report correct PRIbits field in ICV_CTLR_EL1 As noted in the comment, the PRIbits field in ICV_CTLR_EL1 is supposed to match the ICH_VTR_EL2 PRIbits setting; that is, it is the virtual priority bit setting, not the physical priority bit setting. (For QEMU currently we always implement 8 bits of physical priority, so the PRIbits field was previously 7, since it is defined to be "priority bits - 1".) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-3-peter.maydell@linaro.org Message-id: 20220506162129.2896966-2-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/intc') diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index df2f858..ebf269b 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -657,7 +657,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; -- cgit v1.1 From 9774c0f7ba6ae2980a291cb53a13661ddaa2f5de Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:54 +0100 Subject: hw/intc/arm_gicv3_kvm.c: Stop using GIC_MIN_BPR constant The GIC_MIN_BPR constant defines the minimum BPR value that the TCG emulated GICv3 supports. We're currently using this also as the value we reset the KVM GICv3 ICC_BPR registers to, but this is only right by accident. We want to make the emulated GICv3 use a configurable number of priority bits, which means that GIC_MIN_BPR will no longer be a constant. Replace the uses in the KVM reset code with literal 0, plus a constant explaining why this is reasonable. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-4-peter.maydell@linaro.org Message-id: 20220506162129.2896966-3-peter.maydell@linaro.org --- hw/intc/arm_gicv3_kvm.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 2922c51..3ca643e 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -673,9 +673,19 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) s = c->gic; c->icc_pmr_el1 = 0; - c->icc_bpr[GICV3_G0] = GIC_MIN_BPR; - c->icc_bpr[GICV3_G1] = GIC_MIN_BPR; - c->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR; + /* + * Architecturally the reset value of the ICC_BPR registers + * is UNKNOWN. We set them all to 0 here; when the kernel + * uses these values to program the ICH_VMCR_EL2 fields that + * determine the guest-visible ICC_BPR register values, the + * hardware's "writing a value less than the minimum sets + * the field to the minimum value" behaviour will result in + * them effectively resetting to the correct minimum value + * for the host GIC. + */ + c->icc_bpr[GICV3_G0] = 0; + c->icc_bpr[GICV3_G1] = 0; + c->icc_bpr[GICV3_G1NS] = 0; c->icc_sre_el1 = 0x7; memset(c->icc_apr, 0, sizeof(c->icc_apr)); -- cgit v1.1 From 84597ff39484ec171567c7c80061100eb4a6c331 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:55 +0100 Subject: hw/intc/arm_gicv3: Support configurable number of physical priority bits The GICv3 code has always supported a configurable number of virtual priority and preemption bits, but our implementation currently hardcodes the number of physical priority bits at 8. This is not what most hardware implementations provide; for instance the Cortex-A53 provides only 5 bits of physical priority. Make the number of physical priority/preemption bits driven by fields in the GICv3CPUState, the way that we already do for virtual priority/preemption bits. We set cs->pribits to 8, so there is no behavioural change in this commit. A following commit will add the machinery for CPUs to set this to the correct value for their implementation. Note that changing the number of priority bits would be a migration compatibility break, because the semantics of the icc_apr[][] array changes. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-5-peter.maydell@linaro.org Message-id: 20220506162129.2896966-4-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 182 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 128 insertions(+), 54 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index ebf269b..69a15f7 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -787,6 +787,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); +} + +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 @@ -794,14 +824,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; @@ -980,7 +1010,7 @@ static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri, trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value); - value &= 0xff; + value &= icc_fullprio_mask(cs); if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env) && (env->cp15.scr_el3 & SCR_FIQ)) { @@ -1004,7 +1034,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; @@ -1162,7 +1192,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) { @@ -1590,7 +1620,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; } @@ -2171,19 +2201,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; @@ -2238,27 +2268,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, @@ -2267,27 +2276,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, @@ -2430,6 +2418,54 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { }, }; +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) { GICv3CPUState *cs = icc_cs_from_env(env); @@ -2772,6 +2808,44 @@ void gicv3_init_cpuif(GICv3State *s) * get back to the GICv3CPUState from the CPUARMState. */ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); + + /* + * For the moment, retain the existing behaviour of 8 priority bits; + * in a following commit we will take this from the CPU state, + * as we do for the virtual priority bits. + */ + cs->pribits = 8; + /* + * 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; -- cgit v1.1 From 39f29e599355f9512482b67624e7a6c9000c5ddd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:56 +0100 Subject: hw/intc/arm_gicv3: Use correct number of priority bits for the CPU Make the GICv3 set its number of bits of physical priority from the implementation-specific value provided in the CPU state struct, in the same way we already do for virtual priority bits. Because this would be a migration compatibility break, we provide a property force-8-bit-prio which is enabled for 7.0 and earlier versioned board models to retain the legacy "always use 8 bits" behaviour. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-6-peter.maydell@linaro.org Message-id: 20220506162129.2896966-5-peter.maydell@linaro.org --- hw/intc/arm_gicv3_common.c | 5 +++++ hw/intc/arm_gicv3_cpuif.c | 15 +++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 5634c6f..351843d 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -563,6 +563,11 @@ static Property arm_gicv3_common_properties[] = { DEFINE_PROP_UINT32("revision", GICv3State, revision, 3), DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0), DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0), + /* + * Compatibility property: force 8 bits of physical priority, even + * if the CPU being emulated should have fewer. + */ + DEFINE_PROP_BOOL("force-8-bit-prio", GICv3State, force_8bit_prio, 0), DEFINE_PROP_ARRAY("redist-region-count", GICv3State, nb_redist_regions, redist_region_count, qdev_prop_uint32, uint32_t), DEFINE_PROP_LINK("sysmem", GICv3State, dma, TYPE_MEMORY_REGION, diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 69a15f7..66e06b7 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -2798,6 +2798,7 @@ void gicv3_init_cpuif(GICv3State *s) * 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 @@ -2810,11 +2811,17 @@ void gicv3_init_cpuif(GICv3State *s) define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); /* - * For the moment, retain the existing behaviour of 8 priority bits; - * in a following commit we will take this from the CPU state, - * as we do for the virtual priority bits. + * 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. */ - cs->pribits = 8; + 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 -- cgit v1.1 From 5d55f827677a521feaab6dc651168e6136954e88 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 12 May 2022 16:14:57 +0100 Subject: hw/intc/arm_gicv3: Provide ich_num_aprs() We previously open-coded the expression for the number of virtual APR registers and the assertion that it was not going to cause us to overflow the cs->ich_apr[] array. Factor this out into a new ich_num_aprs() function, for consistency with the icc_num_aprs() function we just added for the physical APR handling. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20220512151457.3899052-7-peter.maydell@linaro.org Message-id: 20220506162129.2896966-6-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 66e06b7..8867e2e 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -49,6 +49,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) { @@ -145,9 +153,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] | @@ -1333,9 +1339,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]; -- cgit v1.1