Skip to content

Instantly share code, notes, and snippets.

@lizthegrey
Last active March 8, 2026 19:03
Show Gist options
  • Select an option

  • Save lizthegrey/9344dc71dc4ac11f9d6c79d7c143e535 to your computer and use it in GitHub Desktop.

Select an option

Save lizthegrey/9344dc71dc4ac11f9d6c79d7c143e535 to your computer and use it in GitHub Desktop.
SolidRun LX2160A (HoneyComb LX2K) UEFI Firmware Modernization Report

SolidRun LX2160A (HoneyComb LX2K) UEFI Firmware Modernization

Summary

This project modernized the entire firmware stack for the SolidRun HoneyComb LX2K (LX2160A CEx7) from a stale 2021-era codebase to current upstream releases, bringing the existing OP-TEE/StandaloneMm Secure Boot support forward from OP-TEE 3.14.0 to 4.9.0.

Result: A fully modern, Secure Boot-enabled firmware booting Ubuntu 24.04 via shim → GRUB → signed kernel.

Component Before After
ATF (TF-A) NXP lf_v2.4 (2021) NXP lf_v2.12 (2025)
RCW SolidRun LSDK-20.04-sr (2020) NXP lf-6.6.52-2.2.0 + SolidRun CEX7 configs
EDK2 edk2-stable202105 edk2-stable202602
edk2-platforms SolidRun fork (2021) upstream master + SolidRun overlay
Secure Boot stack OP-TEE 3.14.0 + edk2-stable202105 OP-TEE 4.9.0 + edk2-stable202602

Architecture

┌─────────────────────────────────────────────────┐
│                   Ubuntu 24.04                   │
├─────────────────────────────────────────────────┤
│  GRUB (signed by Canonical, verified by shim)    │
├─────────────────────────────────────────────────┤
│  shim (signed by Microsoft UEFI CA 2011)         │
├─────────────────────────────────────────────────┤
│  UEFI (EDK2 edk2-stable202602)                   │
│  ├─ VariableSmmRuntimeDxe (NS proxy)             │
│  ├─ MmCommunicationOpteeDxe (NS↔S bridge)        │
│  └─ SecurityStubDxe + DxeImageVerificationLib     │
├─────────────────────────────────────────────────┤
│  OP-TEE 4.9.0 (Secure World)                     │
│  └─ StandaloneMm (EFI variable services)         │
│     ├─ VariableStandaloneMm (auth variables)      │
│     ├─ FaultTolerantWriteStandaloneMm             │
│     └─ EepromFvb (I2C EEPROM NV storage)          │
├─────────────────────────────────────────────────┤
│  ATF v2.12 (BL1/BL2/BL31)                        │
│  └─ DDR init, SerDes, PSCI, SPD=opteed            │
├─────────────────────────────────────────────────┤
│  RCW + PBI (NXP lf-6.6.52 + SolidRun CEX7)        │
│  └─ PLL ratios, pin mux, errata workarounds        │
└─────────────────────────────────────────────────┘

Phases

Phase 1: ATF Patch Backport

Cherry-picked SolidRun's 16 board-support patches from their lx2160a_build repo onto NXP's lf_v2.4 ATF branch. Verified the platform boots to GRUB.

Phase 2: EDK2 Update to edk2-stable202602

Updated EDK2 from edk2-stable202105 to edk2-stable202602 (5 years of upstream development). Key source-level fixes required across SolidRun's platform code:

  • AsmMacroIoLibV8.hAsmMacroLib.h (header rename)
  • ARM_CORE_INFO struct: dropped ClusterId field
  • IORT ACPI: RMR_DESCMEM_RANGE_DESC, field renames
  • NET_RANDOM/NetRandomInitSeedPseudoRandomU32
  • SMBIOS_CACHE_SIZE bitfield struct change
  • PROCESSOR_ID_DATA new 4-field struct on AARCH64

