@samitouri / QOSamiQemu / commits / 56f329b54a

target/arm: Implement FGWTE3 traps

Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260806172709.333300-5-richard.henderson@linaro.org [PMM: fixed comment indent] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Richard Henderson committed Aug 6, 2026 at 10:27 UTC 56f329b54a5782781aecb97c16d27d4e3eb1a702
2 files changed +42 -14
target/arm/tcg/op_helper.c
+27 -13
@@ -1061,13 +1061,15 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
1061 * Fine-grained traps also are lower priority than undef-to-EL1,
1062 * higher priority than trap-to-EL3, and we don't care about priority
1063 * order with other EL2 traps because the syndrome value is the same.
1064 + *
1065 + * FGWTE3 traps are exclusively traps to EL3 on registers that are
1066 + * only accessible to EL3, so there's no possibility of a trap to EL2.
1067 + * So we can handle these checks here too.
1068 */
1065 - if (arm_fgt_active(env, arm_current_el(env))) {
1069 + if (ri->fgt) {
1070 uint64_t trapword = 0;
1071 unsigned int idx = FIELD_EX32(ri->fgt, FGT, IDX);
1072 unsigned int bitpos = FIELD_EX32(ri->fgt, FGT, BITPOS);
1069 - bool rev = FIELD_EX32(ri->fgt, FGT, REV);
1070 - bool nxs = FIELD_EX32(ri->fgt, FGT, NXS);
1073 bool trapbit;
1074
1075 if (ri->fgt & FGT_EXEC) {
@@ -1080,19 +1082,31 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
1082 assert(idx < ARRAY_SIZE(env->cp15.fgt_write));
1083 trapword = env->cp15.fgt_write[idx];
1084 }
1085 + trapbit = extract64(trapword, bitpos, 1);
1086
1084 - if (nxs && (arm_hcrx_el2_eff(env) & HCRX_FGTNXS)) {
1087 + if ((ri->access & ~PL3_RW) == 0) {
1088 /*
1086 - * If HCRX_EL2.FGTnXS is 1 then the fine-grained trap for
1087 - * TLBI maintenance insns does *not* apply to the nXS variant.
1089 + * EL3 cpreg -- must be FGWTE3, and FGWTE3_EL3 can only be
1090 + * set from AArch64, and if the feature is enabled.
1091 */
1089 - trapbit = 0;
1090 - } else {
1091 - trapbit = extract64(trapword, bitpos, 1);
1092 - }
1093 - if (trapbit != rev) {
1094 - res = CP_ACCESS_TRAP_EL2;
1095 - goto fail;
1092 + if (trapbit) {
1093 + res = CP_ACCESS_TRAP_EL3;
1094 + goto fail;
1095 + }
1096 + } else if (arm_fgt_active(env, arm_current_el(env))) {
1097 + bool nxs = FIELD_EX32(ri->fgt, FGT, NXS);
1098 + bool rev = FIELD_EX32(ri->fgt, FGT, REV);
1099 + if (nxs && (arm_hcrx_el2_eff(env) & HCRX_FGTNXS)) {
1100 + /*
1101 + * If HCRX_EL2.FGTnXS is 1 then the fine-grained trap for
1102 + * TLBI maintenance insns does *not* apply to the nXS variant.
1103 + */
1104 + trapbit = 0;
1105 + }
1106 + if (trapbit != rev) {
1107 + res = CP_ACCESS_TRAP_EL2;
1108 + goto fail;
1109 + }
1110 }
1111 }
1112
target/arm/tcg/translate-a64.c
+15 -1
@@ -2886,6 +2886,7 @@ static void handle_sys(DisasContext *s, bool isread,
2886 {
2887 uint32_t key = ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2);
2888 const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
2889 + bool need_helper = false;
2890 bool need_exit_tb = false;
2891 bool nv_trap_to_el2 = false;
2892 bool nv_redirect_reg = false;
@@ -2999,7 +3000,20 @@ static void handle_sys(DisasContext *s, bool isread,
3000 ri = redirect_cpreg(s, key, isread);
3001 }
3002
3002 - if (ri->accessfn || (ri->fgt && s->fgt_active)) {
3003 + if (ri->accessfn) {
3004 + need_helper = true;
3005 + } else if (ri->fgt) {
3006 + /*
3007 + * EL3-only access means this must be an FGWTE3 trap (which are
3008 + * always active); otherwise it's an FGT trap to EL2.
3009 + */
3010 + if ((ri->access & ~PL3_RW) == 0) {
3011 + need_helper = dc_isar_feature(aa64_fgwte3, s);
3012 + } else {
3013 + need_helper = s->fgt_active;
3014 + }
3015 + }
3016 + if (need_helper) {
3017 /* Emit code to perform further access permissions checks at
3018 * runtime; this may result in an exception.
3019 */