android: support loading android image separate

This patch support loading android image separate for the
kernel/ramdisk/second images. It is disabled when android
AVB is enabled, because AVB need verify the full android image.

It brings some benefits, mainly for saving a lot of boot time:
  - allow skip load second content when kernel dtb is enabled;
  - allow skip fdt and ramdisk relocation during bootm boot flow;
  - allow loading fdt/ramdisk to "fdt_addr_r"/"ramdisk_addr_r";
  - avoid android image too large when load to ram;

Change-Id: Ia040b3031307a8a7c98b011ce038ec61fee6804a
Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
This commit is contained in:
Joseph Chen 2019-01-23 16:30:16 +08:00 committed by Kever Yang
parent 2280fbdd62
commit 644e344181
3 changed files with 191 additions and 46 deletions

View File

@ -623,6 +623,15 @@ config ANDROID_BOOT_IMAGE
This enables support for booting images which use the Android
image format header.
config ANDROID_BOOT_IMAGE_SEPARATE
bool "Enable support for Android image separate loading"
depends on ANDROID_BOOT_IMAGE
default y
help
This enables support for android image separate loading. With this support,
we can load ramdisk/fdt/kernel separate and skip ramdisk and fdt relocation
safely. It saves a lot of boot time.
config SKIP_RELOCATE_UBOOT
bool "Skip U-Boot relocation"
help

View File

