bootm_find_os() leaves images.os.arch at IH_ARCH_INVALID for Android boot
images: unlike the legacy and FIT headers, the Android boot image header
carries no architecture field. The arm64 Image relocation in
bootm_load_os() (booti_setup()) is therefore skipped, and a kernel that
is executed in place, which android_image_get_kernel_addr() arranges for
any uncompressed kernel whose header holds the default kernel address
(or with ANDROID_BOOT_IMAGE_IGNORE_BLOB_ADDR), whatever the header
version, runs from boot.img + page size, which is not 2 MiB aligned. The
kernel reports "Kernel image misaligned at boot, please fix your
bootloader!" and dies early (observed as a stack overflow in
start_kernel() with a GKI 6.12 kernel on QEMU virt).

Set IH_ARCH_DEFAULT, the one architecture this U-Boot can boot and the
only value available for this image format, so that booti_setup() moves
the kernel to a properly aligned address. The other readers of os.arch
are not affected:

- arch/arm/lib/bootm.c switches to AArch32 only for IH_ARCH_ARM, so an
  Android image keeps taking the AArch64 path exactly as it does with
  IH_ARCH_INVALID. Its update_os_arch_secondary_cores() hook, implemented
  by Layerscape, marks the spin table entries OS_ARCH_SAME only when
  os_arch equals IH_ARCH_DEFAULT, so with IH_ARCH_INVALID an Android
  boot currently releases the secondary cores as if the kernel were a
  different architecture; this is fixed as well.
- the x86 setup.bin lookup in bootm.c is only reached on an x86 U-Boot,
  where the Android format is not bootable through bootm anyway.
- ARM32 and RISC-V do not read os.arch after bootm_find_os().

For a v0-v2 image whose ramdisk is used in place, booti_setup() can now
move the kernel forward by up to 2 MiB, and the memmove() of image_size
bytes (which includes BSS) overwrites the start of the ramdisk that
follows the kernel in boot.img. Executing in place already had the same
problem, since the kernel clears its BSS early, so this is not a
regression; the ramdisk is relocated by the ramdisk_high logic when it is
in use, and loading the kernel to kernel_addr_r instead of executing it
in place, like the compressed case, is a separate change. The LMB
reservation also still covers the original load range, as it does for
FIT.

Signed-off-by: Igor Opaniuk <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
---
Changes in v2:
- reword the commit message (Simon Glass): the Android header has no
  architecture field, the in-place execution is not specific to header
  v3/v4, why IH_ARCH_DEFAULT is safe for the other readers of os.arch
  (and fixes the Layerscape secondary core release), note on the
  ramdisk overlap for v0-v2 images booted in place and on the LMB
  reservation; code unchanged, kept unconditional
- add Simon's Reviewed-by
- Link to v1: 
https://patch.msgid.link/20261011-upstream-bootm_android_b4-v1-1-3e82462ac...@oss.qualcomm.com
---
 boot/bootm.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/boot/bootm.c b/boot/bootm.c
index b6ae0163b27..75b34f39cca 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -432,6 +432,7 @@ static int bootm_find_os(const char *cmd_name, const char 
*addr_fit)
                images.os.type = IH_TYPE_KERNEL;
                images.os.comp = android_image_get_kcomp(boot_img, 
vendor_boot_img);
                images.os.os = IH_OS_LINUX;
+               images.os.arch = IH_ARCH_DEFAULT;
                images.os.end = android_image_get_end(boot_img, 
vendor_boot_img);
                images.os.load = android_image_get_kload(boot_img, 
vendor_boot_img);
                images.ep = images.os.load;

---
base-commit: ed869863c7e2aca50d57a05d843830dd843138c4
change-id: 20261011-upstream-bootm_android_b4-4e94dca526b5

Best regards,
--  
Igor Opaniuk <[email protected]>

Reply via email to