Critical fix: NULL|LzmaCustomDecompressLib must be linked into the PeilessSec module's DSC entry for the LZMA decompression handler to register. Without it, DecompressFirstFv() fails and UEFI hangs after the SEC banner.

Phase 3: ATF Rebase to v2.10

Rebased SolidRun's 16 patches from NXP lf_v2.4 to NXP lf_v2.10. Clean cherry-picks, no conflicts.

Phase 4: edk2-platforms Upstream Rebase

Strategy: Start from upstream tianocore/edk2-platforms master (already edk2-stable202602 compatible) and port SolidRun's hardware support forward. This means future EDK2 updates are nearly free for infrastructure code.

Category Files Action
SolidRun-only 640 Copied onto upstream base
Overlapping 18 Upstream-first, minimal SolidRun additions
Upstream-only 40+ Kept as-is

Key merge decisions:

  • IoAccessLib: Took upstream's GetMmioOperations() API, updated 17 SolidRun files that used the old SwapMmioXxx() functions
  • PciHostBridgeLib: Kept SolidRun's version (1756 lines with SMMU/IORT/FDT integration vs upstream's 430-line version)
  • NxpQoriqLs.dec: Added SolidRun's ~260 additional PCDs/GUIDs to upstream's DEC
  • I2cDxe: Reverted to Phase 2's self-contained driver (upstream's NonDiscoverable Device model requires a platform registration driver that doesn't exist for LX2160aCex7)
  • SocGetClock: Fixed signature mismatch (upstream changed from variadic to enum-based API)

Phase 5: Secure Boot — OP-TEE StandaloneMm Port to 4.9.0

This was the most complex phase. The existing OP-TEE 3.14.0 + edk2-stable202105 Secure Boot support needed porting forward to OP-TEE 4.9.0 + edk2-stable202602, which required significant changes to both the OP-TEE SP hosting and the EDK2 StandaloneMm configuration.

OP-TEE 4.9.0 Rebase (from 3.14.0)

Only 2 of SolidRun's original patches were needed on 4.9.0. API changes:

  • vm_map_pad()vm_map() (padding parameter removed)
  • TEE_MATTR_CACHE_NONCACHETEE_MATTR_MEM_TYPE_DEV (memory attribute rename)
  • CORE_MEM_TA_RAMCORE_MEM_NON_SEC (memory region type rename)

New patches added during bring-up:

  • FFA_FEATURES handler: StandaloneMm issues FFA_FEATURES queries that OP-TEE 4.9.0 didn't handle, causing immediate SP termination
  • StMM heap increase: 402→800 pages. With OpenSSL + AuthVariableLib + VarCheckPolicyLib loaded, 1.57 MiB of heap was insufficient

StandaloneMm DSC/FDF Changes

The StandaloneMm build required extensive library path updates for edk2-stable202602:

  • ArmSvcLib, FvLib, CompilerIntrinsicsLib moved to MdePkg
  • StandaloneMmCoreEntryPoint moved to ArmPkg (ARM-specific version)
  • DevicePathLib for MM_STANDALONE: must use UefiDevicePathLibBase.inf (MODULE_TYPE=BASE)
  • PcdFfaEnable removed from upstream; library selection determines FFA behavior
  • PcdFfaLibConduitSmc=FALSE — SP runs at S-EL0 under OP-TEE, must use SVC not SMC
  • PcdShadowBfv=FALSE — BFV is loaded into RAM by OP-TEE, no shadow copy needed

Debugging the NS↔StMM Communication Chain

The most challenging debugging involved understanding the ARM StandaloneMm communication flow, which differs significantly from x86:

NS DXE side:                          Secure World (StMM):
VariableSmmRuntimeDxe                 VariableStandaloneMm
  → MmCommunicate()                    ← MmiManage(&GUID, ...)
    → OpteeInvokeFunction()              ← PiMmCpuTpFwRootMmiHandler
      → OP-TEE (stmm_sp.c)                ← DelegatedEventLoop
        → FFA_MSG_SEND_DIRECT_REQ            ← ParseFfaSvcRequest

Bug 1: Variable Arch Protocol never installed

