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. Currently, we have supported loading the init_boot image by abootimg command, but we still need bring this ability to bootmeth, so that booting Android 13+ will be more easily. Bootmeth will be able to recognize the new partition layout, and boot Android normally. Link: https://source.android.com/docs/core/architecture/partitions/generic-boot Signed-off-by: Valentin Liu <[email protected]> --- boot/bootmeth_android.c | 67 ++++++++++++++++++++++++++++++++ boot/image-android.c | 16 ++++++++ cmd/abootimg.c | 5 +++ doc/develop/bootstd/overview.rst | 3 ++ include/android_image.h | 1 + include/image.h | 35 +++++++++++++++++ 6 files changed, 127 insertions(+) diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c index ec255b072af..904640d360b 100644 --- a/boot/bootmeth_android.c +++ b/boot/bootmeth_android.c @@ -29,6 +29,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 +48,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 +115,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_boot_image_header(buf)) { + free(buf); + return log_msg_ret("header", -ENOENT); + } + + if (!android_image_get_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); @@ -291,6 +338,17 @@ static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow) goto free_priv; } + if (priv->header_version >= 4) { + ret = scan_init_boot_part(bflow->blk, priv); + if (ret < 0) { + /* + * Android 12 devices do not have the init_boot partition. + * Some devices upgraded to Android 13 or later from + * earlier Android versions may also not have one. + */ + log_debug("scan init_boot failed: err=%d\n", ret); + } + } if (priv->header_version >= 3) { ret = scan_vendor_boot_part(bflow->blk, priv); if (ret < 0) { @@ -556,6 +614,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); @@ -572,6 +631,14 @@ static int boot_android_normal(struct bootflow *bflow) if (ret < 0) return log_msg_ret("read boot", ret); + if (priv->header_version >= 4 && priv->init_boot_img_size > 0) { + 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); + } if (priv->header_version >= 3) { ret = read_slotted_partition(desc, "vendor_boot", priv->slot, priv->vendor_boot_img_size, vloadaddr); diff --git a/boot/image-android.c b/boot/image-android.c index 7740cae8cb6..3f5634b469f 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -326,6 +326,22 @@ 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)) + return false; + + if (!is_android_boot_image_header(init_boot_hdr)) { + printf("Incorrect init boot image header\n"); + return false; + } + + android_boot_image_v3_v4_parse_hdr(init_boot_hdr, data); + + return true; +} + static ulong android_image_get_kernel_addr(struct andr_image_data *img_data, ulong comp) { diff --git a/cmd/abootimg.c b/cmd/abootimg.c index eae3e643b60..e8e6b8f5ced 100644 --- a/cmd/abootimg.c +++ b/cmd/abootimg.c @@ -33,6 +33,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..1c725fc2601 100644 --- a/include/image.h +++ b/include/image.h @@ -2041,6 +2041,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 +2184,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 +2227,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
