@samitouri / QOSamiQemu / commits / 335870f28e

target/arm: honour CCR.BFHFNMIGN for probed data BusFaults

M-profile CCR.BFHFNMIGN lets software executing at a negative execution priority (in HardFault/NMI, or with FAULTMASK set) suppress precise data BusFaults caused by load/store instructions: the access completes returning UNKNOWN data, the fault status is recorded in BFSR/BFAR, but no BusFault exception is taken. Software uses this to probe for the presence of a device. QEMU stored CCR.BFHFNMIGN but never consumed it: arm_cpu_do_transaction_ failed() always raised the external abort, which arm_v7m_cpu_do_interrupt() pended as a BusFault and then escalated to a HardFault it could not take at priority -1, aborting the VM with "Lockup: can't escalate 3 to HardFault". Honour the bit in arm_cpu_do_transaction_failed(): when the access is a data access from M-profile code at negative priority with BFHFNMIGN set, record PRECISERR/BFARVALID and BFAR and return without raising, so the faulting instruction completes instead of re-faulting forever. Instruction fetches are unaffected, since BFHFNMIGN applies only to data accesses. The SG instruction's stack-word load is also an AccType_NORMAL data access that must honour BFHFNMIGN, but QEMU performs it manually in v7m_read_sg_stack_word() (outside the TCG TLB, so it never reaches arm_cpu_do_transaction_failed()). Apply the same suppression there: on a BusFault, record the status and, when BFHFNMIGN is set at negative priority, return the UNKNOWN data instead of pending ARMV7M_EXCP_BUS. The remaining manual EXCP_BUS sites (vector-table loads, stacking, unstacking) are AccType_VECTABLE/STACK/UNSTACK and are not required to honour the bit, so they are left unchanged. This surfaced running the real NXP i.MX 95 System Manager firmware on the emulated Cortex-M33: its SystemMemoryProbe() (set BFHFNMIGN + FAULTMASK, do the access, test CFSR.BFARVALID) locked up the VM. With this change the SM's debug-monitor memory-probe commands run and recover correctly. Signed-off-by: Kyle Fox <kylefoxaustin.github@gmail.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> [PMM: minor tweak to v7m_read_sg_stack_word() code] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Kyle Fox committed Jun 14, 2026 at 19:08 UTC 335870f28e3290f01ae32240b1a98cf40695c4ac
2 files changed +38 -2
target/arm/tcg/m_helper.c
+14 -2
@@ -2086,8 +2086,20 @@ static bool v7m_read_sg_stack_word(ARMCPU *cpu, ARMMMUIdx mmu_idx,
2086 env->v7m.cfsr[M_REG_NS] |=
2087 (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
2088 env->v7m.bfar = addr;
2089 - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
2090 - return false;
2089 + /*
2090 + * The SG instruction's stack-word load is an AccType_NORMAL data
2091 + * access, so CCR.BFHFNMIGN applies: at negative execution priority
2092 + * with BFHFNMIGN set, the BusFault is suppressed -- the access
2093 + * completes returning UNKNOWN data (status recorded above), with no
2094 + * BusFault exception pended.
2095 + */
2096 + if (!((env->v7m.ccr[M_REG_NS] & R_V7M_CCR_BFHFNMIGN_MASK) &&
2097 + armv7m_nvic_neg_prio_requested(env->nvic, env->v7m.secure))) {
2098 + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
2099 + return false;
2100 + }
2101 + /* BusFault suppressed; data value is UNKNOWN, we choose 0 */
2102 + value = 0;
2103 }
2104
2105 *spdata = value;
target/arm/tcg/tlb_helper.c
+24
@@ -10,6 +10,7 @@
10 #include "helper.h"
11 #include "internals.h"
12 #include "cpu-features.h"
13 +#include "hw/intc/armv7m_nvic.h"
14
15 /*
16 * Returns true if the stage 1 translation regime is using LPAE format page
@@ -318,8 +319,31 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
319 MemTxResult response, uintptr_t retaddr)
320 {
321 ARMCPU *cpu = ARM_CPU(cs);
322 + CPUARMState *env = &cpu->env;
323 ARMMMUFaultInfo fi = {};
324
325 + /*
326 + * For M-profile, CCR.BFHFNMIGN lets software executing at a negative
327 + * priority (in HardFault/NMI, or with FAULTMASK set) suppress precise
328 + * data BusFaults from load/store instructions: the access completes
329 + * returning UNKNOWN data (the store is dropped), the fault status is
330 + * recorded in BFSR/BFAR, but no BusFault exception is taken. This is
331 + * the mechanism software uses to probe for the presence of a device
332 + * (e.g. the NXP System Manager's SystemMemoryProbe). Honour it by
333 + * recording the status and returning without raising, so the faulting
334 + * instruction completes rather than re-faulting forever. BFHFNMIGN
335 + * applies only to data accesses, so instruction fetches are unaffected.
336 + */
337 + if (arm_feature(env, ARM_FEATURE_M) &&
338 + access_type != MMU_INST_FETCH &&
339 + (env->v7m.ccr[M_REG_NS] & R_V7M_CCR_BFHFNMIGN_MASK) &&
340 + armv7m_nvic_neg_prio_requested(env->nvic, env->v7m.secure)) {
341 + env->v7m.cfsr[M_REG_NS] |=
342 + (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
343 + env->v7m.bfar = addr;
344 + return;
345 + }
346 +
347 /* now we have a real cpu fault */
348 cpu_restore_state(cs, retaddr);
349