VariableSmmRuntimeDxe (NS side) registers a callback on gEfiSmmVariableProtocolGuid, but nobody installs that signal protocol on the NS DXE side. On x86, PiSmmIpl bridges this from SMM to DXE. On ARM with OP-TEE, no bridge exists — VariableStandaloneMm.c:VariableNotifySmmReady() is an empty no-op.

Fix: Link VariableMmDependency NULL library into MmCommunicationOpteeDxe. This DXE library constructor installs the signal protocols. Used by upstream VExpress-FVP, Juno, and OVMF — but not documented anywhere as a requirement.

Bug 2: ASSERT in MmiManage — VarCheckPolicyLib handler missing

VariablePolicySmmDxe.c (NS side) sends variable policy commands to StMM using gVarCheckPolicyLibMmiHandlerGuid. No MMI handler was registered in StMM because VarCheckPolicyLibStandaloneMm wasn't linked into VariableStandaloneMm.

Fix: Added NULL|VarCheckPolicyLibStandaloneMm.inf to VariableStandaloneMm in StandaloneMm.dsc. Only OVMF's StandaloneMm path had this — none of the upstream ARM DSCs did.

Bug 3: StMM heap exhaustion (EFI_OUT_OF_RESOURCES)

After hundreds of successful MM communications, MmAllocatePool in PiMmStandaloneMmCpuDriverEntry fails. The OpenSSL crypto library + AuthVariableLib + VarCheckPolicyLib consume too much of the 402-page (1.57 MiB) heap.

Fix: Increased stmm_heap_size from 402 to 800 pages (3.2 MiB) in OP-TEE's stmm_sp.c.

EDK2 FVB Double-VA-Conversion Fix

EepromFvb registers a SetVirtualAddressMap event handler that converts physical addresses to virtual. But VariableRuntimeDxe also has a handler that calls through the FVB protocol. If the events fire in the wrong order, the FVB protocol pointers get double-converted, causing a crash.

Fix (applied to edk2 core): Shadow copy approach in VariableDxe.c — saves a pre-conversion copy of the FVB protocol so the variable driver always has valid pointers regardless of event ordering.

Phase 6: ATF Rebase to v2.12

Cherry-picked the same 16 SolidRun patches from lf_v2.10 to NXP's latest lf_v2.12. Only 1 conflict (the DISABLE_S5 build flag, trivially resolved alongside new upstream build options).

Phase 7: RCW Modernization

Replaced the old SolidRun/rcw submodule (LSDK-20.04-sr, 2020-era) with a fork based on NXP's lf-6.6.52-2.2.0 tag plus 6 SolidRun patches (0002–0007 from lx2160a_build).

Old approach: envsubst templates generating a single rcw_lx2160acex7.bin at build time, with PLL ratios computed by shell arithmetic in runme.sh.

New approach: ~150 pre-generated .rcw source files covering all speed/SerDes/boot-source combinations, compiled by rcw.py at build time. No envsubst dependency.

Key improvements:

  • Correct PLL ratios: CGB_PLL2_RAT=7, HWA_CGB_M1_CLK_SEL=6 (old values were 9 and 7, incorrect for 2200/750 MHz)
  • Correct bus speed: 750 MHz auto-selected for 2200 MHz overclock (old code always used 700 MHz)
  • Pin mux: ~20 explicit pin mux settings (IIC4, IIC6, SDHC1_DIR, USB_EXT, etc.) that were previously left at silicon defaults
  • PBI errata workarounds: a050426 (internal RAM), a050479 (PCIe link training), a010554 (SATA), a009531/a008851 (per-lane PCIe) — baked into the RCW binary, applied before ATF runs
  • Fan GPIO: PBI command drives fan full speed at reset (write 0x2320000,0x20000000)
  • Auto-boot: bootlocptr script for automatic boot source selection

