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 <chenjh@rock-chips.com>
Change-Id: I2afce53c43d782fc57baa01acf9c05518b580840
This commit is contained in:
Joseph Chen 2020-09-09 18:05:01 +08:00 committed by Jianhong Chen
parent 5a4b526e82
commit 745aeb1a7d
7 changed files with 687 additions and 187 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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.