Merge branch '2023-04-04-android-image-v3-v4-support'

To quote the author:
* This is based on Roman Stratiienko's work to support boot image header version 3 and 4.

* This supports the new boot image headers v3, v4 and bootconfig feature.
https://source.android.com/docs/core/architecture/bootloader/boot-image-header
https://source.android.com/docs/core/architecture/bootloader/implementing-bootconfig

- Tested on Amlogic Khadas vim3l, a reference board for Android Open Source Project
  https://www.khadas.com/vim3l

  And on AM625 Texas Instruments board with 5.10 linux kernel

Main changes :
- New partition : vendor boot, with a specific vendor ramdisk
- DTB is stored in the vendor boot partition
- The generic ramdisk is placed after the vendor ramdisk
- Bootconfig feature support

Here is a link to see the related android boot flow changes on KHADAS vim3l as an example:
https://gitlab.baylibre.com/baylibre/amlogic/atv/u-boot/-/commits/souajih/BootImagev4/
This commit is contained in:
Tom Rini 2023-04-05 10:40:05 -04:00
commit 25eeda170c
11 changed files with 1013 additions and 165 deletions

View file

@ -113,6 +113,10 @@ static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
const void *os_hdr;
#ifdef CONFIG_ANDROID_BOOT_IMAGE
const void *vendor_boot_img;
const void *boot_img;
#endif
bool ep_found = false;
int ret;
@ -181,14 +185,23 @@ static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc,
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
case IMAGE_FORMAT_ANDROID:
boot_img = os_hdr;
vendor_boot_img = NULL;
if (IS_ENABLED(CONFIG_CMD_ABOOTIMG)) {
boot_img = map_sysmem(get_abootimg_addr(), 0);
vendor_boot_img = map_sysmem(get_avendor_bootimg_addr(), 0);
}
images.os.type = IH_TYPE_KERNEL;
images.os.comp = android_image_get_kcomp(os_hdr);
images.os.comp = android_image_get_kcomp(boot_img, vendor_boot_img);
images.os.os = IH_OS_LINUX;
images.os.end = android_image_get_end(os_hdr);
images.os.load = android_image_get_kload(os_hdr);
images.os.end = android_image_get_end(boot_img, vendor_boot_img);
images.os.load = android_image_get_kload(boot_img, vendor_boot_img);
images.ep = images.os.load;
ep_found = true;
if (IS_ENABLED(CONFIG_CMD_ABOOTIMG)) {
unmap_sysmem(vendor_boot_img);
unmap_sysmem(boot_img);
}
break;
#endif
default:
@ -889,6 +902,10 @@ static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
int os_noffset;
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
const void *boot_img;
const void *vendor_boot_img;
#endif
img_addr = genimg_get_kernel_addr_fit(argc < 1 ? NULL : argv[0],
&fit_uname_config,
&fit_uname_kernel);
@ -964,10 +981,20 @@ static const void *boot_get_kernel(struct cmd_tbl *cmdtp, int flag, int argc,
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
case IMAGE_FORMAT_ANDROID:
boot_img = buf;
vendor_boot_img = NULL;
if (IS_ENABLED(CONFIG_CMD_ABOOTIMG)) {
boot_img = map_sysmem(get_abootimg_addr(), 0);
vendor_boot_img = map_sysmem(get_avendor_bootimg_addr(), 0);
}
printf("## Booting Android Image at 0x%08lx ...\n", img_addr);
if (android_image_get_kernel(buf, images->verify,
if (android_image_get_kernel(boot_img, vendor_boot_img, images->verify,
os_data, os_len))
return NULL;
if (IS_ENABLED(CONFIG_CMD_ABOOTIMG)) {
unmap_sysmem(vendor_boot_img);
unmap_sysmem(boot_img);
}
break;
#endif
default:

View file

@ -18,7 +18,193 @@
static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr)
static ulong checksum(const unsigned char *buffer, ulong size)
{
ulong sum = 0;
for (ulong i = 0; i < size; i++)
sum += buffer[i];
return sum;
}
static bool is_trailer_present(ulong bootconfig_end_addr)
{
return !strncmp((char *)(bootconfig_end_addr - BOOTCONFIG_MAGIC_SIZE),
BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_SIZE);
}
static ulong add_trailer(ulong bootconfig_start_addr, ulong bootconfig_size)
{
ulong end;
ulong sum;
if (!bootconfig_start_addr)
return -1;
if (!bootconfig_size)
return 0;
end = bootconfig_start_addr + bootconfig_size;
if (is_trailer_present(end))
return 0;
memcpy((void *)(end), &bootconfig_size, BOOTCONFIG_SIZE_SIZE);
sum = checksum((unsigned char *)bootconfig_start_addr, bootconfig_size);
memcpy((void *)(end + BOOTCONFIG_SIZE_SIZE), &sum,
BOOTCONFIG_CHECKSUM_SIZE);
memcpy((void *)(end + BOOTCONFIG_SIZE_SIZE + BOOTCONFIG_CHECKSUM_SIZE),
BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_SIZE);
return BOOTCONFIG_TRAILER_SIZE;
}
static void android_boot_image_v3_v4_parse_hdr(const struct andr_boot_img_hdr_v3 *hdr,
struct andr_image_data *data)
{
ulong end;
data->kcmdline = hdr->cmdline;
data->header_version = hdr->header_version;
data->ramdisk_ptr = env_get_ulong("ramdisk_addr_r", 16, 0);
/*
* The header takes a full page, the remaining components are aligned
* on page boundary.
*/
end = (ulong)hdr;
end += ANDR_GKI_PAGE_SIZE;
data->kernel_ptr = end;
data->kernel_size = hdr->kernel_size;
end += ALIGN(hdr->kernel_size, ANDR_GKI_PAGE_SIZE);
data->ramdisk_size = hdr->ramdisk_size;
data->boot_ramdisk_size = hdr->ramdisk_size;
end += ALIGN(hdr->ramdisk_size, ANDR_GKI_PAGE_SIZE);
if (hdr->header_version > 3)
end += ALIGN(hdr->signature_size, ANDR_GKI_PAGE_SIZE);
data->boot_img_total_size = end - (ulong)hdr;
}
static void android_vendor_boot_image_v3_v4_parse_hdr(const struct andr_vnd_boot_img_hdr
*hdr, struct andr_image_data *data)
{
ulong end;
/*
* The header takes a full page, the remaining components are aligned
* on page boundary.
*/
data->kcmdline_extra = hdr->cmdline;
data->tags_addr = hdr->tags_addr;
data->image_name = hdr->name;
data->kernel_addr = hdr->kernel_addr;
data->ramdisk_addr = hdr->ramdisk_addr;
data->dtb_load_addr = hdr->dtb_addr;
data->bootconfig_size = hdr->bootconfig_size;
end = (ulong)hdr;
end += hdr->page_size;
if (hdr->vendor_ramdisk_size) {
data->vendor_ramdisk_ptr = end;
data->vendor_ramdisk_size = hdr->vendor_ramdisk_size;
data->ramdisk_size += hdr->vendor_ramdisk_size;
end += ALIGN(hdr->vendor_ramdisk_size, hdr->page_size);
}
data->dtb_ptr = end;
data->dtb_size = hdr->dtb_size;
end += ALIGN(hdr->dtb_size, hdr->page_size);
end += ALIGN(hdr->vendor_ramdisk_table_size, hdr->page_size);
data->bootconfig_addr = end;
if (hdr->bootconfig_size) {
data->bootconfig_size += add_trailer(data->bootconfig_addr,
data->bootconfig_size);
data->ramdisk_size += data->bootconfig_size;
}
end += ALIGN(data->bootconfig_size, hdr->page_size);
data->vendor_boot_img_total_size = end - (ulong)hdr;
}
static void android_boot_image_v0_v1_v2_parse_hdr(const struct andr_boot_img_hdr_v0 *hdr,
struct andr_image_data *data)
{
ulong end;
data->image_name = hdr->name;
data->kcmdline = hdr->cmdline;
data->kernel_addr = hdr->kernel_addr;
data->ramdisk_addr = hdr->ramdisk_addr;
data->header_version = hdr->header_version;
data->dtb_load_addr = hdr->dtb_addr;
end = (ulong)hdr;
/*
* The header takes a full page, the remaining components are aligned
* on page boundary
*/
end += hdr->page_size;
data->kernel_ptr = end;
data->kernel_size = hdr->kernel_size;
end += ALIGN(hdr->kernel_size, hdr->page_size);
data->ramdisk_ptr = end;
data->ramdisk_size = hdr->ramdisk_size;
end += ALIGN(hdr->ramdisk_size, hdr->page_size);
data->second_ptr = end;
data->second_size = hdr->second_size;
end += ALIGN(hdr->second_size, hdr->page_size);
if (hdr->header_version >= 1) {
data->recovery_dtbo_ptr = end;
data->recovery_dtbo_size = hdr->recovery_dtbo_size;
end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
}
if (hdr->header_version >= 2) {
data->dtb_ptr = end;
data->dtb_size = hdr->dtb_size;
end += ALIGN(hdr->dtb_size, hdr->page_size);
}
data->boot_img_total_size = end - (ulong)hdr;
}
bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr,
struct andr_image_data *data)
{
if (!boot_hdr || !data) {
printf("boot_hdr or data params can't be NULL\n");
return false;
}
if (!is_android_boot_image_header(boot_hdr)) {
printf("Incorrect boot image header\n");
return false;
}
if (((struct andr_boot_img_hdr_v0 *)boot_hdr)->header_version > 2) {
if (!vendor_boot_hdr) {
printf("For boot header v3+ vendor boot image has to be provided\n");
return false;
}
if (!is_android_vendor_boot_image_header(vendor_boot_hdr)) {
printf("Incorrect vendor boot image header\n");
return false;
}
android_boot_image_v3_v4_parse_hdr(boot_hdr, data);
android_vendor_boot_image_v3_v4_parse_hdr(vendor_boot_hdr, data);
} else {
android_boot_image_v0_v1_v2_parse_hdr(boot_hdr, data);
}
return true;
}
static ulong android_image_get_kernel_addr(struct andr_image_data *img_data)
{
/*
* All the Android tools that generate a boot.img use this
@ -31,23 +217,25 @@ static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr)
*
* Otherwise, we will return the actual value set by the user.
*/
if (hdr->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR)
return (ulong)hdr + hdr->page_size;
if (img_data->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR)
return img_data->kernel_ptr;
/*
* abootimg creates images where all load addresses are 0
* and we need to fix them.
*/
if (hdr->kernel_addr == 0 && hdr->ramdisk_addr == 0)
if (img_data->kernel_addr == 0 && img_data->ramdisk_addr == 0)
return env_get_ulong("kernel_addr_r", 16, 0);
return hdr->kernel_addr;
return img_data->kernel_addr;
}
/**
* android_image_get_kernel() - processes kernel part of Android boot images
* @hdr: Pointer to image header, which is at the start
* @hdr: Pointer to boot image header, which is at the start
* of the image.
* @vendor_boot_img: Pointer to vendor boot image header, which is at the
* start of the image.
* @verify: Checksum verification flag. Currently unimplemented.
* @os_data: Pointer to a ulong variable, will hold os data start
* address.
@ -59,30 +247,42 @@ static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr)
* Return: Zero, os start address and length on success,
* otherwise on failure.
*/
int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
int android_image_get_kernel(const void *hdr,
const void *vendor_boot_img, int verify,
ulong *os_data, ulong *os_len)
{
u32 kernel_addr = android_image_get_kernel_addr(hdr);
const struct legacy_img_hdr *ihdr = (const struct legacy_img_hdr *)
((uintptr_t)hdr + hdr->page_size);
struct andr_image_data img_data = {0};
u32 kernel_addr;
const struct legacy_img_hdr *ihdr;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data))
return -EINVAL;
kernel_addr = android_image_get_kernel_addr(&img_data);
ihdr = (const struct legacy_img_hdr *)img_data.kernel_ptr;
/*
* Not all Android tools use the id field for signing the image with
* sha1 (or anything) so we don't check it. It is not obvious that the
* string is null terminated so we take care of this.
*/
strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
strlcpy(andr_tmp_str, img_data.image_name, ANDR_BOOT_NAME_SIZE);
andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
if (strlen(andr_tmp_str))
printf("Android's image name: %s\n", andr_tmp_str);
printf("Kernel load addr 0x%08x size %u KiB\n",
kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
kernel_addr, DIV_ROUND_UP(img_data.kernel_size, 1024));
int len = 0;
if (*hdr->cmdline) {
printf("Kernel command line: %s\n", hdr->cmdline);
len += strlen(hdr->cmdline);
if (*img_data.kcmdline) {
printf("Kernel command line: %s\n", img_data.kcmdline);
len += strlen(img_data.kcmdline);
}
if (img_data.kcmdline_extra) {
printf("Kernel extra command line: %s\n", img_data.kcmdline_extra);
len += strlen(img_data.kcmdline_extra);
}
char *bootargs = env_get("bootargs");
@ -100,8 +300,14 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
strcpy(newbootargs, bootargs);
strcat(newbootargs, " ");
}
if (*hdr->cmdline)
strcat(newbootargs, hdr->cmdline);
if (*img_data.kcmdline)
strcat(newbootargs, img_data.kcmdline);
if (img_data.kcmdline_extra) {
strcat(newbootargs, " ");
strcat(newbootargs, img_data.kcmdline_extra);
}
env_set("bootargs", newbootargs);
@ -109,56 +315,63 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
if (image_get_magic(ihdr) == IH_MAGIC) {
*os_data = image_get_data(ihdr);
} else {
*os_data = (ulong)hdr;
*os_data += hdr->page_size;
*os_data = img_data.kernel_ptr;
}
}
if (os_len) {
if (image_get_magic(ihdr) == IH_MAGIC)
*os_len = image_get_data_size(ihdr);
else
*os_len = hdr->kernel_size;
*os_len = img_data.kernel_size;
}
return 0;
}
int android_image_check_header(const struct andr_img_hdr *hdr)
bool is_android_vendor_boot_image_header(const void *vendor_boot_img)
{
return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE);
return !memcmp(VENDOR_BOOT_MAGIC, vendor_boot_img, ANDR_VENDOR_BOOT_MAGIC_SIZE);
}
ulong android_image_get_end(const struct andr_img_hdr *hdr)
bool is_android_boot_image_header(const void *hdr)
{
ulong end;
/*
* The header takes a full page, the remaining components are aligned
* on page boundary
*/
end = (ulong)hdr;
end += hdr->page_size;
end += ALIGN(hdr->kernel_size, hdr->page_size);
end += ALIGN(hdr->ramdisk_size, hdr->page_size);
end += ALIGN(hdr->second_size, hdr->page_size);
if (hdr->header_version >= 1)
end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
if (hdr->header_version >= 2)
end += ALIGN(hdr->dtb_size, hdr->page_size);
return end;
return !memcmp(ANDR_BOOT_MAGIC, hdr, ANDR_BOOT_MAGIC_SIZE);
}
ulong android_image_get_kload(const struct andr_img_hdr *hdr)
ulong android_image_get_end(const struct andr_boot_img_hdr_v0 *hdr,
const void *vendor_boot_img)
{
return android_image_get_kernel_addr(hdr);
struct andr_image_data img_data;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data))
return -EINVAL;
if (img_data.header_version > 2)
return 0;
return img_data.boot_img_total_size;
}
ulong android_image_get_kcomp(const struct andr_img_hdr *hdr)
ulong android_image_get_kload(const void *hdr,
const void *vendor_boot_img)
{
const void *p = (void *)((uintptr_t)hdr + hdr->page_size);
struct andr_image_data img_data;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data))
return -EINVAL;
return android_image_get_kernel_addr(&img_data);
}
ulong android_image_get_kcomp(const void *hdr,
const void *vendor_boot_img)
{
struct andr_image_data img_data;
const void *p;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data))
return -EINVAL;
p = (const void *)img_data.kernel_ptr;
if (image_get_magic((struct legacy_img_hdr *)p) == IH_MAGIC)
return image_get_comp((struct legacy_img_hdr *)p);
else if (get_unaligned_le32(p) == LZ4F_MAGIC)
@ -167,41 +380,66 @@ ulong android_image_get_kcomp(const struct andr_img_hdr *hdr)
return image_decomp_type(p, sizeof(u32));
}
int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img,
ulong *rd_data, ulong *rd_len)
{
if (!hdr->ramdisk_size) {
struct andr_image_data img_data = {0};
ulong ramdisk_ptr;
if (!android_image_get_data(hdr, vendor_boot_img, &img_data))
return -EINVAL;
if (!img_data.ramdisk_size) {
*rd_data = *rd_len = 0;
return -1;
}
if (img_data.header_version > 2) {
ramdisk_ptr = img_data.ramdisk_ptr;
memcpy((void *)(ramdisk_ptr), (void *)img_data.vendor_ramdisk_ptr,
img_data.vendor_ramdisk_size);
memcpy((void *)(ramdisk_ptr + img_data.vendor_ramdisk_size),
(void *)img_data.ramdisk_ptr,
img_data.boot_ramdisk_size);
if (img_data.bootconfig_size) {
memcpy((void *)
(ramdisk_ptr + img_data.vendor_ramdisk_size +
img_data.boot_ramdisk_size),
(void *)img_data.bootconfig_addr,
img_data.bootconfig_size);
}
}
printf("RAM disk load addr 0x%08x size %u KiB\n",
hdr->ramdisk_addr, DIV_ROUND_UP(hdr->ramdisk_size, 1024));
printf("RAM disk load addr 0x%08lx size %u KiB\n",
img_data.ramdisk_ptr, DIV_ROUND_UP(img_data.ramdisk_size, 1024));
*rd_data = (unsigned long)hdr;
*rd_data += hdr->page_size;
*rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
*rd_data = img_data.ramdisk_ptr;
*rd_len = hdr->ramdisk_size;
*rd_len = img_data.ramdisk_size;
return 0;
}
int android_image_get_second(const struct andr_img_hdr *hdr,
ulong *second_data, ulong *second_len)
int android_image_get_second(const void *hdr, ulong *second_data, ulong *second_len)
{
if (!hdr->second_size) {
struct andr_image_data img_data;
if (!android_image_get_data(hdr, NULL, &img_data))
return -EINVAL;
if (img_data.header_version > 2) {
printf("Second stage bootloader is only supported for boot image version <= 2\n");
return -EOPNOTSUPP;
}
if (!img_data.second_size) {
*second_data = *second_len = 0;
return -1;
}
*second_data = (unsigned long)hdr;
*second_data += hdr->page_size;
*second_data += ALIGN(hdr->kernel_size, hdr->page_size);
*second_data += ALIGN(hdr->ramdisk_size, hdr->page_size);
*second_data = img_data.second_ptr;
printf("second address is 0x%lx\n",*second_data);
*second_len = hdr->second_size;
*second_len = img_data.second_size;
return 0;
}
@ -226,19 +464,19 @@ int android_image_get_second(const struct andr_img_hdr *hdr,
*/
bool android_image_get_dtbo(ulong hdr_addr, ulong *addr, u32 *size)
{
const struct andr_img_hdr *hdr;
const struct andr_boot_img_hdr_v0 *hdr;
ulong dtbo_img_addr;
bool ret = true;
hdr = map_sysmem(hdr_addr, sizeof(*hdr));
if (android_image_check_header(hdr)) {
if (!is_android_boot_image_header(hdr)) {
printf("Error: Boot Image header is incorrect\n");
ret = false;
goto exit;
}
if (hdr->header_version < 1) {
printf("Error: header_version must be >= 1 to get dtbo\n");
if (hdr->header_version != 1 && hdr->header_version != 2) {
printf("Error: header version must be >= 1 and <= 2 to get dtbo\n");
ret = false;
goto exit;
}
@ -269,18 +507,20 @@ exit:
/**
* android_image_get_dtb_img_addr() - Get the address of DTB area in boot image.
* @hdr_addr: Boot image header address
* @vhdr_addr: Vendor Boot image header address
* @addr: Will contain the address of DTB area in boot image
*
* Return: true on success or false on fail.
*/
static bool android_image_get_dtb_img_addr(ulong hdr_addr, ulong *addr)
static bool android_image_get_dtb_img_addr(ulong hdr_addr, ulong vhdr_addr, ulong *addr)
{
const struct andr_img_hdr *hdr;
const struct andr_boot_img_hdr_v0 *hdr;
const struct andr_vnd_boot_img_hdr *v_hdr;
ulong dtb_img_addr;
bool ret = true;
hdr = map_sysmem(hdr_addr, sizeof(*hdr));
if (android_image_check_header(hdr)) {
if (!is_android_boot_image_header(hdr)) {
printf("Error: Boot Image header is incorrect\n");
ret = false;
goto exit;
@ -292,22 +532,40 @@ static bool android_image_get_dtb_img_addr(ulong hdr_addr, ulong *addr)
goto exit;
}
if (hdr->dtb_size == 0) {
printf("Error: dtb_size is 0\n");
ret = false;
goto exit;
if (hdr->header_version == 2) {
if (!hdr->dtb_size) {
printf("Error: dtb_size is 0\n");
ret = false;
goto exit;
}
/* Calculate the address of DTB area in boot image */
dtb_img_addr = hdr_addr;
dtb_img_addr += hdr->page_size;
dtb_img_addr += ALIGN(hdr->kernel_size, hdr->page_size);
dtb_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size);
dtb_img_addr += ALIGN(hdr->second_size, hdr->page_size);
dtb_img_addr += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
*addr = dtb_img_addr;
}
/* Calculate the address of DTB area in boot image */
dtb_img_addr = hdr_addr;
dtb_img_addr += hdr->page_size;
dtb_img_addr += ALIGN(hdr->kernel_size, hdr->page_size);
dtb_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size);
dtb_img_addr += ALIGN(hdr->second_size, hdr->page_size);
dtb_img_addr += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
*addr = dtb_img_addr;
if (hdr->header_version > 2) {
v_hdr = map_sysmem(vhdr_addr, sizeof(*v_hdr));
if (!v_hdr->dtb_size) {
printf("Error: dtb_size is 0\n");
ret = false;
unmap_sysmem(v_hdr);
goto exit;
}
/* Calculate the address of DTB area in boot image */
dtb_img_addr = vhdr_addr;
dtb_img_addr += v_hdr->page_size;
if (v_hdr->vendor_ramdisk_size)
dtb_img_addr += ALIGN(v_hdr->vendor_ramdisk_size, v_hdr->page_size);
*addr = dtb_img_addr;
unmap_sysmem(v_hdr);
goto exit;
}
exit:
unmap_sysmem(hdr);
return ret;
@ -316,6 +574,7 @@ exit:
/**
* android_image_get_dtb_by_index() - Get address and size of blob in DTB area.
* @hdr_addr: Boot image header address
* @vendor_boot_img: Pointer to vendor boot image header, which is at the start of the image.
* @index: Index of desired DTB in DTB area (starting from 0)
* @addr: If not NULL, will contain address to specified DTB
* @size: If not NULL, will contain size of specified DTB
@ -325,20 +584,32 @@ exit:
*
* Return: true on success or false on error.
*/
bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr,
u32 *size)
bool android_image_get_dtb_by_index(ulong hdr_addr, ulong vendor_boot_img,
u32 index, ulong *addr, u32 *size)
{
const struct andr_img_hdr *hdr;
bool res;
struct andr_image_data img_data;
const struct andr_boot_img_hdr_v0 *hdr;
const struct andr_vnd_boot_img_hdr *vhdr;
hdr = map_sysmem(hdr_addr, sizeof(*hdr));
if (vendor_boot_img != -1)
vhdr = map_sysmem(vendor_boot_img, sizeof(*vhdr));
if (!android_image_get_data(hdr, vhdr, &img_data)) {
if (vendor_boot_img != -1)
unmap_sysmem(vhdr);
unmap_sysmem(hdr);
return false;
}
if (vendor_boot_img != -1)
unmap_sysmem(vhdr);
unmap_sysmem(hdr);
ulong dtb_img_addr; /* address of DTB part in boot image */
u32 dtb_img_size; /* size of DTB payload in boot image */
ulong dtb_addr; /* address of DTB blob with specified index */
u32 i; /* index iterator */
res = android_image_get_dtb_img_addr(hdr_addr, &dtb_img_addr);
if (!res)
return false;
android_image_get_dtb_img_addr(hdr_addr, vendor_boot_img, &dtb_img_addr);
/* Check if DTB area of boot image is in DTBO format */
if (android_dt_check_header(dtb_img_addr)) {
return android_dt_get_fdt_by_index(dtb_img_addr, index, addr,
@ -346,9 +617,7 @@ bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr,
}
/* Find out the address of DTB with specified index in concat blobs */
hdr = map_sysmem(hdr_addr, sizeof(*hdr));
dtb_img_size = hdr->dtb_size;
unmap_sysmem(hdr);
dtb_img_size = img_data.dtb_size;
i = 0;
dtb_addr = dtb_img_addr;
while (dtb_addr < dtb_img_addr + dtb_img_size) {
@ -393,8 +662,12 @@ bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr,
* returns:
* no returned results
*/
void android_print_contents(const struct andr_img_hdr *hdr)
void android_print_contents(const struct andr_boot_img_hdr_v0 *hdr)
{
if (hdr->header_version >= 3) {
printf("Content print is not supported for boot image header version > 2");
return;
}
const char * const p = IMAGE_INDENT_STRING;
/* os_version = ver << 11 | lvl */
u32 os_ver = hdr->os_version >> 11;
@ -427,7 +700,7 @@ void android_print_contents(const struct andr_img_hdr *hdr)
hdr->header_size);
}
if (hdr->header_version >= 2) {
if (hdr->header_version == 2) {
printf("%sdtb size: %x\n", p, hdr->dtb_size);
printf("%sdtb addr: %llx\n", p, hdr->dtb_addr);
}
@ -485,14 +758,14 @@ static bool android_image_print_dtb_info(const struct fdt_header *fdt,
*/
bool android_image_print_dtb_contents(ulong hdr_addr)
{
const struct andr_img_hdr *hdr;
const struct andr_boot_img_hdr_v0 *hdr;
bool res;
ulong dtb_img_addr; /* address of DTB part in boot image */
u32 dtb_img_size; /* size of DTB payload in boot image */
ulong dtb_addr; /* address of DTB blob with specified index */
u32 i; /* index iterator */
res = android_image_get_dtb_img_addr(hdr_addr, &dtb_img_addr);
res = android_image_get_dtb_img_addr(hdr_addr, 0, &dtb_img_addr);
if (!res)
return false;

View file

@ -284,7 +284,7 @@ int genimg_get_format(const void *img_addr)
return IMAGE_FORMAT_FIT;
}
if (IS_ENABLED(CONFIG_ANDROID_BOOT_IMAGE) &&
!android_image_check_header(img_addr))
is_android_boot_image_header(img_addr))
return IMAGE_FORMAT_ANDROID;
return IMAGE_FORMAT_INVALID;
@ -426,11 +426,22 @@ static int select_ramdisk(struct bootm_headers *images, const char *select, u8 a
break;
case IMAGE_FORMAT_ANDROID:
if (IS_ENABLED(CONFIG_ANDROID_BOOT_IMAGE)) {
void *ptr = map_sysmem(images->os.start, 0);
int ret;
if (IS_ENABLED(CONFIG_CMD_ABOOTIMG)) {
void *boot_img = map_sysmem(get_abootimg_addr(), 0);
void *vendor_boot_img = map_sysmem(get_avendor_bootimg_addr(), 0);
ret = android_image_get_ramdisk(boot_img, vendor_boot_img,
rd_datap, rd_lenp);
unmap_sysmem(vendor_boot_img);
unmap_sysmem(boot_img);
} else {
void *ptr = map_sysmem(images->os.start, 0);
ret = android_image_get_ramdisk(ptr, NULL, rd_datap, rd_lenp);
unmap_sysmem(ptr);
}
ret = android_image_get_ramdisk(ptr, rd_datap, rd_lenp);
unmap_sysmem(ptr);
if (ret)
return ret;
done = true;

View file

@ -529,14 +529,15 @@ int boot_get_fdt(int flag, int argc, char *const argv[], uint8_t arch,
}
#ifdef CONFIG_ANDROID_BOOT_IMAGE
} else if (genimg_get_format(buf) == IMAGE_FORMAT_ANDROID) {
struct andr_img_hdr *hdr = buf;
void *hdr = buf;
ulong fdt_data, fdt_len;
u32 fdt_size, dtb_idx;
/*
* Firstly check if this android boot image has dtb field.
*/
dtb_idx = (u32)env_get_ulong("adtb_idx", 10, 0);
if (android_image_get_dtb_by_index((ulong)hdr, dtb_idx, &fdt_addr, &fdt_size)) {
if (android_image_get_dtb_by_index((ulong)hdr, 0,
dtb_idx, &fdt_addr, &fdt_size)) {
fdt_blob = (char *)map_sysmem(fdt_addr, 0);
if (fdt_check_header(fdt_blob))
goto no_fdt;

View file

@ -15,17 +15,28 @@
/* Please use abootimg_addr() macro to obtain the boot image address */
static ulong _abootimg_addr = -1;
static ulong _avendor_bootimg_addr = -1;
ulong get_abootimg_addr(void)
{
return (_abootimg_addr == -1 ? image_load_addr : _abootimg_addr);
}
ulong get_avendor_bootimg_addr(void)
{
return _avendor_bootimg_addr;
}
static int abootimg_get_ver(int argc, char *const argv[])
{
const struct andr_img_hdr *hdr;
const struct andr_boot_img_hdr_v0 *hdr;
int res = CMD_RET_SUCCESS;
if (argc > 1)
return CMD_RET_USAGE;
hdr = map_sysmem(abootimg_addr(), sizeof(*hdr));
if (android_image_check_header(hdr)) {
if (!is_android_boot_image_header(hdr)) {
printf("Error: Boot Image header is incorrect\n");
res = CMD_RET_FAILURE;
goto exit;
@ -65,33 +76,43 @@ static int abootimg_get_recovery_dtbo(int argc, char *const argv[])
static int abootimg_get_dtb_load_addr(int argc, char *const argv[])
{
const struct andr_img_hdr *hdr;
int res = CMD_RET_SUCCESS;
if (argc > 1)
return CMD_RET_USAGE;
struct andr_image_data img_data = {0};
const struct andr_boot_img_hdr_v0 *hdr;
const struct andr_vnd_boot_img_hdr *vhdr;
hdr = map_sysmem(abootimg_addr(), sizeof(*hdr));
if (android_image_check_header(hdr)) {
printf("Error: Boot Image header is incorrect\n");
res = CMD_RET_FAILURE;
goto exit;
if (get_avendor_bootimg_addr() != -1)
vhdr = map_sysmem(get_avendor_bootimg_addr(), sizeof(*vhdr));
if (!android_image_get_data(hdr, vhdr, &img_data)) {
if (get_avendor_bootimg_addr() != -1)
unmap_sysmem(vhdr);
unmap_sysmem(hdr);
return CMD_RET_FAILURE;
}
if (hdr->header_version < 2) {
if (get_avendor_bootimg_addr() != -1)
unmap_sysmem(vhdr);
unmap_sysmem(hdr);
if (img_data.header_version < 2) {
printf("Error: header_version must be >= 2 for this\n");
res = CMD_RET_FAILURE;
goto exit;
return CMD_RET_FAILURE;
}
if (!img_data.dtb_load_addr) {
printf("Error: failed to read dtb_load_addr\n");
return CMD_RET_FAILURE;
}
if (argc == 0)
printf("%lx\n", (ulong)hdr->dtb_addr);
printf("%lx\n", (ulong)img_data.dtb_load_addr);
else
env_set_hex(argv[0], (ulong)hdr->dtb_addr);
env_set_hex(argv[0], (ulong)img_data.dtb_load_addr);
exit:
unmap_sysmem(hdr);
return res;
return CMD_RET_SUCCESS;
}
static int abootimg_get_dtb_by_index(int argc, char *const argv[])
@ -117,7 +138,8 @@ static int abootimg_get_dtb_by_index(int argc, char *const argv[])
return CMD_RET_FAILURE;
}
if (!android_image_get_dtb_by_index(abootimg_addr(), num,
if (!android_image_get_dtb_by_index(abootimg_addr(),
get_avendor_bootimg_addr(), num,
&addr, &size)) {
return CMD_RET_FAILURE;
}
@ -158,7 +180,7 @@ static int do_abootimg_addr(struct cmd_tbl *cmdtp, int flag, int argc,
char *endp;
ulong img_addr;
if (argc != 2)
if (argc < 2 || argc > 3)
return CMD_RET_USAGE;
img_addr = hextoul(argv[1], &endp);
@ -168,6 +190,17 @@ static int do_abootimg_addr(struct cmd_tbl *cmdtp, int flag, int argc,
}
_abootimg_addr = img_addr;
if (argc == 3) {
img_addr = simple_strtoul(argv[2], &endp, 16);
if (*endp != '\0') {
printf("Error: Wrong vendor image address\n");
return CMD_RET_FAILURE;
}
_avendor_bootimg_addr = img_addr;
}
return CMD_RET_SUCCESS;
}
@ -211,7 +244,7 @@ static int do_abootimg_dump(struct cmd_tbl *cmdtp, int flag, int argc,
}
static struct cmd_tbl cmd_abootimg_sub[] = {
U_BOOT_CMD_MKENT(addr, 2, 1, do_abootimg_addr, "", ""),
U_BOOT_CMD_MKENT(addr, 3, 1, do_abootimg_addr, "", ""),
U_BOOT_CMD_MKENT(dump, 2, 1, do_abootimg_dump, "", ""),
U_BOOT_CMD_MKENT(get, 5, 1, do_abootimg_get, "", ""),
};
@ -239,7 +272,7 @@ static int do_abootimg(struct cmd_tbl *cmdtp, int flag, int argc,
U_BOOT_CMD(
abootimg, CONFIG_SYS_MAXARGS, 0, do_abootimg,
"manipulate Android Boot Image",
"addr <addr>\n"
"addr <boot_img_addr> [<vendor_boot_img_addr>]>\n"
" - set the address in RAM where boot image is located\n"
" ($loadaddr is used by default)\n"
"abootimg dump dtb\n"

View file

@ -27,11 +27,21 @@ next image headers:
* v2: used in devices launched with Android 10; adds ``dtb`` field, which
references payload containing DTB blobs (either concatenated one after the
other, or in Android DTBO image format)
* v3: used in devices launched with Android 11; adds ``vendor_boot`` partition
and removes the second-stage bootloader and recovery image support. The new
``vendor_boot`` partition holds the device tree blob (DTB) and a vendor ramdisk.
The generic ramdisk in ``boot`` partition is loaded immediately following
the vendor ramdisk.
* v4: used in devices launched with Android 12; provides a boot signature in boot
image header, supports multiple vendor ramdisk fragments in ``vendor_boot``
partition. This version also adds a bootconfig section at the end of the vendor
boot image, this section contains boot configuration parameters known at build time
(see [9]_ for details).
v2, v1 and v0 formats are backward compatible.
The Android Boot Image format is represented by
:c:type:`struct andr_img_hdr <andr_img_hdr>` in U-Boot, and can be seen in
:c:type:`struct andr_image_data <andr_image_data>` in U-Boot, and can be seen in
``include/android_image.h``. U-Boot supports booting Android Boot Image and also
has associated command
@ -153,3 +163,4 @@ References
.. [6] :doc:`avb2`
.. [7] https://source.android.com/devices/bootloader
.. [8] https://connect.linaro.org/resources/san19/san19-217/
.. [9] https://source.android.com/docs/core/architecture/bootloader/implementing-bootconfig

View file

@ -287,7 +287,7 @@ static void fb_mmc_boot_ops(struct blk_desc *dev_desc, void *buffer,
*/
static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc,
struct disk_partition *info,
struct andr_img_hdr *hdr,
struct andr_boot_img_hdr_v0 *hdr,
char *response)
{
ulong sector_size; /* boot partition sector size */
@ -296,7 +296,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc,
/* Calculate boot image sectors count */
sector_size = info->blksz;
hdr_sectors = DIV_ROUND_UP(sizeof(struct andr_img_hdr), sector_size);
hdr_sectors = DIV_ROUND_UP(sizeof(struct andr_boot_img_hdr_v0), sector_size);
if (hdr_sectors == 0) {
pr_err("invalid number of boot sectors: 0\n");
fastboot_fail("invalid number of boot sectors: 0", response);
@ -313,8 +313,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc,
}
/* Check boot header magic string */
res = android_image_check_header(hdr);
if (res != 0) {
if (!is_android_boot_image_header(hdr)) {
pr_err("bad boot image magic\n");
fastboot_fail("boot partition not initialized", response);
return 0;
@ -338,7 +337,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc,
char *response)
{
uintptr_t hdr_addr; /* boot image header address */
struct andr_img_hdr *hdr; /* boot image header */
struct andr_boot_img_hdr_v0 *hdr; /* boot image header */
lbaint_t hdr_sectors; /* boot image header sectors */
u8 *ramdisk_buffer;
u32 ramdisk_sector_start;
@ -361,7 +360,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc,
/* Put boot image header in fastboot buffer after downloaded zImage */
hdr_addr = (uintptr_t)download_buffer + ALIGN(download_bytes, PAGE_SIZE);
hdr = (struct andr_img_hdr *)hdr_addr;
hdr = (struct andr_boot_img_hdr_v0 *)hdr_addr;
/* Read boot image header */
hdr_sectors = fb_mmc_get_boot_header(dev_desc, &info, hdr, response);
@ -371,6 +370,14 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc,
return -1;
}
/* Check if boot image header version is 2 or less */
if (hdr->header_version > 2) {
pr_err("zImage flashing supported only for boot images v2 and less\n");
fastboot_fail("zImage flashing supported only for boot images v2 and less",
response);
return -EOPNOTSUPP;
}
/* Check if boot image has second stage in it (we don't support it) */
if (hdr->second_size > 0) {
pr_err("moving second stage is not supported yet\n");

View file

@ -3,7 +3,7 @@
* This is from the Android Project,
* Repository: https://android.googlesource.com/platform/system/tools/mkbootimg
* File: include/bootimg/bootimg.h
* Commit: e55998a0f2b61b685d5eb4a486ca3a0c680b1a2f
* Commit: cce5b1923e3cd2fcb765b512610bdc5c42bc501d
*
* Copyright (C) 2007 The Android Open Source Project
*/
@ -14,15 +14,70 @@
#include <linux/compiler.h>
#include <linux/types.h>
#define ANDR_GKI_PAGE_SIZE 4096
#define ANDR_BOOT_MAGIC "ANDROID!"
#define ANDR_BOOT_MAGIC_SIZE 8
#define ANDR_BOOT_NAME_SIZE 16
#define ANDR_BOOT_ARGS_SIZE 512
#define ANDR_BOOT_EXTRA_ARGS_SIZE 1024
#define VENDOR_BOOT_MAGIC "VNDRBOOT"
#define ANDR_VENDOR_BOOT_MAGIC_SIZE 8
#define ANDR_VENDOR_BOOT_ARGS_SIZE 2048
#define ANDR_VENDOR_BOOT_NAME_SIZE 16
/* The bootloader expects the structure of andr_img_hdr with header
#define BOOTCONFIG_MAGIC "#BOOTCONFIG\n"
#define BOOTCONFIG_MAGIC_SIZE 12
#define BOOTCONFIG_SIZE_SIZE 4
#define BOOTCONFIG_CHECKSUM_SIZE 4
#define BOOTCONFIG_TRAILER_SIZE BOOTCONFIG_MAGIC_SIZE + \
BOOTCONFIG_SIZE_SIZE + \
BOOTCONFIG_CHECKSUM_SIZE
struct andr_boot_img_hdr_v3 {
u8 magic[ANDR_BOOT_MAGIC_SIZE];
u32 kernel_size; /* size in bytes */
u32 ramdisk_size; /* size in bytes */
u32 os_version;
u32 header_size; /* size of boot image header in bytes */
u32 reserved[4];
u32 header_version; /* offset remains constant for version check */
u8 cmdline[ANDR_BOOT_ARGS_SIZE + ANDR_BOOT_EXTRA_ARGS_SIZE];
/* for boot image header v4 only */
u32 signature_size; /* size in bytes */
};
struct andr_vnd_boot_img_hdr {
u8 magic[ANDR_VENDOR_BOOT_MAGIC_SIZE];
u32 header_version;
u32 page_size; /* flash page size we assume */
u32 kernel_addr; /* physical load addr */
u32 ramdisk_addr; /* physical load addr */
u32 vendor_ramdisk_size; /* size in bytes */
u8 cmdline[ANDR_VENDOR_BOOT_ARGS_SIZE];
u32 tags_addr; /* physical addr for kernel tags */
u8 name[ANDR_VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */
u32 header_size; /* size of vendor boot image header in bytes */
u32 dtb_size; /* size of dtb image */
u64 dtb_addr; /* physical load address */
/* for boot image header v4 only */
u32 vendor_ramdisk_table_size; /* size in bytes for the vendor ramdisk table */
u32 vendor_ramdisk_table_entry_num; /* number of entries in the vendor ramdisk table */
u32 vendor_ramdisk_table_entry_size; /* size in bytes for a vendor ramdisk table entry */
u32 bootconfig_size; /* size in bytes for the bootconfig section */
};
/* The bootloader expects the structure of andr_boot_img_hdr_v0 with header
* version 0 to be as follows: */
struct andr_img_hdr {
struct andr_boot_img_hdr_v0 {
/* Must be ANDR_BOOT_MAGIC. */
char magic[ANDR_BOOT_MAGIC_SIZE];
@ -136,4 +191,171 @@ 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
*/
/* When the boot image header has a version of 4, the structure of the boot
* image is as follows:
*
* +---------------------+
* | boot header | 4096 bytes
* +---------------------+
* | kernel | m pages
* +---------------------+
* | ramdisk | n pages
* +---------------------+
* | boot signature | g pages
* +---------------------+
*
* m = (kernel_size + 4096 - 1) / 4096
* n = (ramdisk_size + 4096 - 1) / 4096
* g = (signature_size + 4096 - 1) / 4096
*
* Note that in version 4 of the boot image header, page size is fixed at 4096
* bytes.
*
* The structure of the vendor boot image version 4, which is required to be
* present when a version 4 boot image is used, is as follows:
*
* +------------------------+
* | vendor boot header | o pages
* +------------------------+
* | vendor ramdisk section | p pages
* +------------------------+
* | dtb | q pages
* +------------------------+
* | vendor ramdisk table | r pages
* +------------------------+
* | bootconfig | s pages
* +------------------------+
*
* o = (2128 + page_size - 1) / page_size
* p = (vendor_ramdisk_size + page_size - 1) / page_size
* q = (dtb_size + page_size - 1) / page_size
* r = (vendor_ramdisk_table_size + page_size - 1) / page_size
* s = (vendor_bootconfig_size + page_size - 1) / page_size
*
* Note that in version 4 of the vendor boot image, multiple vendor ramdisks can
* be included in the vendor boot image. The bootloader can select a subset of
* ramdisks to load at runtime. To help the bootloader select the ramdisks, each
* ramdisk is tagged with a type tag and a set of hardware identifiers
* describing the board, soc or platform that this ramdisk is intended for.
*
* The vendor ramdisk section is consist of multiple ramdisk images concatenated
* one after another, and vendor_ramdisk_size is the size of the section, which
* is the total size of all the ramdisks included in the vendor boot image.
*
* The vendor ramdisk table holds the size, offset, type, name and hardware
* identifiers of each ramdisk. The type field denotes the type of its content.
* The vendor ramdisk names are unique. The hardware identifiers are specified
* in the board_id field in each table entry. The board_id field is consist of a
* vector of unsigned integer words, and the encoding scheme is defined by the
* hardware vendor.
*
* For the different type of ramdisks, there are:
* - VENDOR_RAMDISK_TYPE_NONE indicates the value is unspecified.
* - VENDOR_RAMDISK_TYPE_PLATFORM ramdisks contain platform specific bits, so
* the bootloader should always load these into memory.
* - VENDOR_RAMDISK_TYPE_RECOVERY ramdisks contain recovery resources, so
* the bootloader should load these when booting into recovery.
* - VENDOR_RAMDISK_TYPE_DLKM ramdisks contain dynamic loadable kernel
* modules.
*
* Version 4 of the vendor boot image also adds a bootconfig section to the end
* of the image. This section contains Boot Configuration parameters known at
* build time. The bootloader is responsible for placing this section directly
* after the generic ramdisk, followed by the bootconfig trailer, before
* entering the kernel.
*
* 0. all entities in the boot image are 4096-byte aligned in flash, all
* entities in the vendor boot image are page_size (determined by the vendor
* and specified in the vendor boot image header) aligned in flash
* 1. kernel, ramdisk, and DTB are required (size != 0)
* 2. load the kernel and DTB at the specified physical address (kernel_addr,
* dtb_addr)
* 3. load the vendor ramdisks at ramdisk_addr
* 4. load the generic ramdisk immediately following the vendor ramdisk in
* memory
* 5. load the bootconfig immediately following the generic ramdisk. Add
* additional bootconfig parameters followed by the bootconfig trailer.
* 6. set up registers for kernel entry as required by your architecture
* 7. if the platform has a second stage bootloader jump to it (must be
* contained outside boot and vendor boot partitions), otherwise
* jump to kernel_addr
*/
/* Private struct */
struct andr_image_data {
ulong kernel_ptr; /* kernel address */
u32 kernel_size; /* size in bytes */
u32 ramdisk_size; /* size in bytes */
ulong vendor_ramdisk_ptr; /* vendor ramdisk address */
u32 vendor_ramdisk_size; /* vendor ramdisk size*/
u32 boot_ramdisk_size; /* size in bytes */
ulong second_ptr; /* secondary bootloader address */
u32 second_size; /* secondary bootloader size */
ulong dtb_ptr; /* address of dtb image */
u32 dtb_size; /* size of dtb image */
ulong recovery_dtbo_ptr; /* size in bytes for recovery DTBO/ACPIO image */
u32 recovery_dtbo_size; /* offset to recovery dtbo/acpio in boot image */
const char *kcmdline; /* boot kernel cmdline */
const char *kcmdline_extra; /* vendor-boot extra kernel cmdline */
const char *image_name; /* asciiz product name */
ulong bootconfig_addr; /* bootconfig image address */
ulong bootconfig_size; /* bootconfig image size */
u32 kernel_addr; /* physical load addr */
ulong ramdisk_addr; /* physical load addr */
ulong ramdisk_ptr; /* ramdisk address */
ulong dtb_load_addr; /* physical load address for DTB image */
ulong tags_addr; /* physical addr for kernel tags */
u32 header_version; /* version of the boot image header */
u32 boot_img_total_size; /* boot image size */
u32 vendor_boot_img_total_size; /* vendor boot image size */
};
#endif

View file

@ -1733,24 +1733,173 @@ struct cipher_algo {
int fit_image_cipher_get_algo(const void *fit, int noffset, char **algo);
struct cipher_algo *image_get_cipher_algo(const char *full_name);
struct andr_image_data;
struct andr_img_hdr;
int android_image_check_header(const struct andr_img_hdr *hdr);
int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
/**
* android_image_get_data() - Parse Android boot images
*
* This is used to parse boot and vendor-boot header into
* andr_image_data generic structure.
*
* @boot_hdr: Pointer to boot image header
* @vendor_boot_hdr: Pointer to vendor boot image header
* @data: Pointer to generic boot format structure
* Return: true if succeeded, false otherwise
*/
bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr,
struct andr_image_data *data);
struct andr_boot_img_hdr_v0;
/**
* android_image_get_kernel() - Processes kernel part of Android boot images
*
* This function returns the os image's start address and length. Also,
* it appends the kernel command line to the bootargs env variable.
*
* @hdr: Pointer to image header, which is at the start
* of the image.
* @vendor_boot_img : Pointer to vendor boot image header
* @verify: Checksum verification flag. Currently unimplemented.
* @os_data: Pointer to a ulong variable, will hold os data start
* address.
* @os_len: Pointer to a ulong variable, will hold os data length.
* Return: Zero, os start address and length on success,
* otherwise on failure.
*/
int android_image_get_kernel(const void *hdr,
const void *vendor_boot_img, int verify,
ulong *os_data, ulong *os_len);
int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
/**
* android_image_get_ramdisk() - Extracts the ramdisk load address and its size
*
* This extracts the load address of the ramdisk and its size
*
* @hdr: Pointer to image header
* @vendor_boot_img : Pointer to vendor boot image header
* @rd_data: Pointer to a ulong variable, will hold ramdisk address
* @rd_len: Pointer to a ulong variable, will hold ramdisk length
* Return: 0 if succeeded, -1 if ramdisk size is 0
*/
int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img,
ulong *rd_data, ulong *rd_len);
int android_image_get_second(const struct andr_img_hdr *hdr,
ulong *second_data, ulong *second_len);
/**
* android_image_get_second() - Extracts the secondary bootloader address
* and its size
*
* This extracts the address of the secondary bootloader and its size
*
* @hdr: Pointer to image header
* @second_data: Pointer to a ulong variable, will hold secondary bootloader address
* @second_len : Pointer to a ulong variable, will hold secondary bootloader length
* Return: 0 if succeeded, -1 if secondary bootloader size is 0
*/
int android_image_get_second(const void *hdr, ulong *second_data, ulong *second_len);
bool android_image_get_dtbo(ulong hdr_addr, ulong *addr, u32 *size);
bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr,
u32 *size);
ulong android_image_get_end(const struct andr_img_hdr *hdr);
ulong android_image_get_kload(const struct andr_img_hdr *hdr);
ulong android_image_get_kcomp(const struct andr_img_hdr *hdr);
void android_print_contents(const struct andr_img_hdr *hdr);
/**
* android_image_get_dtb_by_index() - Get address and size of blob in DTB area.
* @hdr_addr: Boot image header address
* @vendor_boot_img: Pointer to vendor boot image header, which is at the start of the image.
* @index: Index of desired DTB in DTB area (starting from 0)
* @addr: If not NULL, will contain address to specified DTB
* @size: If not NULL, will contain size of specified DTB
*
* Get the address and size of DTB blob by its index in DTB area of Android
* Boot Image in RAM.
*
* Return: true on success or false on error.
*/
bool android_image_get_dtb_by_index(ulong hdr_addr, ulong vendor_boot_img,
u32 index, ulong *addr, u32 *size);
/**
* android_image_get_end() - Get the end of Android boot image
*
* This returns the end address of Android boot image address
*
* @hdr: Pointer to image header
* @vendor_boot_img : Pointer to vendor boot image header
* Return: The end address of Android boot image
*/
ulong android_image_get_end(const struct andr_boot_img_hdr_v0 *hdr,
const void *vendor_boot_img);
/**
* android_image_get_kload() - Get the kernel load address
*
* This returns the kernel load address. The load address is extracted
* from the boot image header or the "kernel_addr_r" environment variable
*
* @hdr: Pointer to image header
* @vendor_boot_img : Pointer to vendor boot image header
* Return: The kernel load address
*/
ulong android_image_get_kload(const void *hdr,
const void *vendor_boot_img);
/**
* android_image_get_kcomp() - Get kernel compression type
*
* This gets the kernel compression type from the boot image header
*
* @hdr: Pointer to image header
* @vendor_boot_img : Pointer to vendor boot image header
* Return: Kernel compression type
*/
ulong android_image_get_kcomp(const void *hdr,
const void *vendor_boot_img);
/**
* android_print_contents() - Prints out the contents of the Android format image
*
* This formats a multi line Android image contents description.
* The routine prints out Android image properties
*
* @hdr: Pointer to the Android format image header
* Return: no returned results
*/
void android_print_contents(const struct andr_boot_img_hdr_v0 *hdr);
bool android_image_print_dtb_contents(ulong hdr_addr);
/**
* is_android_boot_image_header() - Check the magic of boot image
*
* This checks the header of Android boot image and verifies the
* magic is "ANDROID!"
*
* @hdr: Pointer to boot image
* Return: non-zero if the magic is correct, zero otherwise
*/
bool is_android_boot_image_header(const void *hdr);
/**
* is_android_vendor_boot_image_header() - Check the magic of vendor boot image
*
* This checks the header of Android vendor boot image and verifies the magic
* is "VNDRBOOT"
*
* @vendor_boot_img: Pointer to boot image
* Return: non-zero if the magic is correct, zero otherwise
*/
bool is_android_vendor_boot_image_header(const void *vendor_boot_img);
/**
* get_abootimg_addr() - Get Android boot image address
*
* Return: Android boot image address
*/
ulong get_abootimg_addr(void);
/**
* get_avendor_bootimg_addr() - Get Android vendor boot image address
*
* Return: Android vendor boot image address
*/
ulong get_avendor_bootimg_addr(void);
/**
* board_fit_config_name_match() - Check for a matching board name
*

View file

@ -32,6 +32,23 @@ Now one can obtain original boot.img from this hex dump like this:
$ xxd -r -p boot.img.gz.hex boot.img.gz
$ gunzip -9 boot.img.gz
For boot image header version 4, these tests rely on two images that are generated
using the same steps above :
1- boot.img :
$ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \
--cmdline "cmdline test" --dtb ./dtb.img \
--os_version R --os_patch_level 2019-06-05 \
--header_version 4 --output ./boot.img
2- vendor_boot.img
$ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \
--cmdline "cmdline test" --dtb ./dtb.img \
--os_version R --os_patch_level 2019-06-05 \
--pagesize 4096 --vendor_ramdisk ./ramdisk.img \
--header_version 4 --vendor_boot ./vboot.img \
"""
# boot.img.gz hex dump
@ -44,6 +61,24 @@ b7762ffff07d345446c1281805e8a0868d81e117a45e111c0d8dc101b253
9c03c41a0c90f17fe85400986d82452b6c3680198a192a0ce17c3610ae34
d4a9820881a70f3873f35352731892f3730b124b32937252a96bb9119ae5
463a5546f82c1f05a360148c8251300a462e000085bf67f200200000"""
# boot img v4 hex dump
boot_img_hex = """1f8b080827b0cd630203626f6f742e696d6700edd8bd0d82601885d1d7c4
58d8c808b88195bd098d8d246e40e42b083f1aa0717be99d003d277916b8
e5bddc8a7b792d8e8788c896ce9b88d32ebe6c971e7ddd3543cae734cd01
c0ffc84c0000b0766d1a87d4e5afeadd3dab7a6f10000000f84163d5d7cd
d43a000000000000000060c53e7544995700400000"""
# vendor boot image v4 hex dump
vboot_img_hex = """1f8b0808baaecd63020376626f6f742e696d6700edd8310b824018c6f1b3
222a08f41b3436b4280dcdd19c11d16ee9109d18d59042d047ec8b04cd0d
d19d5a4345534bf6ffc173ef29272f38e93b1d0ec67dd79d548462aa1cd2
d5d20b0000f8438678f90c18d584b8a4bbb3a557991ecb2a0000f80d6b2f
f4179b656be5c532f2fc066f040000000080e23936af2755f62a3d918df1
db2a7ab67f9ffdeb7df7cda3465ecb79c4ce7e5c577562bb9364b74449a5
1e467e20c53c0a57de763193c1779b3b4fcd9d4ee27c6a0e00000000c0ff
309ffea7010000000040f1dc004129855400400000"""
# Expected response for "abootimg dtb_dump" command
dtb_dump_resp="""## DTB area contents (concat format):
- DTB #0:
@ -56,15 +91,21 @@ dtb_dump_resp="""## DTB area contents (concat format):
(DTB)compatible = y2,z2"""
# Address in RAM where to load the boot image ('abootimg' looks in $loadaddr)
loadaddr = 0x1000
# Address in RAM where to load the vendor boot image ('abootimg' looks in $vloadaddr)
vloadaddr= 0x10000
# Expected DTB #1 offset from the boot image start address
dtb1_offset = 0x187d
# Expected DTB offset from the vendor boot image start address
dtb2_offset = 0x207d
# DTB #1 start address in RAM
dtb1_addr = loadaddr + dtb1_offset
# DTB #2 start address in RAM
dtb2_addr = vloadaddr + dtb2_offset
class AbootimgTestDiskImage(object):
"""Disk image used by abootimg tests."""
def __init__(self, u_boot_console):
def __init__(self, u_boot_console, image_name, hex_img):
"""Initialize a new AbootimgDiskImage object.
Args:
@ -74,13 +115,13 @@ class AbootimgTestDiskImage(object):
Nothing.
"""
gz_hex = u_boot_console.config.persistent_data_dir + '/boot.img.gz.hex'
gz = u_boot_console.config.persistent_data_dir + '/boot.img.gz'
gz_hex = u_boot_console.config.persistent_data_dir + '/' + image_name + '.gz.hex'
gz = u_boot_console.config.persistent_data_dir + '/' + image_name + '.gz'
filename = 'boot.img'
filename = image_name
persistent = u_boot_console.config.persistent_data_dir + '/' + filename
self.path = u_boot_console.config.result_dir + '/' + filename
u_boot_console.log.action('persistent is ' + persistent)
with u_boot_utils.persistent_file_helper(u_boot_console.log, persistent):
if os.path.exists(persistent):
u_boot_console.log.action('Disk image file ' + persistent +
@ -89,19 +130,17 @@ class AbootimgTestDiskImage(object):
u_boot_console.log.action('Generating ' + persistent)
f = open(gz_hex, "w")
f.write(img_hex)
f.write(hex_img)
f.close()
cmd = ('xxd', '-r', '-p', gz_hex, gz)
u_boot_utils.run_and_log(u_boot_console, cmd)
cmd = ('gunzip', '-9', gz)
u_boot_utils.run_and_log(u_boot_console, cmd)
cmd = ('cp', persistent, self.path)
u_boot_utils.run_and_log(u_boot_console, cmd)
gtdi = None
gtdi1 = None
@pytest.fixture(scope='function')
def abootimg_disk_image(u_boot_console):
"""pytest fixture to provide a AbootimgTestDiskImage object to tests.
@ -109,10 +148,36 @@ def abootimg_disk_image(u_boot_console):
function-scoped. However, we don't need to actually do any function-scope
work, so this simply returns the same object over and over each time."""
global gtdi
if not gtdi:
gtdi = AbootimgTestDiskImage(u_boot_console)
return gtdi
global gtdi1
if not gtdi1:
gtdi1 = AbootimgTestDiskImage(u_boot_console, 'boot.img', img_hex)
return gtdi1
gtdi2 = None
@pytest.fixture(scope='function')
def abootimgv4_disk_image_vboot(u_boot_console):
"""pytest fixture to provide a AbootimgTestDiskImage object to tests.
This is function-scoped because it uses u_boot_console, which is also
function-scoped. However, we don't need to actually do any function-scope
work, so this simply returns the same object over and over each time."""
global gtdi2
if not gtdi2:
gtdi2 = AbootimgTestDiskImage(u_boot_console, 'vendor_boot.img', vboot_img_hex)
return gtdi2
gtdi3 = None
@pytest.fixture(scope='function')
def abootimgv4_disk_image_boot(u_boot_console):
"""pytest fixture to provide a AbootimgTestDiskImage object to tests.
This is function-scoped because it uses u_boot_console, which is also
function-scoped. However, we don't need to actually do any function-scope
work, so this simply returns the same object over and over each time."""
global gtdi3
if not gtdi3:
gtdi3 = AbootimgTestDiskImage(u_boot_console, 'bootv4.img', boot_img_hex)
return gtdi3
@pytest.mark.boardspec('sandbox')
@pytest.mark.buildconfigspec('android_boot_image')
@ -157,3 +222,48 @@ def test_abootimg(abootimg_disk_image, u_boot_console):
u_boot_console.run_command('fdt get value v / model')
response = u_boot_console.run_command('env print v')
assert response == 'v=x2'
@pytest.mark.boardspec('sandbox')
@pytest.mark.buildconfigspec('android_boot_image')
@pytest.mark.buildconfigspec('cmd_abootimg')
@pytest.mark.buildconfigspec('cmd_fdt')
@pytest.mark.requiredtool('xxd')
@pytest.mark.requiredtool('gunzip')
def test_abootimgv4(abootimgv4_disk_image_vboot, abootimgv4_disk_image_boot, u_boot_console):
"""Test the 'abootimg' command with boot image header v4."""
cons = u_boot_console
cons.log.action('Loading disk image to RAM...')
cons.run_command('setenv loadaddr 0x%x' % (loadaddr))
cons.run_command('setenv vloadaddr 0x%x' % (vloadaddr))
cons.run_command('host load hostfs - 0x%x %s' % (vloadaddr,
abootimgv4_disk_image_vboot.path))
cons.run_command('host load hostfs - 0x%x %s' % (loadaddr,
abootimgv4_disk_image_boot.path))
cons.run_command('abootimg addr 0x%x 0x%x' % (loadaddr, vloadaddr))
cons.log.action('Testing \'abootimg get ver\'...')
response = cons.run_command('abootimg get ver')
assert response == "4"
cons.run_command('abootimg get ver v')
response = cons.run_command('env print v')
assert response == 'v=4'
cons.log.action('Testing \'abootimg get recovery_dtbo\'...')
response = cons.run_command('abootimg get recovery_dtbo a')
assert response == 'Error: header version must be >= 1 and <= 2 to get dtbo'
cons.log.action('Testing \'abootimg get dtb_load_addr\'...')
cons.run_command('abootimg get dtb_load_addr a')
response = cons.run_command('env print a')
assert response == 'a=11f00000'
cons.log.action('Testing \'abootimg get dtb --index\'...')
cons.run_command('abootimg get dtb --index=1 dtb2_start')
response = cons.run_command('env print dtb2_start')
correct_str = "dtb2_start=%x" % (dtb2_addr)
assert response == correct_str
cons.run_command('fdt addr $dtb2_start')
cons.run_command('fdt get value v / model')
response = cons.run_command('env print v')
assert response == 'v=x2'

View file

@ -284,3 +284,7 @@ RUN /bin/echo -e "\n[toolchain-prefix]\nxtensa = /opt/2020.07/xtensa-dc233c-elf/
RUN /bin/echo -e "\n[toolchain-alias]\nsh = sh2" >> ~/.buildman
RUN /bin/echo -e "\nsandbox = x86_64" >> ~/.buildman
RUN /bin/echo -e "\nx86 = i386" >> ~/.buildman;
# Add mkbootimg tool
RUN git clone https://android.googlesource.com/platform/system/tools/mkbootimg /home/uboot/mkbootimg
ENV PYTHONPATH "${PYTHONPATH}:/home/uboot/mkbootimg"