The runme.sh changes:

  • Removed envsubst dependency, added python3 (for rcw.py)
  • Auto-corrects BUS_SPEED to 750 when SOC_SPEED=2200
  • Maps BOOT_MODE to RCW naming (sdsdhc, flexspi_norxspi, autoauto)
  • Validates RCW binary exists before ATF build
  • Uses make BOARDS="lx2160acex7_rev2" at the top-level RCW directory

Result: Eliminated the ERROR: erratum_a050426: Invalid RCW ATF boot message. Boots to Ubuntu with Secure Boot enabled.

Repository Structure

All work lives on the lizf.uefi-modernize branch of lizthegrey/lx2160a_uefi.

Branches

Repo Branch Base Patches (compare)
lx2160a_uefi (parent) lizf.uefi-modernize SolidRun master 34 commits (submodule pointer updates; could be squashed)
ATF lizf.nxp-v2.12-cex7 NXP lf_v2.12 16 patches
RCW lizf.nxp-lf6.6.52-cex7 NXP lf-6.6.52-2.2.0 6 patches
EDK2 lizf.edk2-stable202602 edk2-stable202602 2 patches
edk2-platforms lizf.upstream-rebase upstream/master 17 patches
edk2-non-osi lizf.upstream-rebase upstream/master 4 patches
OP-TEE lizf.4.9.0-cex7 4.9.0 5 patches

Patch Inventory

ATF — 16 patches (all by SolidRun engineers)

