From 745aeb1a7d34894ca02c79ec6eae74650aa519a8 Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Wed, 9 Sep 2020 18:05:01 +0800 Subject: [PATCH] common: android: add boot_img_hdr_v3 and vendor boot support Android Header v3 and vendor boot partition are introduced from Android-11(R). Header populate: Header v3 is no longer compatible with v0/1/2 header, we add populate_andr_img_hdr() to merge boot and vendor_boot partition header into struct andr_img_hdr in order to compatible with v0/1/2 header. resource.img: The second_addr and second_size fields are removed in v3, so we require resource partition to restore resource.img. A/B system: If not A/B system, the boot.img header version is 3 and recovery header is version 2. AVB load image: - If allow verification error: the image is loaded by ops->get_preloaded_partition() which auto populates boot_img_hdr_v3. - If not allow verification error: the image is full loaded by ops->read_from_partition() which doesn't populate boot_img_hdr_v3, we need to fix it. Signed-off-by: Joseph Chen Change-Id: I2afce53c43d782fc57baa01acf9c05518b580840 --- arch/arm/mach-rockchip/resource_img.c | 159 ++++----- cmd/android.c | 26 +- common/android_bootloader.c | 72 ++-- common/image-android.c | 490 ++++++++++++++++++++++---- include/android_image.h | 123 ++++++- include/boot_rkimg.h | 1 + include/image.h | 3 + 7 files changed, 687 insertions(+), 187 deletions(-) diff --git a/arch/arm/mach-rockchip/resource_img.c b/arch/arm/mach-rockchip/resource_img.c index a8a610e804..3d5f29e9f7 100644 --- a/arch/arm/mach-rockchip/resource_img.c +++ b/arch/arm/mach-rockchip/resource_img.c @@ -273,27 +273,6 @@ static int read_logo_bmps(struct blk_desc *dev_desc) return 0; } -static int read_dtb_from_android_v2(int rsce_base, int dtb_offset, int dtb_size) -{ - if (!dtb_size) - return 0; - - /* - * boot_img_hdr_v2 feature. - * - * If dtb position is present, replace the old with new one if - * we don't need to verify DTB hash from resource.img file entry. - */ -#ifndef CONFIG_ROCKCHIP_DTB_VERIFY - if (replace_resource_entry(DTB_FILE, rsce_base, dtb_offset, dtb_size)) - printf("Failed to load dtb from v2 dtb position\n"); - else -#endif - env_update("bootargs", "androidboot.dtb_idx=0"); - - return 0; -} - int resource_create_ram_list(struct blk_desc *dev_desc, void *rsce_hdr) { struct resource_img_hdr *hdr = rsce_hdr; @@ -385,81 +364,105 @@ err: return ret; } +static int read_dtb_from_android(struct blk_desc *dev_desc, + struct andr_img_hdr *hdr, + ulong rsce_base) +{ + ulong dtb_offset = 0; + ulong dtb_size = 0; + + if (!hdr || hdr->header_version <= 1) { + return 0; + } else if (hdr->header_version == 2) { + dtb_offset += hdr->page_size; + dtb_offset += ALIGN(hdr->kernel_size, hdr->page_size); + dtb_offset += ALIGN(hdr->ramdisk_size, hdr->page_size); + dtb_offset += ALIGN(hdr->recovery_dtbo_size, hdr->page_size) + + ALIGN(hdr->second_size, hdr->page_size); + dtb_size = hdr->dtb_size; + } else if (hdr->header_version == 3) { + dtb_offset += ALIGN(VENDOR_BOOT_HDR_SIZE, + hdr->vendor_page_size) + + ALIGN(hdr->vendor_ramdisk_size, + hdr->vendor_page_size); + dtb_size = hdr->dtb_size; + } + + if (!dtb_size) + return 0; + + /* + * boot_img_hdr_v2,3 feature. + * + * If dtb position is present, replace the old with new one if + * we don't need to verify DTB hash from resource.img file entry. + */ + dtb_offset = DIV_ROUND_UP(dtb_offset, dev_desc->blksz); +#ifndef CONFIG_ROCKCHIP_DTB_VERIFY + if (replace_resource_entry(DTB_FILE, rsce_base, dtb_offset, dtb_size)) + printf("Failed to load dtb from v2 dtb position\n"); + else +#endif + env_update("bootargs", "androidboot.dtb_idx=0"); + + return 0; +} + static int get_resource_base_sector(struct blk_desc *dev_desc, - disk_partition_t *from_part, - int *dtb_off, int *dtb_size) + struct andr_img_hdr **ret_hdr) { disk_partition_t part; - int rsce_base; + int rsce_base = 0; #ifdef CONFIG_ANDROID_BOOT_IMAGE struct andr_img_hdr *hdr; - int blknum; + u32 os_ver = 0, os_lvl; /* * Anyway, we must read android hdr firstly from boot partition to get * the 'os_version' for android_bcb_msg_sector_offset(), in order to - * confirm BCB message offset of misc partition. + * confirm BCB message offset of *MISC* partition. */ if (part_get_info_by_name(dev_desc, PART_BOOT, &part) < 0) goto resource_part; - blknum = DIV_ROUND_UP(sizeof(*hdr), dev_desc->blksz); - hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz * blknum); - if (!hdr) - return -ENOMEM; - - if (blk_dread(dev_desc, part.start, blknum, hdr) != blknum) { - printf("Failed to read %s hdr\n", part.name); - free(hdr); - return -EIO; - } - - if (!android_image_check_header(hdr)) { - u32 os_ver, os_lvl; - + hdr = populate_andr_img_hdr(dev_desc, &part); + if (hdr) { os_ver = hdr->os_version >> 11; os_lvl = hdr->os_version & ((1U << 11) - 1); - if (os_ver) { + if (os_ver) gd->bd->bi_andr_version = hdr->os_version; - printf("Android %u.%u, Build %u.%u\n", - (os_ver >> 14) & 0x7F, (os_ver >> 7) & 0x7F, - (os_lvl >> 4) + 2000, os_lvl & 0x0F); - } } #ifndef CONFIG_ANDROID_AB /* Get boot mode from misc and read if recovery mode */ if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) { + if (hdr) + free(hdr); + if (part_get_info_by_name(dev_desc, PART_RECOVERY, &part) < 0) goto resource_part; - if (blk_dread(dev_desc, part.start, blknum, hdr) != blknum) { - printf("Failed to read %s hdr\n", part.name); - free(hdr); - return -EIO; - } + hdr = populate_andr_img_hdr(dev_desc, &part); + if (!hdr) + goto resource_part; } #endif - /* get ! */ - if (!android_image_check_header(hdr)) { - rsce_base = part.start * dev_desc->blksz; - rsce_base += hdr->page_size; - rsce_base += ALIGN(hdr->kernel_size, hdr->page_size); - rsce_base += ALIGN(hdr->ramdisk_size, hdr->page_size); - - if (hdr->header_version >= 2) { - *dtb_size = hdr->dtb_size; - *dtb_off = - rsce_base + - ALIGN(hdr->recovery_dtbo_size, hdr->page_size) + - ALIGN(hdr->second_size, hdr->page_size); + /* If Android v012, getting resource from second position ! */ + if (hdr) { + if (os_ver) + printf("Android %u.%u, Build %u.%u, v%d\n", + (os_ver >> 14) & 0x7F, (os_ver >> 7) & 0x7F, + (os_lvl >> 4) + 2000, os_lvl & 0x0F, + hdr->header_version); + *ret_hdr = hdr; + if (hdr->header_version < 3) { + rsce_base = part.start * dev_desc->blksz; + rsce_base += hdr->page_size; + rsce_base += ALIGN(hdr->kernel_size, hdr->page_size); + rsce_base += ALIGN(hdr->ramdisk_size, hdr->page_size); + rsce_base = DIV_ROUND_UP(rsce_base, dev_desc->blksz); + goto finish; } - - rsce_base = DIV_ROUND_UP(rsce_base, dev_desc->blksz); - *dtb_off = DIV_ROUND_UP(*dtb_off, dev_desc->blksz) - rsce_base; - *from_part = part; - free(hdr); - goto finish; } resource_part: #endif @@ -467,10 +470,9 @@ resource_part: if (part_get_info_by_name(dev_desc, PART_RESOURCE, &part) < 0) { printf("No resource partition\n"); return -ENODEV; + } else { + rsce_base = part.start; } - - *from_part = part; - rsce_base = part.start; #ifdef CONFIG_ANDROID_BOOT_IMAGE finish: #endif @@ -490,11 +492,9 @@ finish: */ static int init_resource_list(void) { + struct andr_img_hdr *hdr = NULL; struct blk_desc *dev_desc; - disk_partition_t part; int rsce_base; - int dtb_offset; - int dtb_size = 0; dev_desc = rockchip_get_bootdev(); if (!dev_desc) { @@ -502,17 +502,14 @@ static int init_resource_list(void) return -ENODEV; } - rsce_base = get_resource_base_sector(dev_desc, &part, - &dtb_offset, &dtb_size); + rsce_base = get_resource_base_sector(dev_desc, &hdr); if (rsce_base > 0) { if (resource_create_list(dev_desc, rsce_base)) printf("Failed to create resource list\n"); } - /* override the old one if dtb_size != 0 */ - read_dtb_from_android_v2(rsce_base, dtb_offset, dtb_size); - - return 0; + /* override the resource dtb with android dtb if need */ + return read_dtb_from_android(dev_desc, hdr, rsce_base); } static struct resource_file *get_file_info(const char *name) diff --git a/cmd/android.c b/cmd/android.c index 721a67a0f8..6db721fcab 100644 --- a/cmd/android.c +++ b/cmd/android.c @@ -18,7 +18,6 @@ static int do_android_print_hdr(cmd_tbl_t *cmdtp, int flag, struct andr_img_hdr *hdr; disk_partition_t part_info; const char *part_name; - int blkcnt, ret; if (argc != 2) return CMD_RET_USAGE; @@ -31,31 +30,18 @@ static int do_android_print_hdr(cmd_tbl_t *cmdtp, int flag, return -ENODEV; } - ret = part_get_info_by_name(dev_desc, part_name, &part_info); - if (ret < 0) { - printf("Failed to get \"%s\" part, ret=%d\n", part_name, ret); + if (part_get_info_by_name(dev_desc, part_name, &part_info) < 0) { + printf("Failed to get \"%s\" part\n", part_name); return -ENODEV; } - blkcnt = DIV_ROUND_UP(sizeof(*hdr), dev_desc->blksz); - hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz * blkcnt); + hdr = populate_andr_img_hdr(dev_desc, &part_info); if (!hdr) { - printf("%s: out of memory!\n", __func__); - return -ENOMEM; - } - - ret = blk_dread(dev_desc, part_info.start, blkcnt, hdr); - if (ret != blkcnt) { - printf("Failed to read %s sector, ret=%d\n", part_info.name, ret); - free(hdr); - return -EIO; - } - - if (!android_image_check_header(hdr)) { + printf("Not an android image\n"); + return -EINVAL; + } else { printf("Partition \"%s\"\n", part_info.name); android_print_contents(hdr); - } else { - printf("Not an android image\n"); } free(hdr); diff --git a/common/android_bootloader.c b/common/android_bootloader.c index a5169d6ff7..41b5682252 100644 --- a/common/android_bootloader.c +++ b/common/android_bootloader.c @@ -31,6 +31,7 @@ DECLARE_GLOBAL_DATA_PTR; #define ANDROID_PARTITION_BOOT "boot" +#define ANDROID_PARTITION_VENDOR_BOOT "vendor_boot" #define ANDROID_PARTITION_MISC "misc" #define ANDROID_PARTITION_OEM "oem" #define ANDROID_PARTITION_RECOVERY "recovery" @@ -790,8 +791,41 @@ static AvbSlotVerifyResult android_slot_verify(char *boot_partname, strcat(newbootargs, slot_data[0]->cmdline); env_set("bootargs", newbootargs); - /* Reserve page_size */ hdr = (void *)slot_data[0]->loaded_partitions->data; + + /* + * populate boot_img_hdr_v3 + * + * If allow verification error: the image is loaded by + * ops->get_preloaded_partition() which auto populates + * boot_img_hdr_v3. + * + * If not allow verification error: the image is full loaded + * by ops->read_from_partition() which doesn't populate + * boot_img_hdr_v3, we need to fix it here. + */ + if (hdr->header_version >= 3 && + !(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR)) { + struct andr_img_hdr *v3hdr; + struct blk_desc *dev_desc; + disk_partition_t part; + + dev_desc = rockchip_get_bootdev(); + if (!dev_desc) + return -1; + + if (part_get_info_by_name(dev_desc, + boot_partname, &part) < 0) + return -1; + + v3hdr = populate_andr_img_hdr(dev_desc, &part); + if (v3hdr) { + memcpy(hdr, v3hdr, sizeof(*v3hdr)); + free(v3hdr); + } + } + + /* Reserve page_size */ load_address -= hdr->page_size; if (android_image_memcpy_separate(hdr, &load_address)) { printf("Failed to separate copy android image\n"); @@ -948,7 +982,6 @@ int android_fdt_overlay_apply(void *fdt_addr) disk_partition_t part_info; char *part_dtbo; char buf[32] = {0}; - u32 blk_cnt; ulong fdt_dtbo = -1; int index = -1; int ret; @@ -970,32 +1003,25 @@ int android_fdt_overlay_apply(void *fdt_addr) if (ret < 0) return ret; - blk_cnt = DIV_ROUND_UP(sizeof(*hdr), part_info.blksz); - hdr = memalign(ARCH_DMA_MINALIGN, part_info.blksz * blk_cnt); - if (!hdr) { - printf("%s: out of memory!\n", __func__); - return -ENOMEM; - } - - ret = blk_dread(dev_desc, part_info.start, blk_cnt, hdr); - if (ret != blk_cnt) { - printf("%s: failed to read %s hdr!\n", __func__, part_boot); - goto out; - } - + hdr = populate_andr_img_hdr(dev_desc, &part_info); + if (!hdr) + return -EINVAL; #ifdef DEBUG android_print_contents(hdr); #endif - if (android_image_check_header(hdr)) - return -EINVAL; - - /* Check header version */ - if (!hdr->header_version) { - printf("Android header version 0\n"); - ret = -EINVAL; + /* + * recovery_dtbo fields + * + * boot_img_hdr_v0: unsupported + * boot_img_hdr_v1,2: supported + * boot_img_hdr_v3 + boot.img: supported + * boot_img_hdr_v3 + recovery.img: unsupported + */ + if ((hdr->header_version == 0) || + (hdr->header_version == 3 && !strcmp(part_boot, PART_RECOVERY)) || + (hdr->header_version > 3)) goto out; - } ret = android_get_dtbo(&fdt_dtbo, (void *)hdr, &index, part_dtbo); if (!ret) { diff --git a/common/image-android.c b/common/image-android.c index 95a9ed074d..4e2bc62af0 100644 --- a/common/image-android.c +++ b/common/image-android.c @@ -30,9 +30,10 @@ DECLARE_GLOBAL_DATA_PTR; #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000 #define ANDROID_ARG_FDT_FILENAME "rk-kernel.dtb" #define ANDROID_Q_VER 10 +#define ANDROID_PARTITION_VENDOR_BOOT "vendor_boot" -/* Defined by rockchip legacy mkboot tool(SDK version < 8.1) */ -#define ANDROID_ROCKCHIP_LEGACY_PAGE_SIZE 0x4000 +#define BLK_CNT(_num_bytes, _block_size) \ + ((_num_bytes + _block_size - 1) / _block_size) static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1]; static u32 android_kernel_comp_type = IH_COMP_NONE; @@ -131,7 +132,8 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, ulong *os_data, ulong *os_len) { u32 kernel_addr = android_image_get_kernel_addr(hdr); - + const char *cmdline = hdr->header_version < 3 ? + hdr->cmdline : hdr->total_cmdline; /* * Not all Android tools use the id field for signing the image with * sha1 (or anything) so we don't check it. It is not obvious that the @@ -146,9 +148,9 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024)); int len = 0; - if (*hdr->cmdline) { - debug("Kernel command line: %s\n", hdr->cmdline); - len += strlen(hdr->cmdline); + if (cmdline) { + debug("Kernel command line: %s\n", cmdline); + len += strlen(cmdline); } char *bootargs = env_get("bootargs"); @@ -166,8 +168,8 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, strcpy(newbootargs, bootargs); strcat(newbootargs, " "); } - if (*hdr->cmdline) - strcat(newbootargs, hdr->cmdline); + if (cmdline) + strcat(newbootargs, cmdline); env_set("bootargs", newbootargs); @@ -193,16 +195,22 @@ ulong android_image_get_end(const struct andr_img_hdr *hdr) * on page boundary */ end = (ulong)hdr; - end += hdr->page_size; - end += ALIGN(hdr->kernel_size, hdr->page_size); - end += ALIGN(hdr->ramdisk_size, hdr->page_size); - end += ALIGN(hdr->second_size, hdr->page_size); - - if (hdr->header_version >= 2) { - end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size); - end += ALIGN(hdr->dtb_size, hdr->page_size); - } else if (hdr->header_version >= 1) { - end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size); + if (hdr->header_version < 3) { + end += hdr->page_size; + end += ALIGN(hdr->kernel_size, hdr->page_size); + end += ALIGN(hdr->ramdisk_size, hdr->page_size); + end += ALIGN(hdr->second_size, hdr->page_size); + if (hdr->header_version == 1) { + end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size); + } else if (hdr->header_version == 2) { + end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size); + end += ALIGN(hdr->dtb_size, hdr->page_size); + } + } else { + /* boot_img_hdr_v3 */ + end += hdr->page_size; + end += ALIGN(hdr->kernel_size, hdr->page_size); + end += ALIGN(hdr->ramdisk_size, hdr->page_size); } return end; @@ -293,6 +301,7 @@ typedef enum { IMG_RECOVERY_DTBO, IMG_RK_DTB, /* within resource.img in second position */ IMG_DTB, + IMG_VENDOR_RAMDISK, IMG_MAX, } img_t; @@ -301,11 +310,14 @@ static int image_load(img_t img, struct andr_img_hdr *hdr, struct udevice *crypto) { struct blk_desc *desc = rockchip_get_bootdev(); + disk_partition_t part_vendor_boot; __maybe_unused u32 sizesz; ulong pgsz = hdr->page_size; ulong blksz = desc->blksz; ulong blkcnt, blkoff; + ulong orgdst = 0; ulong offset = 0; + ulong extra = 0; ulong datasz; void *ramdst; int ret = 0; @@ -321,15 +333,62 @@ static int image_load(img_t img, struct andr_img_hdr *hdr, (phys_addr_t)ramdst, blkcnt * blksz)) return -ENOMEM; break; + case IMG_VENDOR_RAMDISK: + if (part_get_info_by_name(desc, + ANDROID_PARTITION_VENDOR_BOOT, + &part_vendor_boot) < 0) { + printf("No vendor boot partition\n"); + return -ENOENT; + } + /* Always load vendor boot from storage: avb full load boot/recovery */ + blkstart = part_vendor_boot.start; + ram_base = 0; + + pgsz = hdr->vendor_page_size; + offset = ALIGN(VENDOR_BOOT_HDR_SIZE, pgsz); + blkcnt = DIV_ROUND_UP(hdr->vendor_ramdisk_size, blksz); + ramdst = (void *)env_get_ulong("ramdisk_addr_r", 16, 0); + datasz = hdr->vendor_ramdisk_size; + sizesz = sizeof(hdr->vendor_ramdisk_size); + /* + * Add extra memory for generic ramdisk space. + * + * In case of unaligned vendor ramdisk size, reserve + * 1 more blksz. + */ + if (hdr->header_version == 3) + extra = ALIGN(hdr->ramdisk_size, blksz) + blksz; + if (datasz && !sysmem_alloc_base(MEM_RAMDISK, + (phys_addr_t)ramdst, blkcnt * blksz + extra)) + return -ENOMEM; + break; case IMG_RAMDISK: offset = pgsz + ALIGN(hdr->kernel_size, pgsz); blkcnt = DIV_ROUND_UP(hdr->ramdisk_size, blksz); ramdst = (void *)env_get_ulong("ramdisk_addr_r", 16, 0); + /* + * ramdisk_addr_r: + * |----------------|---------| + * | vendor-ramdisk | ramdisk | + * |----------------|---------| + */ + if (hdr->header_version >= 3) { + ramdst += hdr->vendor_ramdisk_size; + if (!IS_ALIGNED((ulong)ramdst, blksz)) { + orgdst = (ulong)ramdst; + ramdst = (void *)ALIGN(orgdst, blksz); + } + } datasz = hdr->ramdisk_size; sizesz = sizeof(hdr->ramdisk_size); - if (datasz && !sysmem_alloc_base(MEM_RAMDISK, + /* + * skip v3: sysmem has been alloced by vendor ramdisk. + */ + if (hdr->header_version < 3) { + if (datasz && !sysmem_alloc_base(MEM_RAMDISK, (phys_addr_t)ramdst, blkcnt * blksz)) - return -ENOMEM; + return -ENOMEM; + } break; case IMG_SECOND: offset = pgsz + @@ -393,6 +452,9 @@ static int image_load(img_t img, struct andr_img_hdr *hdr, } } + if (orgdst) + memmove((char *)orgdst, ramdst, datasz); + crypto_calc: /* sha1 */ #ifdef CONFIG_DM_CRYPTO @@ -410,6 +472,9 @@ crypto_calc: return 0; } +/* + * @ram_base: !NULL means require memcpy for an exist full android image. + */ static int android_image_separate(struct andr_img_hdr *hdr, const disk_partition_t *part, void *load_address, @@ -508,6 +573,48 @@ static int android_image_separate(struct andr_img_hdr *hdr, return 0; } +static int android_image_separate_v3(struct andr_img_hdr *hdr, + const disk_partition_t *part, + void *load_address, void *ram_base) +{ + ulong bstart; + + if (android_image_check_header(hdr)) { + printf("Bad android image header\n"); + return -EINVAL; + } + + /* set for image_load(IMG_KERNEL, ...) */ + env_set_hex("android_addr_r", (ulong)load_address); + bstart = part ? part->start : 0; + + /* + * 1. Load images to their individual target ram position + * in order to disable fdt/ramdisk relocation. + */ + if (image_load(IMG_RK_DTB, hdr, bstart, ram_base, NULL)) + return -1; + if (image_load(IMG_KERNEL, hdr, bstart, ram_base, NULL)) + return -1; + if (image_load(IMG_VENDOR_RAMDISK, hdr, bstart, ram_base, NULL)) + return -1; + if (image_load(IMG_RAMDISK, hdr, bstart, ram_base, NULL)) + return -1; + + /* + * Copy the populated hdr to load address after image_load(IMG_KERNEL) + * + * The image_load(IMG_KERNEL) only reads boot_img_hdr_v3 while + * vendor_boot_img_hdr_v3 is not included, so fix it here. + */ + memcpy((char *)load_address, hdr, hdr->page_size); + + /* 2. Disable fdt/ramdisk relocation, it saves boot time */ + env_set("bootm-no-reloc", "y"); + + return 0; +} + static ulong android_image_get_comp_addr(struct andr_img_hdr *hdr, int comp) { ulong kernel_addr_c; @@ -605,7 +712,10 @@ static int android_image_load_separate(struct andr_img_hdr *hdr, const disk_partition_t *part, void *load_addr) { - return android_image_separate(hdr, part, load_addr, NULL); + if (hdr->header_version < 3) + return android_image_separate(hdr, part, load_addr, NULL); + else + return android_image_separate_v3(hdr, part, load_addr, NULL); } int android_image_memcpy_separate(struct andr_img_hdr *hdr, ulong *load_addr) @@ -617,8 +727,13 @@ int android_image_memcpy_separate(struct andr_img_hdr *hdr, ulong *load_addr) if (comp_addr == (ulong)hdr) return 0; - if (android_image_separate(hdr, NULL, (void *)comp_addr, hdr)) - return -1; + if (hdr->header_version < 3) { + if (android_image_separate(hdr, NULL, (void *)comp_addr, hdr)) + return -1; + } else { + if (android_image_separate_v3(hdr, NULL, (void *)comp_addr, hdr)) + return -1; + } *load_addr = comp_addr; android_image_set_decomp((void *)comp_addr, comp); @@ -631,54 +746,45 @@ long android_image_load(struct blk_desc *dev_desc, unsigned long load_address, unsigned long max_size) { struct andr_img_hdr *hdr; - u32 blksz = dev_desc->blksz; - u32 pszcnt, hdrcnt, kercnt; int comp, ret; + int blk_off; if (max_size < part_info->blksz) return -1; - /* - * read Android image header and leave enough space for page_size align - * and kernel image header(1 block maybe enough). - * - * ANDROID_ROCKCHIP_LEGACY_PAGE_SIZE is defined by rockchip legacy - * mkboot tool(SDK version < 8.1) and larger than Google defined. - * - * To compatible this, we malloc enough buffer but only read android - * header and kernel image(1 block) from storage(ignore page size). - */ - kercnt = 1; - hdrcnt = DIV_ROUND_UP(sizeof(*hdr), blksz); - pszcnt = DIV_ROUND_UP(ANDROID_ROCKCHIP_LEGACY_PAGE_SIZE, blksz); - - hdr = memalign(ARCH_DMA_MINALIGN, (hdrcnt + pszcnt + kercnt) * blksz); + hdr = populate_andr_img_hdr(dev_desc, (disk_partition_t *)part_info); if (!hdr) { - printf("No memory\n"); + printf("No valid android hdr\n"); return -1; } - if (blk_dread(dev_desc, part_info->start, hdrcnt, hdr) != hdrcnt) { - printf("Failed to read image header\n"); - goto fail; - } - - if (android_image_check_header(hdr) != 0) { - printf("** Invalid Android Image header **\n"); - goto fail; - } - /* - * Update and skip pszcnt(hdr is included) according to hdr->page_size, - * reading kernel image for compress validation. + * create the layout: + * + * |<- page_size ->|1-blk | + * |-----|---------|------|-----| + * | hdr | ... | kernel | + * |-----|----- ---|------------| + * + * Alloc page_size and 1 more blk for reading kernel image to + * get it's compression type, then fill the android hdr what + * we have populated before. + * + * Why? see: android_image_get_kernel_addr(). */ - pszcnt = DIV_ROUND_UP(hdr->page_size, blksz); - if (blk_dread(dev_desc, part_info->start + pszcnt, kercnt, - (void *)((ulong)hdr + hdr->page_size)) != kercnt) { - printf("Failed to read kernel header\n"); - goto fail; + blk_off = BLK_CNT(hdr->page_size, dev_desc->blksz); + hdr = (struct andr_img_hdr *) + realloc(hdr, (blk_off + 1) * dev_desc->blksz); + if (!hdr) + return -1; + + if (blk_dread(dev_desc, part_info->start + blk_off, 1, + (char *)hdr + hdr->page_size) != 1) { + free(hdr); + return -1; } + /* Make kernel start address at load_address */ load_address -= hdr->page_size; /* Let's load kernel now ! */ @@ -700,6 +806,260 @@ fail: return -1; } +static struct andr_img_hdr * +extract_boot_image_v012_header(struct blk_desc *dev_desc, + const disk_partition_t *boot_img) +{ + struct andr_img_hdr *hdr; + long blk_cnt, blks_read; + + blk_cnt = BLK_CNT(sizeof(struct andr_img_hdr), dev_desc->blksz); + hdr = (struct andr_img_hdr *)malloc(blk_cnt * dev_desc->blksz); + + if (!blk_cnt || !hdr) + return NULL; + + blks_read = blk_dread(dev_desc, boot_img->start, blk_cnt, hdr); + if (blks_read != blk_cnt) { + debug("boot img header blk cnt is %ld and blks read is %ld\n", + blk_cnt, blks_read); + return NULL; + } + + if (android_image_check_header((void *)hdr)) { + printf("boot header magic is invalid.\n"); + return NULL; + } + + if (hdr->page_size < sizeof(*hdr)) { + printf("android hdr is over size\n"); + return NULL; + } + + return hdr; +} + +static struct boot_img_hdr_v3 * +extract_boot_image_v3_header(struct blk_desc *dev_desc, + const disk_partition_t *boot_img) +{ + struct boot_img_hdr_v3 *boot_hdr; + long blk_cnt, blks_read; + + blk_cnt = BLK_CNT(sizeof(struct boot_img_hdr_v3), dev_desc->blksz); + boot_hdr = (struct boot_img_hdr_v3 *)malloc(blk_cnt * dev_desc->blksz); + + if (!blk_cnt || !boot_hdr) + return NULL; + + blks_read = blk_dread(dev_desc, boot_img->start, blk_cnt, boot_hdr); + if (blks_read != blk_cnt) { + debug("boot img header blk cnt is %ld and blks read is %ld\n", + blk_cnt, blks_read); + return NULL; + } + + if (android_image_check_header((void *)boot_hdr)) { + printf("boot header magic is invalid.\n"); + return NULL; + } + + if (boot_hdr->header_version != 3) { + printf("boot header is not v3.\n"); + return NULL; + } + + return boot_hdr; +} + +static struct vendor_boot_img_hdr_v3 * +extract_vendor_boot_image_v3_header(struct blk_desc *dev_desc, + const disk_partition_t *part_vendor_boot) +{ + struct vendor_boot_img_hdr_v3 *vboot_hdr; + long blk_cnt, blks_read; + + blk_cnt = BLK_CNT(sizeof(struct vendor_boot_img_hdr_v3), + part_vendor_boot->blksz); + vboot_hdr = (struct vendor_boot_img_hdr_v3 *) + malloc(blk_cnt * part_vendor_boot->blksz); + + if (!blk_cnt || !vboot_hdr) + return NULL; + + blks_read = blk_dread(dev_desc, part_vendor_boot->start, + blk_cnt, vboot_hdr); + if (blks_read != blk_cnt) { + debug("vboot img header blk cnt is %ld and blks read is %ld\n", + blk_cnt, blks_read); + return NULL; + } + + if (strncmp(VENDOR_BOOT_MAGIC, (void *)vboot_hdr->magic, + VENDOR_BOOT_MAGIC_SIZE)) { + printf("vendor boot header is invalid.\n"); + return NULL; + } + + if (vboot_hdr->header_version != 3) { + printf("vendor boot header is not v3.\n"); + return NULL; + } + + return vboot_hdr; +} + +static int populate_boot_info(const struct boot_img_hdr_v3 *boot_hdr, + const struct vendor_boot_img_hdr_v3 *vendor_hdr, + struct andr_img_hdr *hdr) +{ + memset(hdr->magic, 0, ANDR_BOOT_MAGIC_SIZE); + memcpy(hdr->magic, boot_hdr->magic, ANDR_BOOT_MAGIC_SIZE); + + hdr->kernel_size = boot_hdr->kernel_size; + /* don't use vendor_hdr->kernel_addr, we prefer "hdr + hdr->page_size" */ + hdr->kernel_addr = ANDROID_IMAGE_DEFAULT_KERNEL_ADDR; + /* generic ramdisk: immediately following the vendor ramdisk */ + hdr->ramdisk_size = boot_hdr->ramdisk_size + + vendor_hdr->vendor_ramdisk_size; + /* actually, useless */ + hdr->ramdisk_addr = vendor_hdr->ramdisk_addr + + vendor_hdr->vendor_ramdisk_size; + /* removed in v3 */ + hdr->second_size = 0; + hdr->second_addr = 0; + + hdr->tags_addr = vendor_hdr->tags_addr; + + /* fixed in v3 */ + hdr->page_size = 4096; + hdr->header_version = boot_hdr->header_version; + hdr->os_version = boot_hdr->os_version; + + memset(hdr->name, 0, ANDR_BOOT_NAME_SIZE); + strncpy(hdr->name, (const char *)vendor_hdr->name, ANDR_BOOT_NAME_SIZE); + + /* removed in v3 */ + memset(hdr->cmdline, 0, ANDR_BOOT_ARGS_SIZE); + memset(hdr->id, 0, 32); + memset(hdr->extra_cmdline, 0, ANDR_BOOT_EXTRA_ARGS_SIZE); + hdr->recovery_dtbo_size = 0; + hdr->recovery_dtbo_offset = 0; + + hdr->header_size = boot_hdr->header_size; + hdr->dtb_size = vendor_hdr->dtb_size; + hdr->dtb_addr = vendor_hdr->dtb_addr; + + /* boot_img_hdr_v3 fields */ + hdr->vendor_ramdisk_size = vendor_hdr->vendor_ramdisk_size; + hdr->vendor_page_size = vendor_hdr->page_size; + hdr->vendor_header_version = vendor_hdr->header_version; + hdr->vendor_header_size = vendor_hdr->header_size; + + hdr->total_cmdline = calloc(1, TOTAL_BOOT_ARGS_SIZE); + if (!hdr->total_cmdline) + return -ENOMEM; + strncpy(hdr->total_cmdline, (const char *)boot_hdr->cmdline, + sizeof(boot_hdr->cmdline)); + strncat(hdr->total_cmdline, " ", 1); + strncat(hdr->total_cmdline, (const char *)vendor_hdr->cmdline, + sizeof(vendor_hdr->cmdline)); + + if (hdr->page_size < sizeof(*hdr)) { + printf("android hdr is over size\n"); + return -EINVAL; + } + + return 0; +} + +/* + * The possible cases of boot.img + recovery.img: + * + * [N]: 0, 1, 2 + * [M]: 0, 1, 2, 3 + * + * |--------------------|---------------------| + * | boot.img | recovery.img | + * |--------------------|---------------------| + * | boot_img_hdr_v[N] | boot_img_hdr_v[N] | <= if A/B is not required + * |--------------------|---------------------| + * | boot_img_hdr_v3 | boot_img_hdr_v2 | <= if A/B is not required + * |------------------------------------------| + * | boot_img_hdr_v[M], no recovery.img | <= if A/B is required + * |------------------------------------------| + */ +struct andr_img_hdr *populate_andr_img_hdr(struct blk_desc *dev_desc, + disk_partition_t *part_boot) +{ + disk_partition_t part_vendor_boot; + struct vendor_boot_img_hdr_v3 *vboot_hdr; + struct boot_img_hdr_v3 *boot_hdr; + struct andr_img_hdr *andr_hdr; + int header_version; + + if (!dev_desc || !part_boot) + return NULL; + + andr_hdr = (struct andr_img_hdr *)malloc(1 * dev_desc->blksz); + if (!andr_hdr) + return NULL; + + if (blk_dread(dev_desc, part_boot->start, 1, andr_hdr) != 1) { + free(andr_hdr); + return NULL; + } + + if (android_image_check_header(andr_hdr)) { + free(andr_hdr); + return NULL; + } + + header_version = andr_hdr->header_version; + free(andr_hdr); + + if (header_version < 3) { + return extract_boot_image_v012_header(dev_desc, part_boot); + } else { + if (part_get_info_by_name(dev_desc, + ANDROID_PARTITION_VENDOR_BOOT, + &part_vendor_boot) < 0) { + printf("No vendor boot partition\n"); + return NULL; + } + boot_hdr = extract_boot_image_v3_header(dev_desc, part_boot); + vboot_hdr = extract_vendor_boot_image_v3_header(dev_desc, + &part_vendor_boot); + if (!boot_hdr || !vboot_hdr) + goto image_load_exit; + + andr_hdr = (struct andr_img_hdr *) + malloc(sizeof(struct andr_img_hdr)); + if (!andr_hdr) { + printf("No memory for andr hdr\n"); + goto image_load_exit; + } + + if (populate_boot_info(boot_hdr, vboot_hdr, andr_hdr)) { + printf("populate boot info failed\n"); + goto image_load_exit; + } + + free(boot_hdr); + free(vboot_hdr); + + return andr_hdr; + +image_load_exit: + free(boot_hdr); + free(vboot_hdr); + + return NULL; + } + + return NULL; +} + #if !defined(CONFIG_SPL_BUILD) /** * android_print_contents - prints out the contents of the Android format image @@ -723,7 +1083,7 @@ void android_print_contents(const struct andr_img_hdr *hdr) printf("%skernel size: %x\n", p, hdr->kernel_size); printf("%skernel address: %x\n", p, hdr->kernel_addr); printf("%sramdisk size: %x\n", p, hdr->ramdisk_size); - printf("%sramdisk addrress: %x\n", p, hdr->ramdisk_addr); + printf("%sramdisk address: %x\n", p, hdr->ramdisk_addr); printf("%ssecond size: %x\n", p, hdr->second_size); printf("%ssecond address: %x\n", p, hdr->second_addr); printf("%stags address: %x\n", p, hdr->tags_addr); @@ -738,15 +1098,23 @@ void android_print_contents(const struct andr_img_hdr *hdr) printf("%sname: %s\n", p, hdr->name); printf("%scmdline: %s\n", p, hdr->cmdline); - if (header_version >= 1) { + if (header_version == 1 || header_version == 2) { printf("%srecovery dtbo size: %x\n", p, hdr->recovery_dtbo_size); printf("%srecovery dtbo offset: %llx\n", p, hdr->recovery_dtbo_offset); printf("%sheader size: %x\n", p, hdr->header_size); } - if (header_version >= 2) { + if (header_version == 2 || header_version == 3) { printf("%sdtb size: %x\n", p, hdr->dtb_size); printf("%sdtb addr: %llx\n", p, hdr->dtb_addr); } + + if (header_version == 3) { + printf("%scmdline: %s\n", p, hdr->total_cmdline); + printf("%svendor ramdisk size: %x\n", p, hdr->vendor_ramdisk_size); + printf("%svendor page size: %x\n", p, hdr->vendor_page_size); + printf("%svendor header version: %d\n", p, hdr->vendor_header_version); + printf("%svendor header size: %x\n", p, hdr->vendor_header_size); + } } #endif diff --git a/include/android_image.h b/include/android_image.h index 0519ece368..a738089631 100644 --- a/include/android_image.h +++ b/include/android_image.h @@ -12,10 +12,19 @@ #define _ANDROID_IMAGE_H_ #define ANDR_BOOT_MAGIC "ANDROID!" +#define VENDOR_BOOT_MAGIC "VNDRBOOT" #define ANDR_BOOT_MAGIC_SIZE 8 +#define VENDOR_BOOT_MAGIC_SIZE 8 #define ANDR_BOOT_NAME_SIZE 16 +#define VENDOR_BOOT_NAME_SIZE 16 #define ANDR_BOOT_ARGS_SIZE 512 #define ANDR_BOOT_EXTRA_ARGS_SIZE 1024 +#define VENDOR_BOOT_ARGS_SIZE 2048 +#define ANDR_BOOT_IMG_PAGE_SIZE 4096 +#define ANDR_BOOT_IMG_HDR_SIZE (ANDR_BOOT_IMG_PAGE_SIZE) +#define TOTAL_BOOT_ARGS_SIZE (ANDR_BOOT_ARGS_SIZE + ANDR_BOOT_EXTRA_ARGS_SIZE + \ + VENDOR_BOOT_ARGS_SIZE + 1) +#define VENDOR_BOOT_HDR_SIZE 2112 /* * It is expected that callers would explicitly specify which version of the @@ -60,14 +69,78 @@ struct andr_img_hdr { * binary compatibility with older versions of mkbootimg. */ char extra_cmdline[ANDR_BOOT_EXTRA_ARGS_SIZE]; - /* Fields in boot_img_hdr_v1 and newer. */ + /* Fields in boot_img_hdr_v1(Android-9) and newer. */ u32 recovery_dtbo_size; /* size in bytes for recovery DTBO/ACPIO image */ u64 recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */ u32 header_size; - /* Fields in boot_img_hdr_v2 and newer. */ + /* Fields in boot_img_hdr_v2(Android-10) and newer. */ u32 dtb_size; /* size in bytes for DTB image */ u64 dtb_addr; /* physical load address for DTB image */ + + /* + * [Rockchip compatibility] + * + * boot_img_hdr_v3(Android-11) is not compatible with boot_img_hdr_v012, + * we have to partly merge fields from boot_img_hdr_v3 and vendor_boot_img_hdr_v3 + * into this structure to compatible with boot_img_hdr_v012. + */ + u32 vendor_ramdisk_size; /* size in bytes */ + u32 vendor_page_size; + u32 vendor_header_version; + u32 vendor_header_size; + /* + * Don't define 'char total_cmdline[TOTAL_BOOT_ARGS_SIZE]' to avoid + * this structrue is over size than page_size. + */ + char *total_cmdline; +} __attribute__((packed)); + +struct boot_img_hdr_v3 { + /* Must be ANDR_BOOT_MAGIC. */ + uint8_t magic[ANDR_BOOT_MAGIC_SIZE]; + + uint32_t kernel_size; /* size in bytes */ + uint32_t ramdisk_size; /* size in bytes */ + + /* Operating system version and security patch level. + * For version "A.B.C" and patch level "Y-M-D": + * (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M) + * os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0] */ + uint32_t os_version; + + uint32_t header_size; + + uint32_t reserved[4]; + + uint32_t header_version; + + uint8_t cmdline[ANDR_BOOT_ARGS_SIZE + ANDR_BOOT_EXTRA_ARGS_SIZE]; +} __attribute__((packed)); + +struct vendor_boot_img_hdr_v3 { + /* Must be VENDOR_BOOT_MAGIC. */ + uint8_t magic[VENDOR_BOOT_MAGIC_SIZE]; + + /* Version of the vendor boot image header. */ + uint32_t header_version; + + uint32_t page_size; /* flash page size we assume */ + + uint32_t kernel_addr; /* physical load addr */ + uint32_t ramdisk_addr; /* physical load addr */ + + uint32_t vendor_ramdisk_size; /* size in bytes */ + + uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE]; + + uint32_t tags_addr; /* physical addr for kernel tags (if required) */ + uint8_t name[VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */ + + uint32_t header_size; + + uint32_t dtb_size; /* size in bytes for DTB image */ + uint64_t dtb_addr; /* physical load address for DTB image */ } __attribute__((packed)); /* When a boot header is of version 0, the structure of boot image is as @@ -139,4 +212,50 @@ struct andr_img_hdr { * else: jump to kernel_addr */ +/* When the boot image header has a version of 3, the structure of the boot + * image is as follows: + * + * +---------------------+ + * | boot header | 4096 bytes + * +---------------------+ + * | kernel | m pages + * +---------------------+ + * | ramdisk | n pages + * +---------------------+ + * + * m = (kernel_size + 4096 - 1) / 4096 + * n = (ramdisk_size + 4096 - 1) / 4096 + * + * Note that in version 3 of the boot image header, page size is fixed at 4096 bytes. + * + * The structure of the vendor boot image (introduced with version 3 and + * required to be present when a v3 boot image is used) is as follows: + * + * +---------------------+ + * | vendor boot header | o pages + * +---------------------+ + * | vendor ramdisk | p pages + * +---------------------+ + * | dtb | q pages + * +---------------------+ + * + * o = (2112 + page_size - 1) / page_size + * p = (vendor_ramdisk_size + page_size - 1) / page_size + * q = (dtb_size + page_size - 1) / page_size + * + * 0. all entities in the boot image are 4096-byte aligned in flash, all + * entities in the vendor boot image are page_size (determined by the vendor + * and specified in the vendor boot image header) aligned in flash + * 1. kernel, ramdisk, vendor ramdisk, and DTB are required (size != 0) + * 2. load the kernel and DTB at the specified physical address (kernel_addr, + * dtb_addr) + * 3. load the vendor ramdisk at ramdisk_addr + * 4. load the generic ramdisk immediately following the vendor ramdisk in + * memory + * 5. set up registers for kernel entry as required by your architecture + * 6. if the platform has a second stage bootloader jump to it (must be + * contained outside boot and vendor boot partitions), otherwise + * jump to kernel_addr + */ + #endif diff --git a/include/boot_rkimg.h b/include/boot_rkimg.h index 0ad15f4706..8807aede9a 100644 --- a/include/boot_rkimg.h +++ b/include/boot_rkimg.h @@ -54,6 +54,7 @@ struct rockchip_image { #define PART_RESOURCE "resource" #define PART_KERNEL "kernel" #define PART_BOOT "boot" +#define PART_VENDOR_BOOT "vendor_boot" #define PART_RECOVERY "recovery" #define PART_DTBO "dtbo" #define PART_LOGO "logo" diff --git a/include/image.h b/include/image.h index b38efe46d8..95256925b5 100644 --- a/include/image.h +++ b/include/image.h @@ -1365,6 +1365,9 @@ void android_image_set_decomp(struct andr_img_hdr *hdr, int comp); int android_image_parse_comp(struct andr_img_hdr *hdr, ulong *load_addr); int android_image_memcpy_separate(struct andr_img_hdr *hdr, ulong *load_address); +struct andr_img_hdr *populate_andr_img_hdr(struct blk_desc *dev_desc, + disk_partition_t *part_boot); + /** android_image_load - Load an Android Image from storage. * * Load an Android Image based on the header size in the storage.