Commit 9ace3fc81427f6a4036718c2daff9d6f8ee7b69a

Authored by Sebastian Siewior
Committed by Lukasz Majewski
1 parent 8c6004568f

image: add support for Android's boot image format

This patch adds support for the Android boot-image format. The header
file is from the Android project and got slightly alterted so the struct +
its defines are not generic but have something like a namespace. The
header file is from bootloader/legacy/include/boot/bootimg.h. The header
parsing has been written from scratch and I looked at
bootloader/legacy/usbloader/usbloader.c for some details.
The image contains the physical address (load address) of the kernel and
ramdisk. This address is considered only for the kernel image.
The "second image" defined in the image header is currently not
supported. I haven't found anything that is creating this.

v3 (Rob Herring):
This is based on http://patchwork.ozlabs.org/patch/126797/ with the
following changes:
- Rebased to current mainline
- Moved android image handling to separate functions in
  common/image-android.c
- s/u8/char/ in header to fix string function warnings
- Use SPDX identifiers for licenses
- Cleaned-up file source information:
  android_image.h is from file include/boot/bootimg.h in repository:
  https://android.googlesource.com/platform/bootable/bootloader/legacy
  The git commit hash is 4205b865141ff2e255fe1d3bd16de18e217ef06a
  usbloader.c would be from the same commit, but it does not appear
  to have been used for any actual code.
v4:
- s/andriod/android/
- Use a separate flag ep_found to track if the entry point has been set
rather than using a magic value.

Cc: Wolfgang Denk <wd@denx.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Rob Herring <robh@kernel.org>
Reviewed-by: Tom Rini <trini@ti.com>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>

Showing 6 changed files with 204 additions and 6 deletions Side-by-side Diff

... ... @@ -237,6 +237,7 @@
237 237 obj-$(CONFIG_CROS_EC) += cros_ec.o
238 238 obj-y += dlmalloc.o
239 239 obj-y += image.o
  240 +obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
240 241 obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
241 242 obj-$(CONFIG_FIT) += image-fit.o
242 243 obj-$(CONFIG_FIT_SIGNATURE) += image-sig.o
... ... @@ -222,6 +222,7 @@
222 222 char * const argv[])
223 223 {
224 224 const void *os_hdr;
  225 + bool ep_found = false;
225 226  
226 227 /* get kernel image header, start address and length */
227 228 os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
... ... @@ -274,6 +275,18 @@
274 275 }
275 276 break;
276 277 #endif
  278 +#ifdef CONFIG_ANDROID_BOOT_IMAGE
  279 + case IMAGE_FORMAT_ANDROID:
  280 + images.os.type = IH_TYPE_KERNEL;
  281 + images.os.comp = IH_COMP_NONE;
  282 + images.os.os = IH_OS_LINUX;
  283 + images.ep = images.os.load;
  284 + ep_found = true;
  285 +
  286 + images.os.end = android_image_get_end(os_hdr);
  287 + images.os.load = android_image_get_kload(os_hdr);
  288 + break;
  289 +#endif
277 290 default:
278 291 puts("ERROR: unknown image format type!\n");
279 292 return 1;
... ... @@ -293,7 +306,7 @@
293 306 return 1;
294 307 }
295 308 #endif
296   - } else {
  309 + } else if (!ep_found) {
297 310 puts("Could not find kernel entry point!\n");
298 311 return 1;
299 312 }
... ... @@ -1000,6 +1013,14 @@
1000 1013 images->fit_uname_os = fit_uname_kernel;
1001 1014 images->fit_uname_cfg = fit_uname_config;
1002 1015 images->fit_noffset_os = os_noffset;
  1016 + break;
  1017 +#endif
  1018 +#ifdef CONFIG_ANDROID_BOOT_IMAGE
  1019 + case IMAGE_FORMAT_ANDROID:
  1020 + printf("## Booting Android Image at 0x%08lx ...\n", img_addr);
  1021 + if (android_image_get_kernel((void *)img_addr, images->verify,
  1022 + os_data, os_len))
  1023 + return NULL;
