Implement the ICH_APR_EL2 register. This is part of the hypervisor control register interface, and is the hypervisor-facing access to the state which holds the guest's its active priority register.
The only slightly non-straightforward part of this is that because the GICv5 allows a hypervisor to give its guest a GICv3-compatible virtual CPU interface, this register has to UNDEF to the inner guest when legacy-vcpu operation is enabled. We don't implement GCIE_LEGACY in QEMU yet, but since we expect to do so in future, the handling for this is implemented here. Signed-off-by: Peter Maydell <[email protected]> --- target/arm/cpu.h | 2 ++ target/arm/tcg/gicv5-cpuif.c | 44 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 82c13186b68..a93fd362417 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -594,6 +594,8 @@ typedef struct CPUArchState { /* Cached highest-priority pending PPI for each domain */ GICv5PendingIrq ppi_hppi[NUM_GICV5_DOMAINS]; + + uint64_t ich_apr_el2; } gicv5_cpuif; struct { diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c index 0b1033c1ef0..83c9be2b0e6 100644 --- a/target/arm/tcg/gicv5-cpuif.c +++ b/target/arm/tcg/gicv5-cpuif.c @@ -90,6 +90,15 @@ static GICv5Common *gicv5_get_gic(CPUARMState *env) return env->gicv5.gicv5state; } +/* + * Return true if GIC virtual interface legacy operation is enabled. + * We don't currently implement FEAT_GCIE_LEGACY. + */ +static bool gicv5_legacy_enabled(CPUARMState *env) +{ + return false; +} + static GICv5Domain gicv5_logical_domain(CPUARMState *env) { /* @@ -696,6 +705,34 @@ static void gic_cddi_write(CPUARMState *env, const ARMCPRegInfo *ri, } } +static CPAccessResult access_gicv5_ich_reg(CPUARMState *env, + const ARMCPRegInfo *ri, + bool isread) +{ + /* + * accessfn for GICv5 ICH regs. The NV behaviour here is a little + * different from usual because of the optional legacy GIC feature. + * + * At EL1, if GCIE_LEGACY is disabled or not implemented, these + * behave like normal EL2 registers, which is that they redirect + * to memory if NV2 is enabled and trap to EL2 if not. If legacy + * operation is enabled, these registers must UNDEF to EL1 + * (because from the inner guest's point of view it has a GICv3 + * and this sysreg doesn't exist). + * + * The UNDEF at EL1 when NV==0 is handled already because of the + * .access = PL2_RW setting on the cpreg. + */ + if (arm_current_el(env) == 1 && gicv5_legacy_enabled(env)) { + return CP_ACCESS_UNDEFINED; + } + /* + * continue to either redirect-to-memory, trap-to-EL2 or (if + * current EL is 2 or 3) access the register + */ + return CP_ACCESS_OK; +} + static const ARMCPRegInfo gicv5_cpuif_reginfo[] = { /* * Barrier: wait until the effects of a cpuif system register @@ -893,6 +930,13 @@ static const ARMCPRegInfo gicv5_cpuif_reginfo[] = { .writefn = gic_icc_pcr_el1_write, .resetfn = gic_icc_pcr_el1_reset, }, + { .name = "ICH_APR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 4, + .access = PL2_RW, .type = ARM_CP_NO_RAW, + .nv2_redirect_offset = 0xb00, + .accessfn = access_gicv5_ich_reg, + .fieldoffset = offsetof(CPUARMState, gicv5_cpuif.ich_apr_el2), + }, }; void define_gicv5_cpuif_regs(ARMCPU *cpu) -- 2.43.0
