=============================================== 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 :doc:`/abl/verified-boot`; this page starts from "verified images are in the ``BootInfo``" and ends at the kernel jump. RVAs are LinuxLoader-relative (= DXE file offset − ``0xb8``). ``BootLinux`` (RVA ``0x12448``) =============================== ``LinuxLoaderEntry`` calls ``BootLinux (&Info)`` once ``LoadImageAndAuth`` succeeds (:doc:`/abl/linuxloader`, step 12). ``BootLinux`` (source ``QcomModulePkg/Library/BootLib/BootLinux.c``) runs this pipeline; each stage is anchored by debug strings in the ``0x12448`` function body: .. list-table:: :header-rows: 1 :widths: 30 70 * - 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 :doc:`/abl/function-map`. 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 :doc:`/boot/boot-image`). - ``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. .. _Command-line fixups: 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 :doc:`/abl/verified-boot`) 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``, :doc:`/abl/linuxloader`). .. _Device-tree fixups: 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 :doc:`/abl/linuxloader`, then edits the live FDT via ``fdt_*`` helpers: .. list-table:: :header-rows: 1 :widths: 26 74 * - 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 (:doc:`/boot/dtbo`) and are carried through by this generic path — no device-specific code in ``UpdateDeviceTree`` handles them beyond the standard splash/reserved-memory update. 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: .. list-table:: :header-rows: 1 :widths: 30 70 * - 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. 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 — :doc:`/abl/function-map`, :doc:`/open-questions`). :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: :doc:`/abl/linuxloader` (caller, board identity), :doc:`/abl/verified-boot` (image verification, ``VBCmdLine``), :doc:`/boot/boot-image` (kernel/DTB/ramdisk formats), :doc:`/boot/dtbo` (DTB/overlay contents, ``demura``/splash regions), :doc:`/abl/function-map` (function inventory).