@samitouri / QOSamiQemu / commits / da8179efd6

target/arm: Report correct syndrome to AArch32 EL2 for trapped Neon/VFP insns

When an AArch32 Neon or VFP insn is trapped to AArch64 EL2, bits [19:0] of the syndrome in ESR_EL2 are RES0. However, when it is trapped to AArch32 EL2, the HSR syndrome information defines some extra fields: [5] : TA [3:0] : coproc where the TA bit is 1 for a trapped Neon insn and 0 for a trapped VFP insn, and the coproc field is 0b1010 when TA is 0, and 0 when TA is 1. We attempted to address this in commit fa33eead ("target/arm: Add coproc parameter to syn_fp_access_trap"), but got it wrong: we thought the RES0 condition was "is v8A" rather than "is EL2 AArch32", and we made all insns be TA=0 coproc = 0b1010 rather than only the VFP ones. Correct the condition we use to decide the coproc and TA fields. We set these fields unconditionally; later on in arm_cpu_do_interrupt_aarch64() we will squash them to zero if we are taking the exception to AArch64. NB: there is some disagreement between different revisions of the Arm ARM about the exact handling of 'coproc': * the v8A Arm ARM text says coproc is 0b1010 when TA is 1 * the v8A Arm ARM pseudocode in AArch32_CheckFPAdvSIMDTrap() sets coproc to 0b1010 when TA is 0 * the v7A Arm ARM text says coproc is 0b1010 when TA is 0 * the v7A Arm ARM pseudocode sets coproc to 0b1010 when TA is 0 The v7A Arm ARM pseudocode also disagrees with the v7A text, v8A text and v8A pseudocode in only setting TA to 1 for traps caused by HCPTR.TASE; the others set Ta for all trapped AdvSIMD insns (i.e. including traps caused by HCPTR.TCP10). We assume that the v8A pseudocode is incorrect about coproc (as it is the odd one out) and that the v7A pseudocode is incorrect about when TA is set (again, as it is the odd one out). Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/1153 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702184019.3431139-4-peter.maydell@linaro.org

Peter Maydell committed Jul 2, 2026 at 19:40 UTC da8179efd6c4797c1a8c749649b5705e7fd89f71
1 file changed +17 -12
target/arm/tcg/translate-vfp.c
+17 -12
@@ -216,19 +216,20 @@ static void gen_update_fp_context(DisasContext *s)
216 * whether VFP is enabled via FPEXC.EN: this should be true for FMXR/FMRX
217 * accesses to FPSID, FPEXC, MVFR0, MVFR1, MVFR2, and false for all other insns.
218 */
219 -static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled)
219 +static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled,
220 + bool is_neon)
221 {
222 if (s->fp_excp_el) {
223 /*
223 - * The full syndrome is only used for HSR when HCPTR traps:
224 - * For v8, when TA==0, coproc is RES0.
225 - * For v7, any use of a Floating-point instruction or access
226 - * to a Floating-point Extension register that is trapped to
227 - * Hyp mode because of a trap configured in the HCPTR sets
228 - * this field to 0xA.
224 + * The full syndrome is only used for HSR when HCPTR traps.
225 + * When trapping to AArch64, the TA and coproc fields are RES0
226 + * (we will squash them in arm_cpu_do_interrupt_aarch64()).
227 + * When trapping to AArch32:
228 + * - for VFP insns, TA=0 and coproc = 0b1010
229 + * - for Neon insns, TA=1 and coproc = 0
230 */
230 - int coproc = arm_dc_feature(s, ARM_FEATURE_V8) ? 0 : 0xa;
231 - uint32_t syn = syn_a32_fp_access_trap(1, 0xe, 0, coproc);
231 + int coproc = is_neon ? 0 : 0xa;
232 + uint32_t syn = syn_a32_fp_access_trap(1, 0xe, is_neon, coproc);
233
234 gen_exception_insn_el(s, 0, EXCP_UDEF, syn, s->fp_excp_el);
235 return false;
@@ -299,7 +300,7 @@ bool vfp_access_check(DisasContext *s)
300 if (arm_dc_feature(s, ARM_FEATURE_M)) {
301 return vfp_access_check_m(s, false);
302 } else {
302 - return vfp_access_check_a(s, false);
303 + return vfp_access_check_a(s, false, false);
304 }
305 }
306
@@ -311,7 +312,11 @@ bool vfp_access_check(DisasContext *s)
312 */
313 bool neon_access_check(DisasContext *s)
314 {
314 - return vfp_access_check(s);
315 + if (arm_dc_feature(s, ARM_FEATURE_M)) {
316 + return vfp_access_check_m(s, false);
317 + } else {
318 + return vfp_access_check_a(s, false, true);
319 + }
320 }
321
322 static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
@@ -822,7 +827,7 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
827 * Call vfp_access_check_a() directly, because we need to tell
828 * it to ignore FPEXC.EN for some register accesses.
829 */
825 - if (!vfp_access_check_a(s, ignore_vfp_enabled)) {
830 + if (!vfp_access_check_a(s, ignore_vfp_enabled, false)) {
831 return true;
832 }
833