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.
This commit is contained in:
2026-09-18 00:09:27 -03:00
parent bc6a059bf8
commit 7e0a580700
+58 -1
View File
@@ -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 <addr>"). 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 <addr>" 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