2.3. Kernel/DTB/ramdisk load and the kernel hand-off

This page documents BootLinux — the ABL routine that lays out and copies the kernel, ramdisk and device tree into memory, applies the command-line and device-tree fixups, tears down UEFI, and jumps to the Linux kernel — and the two fixup helpers UpdateCmdLine and UpdateDeviceTree it drives. The kernel hand-off contract defined here (entry address, register state, memory layout) is the interface any replacement bootloader or Linux-primary payload must honour.

Verified-boot verification that produces the images and the AVB command-line is on AVB enforcement code path (LoadImageAndAuth / libavb); this page starts from “verified images are in the BootInfo” and ends at the kernel jump. RVAs are LinuxLoader-relative (= DXE file offset − 0xb8).

2.3.1. BootLinux (RVA 0x12448)

LinuxLoaderEntry calls BootLinux (&Info) once LoadImageAndAuth succeeds (ABL entry point and top-level orchestration, step 12). BootLinux (source QcomModulePkg/Library/BootLib/BootLinux.c) runs this pipeline; each stage is anchored by debug strings in the 0x12448 function body:

Stage

Purpose / binary basis

GetImage (kernel/ramdisk/dtb)

Pull each sub-image out of the verified boot image. BootLinux: Get%aImage failed!, BootLinux: invalid parameter Info.

UpdateKernelModeAndPkg / decompress

Detect 32- vs 64-bit (Kernel64Hdr.magic_64), gzip/patched packaging, and decompress. Patched kernel detected, Decompressing kernel image total time: %lu ms, Decompress kernel size is smaller than image header size.

UpdateBootParams (layout)

Compute load addresses (see Load-address layout). Kernel Load Address: 0x%x, Ramdisk Load Address: 0x%x, Device Tree Load Address: 0x%x, plus Integer Overflow: guards.

copy kernel + ramdisk

gBS->CopyMem into the reserved regions. Not Enough space left to load kernel image, Kernel size is over the limit, Ramdisk size is over the limit.

UpdateCmdLine

Build the final kernel command line (see Command-line fixups). Error updating cmdline. Device Error %r.

UpdateDeviceTree

Select and fix up the DTB (see Device-tree fixups). Device Tree update failed Status:%r, Error: Device Tree blob not found.

PreparePlatformHardware + ExitBootServices

Quiesce hardware and exit UEFI (see The hand-off). \nShutting Down UEFI Boot Services: %lu ms, ERROR: Can not shutdown UEFI boot services. Status=0x%X.

jump to kernel

BootStatsSetTimeStamp (BS_KERNEL_ENTRY) then transfer control.

radare2 merges BootLinux with several of its file-local helpers (UpdateBootParams, UpdateKernelModeAndPkg, decompress glue) into the 0x12448 function; the decomposition above is the source’s and is reflected in ABL function map and upstream-source correlation.

2.3.2. Load-address layout

UpdateBootParams derives all three load addresses from a queried BaseMemory (QueryBootParams / EFI variable KernelBaseAddr), not from hard-coded physical addresses:

  • KernelLoadAddr = BaseMemory | KERNEL_64BIT_LOAD_OFFSET (32-bit path adds KERNEL_32BIT_LOAD_OFFSET instead; this unit is arm64, see Boot image: kernel, DTB, ramdisk, config).

  • KernelEndAddr = BaseMemory + reserved kernel size.

  • RamdiskLoadAddr = page-aligned region below KernelEndAddr sized for ramdisk + vendor-ramdisk.

  • DeviceTreeLoadAddr = page-aligned region below RamdiskLoadAddr; ABL asserts DeviceTreeLoadAddr > KernelLoadAddr and bails otherwise.

The device tree is copied to DeviceTreeLoadAddr by gBS->CopyMem (source lines around the CopyMem ((VOID *)DeviceTreeLoadAddr, …) call) after fixups.

2.3.3. Command-line fixups (UpdateCmdLine, RVA 0x1c920)

UpdateCmdLine concatenates the base command line with dynamically generated androidboot.* tokens and the verified-boot command line. Tokens materialised in the binary (all present as literals in the 0x1c920 body):

androidboot.mode= (and …=charger), androidboot.alarmboot=true, androidboot.baseband=, androidboot.bootdevice=, androidboot.boot_devices=soc/, androidboot.slot_suffix=, androidboot.fstab_suffix=, androidboot.force_normal_boot=1, androidboot.dtb_idx=, androidboot.dtbo_idx=, androidboot.serialno=.