1003 1024 break;
1004 1025 #endif
1005 1026 default:
common/image-android.c
  1 +/*
  2 + * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <image.h>
  9 +#include <android_image.h>
  10 +
  11 +static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
  12 +
  13 +int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
  14 + ulong *os_data, ulong *os_len)
  15 +{
  16 + /*
  17 + * Not all Android tools use the id field for signing the image with
  18 + * sha1 (or anything) so we don't check it. It is not obvious that the
  19 + * string is null terminated so we take care of this.
  20 + */
  21 + strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
  22 + andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
  23 + if (strlen(andr_tmp_str))
  24 + printf("Android's image name: %s\n", andr_tmp_str);
  25 +
  26 + printf("Kernel load addr 0x%08x size %u KiB\n",
  27 + hdr->kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
  28 + strncpy(andr_tmp_str, hdr->cmdline, ANDR_BOOT_ARGS_SIZE);
  29 + andr_tmp_str[ANDR_BOOT_ARGS_SIZE] = '\0';
  30 + if (strlen(andr_tmp_str)) {
  31 + printf("Kernel command line: %s\n", andr_tmp_str);
  32 + setenv("bootargs", andr_tmp_str);
  33 + }
  34 + if (hdr->ramdisk_size)
  35 + printf("RAM disk load addr 0x%08x size %u KiB\n",
  36 + hdr->ramdisk_addr,
  37 + DIV_ROUND_UP(hdr->ramdisk_size, 1024));
  38 +
  39 + if (os_data) {
  40 + *os_data = (ulong)hdr;
  41 + *os_data += hdr->page_size;
  42 + }
  43 + if (os_len)
  44 + *os_len = hdr->kernel_size;
  45 + return 0;
  46 +}
  47 +
  48 +int android_image_check_header(const struct andr_img_hdr *hdr)
  49 +{
  50 + return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE);
  51 +}
  52 +
  53 +ulong android_image_get_end(const struct andr_img_hdr *hdr)
  54 +{
  55 + u32 size = 0;
  56 + /*
  57 + * The header takes a full page, the remaining components are aligned
  58 + * on page boundary
  59 + */
  60 + size += hdr->page_size;
  61 + size += ALIGN(hdr->kernel_size, hdr->page_size);
  62 + size += ALIGN(hdr->ramdisk_size, hdr->page_size);
  63 + size += ALIGN(hdr->second_size, hdr->page_size);
  64 +
  65 + return size;
  66 +}
  67 +
  68 +ulong android_image_get_kload(const struct andr_img_hdr *hdr)
  69 +{
  70 + return hdr->kernel_addr;
  71 +}
  72 +
  73 +int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
  74 + ulong *rd_data, ulong *rd_len)
  75 +{
  76 + if (!hdr->ramdisk_size)
  77 + return -1;
  78 + *rd_data = (unsigned long)hdr;
  79 + *rd_data += hdr->page_size;
  80 + *rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
  81 +
  82 + *rd_len = hdr->ramdisk_size;
  83 + return 0;
  84 +}
... ... @@ -659,11 +659,13 @@
659 659 if (image_check_magic(hdr))
660 660 format = IMAGE_FORMAT_LEGACY;
661 661 #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
662   - else {
663   - if (fdt_check_header(img_addr) == 0)
664   - format = IMAGE_FORMAT_FIT;
665   - }
  662 + else if (fdt_check_header(img_addr) == 0)
  663 + format = IMAGE_FORMAT_FIT;
666 664 #endif
  665 +#ifdef CONFIG_ANDROID_BOOT_IMAGE
  666 + else if (android_image_check_header(img_addr) == 0)
  667 + format = IMAGE_FORMAT_ANDROID;
  668 +#endif
