The GICv5 cpu interface includes a set of fine-grained trap registers which allow a hypervisor to trap guest accesses to the various GIC cpu interface registers and instructions. We implement this using the existing fine-grained-trap mechanism.
This commit provides the definitions of the FGT register bits and the registers themselves; we will mark up the cpreg definitions with the fgt trap information in the following commit. Note that because FGWTE3 has only write-traps and the indexes into fgt_read[] and fgt_write[] have to line up, we leave a gap in the fgt_read[] array for the unused slot. We could have moved FGTWE3 to the end of the array, since the array location isn't encoded in the migration stream, but that only saves us 8 bytes in the CPU struct size and leaves the possibility that we forget about the need to align the read/write indexes next time we add an FGT feature. Signed-off-by: Peter Maydell <[email protected]> --- target/arm/cpregs.h | 85 +++++++++++++++++++++++++++++++++++- target/arm/cpu.h | 10 +++-- target/arm/tcg/gicv5-cpuif.c | 22 ++++++++++ 3 files changed, 111 insertions(+), 6 deletions(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index ce651a4faa6..e46c8c979e1 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -389,12 +389,16 @@ typedef enum CPAccessResult { /* Indexes into fgt_read[] */ #define FGTREG_HFGRTR 0 #define FGTREG_HDFGRTR 1 -/* Indexes into fgt_write[] */ +/* 2 unused: FGWTE3 doesn't have read-traps */ +#define FGTREG_ICH_HFGRTR 3 /* GICv5 */ +/* Indexes into fgt_write[]; these must align with the fgt_read[] ones */ #define FGTREG_HFGWTR 0 #define FGTREG_HDFGWTR 1 #define FGTREG_FGWTE3 2 -/* Indexes into fgt_exec[] */ +#define FGTREG_ICH_HFGWTR 3 /* GICv5 */ +/* Indexes into fgt_exec[] (these don't have to line up with read/write) */ #define FGTREG_HFGITR 0 +#define FGTREG_ICH_HFGITR 1 /* GICv5 */ FIELD(HFGRTR_EL2, AFSR0_EL1, 0, 1) FIELD(HFGRTR_EL2, AFSR1_EL1, 1, 1) @@ -720,6 +724,45 @@ FIELD(FGWTE3_EL3, TTBR0_EL3, 20, 1) FIELD(FGWTE3_EL3, VBAR_EL3, 21, 1) FIELD(FGWTE3_EL3, GPCBW_EL3, 22, 1) +/* These are the GICv5 fine-grained trap registers */ +FIELD(ICH_HFGRTR_EL2, ICC_APR_EL1, 0, 1) +FIELD(ICH_HFGRTR_EL2, ICC_IDRN_EL1, 1, 1) +FIELD(ICH_HFGRTR_EL2, ICC_CR0_EL1, 2, 1) +/* Bit 3 is RES1 */ +FIELD(ICH_HFGRTR_EL2, ICC_HPPIR_EL1, 4, 1) +FIELD(ICH_HFGRTR_EL2, ICC_PCR_EL1, 5, 1) +FIELD(ICH_HFGRTR_EL2, ICC_ICSR_EL1, 6, 1) +FIELD(ICH_HFGRTR_EL2, ICC_IAFFIDR_EL1, 7, 1) +FIELD(ICH_HFGRTR_EL2, ICC_PPI_HMRN_EL1, 16, 1) +FIELD(ICH_HFGRTR_EL2, ICC_PPI_ENABLERN_EL1, 17, 1) +FIELD(ICH_HFGRTR_EL2, ICC_PPI_PENDRN_EL1, 18, 1) +FIELD(ICH_HFGRTR_EL2, ICC_PPI_PRIORITYRN_EL1, 19, 1) +FIELD(ICH_HFGRTR_EL2, ICC_PPI_ACTIVERN_EL1, 20, 1) +/* All RES1 bits in this register */ +#define ICH_HFGRTR_EL2_RES1_MASK (1 << 3) + +/* Matches ICH_HFGRTR_EL2, but bits for RO regs are RES0 */ +FIELD(ICH_HFGWTR_EL2, ICC_APR_EL1, 0, 1) +FIELD(ICH_HFGWTR_EL2, ICC_CR0_EL1, 2, 1) +FIELD(ICH_HFGWTR_EL2, ICC_PCR_EL1, 5, 1) +FIELD(ICH_HFGWTR_EL2, ICC_ICSR_EL1, 6, 1) +FIELD(ICH_HFGWTR_EL2, ICC_PPI_ENABLERN_EL1, 17, 1) +FIELD(ICH_HFGWTR_EL2, ICC_PPI_PENDRN_EL1, 18, 1) +FIELD(ICH_HFGWTR_EL2, ICC_PPI_PRIORITYRN_EL1, 19, 1) +FIELD(ICH_HFGWTR_EL2, ICC_PPI_ACTIVERN_EL1, 20, 1) + +FIELD(ICH_HFGITR_EL2, GICCDEN, 0, 1); +FIELD(ICH_HFGITR_EL2, GICCDDIS, 1, 1); +FIELD(ICH_HFGITR_EL2, GICCDPRI, 2, 1); +FIELD(ICH_HFGITR_EL2, GICCDAFF, 3, 1); +FIELD(ICH_HFGITR_EL2, GICCDPEND, 4, 1); +FIELD(ICH_HFGITR_EL2, GICCDRCFG, 5, 1); +FIELD(ICH_HFGITR_EL2, GICCDHM, 6, 1); +FIELD(ICH_HFGITR_EL2, GICCDEOI, 7, 1); +FIELD(ICH_HFGITR_EL2, GICCDDI, 8, 1); +FIELD(ICH_HFGITR_EL2, GICRCDIA, 9, 1); +FIELD(ICH_HFGITR_EL2, GICRCDNMIA, 10, 1); + FIELD(FGT, NXS, 13, 1) /* Honour HCR_EL2.FGTnXS to suppress FGT */ /* Which fine-grained trap bit register to check, if any */ FIELD(FGT, TYPE, 10, 3) @@ -798,6 +841,9 @@ typedef enum FGTBit { FGT_HDFGWTR = FGT_W | (FGTREG_HDFGWTR << R_FGT_IDX_SHIFT), FGT_HFGITR = FGT_EXEC | (FGTREG_HFGITR << R_FGT_IDX_SHIFT), FGT_FGWTE3 = FGT_W | (FGTREG_FGWTE3 << R_FGT_IDX_SHIFT), + FGT_ICH_HFGRTR = FGT_RW | (FGTREG_ICH_HFGRTR << R_FGT_IDX_SHIFT), + FGT_ICH_HFGWTR = FGT_W | (FGTREG_ICH_HFGWTR << R_FGT_IDX_SHIFT), + FGT_ICH_HFGITR = FGT_EXEC | (FGTREG_ICH_HFGITR << R_FGT_IDX_SHIFT), /* Trap bits in HFGRTR_EL2 / HFGWTR_EL2, starting from bit 0. */ DO_BIT(HFGRTR, AFSR0_EL1), @@ -955,6 +1001,41 @@ typedef enum FGTBit { DO_EL3_BIT(FGWTE3, TTBR0_EL3), DO_EL3_BIT(FGWTE3, VBAR_EL3), DO_EL3_BIT(FGWTE3, GPCBW_EL3), + + /* + * Trap bits in ICH_HFGRTR_EL2 / ICH_HFGWTR_EL2, starting from bit 0. + * These are all "trap on 0, don't trap on 1" and don't follow the + * "name starts with 'n' if sense is reversed" convention of the + * main FEAT_FGT registers. + */ + DO_REV_BIT(ICH_HFGRTR, ICC_APR_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_IDRN_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_CR0_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_HPPIR_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_PCR_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_ICSR_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_IAFFIDR_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_PPI_HMRN_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_PPI_ENABLERN_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_PPI_PENDRN_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_PPI_PRIORITYRN_EL1), + DO_REV_BIT(ICH_HFGRTR, ICC_PPI_ACTIVERN_EL1), + + /* + * Trap bits in ICH_HFGITR_EL2, starting from bit 0. These also + * are all "trap on 0". + */ + DO_REV_BIT(ICH_HFGITR, GICCDEN), + DO_REV_BIT(ICH_HFGITR, GICCDDIS), + DO_REV_BIT(ICH_HFGITR, GICCDPRI), + DO_REV_BIT(ICH_HFGITR, GICCDAFF), + DO_REV_BIT(ICH_HFGITR, GICCDPEND), + DO_REV_BIT(ICH_HFGITR, GICCDRCFG), + DO_REV_BIT(ICH_HFGITR, GICCDHM), + DO_REV_BIT(ICH_HFGITR, GICCDEOI), + DO_REV_BIT(ICH_HFGITR, GICCDDI), + DO_REV_BIT(ICH_HFGITR, GICRCDIA), + DO_REV_BIT(ICH_HFGITR, GICRCDNMIA), } FGTBit; #undef DO_BIT diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 4e7076a5339..276466d2b84 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -550,11 +550,13 @@ typedef struct CPUArchState { * Fine-Grained Trap registers. We store these as arrays so the * access checking code doesn't have to manually select * HFGRTR_EL2 vs HFDFGRTR_EL2 etc when looking up the bit to test. - * FEAT_FGT2 will add more elements to these arrays. + * These include the trap registers for all features which have + * FGT-style trapping: FEAT_FGT, FEAT_FGWTE3. GICv5, and (when we + * implement it) FEAT_FGT2. */ - uint64_t fgt_read[2]; /* HFGRTR, HDFGRTR */ - uint64_t fgt_write[3]; /* HFGWTR, HDFGWTR, FGWTE3 */ - uint64_t fgt_exec[1]; /* HFGITR */ + uint64_t fgt_read[4]; /* HFGRTR, HDFGRTR, unused, ICH_HFGRTR */ + uint64_t fgt_write[4]; /* HFGWTR, HDFGWTR, FGWTE3, ICH_HFGWTR */ + uint64_t fgt_exec[2]; /* HFGITR, ICH_HFGITR */ /* RME registers */ uint64_t gpccr_el3; diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c index ac667c84c2f..55dc2e3b3b2 100644 --- a/target/arm/tcg/gicv5-cpuif.c +++ b/target/arm/tcg/gicv5-cpuif.c @@ -979,6 +979,28 @@ static const ARMCPRegInfo gicv5_cpuif_reginfo[] = { .accessfn = access_gicv5_ich_reg, .fieldoffset = offsetof(CPUARMState, gicv5_cpuif.ich_apr_el2), }, + { .name = "ICH_HFGRTR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 4, + .access = PL2_RW, .type = ARM_CP_NO_RAW, + .nv2_redirect_offset = 0xb10, + .accessfn = access_gicv5_ich_reg, + .fieldoffset = offsetof(CPUARMState, cp15.fgt_read[FGTREG_ICH_HFGRTR]), + .resetvalue = ICH_HFGRTR_EL2_RES1_MASK, + }, + { .name = "ICH_HFGWTR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 6, + .access = PL2_RW, .type = ARM_CP_NO_RAW, + .nv2_redirect_offset = 0xb10, + .accessfn = access_gicv5_ich_reg, + .fieldoffset = offsetof(CPUARMState, cp15.fgt_write[FGTREG_ICH_HFGWTR]), + }, + { .name = "ICH_HFGITR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 7, + .access = PL2_RW, .type = ARM_CP_NO_RAW, + .nv2_redirect_offset = 0xb10, + .accessfn = access_gicv5_ich_reg, + .fieldoffset = offsetof(CPUARMState, cp15.fgt_exec[FGTREG_ICH_HFGITR]), + }, /* * Note that DVIR bits RAZ/WI when the PPI isn't assigned to the * current domain, so we will need to mask them when we implement -- 2.43.0
