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:
parent
5a4b526e82
commit
745aeb1a7d
|
|
@ -273,27 +273,6 @@ static int read_logo_bmps(struct blk_desc *dev_desc)
|
||||||
return 0;
|
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)
|
int resource_create_ram_list(struct blk_desc *dev_desc, void *rsce_hdr)
|
||||||
{
|
{
|
||||||
struct resource_img_hdr *hdr = rsce_hdr;
|
struct resource_img_hdr *hdr = rsce_hdr;
|
||||||
|
|
@ -385,81 +364,105 @@ err:
|
||||||
return ret;
|
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,
|
static int get_resource_base_sector(struct blk_desc *dev_desc,
|
||||||
disk_partition_t *from_part,
|
struct andr_img_hdr **ret_hdr)
|
||||||
int *dtb_off, int *dtb_size)
|
|
||||||
{
|
{
|
||||||
disk_partition_t part;
|
disk_partition_t part;
|
||||||
int rsce_base;
|
int rsce_base = 0;
|
||||||
#ifdef CONFIG_ANDROID_BOOT_IMAGE
|
#ifdef CONFIG_ANDROID_BOOT_IMAGE
|
||||||
struct andr_img_hdr *hdr;
|
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
|
* Anyway, we must read android hdr firstly from boot partition to get
|
||||||
* the 'os_version' for android_bcb_msg_sector_offset(), in order to
|
* 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)
|
if (part_get_info_by_name(dev_desc, PART_BOOT, &part) < 0)
|
||||||
goto resource_part;
|
goto resource_part;
|
||||||
|
|
||||||
blknum = DIV_ROUND_UP(sizeof(*hdr), dev_desc->blksz);
|
hdr = populate_andr_img_hdr(dev_desc, &part);
|
||||||
hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz * blknum);
|
if (hdr) {
|
||||||
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;
|
|
||||||
|
|
||||||
os_ver = hdr->os_version >> 11;
|
os_ver = hdr->os_version >> 11;
|
||||||
os_lvl = hdr->os_version & ((1U << 11) - 1);
|
os_lvl = hdr->os_version & ((1U << 11) - 1);
|
||||||
if (os_ver) {
|
if (os_ver)
|
||||||
gd->bd->bi_andr_version = hdr->os_version;
|
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
|
#ifndef CONFIG_ANDROID_AB
|
||||||
/* Get boot mode from misc and read if recovery mode */
|
/* Get boot mode from misc and read if recovery mode */
|
||||||
if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) {
|
if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) {
|
||||||
|
if (hdr)
|
||||||
|
free(hdr);
|
||||||
|
|
||||||
if (part_get_info_by_name(dev_desc, PART_RECOVERY, &part) < 0)
|
if (part_get_info_by_name(dev_desc, PART_RECOVERY, &part) < 0)
|
||||||
goto resource_part;
|
goto resource_part;
|
||||||
|
|
||||||
if (blk_dread(dev_desc, part.start, blknum, hdr) != blknum) {
|
hdr = populate_andr_img_hdr(dev_desc, &part);
|
||||||
printf("Failed to read %s hdr\n", part.name);
|
if (!hdr)
|
||||||
free(hdr);
|
goto resource_part;
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* get ! */
|
/* If Android v012, getting resource from second position ! */
|
||||||
if (!android_image_check_header(hdr)) {
|
if (hdr) {
|
||||||
rsce_base = part.start * dev_desc->blksz;
|
if (os_ver)
|
||||||
rsce_base += hdr->page_size;
|
printf("Android %u.%u, Build %u.%u, v%d\n",
|
||||||
rsce_base += ALIGN(hdr->kernel_size, hdr->page_size);
|
(os_ver >> 14) & 0x7F, (os_ver >> 7) & 0x7F,
|
||||||
rsce_base += ALIGN(hdr->ramdisk_size, hdr->page_size);
|
(os_lvl >> 4) + 2000, os_lvl & 0x0F,
|
||||||
|
hdr->header_version);
|
||||||
if (hdr->header_version >= 2) {
|
*ret_hdr = hdr;
|
||||||
*dtb_size = hdr->dtb_size;
|
if (hdr->header_version < 3) {
|
||||||
*dtb_off =
|
rsce_base = part.start * dev_desc->blksz;
|
||||||
rsce_base +
|
rsce_base += hdr->page_size;
|
||||||
ALIGN(hdr->recovery_dtbo_size, hdr->page_size) +
|
rsce_base += ALIGN(hdr->kernel_size, hdr->page_size);
|
||||||
ALIGN(hdr->second_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:
|
resource_part:
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -467,10 +470,9 @@ resource_part:
|
||||||
if (part_get_info_by_name(dev_desc, PART_RESOURCE, &part) < 0) {
|
if (part_get_info_by_name(dev_desc, PART_RESOURCE, &part) < 0) {
|
||||||
printf("No resource partition\n");
|
printf("No resource partition\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
} else {
|
||||||
|
rsce_base = part.start;
|
||||||
}
|
}
|
||||||
|
|
||||||
*from_part = part;
|
|
||||||
rsce_base = part.start;
|
|
||||||
#ifdef CONFIG_ANDROID_BOOT_IMAGE
|
#ifdef CONFIG_ANDROID_BOOT_IMAGE
|
||||||
finish:
|
finish:
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -490,11 +492,9 @@ finish:
|
||||||
*/
|
*/
|
||||||
static int init_resource_list(void)
|
static int init_resource_list(void)
|
||||||
{
|
{
|
||||||
|
struct andr_img_hdr *hdr = NULL;
|
||||||
struct blk_desc *dev_desc;
|
struct blk_desc *dev_desc;
|
||||||
disk_partition_t part;
|
|
||||||
int rsce_base;
|
int rsce_base;
|
||||||
int dtb_offset;
|
|
||||||
int dtb_size = 0;
|
|
||||||
|
|
||||||
dev_desc = rockchip_get_bootdev();
|
dev_desc = rockchip_get_bootdev();
|
||||||
if (!dev_desc) {
|
if (!dev_desc) {
|
||||||
|
|
@ -502,17 +502,14 @@ static int init_resource_list(void)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
rsce_base = get_resource_base_sector(dev_desc, &part,
|
rsce_base = get_resource_base_sector(dev_desc, &hdr);
|
||||||
&dtb_offset, &dtb_size);
|
|
||||||
if (rsce_base > 0) {
|
if (rsce_base > 0) {
|
||||||
if (resource_create_list(dev_desc, rsce_base))
|
if (resource_create_list(dev_desc, rsce_base))
|
||||||
printf("Failed to create resource list\n");
|
printf("Failed to create resource list\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* override the old one if dtb_size != 0 */
|
/* override the resource dtb with android dtb if need */
|
||||||
read_dtb_from_android_v2(rsce_base, dtb_offset, dtb_size);
|
return read_dtb_from_android(dev_desc, hdr, rsce_base);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct resource_file *get_file_info(const char *name)
|
static struct resource_file *get_file_info(const char *name)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ static int do_android_print_hdr(cmd_tbl_t *cmdtp, int flag,
|
||||||
struct andr_img_hdr *hdr;
|
struct andr_img_hdr *hdr;
|
||||||
disk_partition_t part_info;
|
disk_partition_t part_info;
|
||||||
const char *part_name;
|
const char *part_name;
|
||||||
int blkcnt, ret;
|
|
||||||
|
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
return CMD_RET_USAGE;
|
return CMD_RET_USAGE;
|
||||||
|
|
@ -31,31 +30,18 @@ static int do_android_print_hdr(cmd_tbl_t *cmdtp, int flag,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = part_get_info_by_name(dev_desc, part_name, &part_info);
|
if (part_get_info_by_name(dev_desc, part_name, &part_info) < 0) {
|
||||||
if (ret < 0) {
|
printf("Failed to get \"%s\" part\n", part_name);
|
||||||
printf("Failed to get \"%s\" part, ret=%d\n", part_name, ret);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
blkcnt = DIV_ROUND_UP(sizeof(*hdr), dev_desc->blksz);
|
hdr = populate_andr_img_hdr(dev_desc, &part_info);
|
||||||
hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz * blkcnt);
|
|
||||||
if (!hdr) {
|
if (!hdr) {
|
||||||
printf("%s: out of memory!\n", __func__);
|
printf("Not an android image\n");
|
||||||
return -ENOMEM;
|
return -EINVAL;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
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("Partition \"%s\"\n", part_info.name);
|
printf("Partition \"%s\"\n", part_info.name);
|
||||||
android_print_contents(hdr);
|
android_print_contents(hdr);
|
||||||
} else {
|
|
||||||
printf("Not an android image\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(hdr);
|
free(hdr);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
#define ANDROID_PARTITION_BOOT "boot"
|
#define ANDROID_PARTITION_BOOT "boot"
|
||||||
|
#define ANDROID_PARTITION_VENDOR_BOOT "vendor_boot"
|
||||||
#define ANDROID_PARTITION_MISC "misc"
|
#define ANDROID_PARTITION_MISC "misc"
|
||||||
#define ANDROID_PARTITION_OEM "oem"
|
#define ANDROID_PARTITION_OEM "oem"
|
||||||
#define ANDROID_PARTITION_RECOVERY "recovery"
|
#define ANDROID_PARTITION_RECOVERY "recovery"
|
||||||
|
|
@ -790,8 +791,41 @@ static AvbSlotVerifyResult android_slot_verify(char *boot_partname,
|
||||||
strcat(newbootargs, slot_data[0]->cmdline);
|
strcat(newbootargs, slot_data[0]->cmdline);
|
||||||
env_set("bootargs", newbootargs);
|
env_set("bootargs", newbootargs);
|
||||||
|
|
||||||
/* Reserve page_size */
|
|
||||||
hdr = (void *)slot_data[0]->loaded_partitions->data;
|
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;
|
load_address -= hdr->page_size;
|
||||||
if (android_image_memcpy_separate(hdr, &load_address)) {
|
if (android_image_memcpy_separate(hdr, &load_address)) {
|
||||||
printf("Failed to separate copy android image\n");
|
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;
|
disk_partition_t part_info;
|
||||||
char *part_dtbo;
|
char *part_dtbo;
|
||||||
char buf[32] = {0};
|
char buf[32] = {0};
|
||||||
u32 blk_cnt;
|
|
||||||
ulong fdt_dtbo = -1;
|
ulong fdt_dtbo = -1;
|
||||||
int index = -1;
|
int index = -1;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -970,32 +1003,25 @@ int android_fdt_overlay_apply(void *fdt_addr)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
blk_cnt = DIV_ROUND_UP(sizeof(*hdr), part_info.blksz);
|
hdr = populate_andr_img_hdr(dev_desc, &part_info);
|
||||||
hdr = memalign(ARCH_DMA_MINALIGN, part_info.blksz * blk_cnt);
|
if (!hdr)
|
||||||
if (!hdr) {
|
return -EINVAL;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
android_print_contents(hdr);
|
android_print_contents(hdr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (android_image_check_header(hdr))
|
/*
|
||||||
return -EINVAL;
|
* recovery_dtbo fields
|
||||||
|
*
|
||||||
/* Check header version */
|
* boot_img_hdr_v0: unsupported
|
||||||
if (!hdr->header_version) {
|
* boot_img_hdr_v1,2: supported
|
||||||
printf("Android header version 0\n");
|
* boot_img_hdr_v3 + boot.img: supported
|
||||||
ret = -EINVAL;
|
* 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;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
ret = android_get_dtbo(&fdt_dtbo, (void *)hdr, &index, part_dtbo);
|
ret = android_get_dtbo(&fdt_dtbo, (void *)hdr, &index, part_dtbo);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,10 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||||
#define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000
|
#define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000
|
||||||
#define ANDROID_ARG_FDT_FILENAME "rk-kernel.dtb"
|
#define ANDROID_ARG_FDT_FILENAME "rk-kernel.dtb"
|
||||||
#define ANDROID_Q_VER 10
|
#define ANDROID_Q_VER 10
|
||||||
|
#define ANDROID_PARTITION_VENDOR_BOOT "vendor_boot"
|
||||||
|
|
||||||
/* Defined by rockchip legacy mkboot tool(SDK version < 8.1) */
|
#define BLK_CNT(_num_bytes, _block_size) \
|
||||||
#define ANDROID_ROCKCHIP_LEGACY_PAGE_SIZE 0x4000
|
((_num_bytes + _block_size - 1) / _block_size)
|
||||||
|
|
||||||
static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
|
static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
|
||||||
static u32 android_kernel_comp_type = IH_COMP_NONE;
|
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)
|
ulong *os_data, ulong *os_len)
|
||||||
{
|
{
|
||||||
u32 kernel_addr = android_image_get_kernel_addr(hdr);
|
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
|
* 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
|
* 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));
|
kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
|
||||||
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
if (*hdr->cmdline) {
|
if (cmdline) {
|
||||||
debug("Kernel command line: %s\n", hdr->cmdline);
|
debug("Kernel command line: %s\n", cmdline);
|
||||||
len += strlen(hdr->cmdline);
|
len += strlen(cmdline);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *bootargs = env_get("bootargs");
|
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);
|
strcpy(newbootargs, bootargs);
|
||||||
strcat(newbootargs, " ");
|
strcat(newbootargs, " ");
|
||||||
}
|
}
|
||||||
if (*hdr->cmdline)
|
if (cmdline)
|
||||||
strcat(newbootargs, hdr->cmdline);
|
strcat(newbootargs, cmdline);
|
||||||
|
|
||||||
env_set("bootargs", newbootargs);
|
env_set("bootargs", newbootargs);
|
||||||
|
|
||||||
|
|
@ -193,16 +195,22 @@ ulong android_image_get_end(const struct andr_img_hdr *hdr)
|
||||||
* on page boundary
|
* on page boundary
|
||||||
*/
|
*/
|
||||||
end = (ulong)hdr;
|
end = (ulong)hdr;
|
||||||
end += hdr->page_size;
|
if (hdr->header_version < 3) {
|
||||||
end += ALIGN(hdr->kernel_size, hdr->page_size);
|
end += hdr->page_size;
|
||||||
end += ALIGN(hdr->ramdisk_size, hdr->page_size);
|
end += ALIGN(hdr->kernel_size, hdr->page_size);
|
||||||
end += ALIGN(hdr->second_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) {
|
if (hdr->header_version == 1) {
|
||||||
end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
|
end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
|
||||||
end += ALIGN(hdr->dtb_size, hdr->page_size);
|
} else if (hdr->header_version == 2) {
|
||||||
} else if (hdr->header_version >= 1) {
|
end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
|
||||||
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;
|
return end;
|
||||||
|
|
@ -293,6 +301,7 @@ typedef enum {
|
||||||
IMG_RECOVERY_DTBO,
|
IMG_RECOVERY_DTBO,
|
||||||
IMG_RK_DTB, /* within resource.img in second position */
|
IMG_RK_DTB, /* within resource.img in second position */
|
||||||
IMG_DTB,
|
IMG_DTB,
|
||||||
|
IMG_VENDOR_RAMDISK,
|
||||||
IMG_MAX,
|
IMG_MAX,
|
||||||
} img_t;
|
} img_t;
|
||||||
|
|
||||||
|
|
@ -301,11 +310,14 @@ static int image_load(img_t img, struct andr_img_hdr *hdr,
|
||||||
struct udevice *crypto)
|
struct udevice *crypto)
|
||||||
{
|
{
|
||||||
struct blk_desc *desc = rockchip_get_bootdev();
|
struct blk_desc *desc = rockchip_get_bootdev();
|
||||||
|
disk_partition_t part_vendor_boot;
|
||||||
__maybe_unused u32 sizesz;
|
__maybe_unused u32 sizesz;
|
||||||
ulong pgsz = hdr->page_size;
|
ulong pgsz = hdr->page_size;
|
||||||
ulong blksz = desc->blksz;
|
ulong blksz = desc->blksz;
|
||||||
ulong blkcnt, blkoff;
|
ulong blkcnt, blkoff;
|
||||||
|
ulong orgdst = 0;
|
||||||
ulong offset = 0;
|
ulong offset = 0;
|
||||||
|
ulong extra = 0;
|
||||||
ulong datasz;
|
ulong datasz;
|
||||||
void *ramdst;
|
void *ramdst;
|
||||||
int ret = 0;
|
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))
|
(phys_addr_t)ramdst, blkcnt * blksz))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
break;
|
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:
|
case IMG_RAMDISK:
|
||||||
offset = pgsz + ALIGN(hdr->kernel_size, pgsz);
|
offset = pgsz + ALIGN(hdr->kernel_size, pgsz);
|
||||||
blkcnt = DIV_ROUND_UP(hdr->ramdisk_size, blksz);
|
blkcnt = DIV_ROUND_UP(hdr->ramdisk_size, blksz);
|
||||||
ramdst = (void *)env_get_ulong("ramdisk_addr_r", 16, 0);
|
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;
|
datasz = hdr->ramdisk_size;
|
||||||
sizesz = sizeof(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))
|
(phys_addr_t)ramdst, blkcnt * blksz))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case IMG_SECOND:
|
case IMG_SECOND:
|
||||||
offset = pgsz +
|
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:
|
crypto_calc:
|
||||||
/* sha1 */
|
/* sha1 */
|
||||||
#ifdef CONFIG_DM_CRYPTO
|
#ifdef CONFIG_DM_CRYPTO
|
||||||
|
|
@ -410,6 +472,9 @@ crypto_calc:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @ram_base: !NULL means require memcpy for an exist full android image.
|
||||||
|
*/
|
||||||
static int android_image_separate(struct andr_img_hdr *hdr,
|
static int android_image_separate(struct andr_img_hdr *hdr,
|
||||||
const disk_partition_t *part,
|
const disk_partition_t *part,
|
||||||
void *load_address,
|
void *load_address,
|
||||||
|
|
@ -508,6 +573,48 @@ static int android_image_separate(struct andr_img_hdr *hdr,
|
||||||
return 0;
|
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)
|
static ulong android_image_get_comp_addr(struct andr_img_hdr *hdr, int comp)
|
||||||
{
|
{
|
||||||
ulong kernel_addr_c;
|
ulong kernel_addr_c;
|
||||||
|
|
@ -605,7 +712,10 @@ static int android_image_load_separate(struct andr_img_hdr *hdr,
|
||||||
const disk_partition_t *part,
|
const disk_partition_t *part,
|
||||||
void *load_addr)
|
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)
|
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)
|
if (comp_addr == (ulong)hdr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (android_image_separate(hdr, NULL, (void *)comp_addr, hdr))
|
if (hdr->header_version < 3) {
|
||||||
return -1;
|
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;
|
*load_addr = comp_addr;
|
||||||
android_image_set_decomp((void *)comp_addr, comp);
|
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 load_address,
|
||||||
unsigned long max_size) {
|
unsigned long max_size) {
|
||||||
struct andr_img_hdr *hdr;
|
struct andr_img_hdr *hdr;
|
||||||
u32 blksz = dev_desc->blksz;
|
|
||||||
u32 pszcnt, hdrcnt, kercnt;
|
|
||||||
int comp, ret;
|
int comp, ret;
|
||||||
|
int blk_off;
|
||||||
|
|
||||||
if (max_size < part_info->blksz)
|
if (max_size < part_info->blksz)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/*
|
hdr = populate_andr_img_hdr(dev_desc, (disk_partition_t *)part_info);
|
||||||
* 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);
|
|
||||||
if (!hdr) {
|
if (!hdr) {
|
||||||
printf("No memory\n");
|
printf("No valid android hdr\n");
|
||||||
return -1;
|
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,
|
* create the layout:
|
||||||
* reading kernel image for compress validation.
|
*
|
||||||
|
* |<- 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);
|
blk_off = BLK_CNT(hdr->page_size, dev_desc->blksz);
|
||||||
if (blk_dread(dev_desc, part_info->start + pszcnt, kercnt,
|
hdr = (struct andr_img_hdr *)
|
||||||
(void *)((ulong)hdr + hdr->page_size)) != kercnt) {
|
realloc(hdr, (blk_off + 1) * dev_desc->blksz);
|
||||||
printf("Failed to read kernel header\n");
|
if (!hdr)
|
||||||
goto fail;
|
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;
|
load_address -= hdr->page_size;
|
||||||
|
|
||||||
/* Let's load kernel now ! */
|
/* Let's load kernel now ! */
|
||||||
|
|
@ -700,6 +806,260 @@ fail:
|
||||||
return -1;
|
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)
|
#if !defined(CONFIG_SPL_BUILD)
|
||||||
/**
|
/**
|
||||||
* android_print_contents - prints out the contents of the Android format image
|
* 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 size: %x\n", p, hdr->kernel_size);
|
||||||
printf("%skernel address: %x\n", p, hdr->kernel_addr);
|
printf("%skernel address: %x\n", p, hdr->kernel_addr);
|
||||||
printf("%sramdisk size: %x\n", p, hdr->ramdisk_size);
|
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 size: %x\n", p, hdr->second_size);
|
||||||
printf("%ssecond address: %x\n", p, hdr->second_addr);
|
printf("%ssecond address: %x\n", p, hdr->second_addr);
|
||||||
printf("%stags address: %x\n", p, hdr->tags_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("%sname: %s\n", p, hdr->name);
|
||||||
printf("%scmdline: %s\n", p, hdr->cmdline);
|
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 size: %x\n", p, hdr->recovery_dtbo_size);
|
||||||
printf("%srecovery dtbo offset: %llx\n", p, hdr->recovery_dtbo_offset);
|
printf("%srecovery dtbo offset: %llx\n", p, hdr->recovery_dtbo_offset);
|
||||||
printf("%sheader size: %x\n", p, hdr->header_size);
|
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 size: %x\n", p, hdr->dtb_size);
|
||||||
printf("%sdtb addr: %llx\n", p, hdr->dtb_addr);
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,19 @@
|
||||||
#define _ANDROID_IMAGE_H_
|
#define _ANDROID_IMAGE_H_
|
||||||
|
|
||||||
#define ANDR_BOOT_MAGIC "ANDROID!"
|
#define ANDR_BOOT_MAGIC "ANDROID!"
|
||||||
|
#define VENDOR_BOOT_MAGIC "VNDRBOOT"
|
||||||
#define ANDR_BOOT_MAGIC_SIZE 8
|
#define ANDR_BOOT_MAGIC_SIZE 8
|
||||||
|
#define VENDOR_BOOT_MAGIC_SIZE 8
|
||||||
#define ANDR_BOOT_NAME_SIZE 16
|
#define ANDR_BOOT_NAME_SIZE 16
|
||||||
|
#define VENDOR_BOOT_NAME_SIZE 16
|
||||||
#define ANDR_BOOT_ARGS_SIZE 512
|
#define ANDR_BOOT_ARGS_SIZE 512
|
||||||
#define ANDR_BOOT_EXTRA_ARGS_SIZE 1024
|
#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
|
* 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. */
|
* binary compatibility with older versions of mkbootimg. */
|
||||||
char extra_cmdline[ANDR_BOOT_EXTRA_ARGS_SIZE];
|
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 */
|
u32 recovery_dtbo_size; /* size in bytes for recovery DTBO/ACPIO image */
|
||||||
u64 recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */
|
u64 recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */
|
||||||
u32 header_size;
|
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 */
|
u32 dtb_size; /* size in bytes for DTB image */
|
||||||
u64 dtb_addr; /* physical load address 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));
|
} __attribute__((packed));
|
||||||
|
|
||||||
/* When a boot header is of version 0, the structure of boot image is as
|
/* 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
|
* 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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ struct rockchip_image {
|
||||||
#define PART_RESOURCE "resource"
|
#define PART_RESOURCE "resource"
|
||||||
#define PART_KERNEL "kernel"
|
#define PART_KERNEL "kernel"
|
||||||
#define PART_BOOT "boot"
|
#define PART_BOOT "boot"
|
||||||
|
#define PART_VENDOR_BOOT "vendor_boot"
|
||||||
#define PART_RECOVERY "recovery"
|
#define PART_RECOVERY "recovery"
|
||||||
#define PART_DTBO "dtbo"
|
#define PART_DTBO "dtbo"
|
||||||
#define PART_LOGO "logo"
|
#define PART_LOGO "logo"
|
||||||
|
|
|
||||||
|
|
@ -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_parse_comp(struct andr_img_hdr *hdr, ulong *load_addr);
|
||||||
int android_image_memcpy_separate(struct andr_img_hdr *hdr, ulong *load_address);
|
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.
|
/** android_image_load - Load an Android Image from storage.
|
||||||
*
|
*
|
||||||
* Load an Android Image based on the header size in the storage.
|
* Load an Android Image based on the header size in the storage.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue