Debugging UEFI PEI-to-DXE Handoff Boot Stalls

Troubleshooting boot stalls during the transition from the Pre-EFI Initialization (PEI) phase to the Driver Execution Environment (DXE) phase requires identifying failures that occur as firmware migrates execution from temporary cache to permanent system memory. This guide details the technical mechanisms behind the PEI-to-DXE handoff, outlines common root causes of execution hangs, and provides step-by-step methodologies firmware engineers use to isolate and resolve these issues using hardware and software diagnostics.

The Mechanics of the PEI-to-DXE Transition

The handoff is managed by the DXE Initial Program Loader (DxeIpl) PEI Module (PEIM). To understand where execution freezes, developers monitor these sequential operations:

  1. Memory Initialization: The system transitions from temporary Cache-as-RAM (CAR) to permanent system memory (DRAM).
  2. HOB List Finalization: PEI collects platform data, memory maps, and boot status into the Hand-Off Block (HOB) list.
  3. Firmware Volume (FV) Discovery: The DxeIpl locates the Firmware Volume containing the DXE Foundation (DXE Core).
  4. Architectural State Transition: If PEI operates in 32-bit mode (IA32) and DXE executes in 64-bit mode (X64), the DxeIpl constructs 64-bit page tables, configures control registers (such as enabling PAE and Long Mode via CR0, CR3, and CR4), and switches processor execution modes.
  5. Entry Point Invocation: DxeIpl calls the DXE Core entry point, passing the address of the HOB list.

Common Failure Modes

Stalls at this boundary typically stem from hardware state changes or memory structure corruption:

  • Stack and Memory Migration Failures: If DRAM initialization succeeds but memory timings, termination resistances, or refresh rates are unstable, tearing down CAR and copying the stack to DRAM causes silent corruption.
  • Corrupt or Malformed HOBs: If a PEIM produces an invalid HOB (e.g., miscalculated length, missing terminator HOB, or overlapping memory resource descriptors), the DXE Core will crash or loop infinitely while parsing the list.
  • Paging and Mode Switching Errors: When transitioning to 64-bit long mode, incorrect page table mappings, unaligned page directories, or mapping execution-disabled (NX/XD) attributes over the DXE Core code region trigger immediate General Protection (#GP) or Page Fault (#PF) exceptions.
  • Firmware Volume Decompression Errors: If the DXE Firmware Volume is compressed (e.g., using Tiano or LZMA compression) and the decompressor receives corrupted headers or insufficient scratch space, execution deadlocks.

Primary Troubleshooting Methodologies

Firmware engineers employ a combination of hardware instruments, telemetry, and source instrumentation to isolate the stall point.

1. Port 80h Checkpoints

Port 80h POST codes provide the fastest indicator of handoff progress. Developers monitor POST codes output by DxeIplPeim and the early DxeMain function. A freeze between the last PEI status code (such as memory configured) and the first DXE status code (such as DXE Core loaded) narrows the failure to the mode switch, relocation, or HOB verification.

2. Early Serial Telemetry

When POST codes are too coarse, developers route debug prints to a low-overhead interface, typically an on-chip UART, LPC debug card, or USB debug port.

  • Enable high-verbosity logging (DEBUG_VERBOSE or DEBUG_INFO) in MdeModulePkg/Core/DxeIplPeim and MdeModulePkg/Core/Dxe.

  • Insert explicit raw I/O writes or assembly-level character writes directly before and after the DXE Core invocation:

    // Direct serial write inside DxeLoadCore before handoff
    DebugPrint (DEBUG_INFO, "Handing off to DXE Core at: 0x%p\n", (VOID*)(UINTN)DxeCoreEntryPoint);
    DxeCoreEntryPoint (HobList);
  • If serial output ceases before the DXE Core header prints, verify whether the serial controller's base address changed or if its clock gating was altered during the transition.

3. Hardware JTAG/ICE Debugging

In-Circuit Emulators (ICE) connected via JTAG/XDP provide non-intrusive visibility when the CPU halts without emitting serial data.

  • Halt and Inspect PC/IP: Halt the target immediately after the stall occurs to observe the Instruction Pointer (RIP/EIP).
  • Inspect Registers: If the core has entered an exception loop, check the Interrupt Descriptor Table (IDTR), CR2 (Page Fault Linear Address), and CR3 (Page Table Base) to diagnose access violations.
  • Stack Backtrace: Verify that the stack pointer (RSP/ESP) points to valid, accessible DRAM addresses and matches the location assigned during the CAR teardown.

4. Validating the HOB List Structure

If the DXE Core entry point is reached but hangs immediately, the HOB list is frequently the cause. Developers validate HOB integrity by implementing a validation routine at the start of DxeMain:

  • Verify the first HOB is EFI_HOB_TYPE_HANDOFF and contains valid boot modes and memory ranges.
  • Traverse the list using GetNextHob() to ensure every block has a valid, non-zero length and ends with EFI_HOB_TYPE_END_OF_HOB_LIST.
  • Confirm that memory allocation HOBs do not overlap with the DXE Core image relocation target.

5. Page Table and Memory Map Auditing

When switching to Long Mode, developers inspect the identity-mapped page tables created by DxeIpl. Engineers verify that:

  • The page directory entries accurately map all physical memory where the DXE Core and stacks reside.
  • The Global Descriptor Table (GDT) registers are loaded with valid 64-bit code and data segment selectors before jumping to the DXE Core.