diff options
Diffstat (limited to 'boot/bootmeth_android.c')
-rw-r--r-- | boot/bootmeth_android.c | 104 |
1 files changed, 76 insertions, 28 deletions
diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c index 19b1f2c377b..3a5144aaa3b 100644 --- a/boot/bootmeth_android.c +++ b/boot/bootmeth_android.c @@ -29,6 +29,7 @@ #define BCB_PART_NAME "misc" #define BOOT_PART_NAME "boot" #define VENDOR_BOOT_PART_NAME "vendor_boot" +#define SLOT_LEN 2 /** * struct android_priv - Private data @@ -42,8 +43,10 @@ */ struct android_priv { enum android_boot_mode boot_mode; - char slot[2]; + char *slot; u32 header_version; + u32 boot_img_size; + u32 vendor_boot_img_size; }; static int android_check(struct udevice *dev, struct bootflow_iter *iter) @@ -71,7 +74,11 @@ static int scan_boot_part(struct udevice *blk, struct android_priv *priv) char *buf; int ret; - sprintf(partname, BOOT_PART_NAME "_%s", priv->slot); + if (priv->slot) + sprintf(partname, BOOT_PART_NAME "_%s", priv->slot); + else + sprintf(partname, BOOT_PART_NAME); + ret = part_get_info_by_name(desc, partname, &partition); if (ret < 0) return log_msg_ret("part info", ret); @@ -93,7 +100,13 @@ static int scan_boot_part(struct udevice *blk, struct android_priv *priv) return log_msg_ret("header", -ENOENT); } + if (!android_image_get_bootimg_size(buf, &priv->boot_img_size)) { + free(buf); + return log_msg_ret("get bootimg size", -EINVAL); + } + priv->header_version = ((struct andr_boot_img_hdr_v0 *)buf)->header_version; + free(buf); return 0; @@ -108,7 +121,11 @@ static int scan_vendor_boot_part(struct udevice *blk, struct android_priv *priv) char *buf; int ret; - sprintf(partname, VENDOR_BOOT_PART_NAME "_%s", priv->slot); + if (priv->slot) + sprintf(partname, VENDOR_BOOT_PART_NAME "_%s", priv->slot); + else + sprintf(partname, VENDOR_BOOT_PART_NAME); + ret = part_get_info_by_name(desc, partname, &partition); if (ret < 0) return log_msg_ret("part info", ret); @@ -129,6 +146,12 @@ static int scan_vendor_boot_part(struct udevice *blk, struct android_priv *priv) free(buf); return log_msg_ret("header", -ENOENT); } + + if (!android_image_get_vendor_bootimg_size(buf, &priv->vendor_boot_img_size)) { + free(buf); + return log_msg_ret("get vendor bootimg size", -EINVAL); + } + free(buf); return 0; @@ -142,6 +165,11 @@ static int android_read_slot_from_bcb(struct bootflow *bflow, bool decrement) char slot_suffix[3]; int ret; + if (!CONFIG_IS_ENABLED(ANDROID_AB)) { + priv->slot = NULL; + return 0; + } + ret = part_get_info_by_name(desc, BCB_PART_NAME, &misc); if (ret < 0) return log_msg_ret("part", ret); @@ -150,6 +178,7 @@ static int android_read_slot_from_bcb(struct bootflow *bflow, bool decrement) if (ret < 0) return log_msg_ret("slot", ret); + priv->slot = malloc(SLOT_LEN); priv->slot[0] = BOOT_SLOT_NAME(ret); priv->slot[1] = '\0'; @@ -259,16 +288,12 @@ static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow) goto free_priv; } - if (priv->header_version != 4) { - log_debug("only boot.img v4 is supported %u\n", priv->header_version); - ret = -EINVAL; - goto free_priv; - } - - ret = scan_vendor_boot_part(bflow->blk, priv); - if (ret < 0) { - log_debug("scan vendor_boot failed: err=%d\n", ret); - goto free_priv; + if (priv->header_version >= 3) { + ret = scan_vendor_boot_part(bflow->blk, priv); + if (ret < 0) { + log_debug("scan vendor_boot failed: err=%d\n", ret); + goto free_priv; + } } /* @@ -278,7 +303,7 @@ static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow) configure_serialno(bflow); configure_bootloader_version(bflow); - if (priv->boot_mode == ANDROID_BOOT_MODE_NORMAL) { + if (priv->boot_mode == ANDROID_BOOT_MODE_NORMAL && priv->slot) { ret = bootflow_cmdline_set_arg(bflow, "androidboot.force_normal_boot", "1", false); if (ret < 0) { @@ -319,28 +344,44 @@ static int android_read_file(struct udevice *dev, struct bootflow *bflow, * @blk: Block device to read * @name: Partition name to read * @slot: Nul-terminated slot suffixed to partition name ("a\0" or "b\0") + * @image_size: Image size in bytes used when reading the partition * @addr: Address where the partition content is loaded into * Return: 0 if OK, negative errno on failure. */ static int read_slotted_partition(struct blk_desc *desc, const char *const name, - const char slot[2], ulong addr) + const char slot[2], ulong image_size, ulong addr) { struct disk_partition partition; char partname[PART_NAME_LEN]; + size_t partname_len; + ulong num_blks = DIV_ROUND_UP(image_size, desc->blksz); int ret; u32 n; - /* Ensure name fits in partname it should be: <name>_<slot>\0 */ - if (strlen(name) > (PART_NAME_LEN - 2 - 1)) + /* + * Ensure name fits in partname. + * For A/B, it should be <name>_<slot>\0 + * For non A/B, it should be <name>\0 + */ + if (CONFIG_IS_ENABLED(ANDROID_AB)) + partname_len = PART_NAME_LEN - 2 - 1; + else + partname_len = PART_NAME_LEN - 1; + + if (strlen(name) > partname_len) return log_msg_ret("name too long", -EINVAL); - sprintf(partname, "%s_%s", name, slot); + if (slot) + sprintf(partname, "%s_%s", name, slot); + else + sprintf(partname, "%s", name); + ret = part_get_info_by_name(desc, partname, &partition); if (ret < 0) return log_msg_ret("part", ret); - n = blk_dread(desc, partition.start, partition.size, map_sysmem(addr, 0)); - if (n < partition.size) + n = blk_dread(desc, partition.start, num_blks, map_sysmem(addr, 0)); + if (n < num_blks) return log_msg_ret("part read", -EIO); return 0; @@ -386,7 +427,7 @@ static int run_avb_verification(struct bootflow *bflow) AvbSlotVerifyData *out_data; enum avb_boot_state boot_state; char *extra_args; - char slot_suffix[3]; + char slot_suffix[3] = ""; bool unlocked = false; int ret; @@ -394,7 +435,8 @@ static int run_avb_verification(struct bootflow *bflow) if (!avb_ops) return log_msg_ret("avb ops", -ENOMEM); - sprintf(slot_suffix, "_%s", priv->slot); + if (priv->slot) + sprintf(slot_suffix, "_%s", priv->slot); ret = avb_ops->read_is_device_unlocked(avb_ops, &unlocked); if (ret != AVB_IO_RESULT_OK) @@ -472,16 +514,22 @@ static int boot_android_normal(struct bootflow *bflow) if (ret < 0) return log_msg_ret("read slot", ret); - ret = read_slotted_partition(desc, "boot", priv->slot, loadaddr); + ret = read_slotted_partition(desc, "boot", priv->slot, priv->boot_img_size, + loadaddr); if (ret < 0) return log_msg_ret("read boot", ret); - ret = read_slotted_partition(desc, "vendor_boot", priv->slot, vloadaddr); - if (ret < 0) - return log_msg_ret("read vendor_boot", ret); - + if (priv->header_version >= 3) { + ret = read_slotted_partition(desc, "vendor_boot", priv->slot, + priv->vendor_boot_img_size, vloadaddr); + if (ret < 0) + return log_msg_ret("read vendor_boot", ret); + set_avendor_bootimg_addr(vloadaddr); + } set_abootimg_addr(loadaddr); - set_avendor_bootimg_addr(vloadaddr); + + if (priv->slot) + free(priv->slot); ret = bootm_boot_start(loadaddr, bflow->cmdline); |