diff --git a/boot/bootm.c b/boot/bootm.c index 00c00aef84aed3398e4b9fe450b9128422534815..6dc39146b60cf2551e9d0af252ae72261c8bf89a 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -159,14 +159,24 @@ static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc, #endif #ifdef CONFIG_ANDROID_BOOT_IMAGE case IMAGE_FORMAT_ANDROID: + { + void *boot_img = (void *)os_hdr; + void *vendor_boot_img = 0; +#ifdef CONFIG_CMD_ABOOTIMG + if (_abootimg_addr != -1) { + boot_img = (void *)_abootimg_addr; + vendor_boot_img = (void *)_avendor_bootimg_addr; + } +#endif images.os.type = IH_TYPE_KERNEL; - images.os.comp = android_image_get_kcomp(os_hdr); + images.os.comp = android_image_get_kcomp(boot_img, vendor_boot_img); images.os.os = IH_OS_LINUX; - images.os.end = android_image_get_end(os_hdr); - images.os.load = android_image_get_kload(os_hdr); + images.os.end = 0; + images.os.load = android_image_get_kload(boot_img, vendor_boot_img); images.ep = images.os.load; ep_found = true; + } break; #endif default: @@ -934,10 +944,20 @@ static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc, #endif #ifdef CONFIG_ANDROID_BOOT_IMAGE case IMAGE_FORMAT_ANDROID: + { + void *boot_img = (void *)buf; + void *vendor_boot_img = 0; +#ifdef CONFIG_CMD_ABOOTIMG + if (_abootimg_addr != -1) { + boot_img = (void *)_abootimg_addr; + vendor_boot_img = (void *)_avendor_bootimg_addr; + } +#endif printf("## Booting Android Image at 0x%08lx ...\n", img_addr); - if (android_image_get_kernel(buf, images->verify, + if (android_image_get_kernel(boot_img, vendor_boot_img, images->verify, os_data, os_len)) return NULL; + } break; #endif default: diff --git a/boot/image-android.c b/boot/image-android.c index 1fbbbba1eb0e0707de9f4892b06fa4147913d40c..39cdce11abec86ef5f4dc320ce078728b47738cd 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -18,7 +18,152 @@ static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1]; -static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr) +bool is_android_boot_image_header(const void *boot_img) +{ + return memcmp(ANDR_BOOT_MAGIC, boot_img, ANDR_BOOT_MAGIC_SIZE) == 0; +} + +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) == 0; +} + +void android_boot_image_v3_v4_get_data(const struct andr_boot_img_hdr_v3_v4 *hdr, + struct andr_image_data *data) +{ + ulong end; + + data->kcmdline = hdr->cmdline; + data->header_version = hdr->header_version; + data->ramdisk_ptr = env_get_ulong("ramdisk_addr_r", 16, 0); + + /* + * The header takes a full page, the remaining components are aligned + * on page boundary. + */ + end = (ulong)hdr; + end += ANDR_GKI_PAGE_SIZE; + data->kernel_ptr = end; + data->kernel_size = hdr->kernel_size; + end += ALIGN(hdr->kernel_size, ANDR_GKI_PAGE_SIZE); + data->ramdisk_size = hdr->ramdisk_size; + data->boot_ramdisk_size = hdr->ramdisk_size; + end += ALIGN(hdr->ramdisk_size, ANDR_GKI_PAGE_SIZE); + + if (hdr->header_version > 3) { + end += ALIGN(hdr->signature_size, ANDR_GKI_PAGE_SIZE); + } + + data->boot_img_total_size = end - (ulong)hdr; +} + +void android_boot_image_v0_v1_v2_get_data(const struct andr_boot_img_hdr_v0_v1_v2 *hdr, + struct andr_image_data *data) +{ + ulong end; + + data->image_name = hdr->name; + data->kcmdline = hdr->cmdline; + data->kcmdline_extra = hdr->extra_cmdline; + data->kernel_load_addr = hdr->kernel_addr; + data->ramdisk_load_addr = hdr->ramdisk_addr; + data->header_version = hdr->header_version; + + /* + * The header takes a full page, the remaining components are aligned + * on page boundary + */ + + end = (ulong)hdr; + end += hdr->page_size; + data->kernel_ptr = end; + data->kernel_size = hdr->kernel_size; + end += ALIGN(hdr->kernel_size, hdr->page_size); + data->ramdisk_ptr = end; + data->ramdisk_size = hdr->ramdisk_size; + end += ALIGN(hdr->ramdisk_size, hdr->page_size); + data->second_ptr = end; + data->second_size = hdr->second_size; + end += ALIGN(hdr->second_size, hdr->page_size); + + if (hdr->header_version >= 1) { + data->recovery_dtbo_ptr = end; + data->recovery_dtbo_size = hdr->recovery_dtbo_size; + end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size); + } + + if (hdr->header_version >= 2) { + data->dtb_ptr = end; + data->dtb_size = hdr->dtb_size; + end += ALIGN(hdr->dtb_size, hdr->page_size); + } + + data->boot_img_total_size = end - (ulong)hdr; +} + +void android_vendor_boot_image_v3_v4_get_end(const struct andr_vendor_boot_img_hdr_v3_v4 *hdr, + struct andr_image_data *data) +{ + ulong end; + + /* + * The header takes a full page, the remaining components are aligned + * on page boundary. + */ + data->kcmdline_extra = hdr->cmdline; + data->tags_addr = hdr->tags_addr; + data->image_name = hdr->name; + data->kernel_load_addr = hdr->kernel_addr; + data->ramdisk_load_addr = hdr->ramdisk_addr; + end = (ulong)hdr; + end += hdr->page_size; + if (hdr->vendor_ramdisk_size) { + data->vendor_ramdisk_ptr = end; + data->vendor_ramdisk_size = hdr->vendor_ramdisk_size; + data->ramdisk_size += hdr->vendor_ramdisk_size; + end += ALIGN(hdr->vendor_ramdisk_size, hdr->page_size); + } + + data->dtb_ptr = end; + data->dtb_size = hdr->dtb_size; + + end += ALIGN(hdr->dtb_size, hdr->page_size); + end += ALIGN(hdr->vendor_ramdisk_table_size, hdr->page_size); + end += ALIGN(hdr->bootconfig_size, hdr->page_size); + data->boot_img_total_size = end - (ulong)hdr; +} + +bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr, + struct andr_image_data *data) { + if (!boot_hdr || !data) { + printf("boot_hdr or data params can't be NULL\n"); + return false; + } + + if (!is_android_boot_image_header(boot_hdr)) { + printf("Incorrect boot image header\n"); + return false; + } + + if (((struct andr_boot_img_hdr_v0_v1_v2 *)boot_hdr)->header_version > 2) { + if (!vendor_boot_hdr) { + printf("For boot header v3+ vendor_boot image has to be provided\n"); + return false; + } + if (!is_android_vendor_boot_image_header(vendor_boot_hdr)) { + printf("Incorrect vendor boot image header\n"); + return false; + } + android_boot_image_v3_v4_get_data(boot_hdr, data); + android_vendor_boot_image_v3_v4_get_end(vendor_boot_hdr, data); + } else { + android_boot_image_v0_v1_v2_get_data(boot_hdr, data); + } + + return true; +} + +static ulong android_get_fixed_kernel_load_addr(struct andr_image_data *img_data) { /* * All the Android tools that generate a boot.img use this @@ -31,17 +176,17 @@ static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr) * * Otherwise, we will return the actual value set by the user. */ - if (hdr->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR) - return (ulong)hdr + hdr->page_size; + if (img_data->kernel_load_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR) + return img_data->kernel_ptr; /* * abootimg creates images where all load addresses are 0 * and we need to fix them. */ - if (hdr->kernel_addr == 0 && hdr->ramdisk_addr == 0) + if (img_data->kernel_load_addr == 0 && img_data->ramdisk_load_addr == 0) return env_get_ulong("kernel_addr_r", 16, 0); - return hdr->kernel_addr; + return img_data->kernel_load_addr; } /** @@ -59,30 +204,34 @@ static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr) * Return: Zero, os start address and length on success, * otherwise on failure. */ -int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, +int android_image_get_kernel(const void *boot_img, const void *vendor_boot_img, int verify, ulong *os_data, ulong *os_len) { - u32 kernel_addr = android_image_get_kernel_addr(hdr); - const struct image_header *ihdr = (const struct image_header *) - ((uintptr_t)hdr + hdr->page_size); - + struct andr_image_data img_data = {0}; + if (!android_image_get_data(boot_img, vendor_boot_img, &img_data)) + return -1; /* * 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 * string is null terminated so we take care of this. */ - strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE); + strncpy(andr_tmp_str, img_data.image_name, ANDR_BOOT_NAME_SIZE); andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0'; if (strlen(andr_tmp_str)) printf("Android's image name: %s\n", andr_tmp_str); + u32 kernel_load_addr = android_get_fixed_kernel_load_addr(&img_data); printf("Kernel load addr 0x%08x size %u KiB\n", - kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024)); - + kernel_load_addr, DIV_ROUND_UP(img_data.kernel_size, 1024)); int len = 0; - if (*hdr->cmdline) { - printf("Kernel command line: %s\n", hdr->cmdline); - len += strlen(hdr->cmdline); + if (*img_data.kcmdline) { + printf("Kernel command line: %s\n", img_data.kcmdline); + len += strlen(img_data.kcmdline); + } + + if (*img_data.kcmdline_extra) { + printf("Kernel extra command line: %s\n", img_data.kcmdline_extra); + len += strlen(img_data.kcmdline_extra); } char *bootargs = env_get("bootargs"); @@ -100,65 +249,52 @@ 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 (*img_data.kcmdline) + strcat(newbootargs, img_data.kcmdline); + + if (*img_data.kcmdline_extra) { + strcat(newbootargs, " "); + strcat(newbootargs, img_data.kcmdline_extra); + } env_set("bootargs", newbootargs); + const struct image_header *ihdr = (const struct image_header *)img_data.kernel_ptr; + if (os_data) { if (image_get_magic(ihdr) == IH_MAGIC) { *os_data = image_get_data(ihdr); } else { - *os_data = (ulong)hdr; - *os_data += hdr->page_size; + *os_data = img_data.kernel_ptr; } } if (os_len) { if (image_get_magic(ihdr) == IH_MAGIC) *os_len = image_get_data_size(ihdr); else - *os_len = hdr->kernel_size; + *os_len = img_data.kernel_size; } return 0; } -int android_image_check_header(const struct andr_img_hdr *hdr) -{ - return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE); -} - -ulong android_image_get_end(const struct andr_img_hdr *hdr) +ulong android_image_get_kload(const void *boot_img, const void *vendor_boot_img) { - ulong end; - - /* - * The header takes a full page, the remaining components are aligned - * 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 >= 1) - end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size); - - if (hdr->header_version >= 2) - end += ALIGN(hdr->dtb_size, hdr->page_size); - - return end; -} - -ulong android_image_get_kload(const struct andr_img_hdr *hdr) -{ - return android_image_get_kernel_addr(hdr); + struct andr_image_data img_data = {0}; + if (!android_image_get_data(boot_img, vendor_boot_img, &img_data)) { + return 0; + } + return android_get_fixed_kernel_load_addr(&img_data); } -ulong android_image_get_kcomp(const struct andr_img_hdr *hdr) +ulong android_image_get_kcomp(const void *boot_img, const void *vendor_boot_img) { - const void *p = (void *)((uintptr_t)hdr + hdr->page_size); + struct andr_image_data img_data = {0}; + if (!android_image_get_data(boot_img, vendor_boot_img, &img_data)) { + return -EINVAL; + } + const void *p = (const void *)img_data.kernel_ptr; if (image_get_magic((image_header_t *)p) == IH_MAGIC) return image_get_comp((image_header_t *)p); else if (get_unaligned_le32(p) == LZ4F_MAGIC) @@ -167,28 +303,46 @@ ulong android_image_get_kcomp(const struct andr_img_hdr *hdr) return image_decomp_type(p, sizeof(u32)); } -int android_image_get_ramdisk(const struct andr_img_hdr *hdr, +int android_image_get_ramdisk(const void *boot_img, const void *vendor_boot_img, ulong *rd_data, ulong *rd_len) { - if (!hdr->ramdisk_size) { + struct andr_image_data img_data = {0}; + if (!android_image_get_data(boot_img, vendor_boot_img, &img_data)) { + return -EINVAL; + } + + if (!img_data.ramdisk_size) { *rd_data = *rd_len = 0; return -1; } - printf("RAM disk load addr 0x%08x size %u KiB\n", - hdr->ramdisk_addr, DIV_ROUND_UP(hdr->ramdisk_size, 1024)); + if (img_data.header_version > 2) { + ulong ramdisk_ptr = img_data.ramdisk_ptr; + memcpy((void *)(ramdisk_ptr), (void *)img_data.vendor_ramdisk_ptr, img_data.vendor_ramdisk_size); + memcpy((void *)(ramdisk_ptr + img_data.vendor_ramdisk_size), (void*)img_data.ramdisk_ptr, img_data.boot_ramdisk_size); + } - *rd_data = (unsigned long)hdr; - *rd_data += hdr->page_size; - *rd_data += ALIGN(hdr->kernel_size, hdr->page_size); + printf("RAM disk load addr 0x%08lx size %u KiB\n", + img_data.ramdisk_ptr, DIV_ROUND_UP(img_data.ramdisk_size, 1024)); - *rd_len = hdr->ramdisk_size; + *rd_data = img_data.ramdisk_ptr; + *rd_len = img_data.ramdisk_size; return 0; } -int android_image_get_second(const struct andr_img_hdr *hdr, - ulong *second_data, ulong *second_len) +int android_image_get_second(void *boot_img, ulong *second_data, ulong *second_len) { + if (!is_android_boot_image_header(boot_img)) { + printf("Invalid boot image"); + return -1; + } + + struct andr_boot_img_hdr_v0_v1_v2 *hdr = boot_img; + if (hdr->header_version > 2) { + printf("Only supported for boot image version 2 and below"); + return -1; + } + if (!hdr->second_size) { *second_data = *second_len = 0; return -1; @@ -224,33 +378,26 @@ int android_image_get_second(const struct andr_img_hdr *hdr, * * Return: true on success or false on error. */ -bool android_image_get_dtbo(ulong hdr_addr, ulong *addr, u32 *size) +bool android_image_get_dtbo(const void *boot_img, ulong *addr, u32 *size) { - const struct andr_img_hdr *hdr; - ulong dtbo_img_addr; - bool ret = true; - - hdr = map_sysmem(hdr_addr, sizeof(*hdr)); - if (android_image_check_header(hdr)) { - printf("Error: Boot Image header is incorrect\n"); - ret = false; - goto exit; + if (!is_android_boot_image_header(boot_img)) { + printf("Invalid boot image"); + return false; } - if (hdr->header_version < 1) { - printf("Error: header_version must be >= 1 to get dtbo\n"); - ret = false; - goto exit; + const struct andr_boot_img_hdr_v0_v1_v2 *hdr = boot_img; + if (hdr->header_version < 1 || hdr->header_version > 2) { + printf("Error: header_version must >= 1 and <=2 to get dtbo\n"); + return false; } if (hdr->recovery_dtbo_size == 0) { printf("Error: recovery_dtbo_size is 0\n"); - ret = false; - goto exit; + return false; } /* Calculate the address of DTB area in boot image */ - dtbo_img_addr = hdr_addr; + ulong dtbo_img_addr = (ulong)boot_img; dtbo_img_addr += hdr->page_size; dtbo_img_addr += ALIGN(hdr->kernel_size, hdr->page_size); dtbo_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size); @@ -261,56 +408,7 @@ bool android_image_get_dtbo(ulong hdr_addr, ulong *addr, u32 *size) if (size) *size = hdr->recovery_dtbo_size; -exit: - unmap_sysmem(hdr); - return ret; -} - -/** - * android_image_get_dtb_img_addr() - Get the address of DTB area in boot image. - * @hdr_addr: Boot image header address - * @addr: Will contain the address of DTB area in boot image - * - * Return: true on success or false on fail. - */ -static bool android_image_get_dtb_img_addr(ulong hdr_addr, ulong *addr) -{ - const struct andr_img_hdr *hdr; - ulong dtb_img_addr; - bool ret = true; - - hdr = map_sysmem(hdr_addr, sizeof(*hdr)); - if (android_image_check_header(hdr)) { - printf("Error: Boot Image header is incorrect\n"); - ret = false; - goto exit; - } - - if (hdr->header_version < 2) { - printf("Error: header_version must be >= 2 to get dtb\n"); - ret = false; - goto exit; - } - - if (hdr->dtb_size == 0) { - printf("Error: dtb_size is 0\n"); - ret = false; - goto exit; - } - - /* Calculate the address of DTB area in boot image */ - dtb_img_addr = hdr_addr; - dtb_img_addr += hdr->page_size; - dtb_img_addr += ALIGN(hdr->kernel_size, hdr->page_size); - dtb_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size); - dtb_img_addr += ALIGN(hdr->second_size, hdr->page_size); - dtb_img_addr += ALIGN(hdr->recovery_dtbo_size, hdr->page_size); - - *addr = dtb_img_addr; - -exit: - unmap_sysmem(hdr); - return ret; + return true; } /** @@ -325,20 +423,18 @@ exit: * * Return: true on success or false on error. */ -bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr, +bool android_image_get_dtb_by_index(const void *boot_img, const void *vendor_boot_img, u32 index, ulong *addr, u32 *size) { - const struct andr_img_hdr *hdr; - bool res; + struct andr_image_data img_data = {0}; + if (!android_image_get_data(boot_img, vendor_boot_img, &img_data)) + return false; ulong dtb_img_addr; /* address of DTB part in boot image */ u32 dtb_img_size; /* size of DTB payload in boot image */ ulong dtb_addr; /* address of DTB blob with specified index */ u32 i; /* index iterator */ - res = android_image_get_dtb_img_addr(hdr_addr, &dtb_img_addr); - if (!res) - return false; - + dtb_img_addr = img_data.dtb_ptr; /* Check if DTB area of boot image is in DTBO format */ if (android_dt_check_header(dtb_img_addr)) { return android_dt_get_fdt_by_index(dtb_img_addr, index, addr, @@ -346,9 +442,7 @@ bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr, } /* Find out the address of DTB with specified index in concat blobs */ - hdr = map_sysmem(hdr_addr, sizeof(*hdr)); - dtb_img_size = hdr->dtb_size; - unmap_sysmem(hdr); + dtb_img_size = img_data.dtb_size; i = 0; dtb_addr = dtb_img_addr; while (dtb_addr < dtb_img_addr + dtb_img_size) { @@ -382,6 +476,42 @@ bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr, } #if !defined(CONFIG_SPL_BUILD) + +/** + * android_print_contents - prints out the contents of the Android boot image v3 or v4 + * @hdr: pointer to the Android boot image header v3 or v4 + * + * android_print_contents() formats a multi line Android image contents + * description. + * The routine prints out Android image properties + * + * returns: + * no returned results + */ +static void +android_print_bootimg_v3_v4_contents(const struct andr_boot_img_hdr_v3_v4 *hdr) +{ + const char *const p = IMAGE_INDENT_STRING; + /* os_version = ver << 11 | lvl */ + u32 os_ver = hdr->os_version >> 11; + u32 os_lvl = hdr->os_version & ((1U << 11) - 1); + + printf("%skernel size: %x\n", p, hdr->kernel_size); + printf("%sramdisk size: %x\n", p, hdr->ramdisk_size); + + printf("%sos_version: %x (ver: %u.%u.%u, level: %u.%u)\n", p, + hdr->os_version, (os_ver >> 7) & 0x7F, (os_ver >> 14) & 0x7F, + os_ver & 0x7F, (os_lvl >> 4) + 2000, os_lvl & 0x0F); + + printf("%sheader size: %x\n", p, hdr->header_size); + printf("%sheader_version: %d\n", p, hdr->header_version); + printf("%scmdline: %s\n", p, hdr->cmdline); + + if (hdr->header_version >= 4) { + printf("%ssignature size: %x\n", p, hdr->signature_size); + } +} + /** * android_print_contents - prints out the contents of the Android format image * @hdr: pointer to the Android format image header @@ -393,9 +523,16 @@ bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr, * returns: * no returned results */ -void android_print_contents(const struct andr_img_hdr *hdr) +void android_print_contents(const struct andr_boot_img_hdr_v0_v1_v2 *hdr) { const char * const p = IMAGE_INDENT_STRING; + + if (hdr->header_version >= 3) { + return android_print_bootimg_v3_v4_contents( + (const struct andr_boot_img_hdr_v3_v4 *)hdr); + } + + /* os_version = ver << 11 | lvl */ u32 os_ver = hdr->os_version >> 11; u32 os_lvl = hdr->os_version & ((1U << 11) - 1); @@ -427,7 +564,7 @@ void android_print_contents(const struct andr_img_hdr *hdr) hdr->header_size); } - if (hdr->header_version >= 2) { + if (hdr->header_version == 2) { printf("%sdtb size: %x\n", p, hdr->dtb_size); printf("%sdtb addr: %llx\n", p, hdr->dtb_addr); } @@ -483,35 +620,32 @@ static bool android_image_print_dtb_info(const struct fdt_header *fdt, * * Return: true on success or false on error. */ -bool android_image_print_dtb_contents(ulong hdr_addr) +bool android_image_print_dtb_contents(const void *boot_img, const void *vendor_boot_img) { - const struct andr_img_hdr *hdr; + struct andr_image_data img_data = {0}; + if (!android_image_get_data(boot_img, vendor_boot_img, &img_data)) + return false; bool res; - ulong dtb_img_addr; /* address of DTB part in boot image */ - u32 dtb_img_size; /* size of DTB payload in boot image */ + u32 dtb_img_size = img_data.dtb_size; /* size of DTB payload in boot image */ ulong dtb_addr; /* address of DTB blob with specified index */ u32 i; /* index iterator */ - res = android_image_get_dtb_img_addr(hdr_addr, &dtb_img_addr); - if (!res) + if (!dtb_img_size) return false; /* Check if DTB area of boot image is in DTBO format */ - if (android_dt_check_header(dtb_img_addr)) { + if (android_dt_check_header(img_data.dtb_ptr)) { printf("## DTB area contents (DTBO format):\n"); - android_dt_print_contents(dtb_img_addr); + android_dt_print_contents(img_data.dtb_ptr); return true; } printf("## DTB area contents (concat format):\n"); /* Iterate over concatenated DTB blobs */ - hdr = map_sysmem(hdr_addr, sizeof(*hdr)); - dtb_img_size = hdr->dtb_size; - unmap_sysmem(hdr); i = 0; - dtb_addr = dtb_img_addr; - while (dtb_addr < dtb_img_addr + dtb_img_size) { + dtb_addr = img_data.dtb_ptr; + while (dtb_addr < img_data.dtb_ptr + dtb_img_size) { const struct fdt_header *fdt; u32 dtb_size; diff --git a/boot/image-board.c b/boot/image-board.c index 0d2e0fc9692e8f09b0f2a720a65c0878a1926b2a..5449fcd3447ad2282f9333567e793de273aa1c0c 100644 --- a/boot/image-board.c +++ b/boot/image-board.c @@ -288,7 +288,7 @@ int genimg_get_format(const void *img_addr) return IMAGE_FORMAT_FIT; } if (IS_ENABLED(CONFIG_ANDROID_BOOT_IMAGE) && - !android_image_check_header(img_addr)) + is_android_boot_image_header(img_addr)) return IMAGE_FORMAT_ANDROID; return IMAGE_FORMAT_INVALID; @@ -426,7 +426,13 @@ static int select_ramdisk(bootm_headers_t *images, const char *select, u8 arch, #endif #ifdef CONFIG_ANDROID_BOOT_IMAGE case IMAGE_FORMAT_ANDROID: - android_image_get_ramdisk((void *)images->os.start, +#ifdef CONFIG_CMD_ABOOTIMG + if (_abootimg_addr != -1) + android_image_get_ramdisk((void *)_abootimg_addr, (void *)_avendor_bootimg_addr, + rd_datap, rd_lenp); + else +#endif + android_image_get_ramdisk((void *)images->os.start, 0, rd_datap, rd_lenp); break; #endif diff --git a/boot/image-fdt.c b/boot/image-fdt.c index 692a9ad3e429c83b8f4f9428b44456134c75eab8..3adaca31431e8a6803f29d0945a8615b33725b7c 100644 --- a/boot/image-fdt.c +++ b/boot/image-fdt.c @@ -500,21 +500,9 @@ int boot_get_fdt(int flag, int argc, char *const argv[], uint8_t arch, } #ifdef CONFIG_ANDROID_BOOT_IMAGE } else if (genimg_get_format(buf) == IMAGE_FORMAT_ANDROID) { - struct andr_img_hdr *hdr = buf; - ulong fdt_data, fdt_len; - u32 fdt_size, dtb_idx; - /* - * Firstly check if this android boot image has dtb field. - */ - dtb_idx = (u32)env_get_ulong("adtb_idx", 10, 0); - if (android_image_get_dtb_by_index((ulong)hdr, dtb_idx, &fdt_addr, &fdt_size)) { - fdt_blob = (char *)map_sysmem(fdt_addr, 0); - if (fdt_check_header(fdt_blob)) - goto no_fdt; - - debug("## Using FDT in Android image dtb area with idx %u\n", dtb_idx); - } else if (!android_image_get_second(hdr, &fdt_data, &fdt_len) && - !fdt_check_header((char *)fdt_data)) { + void *hdr = buf; + ulong fdt_data, fdt_len; + if (!android_image_get_second(hdr, &fdt_data, &fdt_len) && !fdt_check_header((char *)fdt_data)) { fdt_blob = (char *)fdt_data; if (fdt_totalsize(fdt_blob) != fdt_len) goto error; diff --git a/cmd/abootimg.c b/cmd/abootimg.c index f48a9dcb021d4fc05b0988e9fd2bc1d798716faa..614976f4df7b5e318d4867be50b0c0a63c55c009 100644 --- a/cmd/abootimg.c +++ b/cmd/abootimg.c @@ -14,18 +14,19 @@ (_abootimg_addr == -1 ? image_load_addr : _abootimg_addr) /* Please use abootimg_addr() macro to obtain the boot image address */ -static ulong _abootimg_addr = -1; +ulong _abootimg_addr = -1; +ulong _avendor_bootimg_addr = 0; static int abootimg_get_ver(int argc, char *const argv[]) { - const struct andr_img_hdr *hdr; + const struct andr_boot_img_hdr_v0_v1_v2 *hdr; int res = CMD_RET_SUCCESS; if (argc > 1) return CMD_RET_USAGE; hdr = map_sysmem(abootimg_addr(), sizeof(*hdr)); - if (android_image_check_header(hdr)) { + if (is_android_boot_image_header(hdr)) { printf("Error: Boot Image header is incorrect\n"); res = CMD_RET_FAILURE; goto exit; @@ -49,7 +50,7 @@ static int abootimg_get_recovery_dtbo(int argc, char *const argv[]) if (argc > 2) return CMD_RET_USAGE; - if (!android_image_get_dtbo(abootimg_addr(), &addr, &size)) + if (!android_image_get_dtbo((void *)abootimg_addr(), &addr, &size)) return CMD_RET_FAILURE; if (argc == 0) { @@ -65,33 +66,24 @@ static int abootimg_get_recovery_dtbo(int argc, char *const argv[]) static int abootimg_get_dtb_load_addr(int argc, char *const argv[]) { - const struct andr_img_hdr *hdr; - int res = CMD_RET_SUCCESS; - if (argc > 1) return CMD_RET_USAGE; - hdr = map_sysmem(abootimg_addr(), sizeof(*hdr)); - if (android_image_check_header(hdr)) { - printf("Error: Boot Image header is incorrect\n"); - res = CMD_RET_FAILURE; - goto exit; - } + struct andr_image_data img_data = {0}; + if (!android_image_get_data((void *)abootimg_addr(), (void *)_avendor_bootimg_addr, &img_data)) + return CMD_RET_FAILURE; - if (hdr->header_version < 2) { - printf("Error: header_version must be >= 2 for this\n"); - res = CMD_RET_FAILURE; - goto exit; + if (!img_data.dtb_load_addr) { + printf("Error: failed to read dtb_load_addr\n"); + return CMD_RET_FAILURE; } if (argc == 0) - printf("%lx\n", (ulong)hdr->dtb_addr); + printf("%lx\n", (ulong)img_data.dtb_load_addr); else - env_set_hex(argv[0], (ulong)hdr->dtb_addr); + env_set_hex(argv[0], (ulong)img_data.dtb_load_addr); -exit: - unmap_sysmem(hdr); - return res; + return CMD_RET_SUCCESS; } static int abootimg_get_dtb_by_index(int argc, char *const argv[]) @@ -111,13 +103,13 @@ static int abootimg_get_dtb_by_index(int argc, char *const argv[]) return CMD_RET_FAILURE; } - num = simple_strtoul(index_str, &endp, 0); + num = hextoul(index_str, &endp); if (*endp != '\0') { printf("Error: Wrong index num\n"); return CMD_RET_FAILURE; } - if (!android_image_get_dtb_by_index(abootimg_addr(), num, + if (!android_image_get_dtb_by_index((void *)abootimg_addr(), (void *)_avendor_bootimg_addr, num, &addr, &size)) { return CMD_RET_FAILURE; } @@ -158,7 +150,7 @@ static int do_abootimg_addr(struct cmd_tbl *cmdtp, int flag, int argc, char *endp; ulong img_addr; - if (argc != 2) + if (argc < 2 && argc > 3) return CMD_RET_USAGE; img_addr = hextoul(argv[1], &endp); @@ -168,6 +160,16 @@ static int do_abootimg_addr(struct cmd_tbl *cmdtp, int flag, int argc, } _abootimg_addr = img_addr; + + if (argc == 3) { + img_addr = simple_strtoul(argv[2], &endp, 16); + if (*endp != '\0') { + printf("Error: Wrong image address\n"); + return CMD_RET_FAILURE; + } + + _avendor_bootimg_addr = img_addr; + } return CMD_RET_SUCCESS; } @@ -201,7 +203,7 @@ static int do_abootimg_dump(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_USAGE; if (!strcmp(argv[1], "dtb")) { - if (android_image_print_dtb_contents(abootimg_addr())) + if (android_image_print_dtb_contents((void *)abootimg_addr(), (void *)_avendor_bootimg_addr)) return CMD_RET_FAILURE; } else { return CMD_RET_USAGE; @@ -211,7 +213,7 @@ static int do_abootimg_dump(struct cmd_tbl *cmdtp, int flag, int argc, } static struct cmd_tbl cmd_abootimg_sub[] = { - U_BOOT_CMD_MKENT(addr, 2, 1, do_abootimg_addr, "", ""), + U_BOOT_CMD_MKENT(addr, 3, 1, do_abootimg_addr, "", ""), U_BOOT_CMD_MKENT(dump, 2, 1, do_abootimg_dump, "", ""), U_BOOT_CMD_MKENT(get, 5, 1, do_abootimg_get, "", ""), }; @@ -239,7 +241,7 @@ static int do_abootimg(struct cmd_tbl *cmdtp, int flag, int argc, U_BOOT_CMD( abootimg, CONFIG_SYS_MAXARGS, 0, do_abootimg, "manipulate Android Boot Image", - "addr <addr>\n" + "addr <boot_img_addr> [<vendor_boot_img_addr>]>\n" " - set the address in RAM where boot image is located\n" " ($loadaddr is used by default)\n" "abootimg dump dtb\n" diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index ad72c6979a913900fc088017b0c0c742ae1c0b59..ca0ca78cf292103abfb8562ab4ff4e61c7453b2e 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -288,7 +288,7 @@ static void fb_mmc_boot_ops(struct blk_desc *dev_desc, void *buffer, */ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, struct disk_partition *info, - struct andr_img_hdr *hdr, + void *hdr, char *response) { ulong sector_size; /* boot partition sector size */ @@ -297,7 +297,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, /* Calculate boot image sectors count */ sector_size = info->blksz; - hdr_sectors = DIV_ROUND_UP(sizeof(struct andr_img_hdr), sector_size); + hdr_sectors = DIV_ROUND_UP(ANDR_GKI_PAGE_SIZE, sector_size); if (hdr_sectors == 0) { pr_err("invalid number of boot sectors: 0\n"); fastboot_fail("invalid number of boot sectors: 0", response); @@ -314,7 +314,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, } /* Check boot header magic string */ - res = android_image_check_header(hdr); + res = is_android_boot_image_header(hdr); if (res != 0) { pr_err("bad boot image magic\n"); fastboot_fail("boot partition not initialized", response); @@ -339,7 +339,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, char *response) { uintptr_t hdr_addr; /* boot image header address */ - struct andr_img_hdr *hdr; /* boot image header */ + struct andr_boot_img_hdr_v0_v1_v2 *hdr; /* boot image header */ lbaint_t hdr_sectors; /* boot image header sectors */ u8 *ramdisk_buffer; u32 ramdisk_sector_start; @@ -362,7 +362,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, /* Put boot image header in fastboot buffer after downloaded zImage */ hdr_addr = (uintptr_t)download_buffer + ALIGN(download_bytes, PAGE_SIZE); - hdr = (struct andr_img_hdr *)hdr_addr; + hdr = (struct andr_boot_img_hdr_v0_v1_v2 *)hdr_addr; /* Read boot image header */ hdr_sectors = fb_mmc_get_boot_header(dev_desc, &info, hdr, response); @@ -372,6 +372,13 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, return -1; } + + if (hdr->header_version > 2) { + pr_err("zImage flashing supported only for boot images v2 and less\n"); + fastboot_fail("zImage flashing supported only for boot images v2 and less", response); + return -1; + } + /* Check if boot image has second stage in it (we don't support it) */ if (hdr->second_size > 0) { pr_err("moving second stage is not supported yet\n"); diff --git a/include/android_image.h b/include/android_image.h index 54d25af0684adf487a85fd59fe519d797f1da05b..529680076bdcfb1f81941b6f7683ce3d64f6050f 100644 --- a/include/android_image.h +++ b/include/android_image.h @@ -14,15 +14,66 @@ #include <linux/compiler.h> #include <linux/types.h> +#define ANDR_GKI_PAGE_SIZE 4096 + #define ANDR_BOOT_MAGIC "ANDROID!" #define ANDR_BOOT_MAGIC_SIZE 8 #define ANDR_BOOT_NAME_SIZE 16 #define ANDR_BOOT_ARGS_SIZE 512 #define ANDR_BOOT_EXTRA_ARGS_SIZE 1024 -/* The bootloader expects the structure of andr_img_hdr with header - * version 0 to be as follows: */ -struct andr_img_hdr { +#define VENDOR_BOOT_MAGIC "VNDRBOOT" +#define ANDR_VENDOR_BOOT_MAGIC_SIZE 8 +#define ANDR_VENDOR_BOOT_ARGS_SIZE 2048 +#define ANDR_VENDOR_BOOT_NAME_SIZE 16 + +struct andr_boot_img_hdr_v3_v4 +{ +#define BOOT_MAGIC_SIZE 8 + uint8_t magic[ANDR_BOOT_MAGIC_SIZE]; + + uint32_t kernel_size; /* size in bytes */ + uint32_t ramdisk_size; /* size in bytes */ + + uint32_t os_version; + + uint32_t header_size; /* size of boot image header in bytes */ + uint32_t reserved[4]; + uint32_t header_version; /* offset remains constant for version check */ + + uint8_t cmdline[ANDR_BOOT_ARGS_SIZE + ANDR_BOOT_EXTRA_ARGS_SIZE]; + /* for boot image header v4 only */ + uint32_t signature_size; /* size in bytes */ +}; + +struct andr_vendor_boot_img_hdr_v3_v4 +{ + uint8_t magic[ANDR_VENDOR_BOOT_MAGIC_SIZE]; + 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[ANDR_VENDOR_BOOT_ARGS_SIZE]; + + uint32_t tags_addr; /* physical addr for kernel tags */ + + uint8_t name[ANDR_VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */ + uint32_t header_size; /* size of vendor boot image header in + * bytes */ + uint32_t dtb_size; /* size of dtb image */ + uint64_t dtb_addr; /* physical load address */ + /* for boot image header v4 only */ + uint32_t vendor_ramdisk_table_size; /* size in bytes for the vendor ramdisk table */ + uint32_t vendor_ramdisk_table_entry_num; /* number of entries in the vendor ramdisk table */ + uint32_t vendor_ramdisk_table_entry_size; /* size in bytes for a vendor ramdisk table entry */ + uint32_t bootconfig_size; /* size in bytes for the bootconfig section */ +}; + +struct andr_boot_img_hdr_v0_v1_v2 { /* Must be ANDR_BOOT_MAGIC. */ char magic[ANDR_BOOT_MAGIC_SIZE]; @@ -67,6 +118,136 @@ struct andr_img_hdr { u64 dtb_addr; /* physical load address for DTB image */ } __attribute__((packed)); +/* When the boot image header has a version of 4, the structure of the boot + * image is the same as version 3: + * + * +---------------------+ + * | 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 4 of the boot image header, page size is fixed at 4096 + * bytes. + * + * The structure of the vendor boot image version 4, which is required to be + * present when a version 4 boot image is used, is as follows: + * + * +------------------------+ + * | vendor boot header | o pages + * +------------------------+ + * | vendor ramdisk section | p pages + * +------------------------+ + * | dtb | q pages + * +------------------------+ + * | vendor ramdisk table | r pages + * +------------------------+ + * | bootconfig | s pages + * +------------------------+ + * + * o = (2124 + page_size - 1) / page_size + * p = (vendor_ramdisk_size + page_size - 1) / page_size + * q = (dtb_size + page_size - 1) / page_size + * r = (vendor_ramdisk_table_size + page_size - 1) / page_size + * s = (vendor_bootconfig_size + page_size - 1) / page_size + * + * Note that in version 4 of the vendor boot image, multiple vendor ramdisks can + * be included in the vendor boot image. The bootloader can select a subset of + * ramdisks to load at runtime. To help the bootloader select the ramdisks, each + * ramdisk is tagged with a type tag and a set of hardware identifiers + * describing the board, soc or platform that this ramdisk is intended for. + * + * The vendor ramdisk section is consist of multiple ramdisk images concatenated + * one after another, and vendor_ramdisk_size is the size of the section, which + * is the total size of all the ramdisks included in the vendor boot image. + * + * The vendor ramdisk table holds the size, offset, type, name and hardware + * identifiers of each ramdisk. The type field denotes the type of its content. + * The hardware identifiers are specified in the board_id field in each table + * entry. The board_id field is consist of a vector of unsigned integer words, + * and the encoding scheme is defined by the hardware vendor. + * + * For the different type of ramdisks, there are: + * - VENDOR_RAMDISK_TYPE_NONE indicates the value is unspecified. + * - VENDOR_RAMDISK_TYPE_PLATFORM ramdisk contains platform specific bits. + * - VENDOR_RAMDISK_TYPE_RECOVERY ramdisk contains recovery resources. + * - VENDOR_RAMDISK_TYPE_DLKM ramdisk contains dynamic loadable kernel + * modules. + * + * Version 4 of the vendor boot image also adds a bootconfig section to the end + * of the image. This section contains Boot Configuration parameters known at + * build time. The bootloader is responsible for placing this section directly + * after the boot image ramdisk, followed by the bootconfig trailer, before + * entering the kernel. + * + * 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, 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 ramdisks at ramdisk_addr + * 4. load the generic ramdisk immediately following the vendor ramdisk in + * memory + * 5. load the vendor bootconfig immediately following the generic ramdisk. Add + * additional bootconfig parameters followed by the bootconfig trailer. + * 6. set up registers for kernel entry as required by your architecture + * 7. 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 + */ + +/* 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 + */ + /* When a boot header is of version 0, the structure of boot image is as * follows: * @@ -136,4 +317,33 @@ struct andr_img_hdr { * else: jump to kernel_addr */ +/* Private struct */ +struct andr_image_data { + ulong kernel_ptr; + uint32_t kernel_size; + ulong ramdisk_ptr; + uint32_t ramdisk_size; + ulong vendor_ramdisk_ptr; + uint32_t vendor_ramdisk_size; + uint32_t boot_ramdisk_size; + ulong second_ptr; + uint32_t second_size; + ulong dtb_ptr; + uint32_t dtb_size; + ulong recovery_dtbo_ptr; + uint32_t recovery_dtbo_size; + + const char *kcmdline; + const char *kcmdline_extra; + const char *image_name; + + uint32_t kernel_load_addr; + ulong ramdisk_load_addr; + ulong dtb_load_addr; + ulong tags_addr; + uint32_t header_version; + uint32_t boot_img_total_size; + uint32_t vendor_boot_img_total_size; +}; + #endif diff --git a/include/image.h b/include/image.h index 97e5f2eb24d6c5222608bdb3de536c7a0d5003e7..de4e33cc07a13abbd6c01dcececc38373aa6c486 100644 --- a/include/image.h +++ b/include/image.h @@ -1449,23 +1449,30 @@ struct cipher_algo { int fit_image_cipher_get_algo(const void *fit, int noffset, char **algo); struct cipher_algo *image_get_cipher_algo(const char *full_name); - -struct andr_img_hdr; -int android_image_check_header(const struct andr_img_hdr *hdr); -int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, +struct andr_boot_img_hdr_v0_v1_v2; +struct andr_image_data; +bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr, + struct andr_image_data *data); +bool is_android_boot_image_header(const void *boot_img); +bool is_android_vendor_boot_image_header(const void *vendor_boot_img); +int android_image_get_kernel(const void *boot_img, const void *vendor_boot_img, int verify, ulong *os_data, ulong *os_len); -int android_image_get_ramdisk(const struct andr_img_hdr *hdr, +int android_image_get_ramdisk(const void *boot_img, const void *vendor_boot_img, ulong *rd_data, ulong *rd_len); -int android_image_get_second(const struct andr_img_hdr *hdr, - ulong *second_data, ulong *second_len); -bool android_image_get_dtbo(ulong hdr_addr, ulong *addr, u32 *size); -bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr, +int android_image_get_second(void *boot_img, ulong *second_data, ulong *second_len); +bool android_image_get_dtbo(const void *boot_img, ulong *addr, u32 *size); +bool android_image_get_dtb_by_index(const void *boot_img, const void *vendor_boot_img, u32 index, ulong *addr, u32 *size); -ulong android_image_get_end(const struct andr_img_hdr *hdr); -ulong android_image_get_kload(const struct andr_img_hdr *hdr); -ulong android_image_get_kcomp(const struct andr_img_hdr *hdr); -void android_print_contents(const struct andr_img_hdr *hdr); -bool android_image_print_dtb_contents(ulong hdr_addr); + +ulong android_image_get_kload(const void *boot_img, const void *vendor_boot_img); +ulong android_image_get_kcomp(const void *boot_img, const void *vendor_boot_img); +void android_print_contents(const struct andr_boot_img_hdr_v0_v1_v2 *hdr); +bool android_image_print_dtb_contents(const void *boot_img, const void *vendor_boot_img); + +#ifdef CONFIG_CMD_ABOOTIMG +extern ulong _abootimg_addr; +extern ulong _avendor_bootimg_addr; +#endif /** * board_fit_config_name_match() - Check for a matching board name