The devices launching Android 13+ were using a new partition named init_boot to store generic ramdisk.
In the new bootflow, kernel still be stored in boot image, however, the First Stage files in ramdisk were moved to init_boot image. We should load it to memory and verify it so that the kernel can execute init program to continue booting. Link: https://source.android.com/docs/core/architecture/partitions/generic-boot Signed-off-by: Valentin Liu <[email protected]> --- boot/bootmeth_android.c | 65 ++++++++++++++++++++++++++++++- boot/image-android.c | 67 ++++++++++++++++++++++++++++++++ cmd/abootimg.c | 6 +++ doc/develop/bootstd/overview.rst | 3 ++ include/android_image.h | 1 + include/image.h | 59 ++++++++++++++++++++++++++++ 6 files changed, 200 insertions(+), 1 deletion(-) diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c index ec255b072af..c11ef849c56 100644 --- a/boot/bootmeth_android.c +++ b/boot/bootmeth_android.c @@ -4,6 +4,7 @@ * * Copyright (C) 2024 BayLibre, SAS * Written by Mattijs Korpershoek <[email protected]> + * Copyright (c) 2026 Valentin Liu <[email protected]> */ #define LOG_CATEGORY UCLASS_BOOTSTD @@ -29,6 +30,7 @@ #define BCB_FIELD_COMMAND_SZ 32 #define BCB_PART_NAME "misc" #define BOOT_PART_NAME "boot" +#define INIT_BOOT_PART_NAME "init_boot" #define VENDOR_BOOT_PART_NAME "vendor_boot" #define SLOT_LEN 2 @@ -47,6 +49,7 @@ struct android_priv { char *slot; u32 header_version; u32 boot_img_size; + u32 init_boot_img_size; u32 vendor_boot_img_size; }; @@ -113,6 +116,51 @@ static int scan_boot_part(struct udevice *blk, struct android_priv *priv) return 0; } +static int scan_init_boot_part(struct udevice *blk, struct android_priv *priv) +{ + struct blk_desc *desc = dev_get_uclass_plat(blk); + struct disk_partition partition; + char partname[PART_NAME_LEN]; + ulong num_blks, bufsz; + char *buf; + int ret; + + if (priv->slot) + sprintf(partname, INIT_BOOT_PART_NAME "_%s", priv->slot); + else + sprintf(partname, INIT_BOOT_PART_NAME); + + ret = part_get_info_by_name(desc, partname, &partition); + if (ret < 0) + return log_msg_ret("part info", ret); + + num_blks = DIV_ROUND_UP(sizeof(struct andr_boot_img_hdr_v3), desc->blksz); + bufsz = num_blks * desc->blksz; + buf = malloc(bufsz); + if (!buf) + return log_msg_ret("buf", -ENOMEM); + + ret = blk_read(blk, partition.start, num_blks, buf); + if (ret != num_blks) { + free(buf); + return log_msg_ret("part read", -EIO); + } + + if (!is_android_init_boot_image_header(buf)) { + free(buf); + return log_msg_ret("header", -ENOENT); + } + + if (!android_image_get_init_bootimg_size(buf, &priv->init_boot_img_size)) { + free(buf); + return log_msg_ret("get init bootimg size", -EINVAL); + } + + free(buf); + + return 0; +} + static int scan_vendor_boot_part(struct udevice *blk, struct android_priv *priv) { struct blk_desc *desc = dev_get_uclass_plat(blk); @@ -292,6 +340,13 @@ static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow) } if (priv->header_version >= 3) { + if (priv->header_version >= 4) { + ret = scan_init_boot_part(bflow->blk, priv); + if (ret < 0) { + log_debug("scan init_boot failed: err=%d\n", ret); + goto free_priv; + } + } ret = scan_vendor_boot_part(bflow->blk, priv); if (ret < 0) { log_debug("scan vendor_boot failed: err=%d\n", ret); @@ -425,7 +480,7 @@ static int run_avb_verification(struct bootflow *bflow) { struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); struct android_priv *priv = bflow->bootmeth_priv; - const char * const requested_partitions[] = {"boot", "vendor_boot", NULL}; + const char * const requested_partitions[] = {"boot", "init_boot", "vendor_boot", NULL}; struct AvbOps *avb_ops; AvbSlotVerifyResult result; AvbSlotVerifyData *out_data = NULL; @@ -556,6 +611,7 @@ static int boot_android_normal(struct bootflow *bflow) struct android_priv *priv = bflow->bootmeth_priv; int ret; ulong loadaddr = env_get_hex("loadaddr", 0); + ulong iloadaddr = env_get_hex("init_boot_comp_addr_r", 0); ulong vloadaddr = env_get_hex("vendor_boot_comp_addr_r", 0); ret = run_avb_verification(bflow); @@ -573,6 +629,13 @@ static int boot_android_normal(struct bootflow *bflow) return log_msg_ret("read boot", ret); if (priv->header_version >= 3) { + if (priv->header_version >= 4) { + ret = read_slotted_partition(desc, "init_boot", priv->slot, + priv->init_boot_img_size, iloadaddr); + if (ret < 0) + return log_msg_ret("read init_boot", ret); + set_ainit_bootimg_addr(iloadaddr); + } ret = read_slotted_partition(desc, "vendor_boot", priv->slot, priv->vendor_boot_img_size, vloadaddr); if (ret < 0) diff --git a/boot/image-android.c b/boot/image-android.c index 7740cae8cb6..05eb7e9b6be 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2011 Sebastian Andrzej Siewior <[email protected]> + * Copyright (c) 2026 Valentin Liu <[email protected]> */ #include <env.h> @@ -130,6 +131,28 @@ static void android_boot_image_v3_v4_parse_hdr(const struct andr_boot_img_hdr_v3 data->boot_img_total_size = end - map_to_sysmem(hdr); } +static void android_init_boot_image_v4_parse_hdr(const struct andr_boot_img_hdr_v3 *hdr, + struct andr_image_data *data) +{ + ulong end; + + /* + * The header takes a full page, the remaining components are aligned + * on page boundary. + */ + end = (ulong)hdr; + end += ANDR_GKI_PAGE_SIZE; + end += ALIGN(hdr->kernel_size, ANDR_GKI_PAGE_SIZE); + data->ramdisk_ptr = end; + data->ramdisk_size = hdr->ramdisk_size; + data->boot_ramdisk_size = hdr->ramdisk_size; + end += ALIGN(hdr->ramdisk_size, ANDR_GKI_PAGE_SIZE); + + end += ALIGN(hdr->signature_size, ANDR_GKI_PAGE_SIZE); + + data->init_boot_img_total_size = end - (ulong)hdr; +} + static void android_vendor_boot_image_v3_v4_parse_hdr(const struct andr_vnd_boot_img_hdr *hdr, struct andr_image_data *data, bool write_trailer) @@ -263,6 +286,27 @@ bool android_image_get_bootimg_size(const void *hdr, u32 *boot_img_size) return true; } +bool android_image_get_init_bootimg_size(const void *hdr, u32 *init_boot_img_size) +{ + struct andr_image_data data; + + if (!hdr || !init_boot_img_size) { + printf("hdr or init_boot_img_size can't be NULL\n"); + return false; + } + + if (!is_android_init_boot_image_header(hdr)) { + printf("Incorrect init boot image header\n"); + return false; + } + + android_init_boot_image_v4_parse_hdr(hdr, &data); + + *init_boot_img_size = data.init_boot_img_total_size; + + return true; +} + bool android_image_get_vendor_bootimg_size(const void *hdr, u32 *vendor_boot_img_size) { struct andr_image_data data; @@ -326,6 +370,24 @@ bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr, return true; } +bool android_image_get_data_v4(const void *boot_hdr, const void *vendor_boot_hdr, + const void *init_boot_hdr, struct andr_image_data *data) +{ + if (!android_image_get_data(boot_hdr, vendor_boot_hdr, data)) { + printf("An error happened while calling android_image_get_data().\n"); + return false; + } + + if (!is_android_init_boot_image_header(init_boot_hdr)) { + printf("Incorrect init boot image header\n"); + return false; + } + + android_init_boot_image_v4_parse_hdr(init_boot_hdr, data); + + return true; +} + static ulong android_image_get_kernel_addr(struct andr_image_data *img_data, ulong comp) { @@ -466,6 +528,11 @@ bool is_android_vendor_boot_image_header(const void *vendor_boot_img) return !memcmp(VENDOR_BOOT_MAGIC, vendor_boot_img, ANDR_VENDOR_BOOT_MAGIC_SIZE); } +bool is_android_init_boot_image_header(const void *init_boot_img) +{ + return !memcmp(ANDR_BOOT_MAGIC, init_boot_img, ANDR_BOOT_MAGIC_SIZE); +} + bool is_android_boot_image_header(const void *hdr) { return !memcmp(ANDR_BOOT_MAGIC, hdr, ANDR_BOOT_MAGIC_SIZE); diff --git a/cmd/abootimg.c b/cmd/abootimg.c index eae3e643b60..b32872bba7f 100644 --- a/cmd/abootimg.c +++ b/cmd/abootimg.c @@ -2,6 +2,7 @@ /* * (C) Copyright 2020 * Sam Protsenko <[email protected]> + * Copyright (c) 2026 Valentin Liu <[email protected]> */ #include <android_image.h> @@ -33,6 +34,11 @@ ulong get_ainit_bootimg_addr(void) return _ainit_bootimg_addr; } +void set_ainit_bootimg_addr(ulong addr) +{ + _ainit_bootimg_addr = addr; +} + ulong get_avendor_bootimg_addr(void) { return _avendor_bootimg_addr; diff --git a/doc/develop/bootstd/overview.rst b/doc/develop/bootstd/overview.rst index ec9fafa0fa0..f1306ae0a8f 100644 --- a/doc/develop/bootstd/overview.rst +++ b/doc/develop/bootstd/overview.rst @@ -293,6 +293,9 @@ script_offset_f script_size_f Size of the script to load, e.g. 0x2000 +init_boot_comp_addr_r + Address to which to load the init_boot Android image, e.g. 0xd0000000 + vendor_boot_comp_addr_r Address to which to load the vendor_boot Android image, e.g. 0xe0000000 diff --git a/include/android_image.h b/include/android_image.h index a2d80499ba3..134b5ed74d6 100644 --- a/include/android_image.h +++ b/include/android_image.h @@ -357,6 +357,7 @@ struct andr_image_data { ulong tags_addr; /* physical addr for kernel tags */ u32 header_version; /* version of the boot image header */ u32 boot_img_total_size; /* boot image size */ + u32 init_boot_img_total_size; /* init boot image size */ u32 vendor_boot_img_total_size; /* vendor boot image size */ }; diff --git a/include/image.h b/include/image.h index 6edcb1995bf..b323b5f880e 100644 --- a/include/image.h +++ b/include/image.h @@ -2015,6 +2015,30 @@ struct andr_image_data; */ bool android_image_get_bootimg_size(const void *hdr, u32 *boot_img_size); +/** + * android_image_get_init_bootimg_size() - Extract size of Android init_boot image + * + * This is used to extract the size of an Android init_boot image + * from init_boot image header. + * + * @hdr: Pointer to init_boot image header + * @init_boot_img_size: On exit returns the size in bytes of the init_boot image + * Return: true if succeeded, false otherwise + */ +bool android_image_get_bootimg_size(const void *hdr, u32 *init_boot_img_size); + +/** + * android_image_get_init_bootimg_size() - Extract size of Android init_boot image + * + * This is used to extract the size of an Android init_boot image + * from init_boot image header. + * + * @hdr: Pointer to init_boot image header + * @init_boot_img_size: On exit returns the size in bytes of the init_boot image + * Return: true if succeeded, false otherwise + */ +bool android_image_get_init_bootimg_size(const void *hdr, u32 *init_boot_img_size); + /** * android_image_get_vendor_bootimg_size() - Extract size of Android vendor-boot image * @@ -2041,6 +2065,23 @@ bool android_image_get_vendor_bootimg_size(const void *hdr, u32 *vendor_boot_img bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr, struct andr_image_data *data); +/** + * android_image_get_data_v4() - Parse Android header version 4 boot images + * + * This is used to parse boot, vendor-boot and init boot header into + * andr_image_data generic structure. + * The Android 13 and newer has splited parameters from boot and + * vendor_boot images to the init_boot image. + * + * @boot_hdr: Pointer to boot image header + * @vendor_boot_hdr: Pointer to vendor boot image header + * @init_boot_hdr: Pointer to init boot image header + * @data: Pointer to generic boot format structure + * Return: true if succeeded, false otherwise + */ +bool android_image_get_data_v4(const void *boot_hdr, const void *vendor_boot_hdr, + const void *init_boot_hdr, struct andr_image_data *data); + struct andr_boot_img_hdr_v0; /** @@ -2167,6 +2208,17 @@ bool android_image_print_dtb_contents(ulong hdr_addr); */ bool is_android_boot_image_header(const void *hdr); +/** + * is_android_init_boot_image_header() - Check the magic of init boot image + * + * This checks the header of Android init boot image and verifies the + * magic is "ANDROID!" (same with the boot image) + * + * @init_boot_img: Pointer to boot image + * Return: non-zero if the magic is correct, zero otherwise + */ +bool is_android_init_boot_image_header(const void *init_boot_img); + /** * is_android_vendor_boot_image_header() - Check the magic of vendor boot image * @@ -2199,6 +2251,13 @@ void set_abootimg_addr(ulong addr); */ ulong get_ainit_bootimg_addr(void); +/** + * set_ainit_bootimg_addr() - Set Android init boot image address + * + * Return: no returned results + */ +void set_ainit_bootimg_addr(ulong addr); + /** * get_avendor_bootimg_addr() - Get Android vendor boot image address * -- 2.53.0
