Implement ICC_CR0_EL1, which is the main control register. This is banked between interrupt domains in the same way as ICC_APR_*.
The GICv5 spec assumes that typically there will need to be a hardware handshake between the CPU and the IRS, which is kicked off by guest software setting a LINK bit in this register to bring the link between the two online. However it is permitted to have an implementation where the link is permanently up. We take advantage of this, so our LINK and LINK_IDLE bits are read-only and always 1. This means the only interesting bit in this register for us is the main enable bit: when disabled for a domain, the cpuif considers that there is never an available highest priority interrupt. Signed-off-by: Peter Maydell <[email protected]> --- target/arm/cpu.h | 1 + target/arm/tcg/gicv5-cpuif.c | 44 ++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index e0a7d02386..1263841a1d 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -605,6 +605,7 @@ typedef struct CPUArchState { /* GICv5 CPU interface data */ uint64_t icc_icsr_el1; uint64_t icc_apr[NUM_GICV5_DOMAINS]; + uint64_t icc_cr0[NUM_GICV5_DOMAINS]; /* Most PPI registers have 1 bit per PPI, so 64 PPIs to a register */ uint64_t ppi_active[GICV5_NUM_PPIS / 64]; uint64_t ppi_hm[GICV5_NUM_PPIS / 64]; diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c index 2f6827dc13..5af9fdb1db 100644 --- a/target/arm/tcg/gicv5-cpuif.c +++ b/target/arm/tcg/gicv5-cpuif.c @@ -43,6 +43,12 @@ FIELD(ICC_IDR0_EL1, ID_BITS, 0, 4) FIELD(ICC_IDR0_EL1, PRI_BITS, 4, 4) FIELD(ICC_IDR0_EL1, GCIE_LEGACY, 8, 4) +FIELD(ICC_CR0, EN, 0, 1) +FIELD(ICC_CR0, LINK, 1, 1) +FIELD(ICC_CR0, LINK_IDLE, 2, 1) +FIELD(ICC_CR0, IPPT, 32, 6) +FIELD(ICC_CR0, PID, 38, 1) + /* * We implement 24 bits of interrupt ID, the mandated 5 bits of priority, * and no legacy GICv3.3 vcpu interface (yet) @@ -346,6 +352,37 @@ static uint64_t gic_icc_hapr_el1_read(CPUARMState *env, const ARMCPRegInfo *ri) return gic_running_prio(env, gicv5_current_phys_domain(env)); } +/* ICC_CR0_EL1 is also banked */ +static uint64_t gic_icc_cr0_el1_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + GICv5Domain domain = gicv5_logical_domain(env); + return env->gicv5_cpuif.icc_cr0[domain]; +} + +static void gic_icc_cr0_el1_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* + * For our implementation the link to the IRI is always connected, + * so LINK and LINK_IDLE are always 1. Without EL3, PID and IPPT + * are RAZ/WI, so the only writeable bit is the main enable bit EN. + */ + GICv5Domain domain = gicv5_logical_domain(env); + value &= R_ICC_CR0_EN_MASK; + value |= R_ICC_CR0_LINK_MASK | R_ICC_CR0_LINK_IDLE_MASK; + + env->gicv5_cpuif.icc_cr0[domain] = value; +} + +static void gic_icc_cr0_el1_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + /* The link is always connected so we reset with LINK and LINK_IDLE set */ + for (int i = 0; i < ARRAY_SIZE(env->gicv5_cpuif.icc_cr0); i++) { + env->gicv5_cpuif.icc_cr0[i] = + R_ICC_CR0_LINK_MASK | R_ICC_CR0_LINK_IDLE_MASK; + } +} + static const ARMCPRegInfo gicv5_cpuif_reginfo[] = { /* * Barrier: wait until the effects of a cpuif system register @@ -504,6 +541,13 @@ static const ARMCPRegInfo gicv5_cpuif_reginfo[] = { .writefn = gic_icc_apr_el1_write, .resetfn = gic_icc_apr_el1_reset, }, + { .name = "ICC_CR0_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 12, .crm = 0, .opc2 = 1, + .access = PL1_RW, .type = ARM_CP_IO | ARM_CP_NO_RAW, + .readfn = gic_icc_cr0_el1_read, + .writefn = gic_icc_cr0_el1_write, + .resetfn = gic_icc_cr0_el1_reset, + }, { .name = "ICC_HAPR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 1, .crn = 12, .crm = 0, .opc2 = 3, .access = PL1_R, .type = ARM_CP_IO | ARM_CP_NO_RAW, -- 2.43.0