@ -22,6 +22,7 @@
#include <keymaster.h>
#include <linux/libfdt_env.h>
#include <optee_include/OpteeClientInterface.h>
#include <sysmem.h>
#define ANDROID_PARTITION_BOOT "boot"
#define ANDROID_PARTITION_MISC "misc"
@ -331,6 +332,8 @@ int android_bootloader_boot_kernel(unsigned long kernel_address)
printf("Booting kernel at %s with fdt at %s...\n\n\n",
kernel_addr_r, fdt_addr);
sysmem_dump_check();
do_bootm(NULL, 0, 4, bootm_args);
return -1;
@ -802,7 +805,16 @@ int android_fdt_overlay_apply(void *fdt_addr)
ret = android_get_dtbo(&fdt_dtbo, (void *)hdr, &index);
if (!ret) {
phys_size_t fdt_size;
/* Must incease size before overlay */
fdt_size = fdt_totalsize((void *)fdt_addr) +
fdt_totalsize((void *)fdt_dtbo);
if (sysmem_free((phys_addr_t)fdt_addr))
goto out;
if (!sysmem_alloc_base("fdt(dtbo)",
(phys_addr_t)fdt_addr,
fdt_size))
goto out;
fdt_increase_size(fdt_addr, fdt_totalsize((void *)fdt_dtbo));
ret = fdt_overlay_apply(fdt_addr, (void *)fdt_dtbo);
if (!ret) {
@ -842,8 +854,8 @@ static int load_android_image(struct blk_desc *dev_desc,
ret = android_image_load(dev_desc, &boot_part, *load_address, -1UL);
if (ret < 0) {
printf("%s: %s part load fail, ret=%d\n",
__func__, boot_part.name, ret);
debug("%s: %s part load fail, ret=%d\n",
__func__, boot_part.name, ret);
return ret;
}
*load_address = ret;

View File

@ -10,9 +10,17 @@
#include <malloc.h>
#include <mapmem.h>
#include <errno.h>
#include <boot_rkimg.h>
#include <sysmem.h>
#ifdef CONFIG_RKIMG_BOOTLOADER
#include <asm/arch/resource_img.h>
#endif
#ifdef CONFIG_RK_AVB_LIBAVB_USER
#include <android_avb/avb_slot_verify.h>
#include <android_avb/avb_ops_user.h>
#include <android_avb/rk_avb_ops_user.h>
#endif
#include <optee_include/OpteeClientInterface.h>
DECLARE_GLOBAL_DATA_PTR;
@ -29,7 +37,7 @@ static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr)
* address as the default.
*
* Even though it doesn't really make a lot of sense, and it
* might be valid on some platforms, we treat that adress as
* might be valid on some platforms, we treat that address as
* the default value for this field, and try to execute the
* kernel in place in such a case.
*
@ -190,9 +198,25 @@ int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
return -1;
}
/*
* We load ramdisk at "ramdisk_addr_r" when CONFIG_ANDROID_BOOT_IMAGE_SEPARATE
* CONFIG_USING_KERNEL_DTB is enabled.
*/
#ifdef CONFIG_ANDROID_BOOT_IMAGE_SEPARATE
ulong ramdisk_addr_r;
ramdisk_addr_r = env_get_ulong("ramdisk_addr_r", 16, 0);
if (!ramdisk_addr_r) {
printf("No Found Ramdisk Load Address.\n");
return -1;
}
*rd_data = ramdisk_addr_r;
#else
*rd_data = (unsigned long)hdr;
*rd_data += hdr->page_size;
*rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
#endif
*rd_len = hdr->ramdisk_size;
printf("RAM disk load addr 0x%08lx size %u KiB\n",
@ -209,65 +233,123 @@ int android_image_get_fdt(const struct andr_img_hdr *hdr,
return -1;
}
/*
* If kernel dtb is enabled, it means we have read kernel dtb before do_bootm(),
* that's: init_kernel_dtb() -> rockchip_read_dtb_file().
* And maybe some operations(optional) are done:
*
* 1. apply fdt overlay;
* 2. select fdt by adc or gpio;
*
* After that, we didn't update dtb at all untill run here, it's fine to
* pass current fdt to kernel.
*
* This case has higher priority then the others(#elif, #else...).
* We load fdt at "fdt_addr_r" when CONFIG_ANDROID_BOOT_IMAGE_SEPARATE or
* or CONFIG_USING_KERNEL_DTB is enabled.
*/
#if defined(CONFIG_USING_KERNEL_DTB)
*rd_data = (ulong)gd->fdt_blob;
#if defined(CONFIG_ANDROID_BOOT_IMAGE_SEPARATE) || \
defined(CONFIG_USING_KERNEL_DTB)
ulong fdt_addr_r;
/*
* If kernel dtb is disabled, it means kernel dtb is not read before do_bootm(),
* we need to read it from boot.img/recovery.img now.
*
* For rockchip AOSP firmware(CONFIG_RKIMG_BOOTLOADER), we pack resource.img in
* second position. we need read kernel dtb by rockchip_read_dtb_file() which
* can do the above "some operations(optional)".
*/
#elif defined(CONFIG_RKIMG_BOOTLOADER)
ulong fdt_addr = 0;
int ret;
/* Get resource addr and fdt addr */
fdt_addr = env_get_ulong("fdt_addr_r", 16, 0);
if (!fdt_addr) {
fdt_addr_r = env_get_ulong("fdt_addr_r", 16, 0);
if (!fdt_addr_r) {
printf("No Found FDT Load Address.\n");
return -1;
}
ret = rockchip_read_dtb_file((void *)fdt_addr);
if (ret < 0) {
printf("%s: failed to read dtb file, ret=%d\n", __func__, ret);
return ret;
}
*rd_data = fdt_addr;
/*
* If kernel dtb is disabled and it's not rockchip AOSP firmware, kernel dtb is
* in second position, let't read it directly.
*/
*rd_data = fdt_addr_r;
#else
*rd_data = (unsigned long)hdr;
*rd_data += hdr->page_size;
*rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
*rd_data += ALIGN(hdr->ramdisk_size, hdr->page_size);
#endif
printf("FDT load addr 0x%08x size %u KiB\n",
hdr->second_addr, DIV_ROUND_UP(hdr->second_size, 1024));
#endif
return 0;
}
#ifdef CONFIG_ANDROID_BOOT_IMAGE_SEPARATE
static int android_image_load_separate(struct blk_desc *dev_desc,
struct andr_img_hdr *hdr,
const disk_partition_t *part,
void *android_load_address)
{
ulong fdt_addr_r = env_get_ulong("fdt_addr_r", 16, 0);
ulong blk_start, blk_cnt, size;
int ret, blk_read = 0;
if (hdr->kernel_size) {
size = hdr->kernel_size + hdr->page_size;
blk_start = part->start;
blk_cnt = DIV_ROUND_UP(size, dev_desc->blksz);
if (!sysmem_alloc_base("kernel",
(phys_addr_t)android_load_address,
blk_cnt * dev_desc->blksz))
return -ENXIO;
ret = blk_dread(dev_desc, blk_start,
blk_cnt, android_load_address);
if (ret < 0) {
debug("%s: read kernel failed, ret=%d\n",
__func__, ret);
return ret;
}
blk_read += ret;
}
if (hdr->ramdisk_size) {
ulong ramdisk_addr_r = env_get_ulong("ramdisk_addr_r", 16, 0);
size = hdr->page_size + ALIGN(hdr->kernel_size, hdr->page_size);
blk_start = part->start + DIV_ROUND_UP(size, dev_desc->blksz);
blk_cnt = DIV_ROUND_UP(hdr->ramdisk_size, dev_desc->blksz);
if (!sysmem_alloc_base("ramdisk",
ramdisk_addr_r,
blk_cnt * dev_desc->blksz))
return -ENXIO;
ret = blk_dread(dev_desc, blk_start,
blk_cnt, (void *)ramdisk_addr_r);
if (ret < 0) {
debug("%s: read ramdisk failed, ret=%d\n",
__func__, ret);
return ret;
}
blk_read += ret;
}
if ((gd->fdt_blob != (void *)fdt_addr_r) && hdr->second_size) {
#ifdef CONFIG_RKIMG_BOOTLOADER
/* Rockchip AOSP, resource.img is in second position */
ulong fdt_size;
fdt_size = rockchip_read_dtb_file((void *)fdt_addr_r);
if (fdt_size < 0) {
printf("%s: read fdt failed\n", __func__);
return ret;
}
blk_read += DIV_ROUND_UP(fdt_size, dev_desc->blksz);
#else
/* Standard AOSP, dtb is in second position */
ulong blk_start, blk_cnt;
size = hdr->page_size +
ALIGN(hdr->kernel_size, hdr->page_size) +
ALIGN(hdr->ramdisk_size, hdr->page_size);
blk_start = part->start + DIV_ROUND_UP(size, dev_desc->blksz);
blk_cnt = DIV_ROUND_UP(hdr->second_size, dev_desc->blksz);
if (!sysmem_alloc_base("fdt(AOSP)",
fdt_addr_r,
blk_cnt * dev_desc->blksz))
return -ENXIO;
ret = blk_dread(dev_desc, blk_start, blk_cnt, (void *)fdt_addr_r);
if (ret < 0) {
debug("%s: read dtb failed, ret=%d\n", __func__, ret);
return ret;
}
blk_read += blk_cnt;
#endif /* CONFIG_RKIMG_BOOTLOADER */
}
return blk_read;
}
#endif /* CONFIG_ANDROID_BOOT_IMAGE_SEPARATE */
long android_image_load(struct blk_desc *dev_desc,
const disk_partition_t *part_info,
unsigned long load_address,
@ -279,6 +361,7 @@ long android_image_load(struct blk_desc *dev_desc,
u32 kload_addr;
u32 blkcnt;
struct andr_img_hdr *hdr;
__maybe_unused uint8_t vboot_flag = 0;
if (max_size < part_info->blksz)
return -1;
@ -333,8 +416,43 @@ long android_image_load(struct blk_desc *dev_desc,
} else {
debug("Loading Android Image (%lu blocks) to 0x%lx... ",
blk_cnt, load_address);
blk_read = blk_dread(dev_desc, part_info->start,
blk_cnt, buf);
#if defined(CONFIG_ANDROID_AVB) && defined(CONFIG_OPTEE_CLIENT)
if (trusty_read_vbootkey_enable_flag(&vboot_flag))
return -1;
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE_SEPARATE
if (!vboot_flag) {
char *fdt_high = env_get("fdt_high");
char *ramdisk_high = env_get("initrd_high");
blk_read =
android_image_load_separate(dev_desc, hdr,
part_info, buf);
if (blk_read > 0) {
if (!fdt_high) {
env_set_hex("fdt_high", -1UL);
printf("Fdt ");
}
if (!ramdisk_high) {
env_set_hex("initrd_high", -1UL);
printf("Ramdisk ");
}
if (!fdt_high || !ramdisk_high)
printf("skip relocation\n");
}
} else
#endif
{
if (!sysmem_alloc_base("android",
(phys_addr_t)buf,
blk_cnt * part_info->blksz))
return -ENXIO;
blk_read = blk_dread(dev_desc, part_info->start,
blk_cnt, buf);
}
}
/*
@ -354,10 +472,16 @@ long android_image_load(struct blk_desc *dev_desc,
free(hdr);
unmap_sysmem(buf);
#ifndef CONFIG_ANDROID_BOOT_IMAGE_SEPARATE
debug("%lu blocks read: %s\n",
blk_read, (blk_read == blk_cnt) ? "OK" : "ERROR");
if (blk_read != blk_cnt)
return -1;
#else
debug("%lu blocks read\n", blk_read);
if (blk_read < 0)
return blk_read;
#endif
return load_address;
}