667 669  
668 670 return format;
669 671 }
... ... @@ -932,7 +934,15 @@
932 934 (ulong)images->legacy_hdr_os);
933 935  
934 936 image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
935   - } else {
  937 + }
  938 +#ifdef CONFIG_ANDROID_BOOT_IMAGE
  939 + else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID) &&
  940 + (!android_image_get_ramdisk((void *)images->os.start,
  941 + &rd_data, &rd_len))) {
  942 + /* empty */
  943 + }
  944 +#endif
  945 + else {
936 946 /*
937 947 * no initrd image
938 948 */
include/android_image.h
  1 +/*
  2 + * This is from the Android Project,
  3 + * Repository: https://android.googlesource.com/platform/bootable/bootloader/legacy
  4 + * File: include/boot/bootimg.h
  5 + * Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
  6 + *
  7 + * Copyright (C) 2008 The Android Open Source Project
  8 + *
  9 + * SPDX-License-Identifier: BSD-2-Clause
  10 + */
  11 +
  12 +#ifndef _ANDROID_IMAGE_H_
  13 +#define _ANDROID_IMAGE_H_
  14 +
  15 +#define ANDR_BOOT_MAGIC "ANDROID!"
  16 +#define ANDR_BOOT_MAGIC_SIZE 8
  17 +#define ANDR_BOOT_NAME_SIZE 16
  18 +#define ANDR_BOOT_ARGS_SIZE 512
  19 +
  20 +struct andr_img_hdr {
  21 + char magic[ANDR_BOOT_MAGIC_SIZE];
  22 +
  23 + u32 kernel_size; /* size in bytes */
  24 + u32 kernel_addr; /* physical load addr */
  25 +
  26 + u32 ramdisk_size; /* size in bytes */
  27 + u32 ramdisk_addr; /* physical load addr */
  28 +
  29 + u32 second_size; /* size in bytes */
  30 + u32 second_addr; /* physical load addr */
  31 +
  32 + u32 tags_addr; /* physical addr for kernel tags */
  33 + u32 page_size; /* flash page size we assume */
  34 + u32 unused[2]; /* future expansion: should be 0 */
  35 +
  36 + char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
  37 +
  38 + char cmdline[ANDR_BOOT_ARGS_SIZE];
  39 +
  40 + u32 id[8]; /* timestamp / checksum / sha1 / etc */
  41 +};
  42 +
  43 +/*
  44 + * +-----------------+
  45 + * | boot header | 1 page
  46 + * +-----------------+
  47 + * | kernel | n pages
  48 + * +-----------------+
  49 + * | ramdisk | m pages
  50 + * +-----------------+
  51 + * | second stage | o pages
  52 + * +-----------------+
  53 + *
  54 + * n = (kernel_size + page_size - 1) / page_size
  55 + * m = (ramdisk_size + page_size - 1) / page_size
  56 + * o = (second_size + page_size - 1) / page_size
  57 + *
  58 + * 0. all entities are page_size aligned in flash
  59 + * 1. kernel and ramdisk are required (size != 0)
  60 + * 2. second is optional (second_size == 0 -> no second)
  61 + * 3. load each element (kernel, ramdisk, second) at
  62 + * the specified physical address (kernel_addr, etc)
  63 + * 4. prepare tags at tag_addr. kernel_args[] is
  64 + * appended to the kernel commandline in the tags.
  65 + * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
  66 + * 6. if second_size != 0: jump to second_addr
  67 + * else: jump to kernel_addr
  68 + */
  69 +#endif
... ... @@ -412,6 +412,7 @@
412 412 #define IMAGE_FORMAT_INVALID 0x00
413 413 #define IMAGE_FORMAT_LEGACY 0x01 /* legacy image_header based format */
414 414 #define IMAGE_FORMAT_FIT 0x02 /* new, libfdt based format */
  415 +#define IMAGE_FORMAT_ANDROID 0x03 /* Android boot image */
415 416  
416 417 int genimg_get_format(const void *img_addr);
417 418 int genimg_has_config(bootm_headers_t *images);
... ... @@ -1029,6 +1030,18 @@
1029 1030 #define fit_unsupported_reset(msg)
1030 1031 #endif /* CONFIG_FIT_VERBOSE */
1031 1032 #endif /* CONFIG_FIT */
  1033 +
  1034 +#if defined(CONFIG_ANDROID_BOOT_IMAGE)
  1035 +struct andr_img_hdr;
  1036 +int android_image_check_header(const struct andr_img_hdr *hdr);
  1037 +int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
  1038 + ulong *os_data, ulong *os_len);
  1039 +int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
  1040 + ulong *rd_data, ulong *rd_len);
  1041 +ulong android_image_get_end(const struct andr_img_hdr *hdr);
  1042 +ulong android_image_get_kload(const struct andr_img_hdr *hdr);
  1043 +
  1044 +#endif /* CONFIG_ANDROID_BOOT_IMAGE */
1032 1045  
1033 1046 #endif /* __IMAGE_H__ */