ARM FVP executes XN‑protected code that faults on real silicon

Summary

During a firmware bring-up exercise using the ARM Trusted Firmware (TF-A) on an Arm FVP (Fixed Virtual Platform), an unexpected architectural behavior was observed. A memory region containing BL31 code was explicitly marked with the Execute-Never (XN) attribute in the Stage 1 translation tables at EL3. Despite the MMU being enabled and synchronization instructions (DSB, ISB) being issued, the processor successfully fetched and executed instructions from this “forbidden” region without triggering a Permission Fault. This behavior contrasted sharply with tests on physical FPGA hardware, where the same configuration correctly triggered a synchronous exception.

Root Cause

The root cause is the fundamental difference between Architectural Specification and Microarchitectural Implementation in hardware emulators versus physical silicon.

  • The “Perfect” vs. “Realistic” Model: The Arm FVP is a functional simulator. While it adheres to the ARMv8-A architecture, simulators often prioritize functional correctness of the instruction stream over the strict enforcement of side-channel or permission-based aborts unless specifically configured to do so.
  • Instruction Prefetch vs. Execution: In many high-performance implementations, the instruction fetch unit and the execution unit are decoupled. In a simulator, if the instruction has already been “seen” by the fetcher or is part of a pre-buffered pipeline, the simulator may bypass the MMU permission check for that specific cycle to maintain simulation throughput.
  • The “Definition of Done” in Simulation: In the FVP environment, the XN bit is a request to the MMU. If the simulator’s internal state machine does not explicitly trigger an exception signal for a “hit” on an XN descriptor during a prefetch, the execution continues. On physical silicon, the hardware logic for the MMU is hard-wired to assert an exception signal to the pipeline controller the moment an instruction fetch hits a descriptor with XN=1.

Why This Happens in Real Systems

This phenomenon highlights a critical gap in software development: The Simulation-Reality Gap.

  • Abstraction Leakage: Emulators provide an abstraction of the architecture. They guarantee that A + B = C, but they do not always guarantee that the timing, faults, and side effects of the underlying transistors are perfectly mirrored.
  • Performance Optimization: Simulators often use “lazy evaluation” for memory attributes. Checking every single permission bit for every single prefetch in a software-based model is computationally expensive. To stay fast, simulators might skip certain permission-check validations.
  • Hardware Complexity: In real silicon, the MMU is a massive, complex piece of logic that interacts with the L1 Instruction Cache. An XN fault is a complex state transition involving the pipeline flush and exception vector jump. Simulators often simplify these transitions to ensure the simulation doesn’t hang.

Real-World Impact

  • False Sense of Security: Developers may write firmware that inadvertently leaves sensitive memory regions executable, believing their MMU configuration is working because “the simulator didn’t complain.”
  • Debugging Nightmares: When the code is eventually ported to physical silicon (ASIC or FPGA), the system will suddenly start crashing with Permission Faults or Instruction Aborts, leading to wasted engineering hours trying to find a “bug” that is actually a difference in hardware behavior.
  • Security Vulnerabilities: If a developer relies on XN to mitigate Code Injection attacks, and the hardware implementation has subtle flaws (or the simulation hides them), the security posture of the entire Trusted Execution Environment (TEE) is compromised.

Example or Code

The following pseudo-code demonstrates the logical setup that led to the observation:

// Conceptual representation of the failing configuration
void setup_bl31_mmu(void) {
    // 1. Define the descriptor for BL31 code region
    // Attributes: AP=1 (RW), XN=1 (Execute-Never), AF=1, AttrIndx=0
    uint64_t bl31_descriptor = 0x00400000_04003743; 

    // 2. Install descriptor into the L3 Translation Table
    install_descriptor(BL31_CODE_ADDR, bl31_descriptor);

    // 3. Enable MMU and synchronize
    enable_mmu_el3();
    dsb_sy();
    isb();

    // 4. Jump to BL31 entry point
    // ARCHITECTURAL EXPECTATION: Instruction Abort (ESR_EL3 = 0x8600000F)
    // SIMULATOR OBSERVATION: Execution continues normally
    ((void (*)(void))BL31_CODE_ADDR)();
}

How Senior Engineers Fix It

Senior engineers do not trust the simulator blindly. They employ several strategies to ensure correctness:

  • Hardware-in-the-Loop (HIL) Testing: They mandate that any “critical” security or memory-management code must be validated on actual silicon or FPGA prototypes before being marked as “passed.”
  • Negative Testing: They don’t just test if the code works; they intentionally write tests to see if the system fails when it should. If a test is designed to trigger an XN fault, and the simulator doesn’t fault, the engineer marks the simulation environment as unreliable for permission validation.
  • Verification Suites: They use formal verification tools or highly specialized architectural models (like ARM’s Cycle Model) which are much slower than functional simulators but are designed to be architecturally exact.

Why Juniors Miss It

  • Over-reliance on Tools: Juniors often treat the debugger and the simulator as the “source of truth.” If the simulator says the code is running, they assume the code is correct.
  • Lack of Architectural Depth: They focus on functional logic (does the code do what it’s supposed to?) rather than architectural side-effects (how does the hardware react to illegal states?).
  • Confusion between Logic and Implementation: They struggle to distinguish between the ARM Architecture Manual (the rules) and the FVP/Silicon (the implementation of those rules). They assume that because the manual says XN prevents execution, the simulator must behave that way, failing to realize the simulator is just a software approximation.

Leave a Comment