From 7e0a580700302a456068171c5addbec17d2dd5e6 Mon Sep 17 00:00:00 2001 From: snlavaise Date: Fri, 18 Sep 2026 00:09:27 -0300 Subject: [PATCH] rtwo: switch chainload boot from bootm+FIT to bootefi (EFI stub) bootm's ramdisk initrd delivery (boot_ramdisk_high()/LMB high-address placement plus the fixed start/loados/ramdisk/fdt/cmdline/bdt/prep/go ordering in bootm_run_states()) kept producing a kernel that booted cleanly but silently discarded its initramfs, ending in "VFS: Cannot open root device". Confirmed on hardware, multiple attempts, none panned out (in-place mode collided with the kernel relocation; reordering bootm substates is rejected by U-Boot itself as "out of order"; the reserved-memory collision theory was disproven against the compiled dtb). Switched to bootefi instead: same FIT (no repackaging), parsed with imxtract (kernel/fdt/ramdisk each extracted to a separate address), then booted via the kernel's own EFI stub + LoadFile2 initrd protocol -- a different code path in both U-Boot (efi_loader, not boot_ramdisk_high()) and the kernel (efi_load_initrd(), never touches reserve_initrd_mem()). Two real bugs found and fixed along the way, both confirmed on hardware: - ramdisk destination must not be a hand-computed offset from (that address is our own scratch buffer holding the whole FIT, not the board's dedicated ramdisk block) -- use $kernel_comp_addr_r instead, a separate 64 MiB LMB block the board reserves for kernel decompression, unused since our Image is uncompressed. - bootefi's first argument (the kernel) needs an explicit ":size" suffix. Without it, cmd/bootefi.c assumes the address was set by a prior load/tftp command tracked via efi_set_image_parameters() -- imxtract never touches that tracking, so the address never matches and bootefi fails with "No UEFI binary known" even though the bytes there are a perfectly valid kernel image. CONFIRMED ON HARDWARE 2026-09-18: reaches a live debug shell console. --- board/qualcomm/qcom-phone.env | 59 ++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/board/qualcomm/qcom-phone.env b/board/qualcomm/qcom-phone.env index 03eb0231..9f62a8a3 100644 --- a/board/qualcomm/qcom-phone.env +++ b/board/qualcomm/qcom-phone.env @@ -41,7 +41,64 @@ serial_gadget=setenv stdin serial,button-kbd,usbacm; \ # prevbl_initrd_start_addr attempt, then to the phone menu, if this # fails -- see memoria rtwo-uboot-chainload-fit-raw-read. pmos_bootargs=earlycon console=ttyMSM0,115200n8 console=tty0 ignore_loglevel panic=5 pmos.debug-shell clk_ignore_unused pd_ignore_unused regulator_ignore_unused allow_mismatched_32bit_el0 pmos_boot_uuid=d4373976-057c-4cf3-a43d-00734001b405 pmos_root_uuid=09804032-85bb-4d57-95a5-00d1965fb10f pmos_rootfsopts=defaults -bootcmd=setenv bootargs $pmos_bootargs; if part start scsi 3 boot_a boot_a_start && part size scsi 3 boot_a boot_a_size; then setexpr blksz 0x6000000 / $boot_a_size; setexpr fit_blk_off 0x18c000 / $blksz; setexpr fit_lba $boot_a_start + $fit_blk_off; setexpr fit_blk_cnt $boot_a_size - $fit_blk_off; echo pmOS: boot_a start=$boot_a_start size=$boot_a_size blksz=$blksz fit_lba=$fit_lba fit_cnt=$fit_blk_cnt; pause; scsi dev 3; if scsi read $ramdisk_addr_r $fit_lba $fit_blk_cnt; then echo pmOS: FIT read OK, about to bootm at $ramdisk_addr_r; pause; bootm $ramdisk_addr_r; echo pmOS: bootm on FIT returned control, this should not happen; pause; else echo pmOS: scsi read of FIT failed; pause; fi; else echo pmOS: could not resolve boot_a partition; fi; echo pmOS: raw boot_a read failed, trying prevbl_initrd_start_addr=$prevbl_initrd_start_addr; bootm $prevbl_initrd_start_addr; echo pmOS: bootm failed; bootefi bootmgr; pause; run menucmd +# ESTADO 2026-09-17: vuelto a dejar tal cual quedo justo despues del PRIMER +# cambio de la implementacion EFI (antes de corregir el offset del ramdisk +# de imxtract y antes de sacar ignore_loglevel) -- checkpoint pedido para +# retomar la exploracion del camino EFI, esta vez via una particion real +# (userdata) en vez del RAM-only que se probo primero. +# +# DEBUG 2026-09-17 (quinta vuelta): probar el camino EFI en vez de bootm+FIT. +# bootefi usa boot/efi_loader (AllocatePages/LoadFile2) para el initrd, no +# boot_ramdisk_high()/LMB "high address" -- codigo completamente distinto, +# asi que el bug de orden fijo start/loados/ramdisk/fdt de bootm no aplica +# aca. Ademas, en el lado del kernel, el stub EFI arm64 (CONFIG_EFI_STUB=y, +# ya compilado) carga el initrd via efi_load_initrd()/LoadFile2, que NUNCA +# pasa por early_init_dt_check_for_initrd()/reserve_initrd_mem() -- el +# chequeo memblock_is_region_reserved() que sospechabamos ni siquiera se +# ejecuta para este camino. bootargs se sigue pasando igual (bootefi +# convierte $bootargs a UTF-16 como load options). +# +# Mismo FIT de siempre (sin repackaging), pero en vez de bootm lo parseamos +# con imxtract (CONFIG_CMD_XIMG=y, ya compilado) para sacar cada sub-imagen +# a una direccion de RAM aparte: +# - kernel -> $kernel_addr_r (misma que bootm usaba para relocar) +# - fdt -> $fdt_addr_r (la misma que bootmenu_10 ya usa con exito) +# - ramdisk -> $kernel_comp_addr_r (NO un offset inventado desde +# $ramdisk_addr_r -- eso fue el bug original: $ramdisk_addr_r + 0x8000000 +# coincidia EXACTO con $kernel_addr_r y piso el kernel ya extraido +# ("No UEFI binary known at "). Investigado en la lista de U-Boot +# (parche "mach-snapdragon: dynamic load addresses", 2026): board.c +# arma estas variables como bloques LMB DEDICADOS y consecutivos -- +# kernel_addr_r=128MiB, ramdisk_addr_r=128MiB (por eso el offset exacto +# de 0x8000000=128MiB), kernel_comp_addr_r=64MiB, fdt_addr_r=2MiB. El +# bug de fondo era usar $ramdisk_addr_r para algo que NO es su proposito +# (nuestro buffer crudo del FIT completo, ~55 MiB) y encima calcular un +# offset a mano dentro de ese mismo bloque de 128 MiB, invadiendo el +# vecino. $kernel_comp_addr_r es un bloque separado, dedicado a +# descomprimir un kernel comprimido -- el nuestro (Image sin comprimir, +# CONFIG_EFI_ZBOOT apagado) no lo usa, asi que esta libre y garantizado +# sin solaparse con ningun otro _addr_r por construccion. +# imxtract fija $filesize despues de cada extraccion (confirmado en +# cmd/ximg.c), por eso el tamano del ramdisk y del kernel se guardan aparte +# antes de que la siguiente llamada los pise. +# +# 2026-09-18: "No UEFI binary known at " seguia apareciendo incluso +# con las tres direcciones ya sin solaparse (kernel_comp_addr_r confirmado +# en hardware como un bloque separado y limpio). Causa real, en +# cmd/bootefi.c:204-226 (do_bootefi_image): si el PRIMER argumento de +# `bootefi` NO lleva ":tamano", el comando asume que la direccion ya viene +# de un `load`/`tftp` previo (que actualiza un registro interno de "ultima +# imagen cargada" via efi_set_image_parameters()) y compara contra ESE +# registro -- si no matchea (o nunca se seteo, como en nuestro caso porque +# usamos `imxtract`, que NO actualiza ese registro), falla con este mensaje +# sin importar que los bytes en esa direccion sean un kernel EFI valido. +# Fix: pasarle ":tamano" tambien al kernel (no solo al ramdisk, que ya lo +# llevaba) -- eso fuerza la rama que trata la direccion como explicita +# (efi_clear_bootdev()) sin depender de ningun registro previo. +# +# Si bootefi no funciona por algun motivo, cae al `bootm` de siempre como +# red de seguridad (mismo fallback que ya existia). +bootcmd=setenv bootargs $pmos_bootargs; if part start scsi 3 boot_a boot_a_start && part size scsi 3 boot_a boot_a_size; then setexpr blksz 0x6000000 / $boot_a_size; setexpr fit_blk_off 0x18c000 / $blksz; setexpr fit_lba $boot_a_start + $fit_blk_off; setexpr fit_blk_cnt $boot_a_size - $fit_blk_off; echo pmOS: boot_a start=$boot_a_start size=$boot_a_size blksz=$blksz fit_lba=$fit_lba fit_cnt=$fit_blk_cnt; scsi dev 3; if scsi read $ramdisk_addr_r $fit_lba $fit_blk_cnt; then echo pmOS: FIT read OK, addr=$ramdisk_addr_r; setenv verify no; setenv initrd_stage_addr $kernel_comp_addr_r; if imxtract $ramdisk_addr_r kernel $kernel_addr_r; then setenv kernel_stage_size $filesize; echo pmOS: kernel extracted addr=$kernel_addr_r size=$kernel_stage_size; if imxtract $ramdisk_addr_r fdt $fdt_addr_r; then echo pmOS: fdt extracted addr=$fdt_addr_r size=$filesize; if imxtract $ramdisk_addr_r ramdisk $initrd_stage_addr; then setenv initrd_stage_size $filesize; echo pmOS: ramdisk extracted addr=$initrd_stage_addr size=$initrd_stage_size; echo pmOS: trying bootefi; pause; bootefi $kernel_addr_r:$kernel_stage_size $initrd_stage_addr:$initrd_stage_size $fdt_addr_r; echo pmOS: bootefi returned, should not happen; pause; else echo pmOS: ramdisk imxtract FAILED; pause; fi; else echo pmOS: fdt imxtract FAILED; pause; fi; else echo pmOS: kernel imxtract FAILED; pause; fi; else echo pmOS: scsi read of FIT failed; pause; fi; else echo pmOS: could not resolve boot_a partition; fi; echo pmOS: bootefi path failed, trying old bootm path via prevbl_initrd_start_addr=$prevbl_initrd_start_addr; bootm $prevbl_initrd_start_addr; echo pmOS: bootm failed; bootefi bootmgr; pause; run menucmd # When entering the menu (either from button press or failed boot) # remap bootcmd so it will re-open the menu and we won't get stuck