The AVB result is spliced in here: UpdateCmdLine VBCmdLine present len %d shows the verified-boot command line (androidboot.verifiedbootstate=… etc., produced on AVB enforcement code path (LoadImageAndAuth / libavb)) being appended, and Failed to get LEVerityCmdLine: %r the dm-verity arguments. The assembled line is logged as Cmdline: %a immediately before hand-off. Serial number comes from the board layer (Error Finding board serial num: %x, ABL entry point and top-level orchestration).

2.3.4. Device-tree fixups (UpdateDeviceTree, RVA 0x148d0)

UpdateDeviceTree first selects the best-matching DTB from the appended DT table (Best match DTB tags , Exact DTB match found, ERROR: Couldn't find the suitable DTB!) using the board identity from ABL entry point and top-level orchestration, then edits the live FDT via fdt_* helpers:

Node

Properties written (binary basis)

/chosen

bootargs (the UpdateCmdLine string), linux,initrd-start / linux,initrd-end (ramdisk bounds), kaslr-seed, rng-seed. ERROR: Cannot update chosen node [linux,initrd-start] - 0x%x etc.

/memory

DDR device type and per-channel/rank descriptors (ddr_device_type, ddr_device_rank_ch%d, ddr_device_hbb_ch%d_rank%d). ERROR: Cannot update memory node .

/reserved-memory

Splash region carve-out updated to the running framebuffer (splash_region, Splash memory region before/after updating), plus demura_region_0 / demura_region_1 (e-ink demura buffers).

Total fixup time is logged (Update Device Tree total time: %lu ms). The demura_region_* reserved-memory entries are e-ink-panel specific; they are present in the stock DTB (DTBO overlays) and are carried through by this generic path — no device-specific code in UpdateDeviceTree handles them beyond the standard splash/reserved-memory update.

2.3.5. The hand-off

After PreparePlatformHardware and ExitBootServices succeed, BootLinux transfers control to the kernel. From BootLinux.c (confirmed against the 0x12448 tail):

  • 64-bit (this device): LinuxKernel ((UINT64)DeviceTreeLoadAddr, 0, 0, 0) — the standard arm64 Linux boot protocol call; see the register contract below.

  • 32-bit (not used here): LinuxKernel32 (0, 0, (UINTN)DeviceTreeLoadAddr)r0 = 0, r1 = 0 (machine type), r2 = DTB.

Contract summary for a replacement payload:

Item

Value at kernel entry

Entry PC

KernelLoadAddr (= BaseMemory | KERNEL_64BIT_LOAD_OFFSET)

x0

physical address of the fixed-up FDT (DeviceTreeLoadAddr)

x1 / x2 / x3

0 / 0 / 0

UEFI state

Boot Services exited (ExitBootServices done); Runtime Services still resident in reserved memory

MMU / caches

quiesced by PreparePlatformHardware per arm64 boot requirements

ramdisk

at RamdiskLoadAddr; bounds passed via /chosen initrd properties, not a register

The kernel is not expected to return control to ABL; no ABL services remain available after this point.

2.3.6. Provenance

Source:

../artifacts/abl_a/abl_dxe_fv.bin (RVAs 0x12448 BootLinux, 0x1c920 UpdateCmdLine, 0x148d0 UpdateDeviceTree). Structural correlation against QcomModulePkg/Library/BootLib/BootLinux.c, UpdateCmdLine.c, UpdateDeviceTree.c at CodeLinaro tag LA.UM.9.12.1.r2-05100-SMxx50.QSSI12.0 (QSSI12; version gap is an open question — ABL function map and upstream-source correlation, Open questions and limits of analysis).

Method:

functions identified by their embedded debug/error strings (AArch64 adrp/add literals resolved with Capstone); load-layout arithmetic and the exact kernel-jump register contract read from BootLinux.c and matched to the 0x12448 tail (LinuxKernel/LinuxKernel32 indirect calls after ExitBootServices). Where radare2 merges BootLinux with its helpers the source decomposition is used and the merge is noted.

Cross-refs:

ABL entry point and top-level orchestration (caller, board identity), AVB enforcement code path (LoadImageAndAuth / libavb) (image verification, VBCmdLine), Boot image: kernel, DTB, ramdisk, config (kernel/DTB/ramdisk formats), DTBO overlays (DTB/overlay contents, demura/splash regions), ABL function map and upstream-source correlation (function inventory).