Kevin Boone’s guide to UEFI, the firmware interface used to boot modern PCs, takes a pragmatic detour in part four. An application running directly under firmware still contains plenty of ordinary C. Keeping that code testable on Linux makes development much less painful.
His approach puts the platform boundary in plain sight:
- Build a Linux test harness. Lists, tokenizers, and other portable logic can run under familiar debugging and profiling tools. Boone maintains separate Linux and EFI Makefiles that share source files.
- Choose how much compatibility to buy. EFI uses two-byte characters, backslash-separated paths, and handle-based APIs. Decide early whether to adopt those conventions throughout or contain them behind wrappers.
- Preserve the interface’s types. Boone lost hours after storing an
EFI_STATUSvalue in anint. On his 64-bit target, the status value needs 64 bits. - Budget for missing services. Standard C library calls need implementations or suitable replacements. File access, console control, and memory management each bring assumptions that firmware may fail to satisfy.
A compatibility layer can make a substantial application easier to understand and maintain. It also creates more work as each familiar function pulls in another expectation. Boone argues that this trade can pay off as the program grows; a Hello World hardly needs it.
The design carries beyond firmware: keep portable logic runnable where the tools are strongest, and make the platform-specific contract explicit. Testability becomes an architectural choice made before debugging gets difficult.