All originally authored by Josua Mayer, Rabeeh Khoury, and Jon Nettleton (@linux4kix) at SolidRun. Cherry-picked across v2.4 → v2.10 (clean) → v2.12 (one conflict on DISABLE_S5 build flag, resolved by keeping both the new upstream build options and SolidRun's DISABLE_S5 addition in Makefile and make_helpers/defaults.mk).

Commit Description Author Upstreamable?
1c50a1a fiptool: disable pedantic flag for older libc Josua Mayer Maybe (workaround)
e643180 lx2160a auto boot Rabeeh Khoury Yes (platform)
883e939 dcfg: MEM_PLL_CFG_SHIFT for DDR frequency Jon Nettleton Yes (bug fix)
a0a1e36 lx2160a: optional S5 GPIO from Makefile Rabeeh Khoury Yes (platform)
fa452b0 lx2160a: flexible CONFIG_DDR_NODIMM Josua Mayer Yes (platform)
c1a7dd9 layerscape: mmap dynamic config region in BL2 Josua Mayer Yes (bug fix)
eef680a lx2160a: flush I2C bus before DDR init Josua Mayer Yes (platform)
b3f7b21 DDR: dump SPD EEPROM on debug builds Josua Mayer Yes (debug)
ec9a59a DDR: disarm error for non-identical DIMMs Josua Mayer Yes (improvement)
fc1a3ce DDR: debug output for parsed DIMM params Josua Mayer Yes (debug)
bf7fc9f lx2160a: fix build without NV_SW_MAINT Josua Mayer Yes (bug fix)
7d298be lx2160a: fix boot without SPI flash Josua Mayer Yes (bug fix)
726c768 Add SolidRun CEX7 platform Josua Mayer Yes (new platform)
976d615 Add SolidRun LX2162A SOM platform Josua Mayer Yes (new platform)
4145d77 Add SolidRun CEX6 platform Josua Mayer Yes (new platform)
d97591f PSCI: build-time flag to disable SYSTEM_OFF Josua Mayer Yes (feature)

EDK2 — 2 patches

Commit Description Upstreamable?
ac53afd OP-TEE MM communication driver + OpteeLib Partially (NXP-originated, needs cleanup)
4e75ff7 VariableRuntimeDxe: avoid double VA conversion of FVB Yes — bug fix applicable to all ARM StMM platforms

The FVB double-VA-conversion fix (4e75ff7) is a genuine upstream bug. When SetVirtualAddressMap events fire in arbitrary order, the FVB protocol pointers can be double-converted, crashing any ARM platform using EepromFvb or similar non-flash FVB backends with StandaloneMm.

edk2-platforms — 17 patches

Commit Description Category
fff9746 Add 640 SolidRun/NXP hardware support files Platform support
dc6cfe4 Merge SolidRun HW support into 18 overlapping files Platform support
d0b30e4 Fix FeatureFlag PCDs, DTB rule, IoAccessLib, clock PPI API compat
266ec3a OP-TEE MM communication driver for Secure Boot Secure Boot
02be32a Remove SwapMmio compat macros → GetMmioOperations API cleanup
d11b663 Fix NxpPlatformGetClock for upstream SocGetClock API API compat
4deae84 Revert I2cDxe to self-contained driver Platform workaround
60593b8 Increase FD size to 3MB for Secure Boot Build config
adf81d0 Update StandaloneMm MMIO VAs for OP-TEE 4.9.0 Platform config
ac2fdc5 StandaloneMm: PcdFfaLibConduitSmc=FALSE Platform config
e21a324 StandaloneMm: enable serial debug output Debug
8db1d1f StandaloneMm: fix ExtractGuidedSectionLib for MM Core Bug fix
2e67b4c StandaloneMm: disable BFV shadowing Platform config
83209ed Link VariableMmDependency into MmCommunicationOpteeDxe Bug fix (affects all ARM StMM)
3c93275 Link VarCheckPolicyLibStandaloneMm into VariableStandaloneMm Bug fix (affects all ARM StMM)
a40b39a StandaloneMm: use BaseDebugLibNull for RELEASE Build fix
ec46a99 SmbiosPlatformDxe: report actual CPU frequency in SMBIOS Type 4 Bug fix

OP-TEE — 5 patches

Commit Description Upstreamable?
66988ca ls: lx2160ardb: Add MMIO device mapping for StMM SP Yes (platform)
c34fd89 Fix mobj_phys_alloc for StMM IO mapping Yes — bug fix
0cf3685 ls: fix StMM MMIO VA assignment Yes (platform)
a7a4ebd stmm_sp: handle FFA_FEATURES syscall from SP Yes — bug fix for all StMM users
57cc281 stmm_sp: increase StMM heap from 402→800 pages Debatable (might need per-platform config)

RCW — 6 patches (all by SolidRun engineers)

All originally authored by Rabeeh Khoury and Josua Mayer at SolidRun. Applied via git am from lx2160a_build/patches/rcw/ (patches 0002–0007; 0001 and 0008–0014 are for other boards/SoMs).

Commit Description Author
03d5ca0 rcw.py: add loadc, jumpc, jump PBI instructions Rabeeh Khoury
328f3a8 lx2160asi: bootlocptr auto-boot script Josua Mayer
93ee51f lx2160asi: split SD1 lanes A-D 40GE into 4x10G Josua Mayer
c51d17b lx2160asi: convert SD1 lanes G&H from 10G to 25G Josua Mayer
f2b5286 Config generator script for SolidRun boards Josua Mayer
a723a86 LX2160A CEX7 rev2 ClearFog-CX board configs Josua Mayer

edk2-non-osi — 4 patches (binary blobs cherry-picked from SolidRun's fork)

Commit Description
b2db5ae SolidRun/LX2160aCex7: DPC and DPL firmware images (DPAA2 network config)
170e534 NXP Qoriq Management Complex binary
4b87eb9 AMD GOP driver (AARCH64 graphics output)
28aed83 NXP Qoriq binary update to 10.28.1

These are vendor-provided binaries required for DPAA2 Ethernet and graphics output. Not candidates for upstream contribution (already from vendor sources).

Upstreaming Status

Submitted

  1. EDK2 4e75ff7 — FVB double VA conversion fix in MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c. Affects any ARM platform using a non-flash FVB backend with StandaloneMm. Originally written by Ard Biesheuvel for SolidRun's edk2 fork. Upstream PR: tianocore/edk2#12259.

Already fixed upstream

  1. OP-TEE a7a4ebd — FFA_FEATURES handler in stmm_sp.c. Fixed upstream in ed89aa36c (August 2025) by Yeoreum Yun at ARM, with a broader fix that returns FFA_NOT_SUPPORTED for all undefined FFA functions (not just FFA_FEATURES).

  2. edk2-platforms 83209ed + 3c93275 — VariableMmDependency and VarCheckPolicyLib linkage for ARM StandaloneMm. Both are already present in the upstream ARM reference DSCs (PlatformStandaloneMm.dsc.inc for VExpress-FVP and Juno). Our SolidRun DSC was missing them because it was written independently rather than including the upstream .dsc.inc.

Not applicable upstream

  1. OP-TEE c34fd89mobj_phys_alloc fix for CORE_MEM_NON_SEC IO mapping. The alloc_and_map_io() function that uses this code path only exists in SolidRun's fork; upstream stmm_sp.c doesn't map platform MMIO into StMM this way.

Medium-priority: SolidRun platform support

  1. ATF platform patches — The CEX7/CEX6/LX2162A SOM platform definitions and DDR fixes could be submitted to NXP's nxp-qoriq/atf fork, making SolidRun a first-class NXP Layerscape platform. Interest issue: nxp-qoriq/atf#3.

  2. edk2-platforms SolidRun overlay — The 640 SolidRun-only files (DPAA2 Ethernet, SPI, MMC, SMBIOS, ACPI tables) represent a complete board package that could be submitted to tianocore/edk2-platforms. Interest issue: tianocore/edk2-platforms#951.

Lower priority

  1. OP-TEE StMM heap size — 402 pages is too small for any StMM build with OpenSSL crypto. This should either be increased upstream or made configurable via a CFG_STMM_HEAP_SIZE build option. Issue: OP-TEE/optee_os#7728.

Build Instructions

git clone --recursive https://github.com/lizthegrey/lx2160a_uefi.git -b lizf.uefi-modernize
cd lx2160a_uefi

# Standard build (2000 MHz, no Secure Boot, RELEASE)
bash ./runme.sh

# Overclock + Secure Boot
SOC_SPEED=2200 DDR_SPEED=3200 SECURE_BOOT=true bash ./runme.sh

# Debug build
UEFI_RELEASE=DEBUG SECURE_BOOT=true bash ./runme.sh

# Clean build
CLEAN=1 SOC_SPEED=2200 DDR_SPEED=3200 SECURE_BOOT=true bash ./runme.sh

Flash to SD card (no seek — offset is baked into the image):

dd if=images/lx2160acex7_*.img of=/dev/sdX bs=512 conv=notrunc

Secure Boot Key Enrollment

After first boot with a Secure Boot-enabled image, the platform is in Setup Mode. Enroll a self-generated PK and Microsoft's standard db/KEK certificates using efitools (efi-updatevar, cert-to-efi-sig-list, sign-efi-sig-list). Note: cert-to-efi-sig-list requires PEM format — convert Microsoft's DER .crt files with openssl x509 -inform DER first. Enroll db and KEK before PK, as setting PK exits Setup Mode.

Known Issues

  • ERROR: SPD different between DIMMs — pre-existing with mixed DIMM configs, uses first DIMM timings
  • Failed to find MM Communication Buffer HOB — non-fatal on ARM (x86-style HOB not used; ARM uses mNsCommBuffer from OP-TEE)
  • DKMS modules (e.g., v4l2loopback) need MOK signing for Secure Boot

Credits

  • SolidRun engineers (Jon Nettleton @linux4kix, Josua Mayer, Rabeeh Khoury) — original platform support patches for ATF, EDK2, and OP-TEE
  • NXP — LX2160A platform code in ATF and edk2-platforms
  • Ard Biesheuvel — FVB virtual address conversion pattern used in the double-VA fix
  • Liz Fong-Jones (@lizthegrey) — project lead, testing, hardware access
  • Claude (Anthropic) — code analysis, debugging, implementation assistance

License

All patches follow the licensing of their respective upstream projects (BSD-2-Clause-Patent for EDK2/edk2-platforms, BSD-2-Clause for OP-TEE/ATF).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment