[U-Boot] [PATCH v3 3/5] image: add support for Android's boot image format

Lukasz Majewski
2014-04-15T13:59:14Z

Hi Rob,

> From: Sebastian Siewior <bigeasy@linutronix.de>
>
> 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" is currently ignored. 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.
>
> Cc: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
> common/Makefile | 1 +
> common/cmd_bootm.c | 23 +++++++++++++-
> common/image-android.c | 84
> +++++++++++++++++++++++++++++++++++++++++++++++++
> common/image.c | 20 +++++++++--- include/android_image.h |
> 69 ++++++++++++++++++++++++++++++++++++++++ include/image.h |
> 13 ++++++++ 6 files changed, 204 insertions(+), 6 deletions(-)
> create mode 100644 common/image-android.c
> create mode 100644 include/android_image.h
>
> diff --git a/common/Makefile b/common/Makefile
> index cecd81a..da208f3 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -236,6 +236,7 @@ obj-y += console.o
> obj-$(CONFIG_CROS_EC) += cros_ec.o
> obj-y += dlmalloc.o
> obj-y += image.o
> +obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
> obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
> obj-$(CONFIG_FIT) += image-fit.o
> obj-$(CONFIG_FIT_SIGNATURE) += image-sig.o
> diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
> index 9751edc..b6c8288 100644
> --- a/common/cmd_bootm.c
> +++ b/common/cmd_bootm.c
> @@ -223,6 +223,8 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int
> flag, int argc, {
> const void *os_hdr;
>
> + images.ep = ~0UL;
> +
> /* get kernel image header, start address and length */
> os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
> &images, &images.os.image_start,
> &images.os.image_len); @@ -274,6 +276,17 @@ static int
> bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, }
> break;
> #endif
> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
> + case IMAGE_FORMAT_ANDROID:
> + images.os.type = IH_TYPE_KERNEL;
> + images.os.comp = IH_COMP_NONE;
> + images.os.os = IH_OS_LINUX;
> + images.ep = images.os.load;
> +
> + images.os.end = android_image_get_end(os_hdr);
> + images.os.load = android_image_get_kload(os_hdr);
> + break;
> +#endif
> default:
> puts("ERROR: unknown image format type!\n");
> return 1;
> @@ -293,7 +306,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int
> flag, int argc, return 1;
> }
> #endif
> - } else {
> + } else if (images.ep == ~0UL) {
> puts("Could not find kernel entry point!\n");
> return 1;
> }
> @@ -1002,6 +1015,14 @@ static const void *boot_get_kernel(cmd_tbl_t
> *cmdtp, int flag, int argc, images->fit_noffset_os = os_noffset;
> break;
> #endif
> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
> + case IMAGE_FORMAT_ANDROID:
> + printf("## Booting Android Image at 0x%08lx ...\n",
> img_addr);
> + if (android_image_get_kernel((void *)img_addr,
> images->verify,
> + os_data, os_len))
> + return NULL;
> + break;
> +#endif
> default:
> printf("Wrong Image Format for %s command\n",
> cmdtp->name); bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO);
> diff --git a/common/image-android.c b/common/image-android.c
> new file mode 100644
> index 0000000..ec6fb3d
> --- /dev/null
> +++ b/common/image-android.c
> @@ -0,0 +1,84 @@
> +/*
> + * Copyright (c) 2011 Sebastian Andrzej Siewior
> <bigeasy@linutronix.de>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <image.h>
> +#include <android_image.h>
> +
> +static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
> +
> +int android_image_get_kernel(const struct andr_img_hdr *hdr, int
> verify,
> + ulong *os_data, ulong *os_len)
> +{
> + /*
> + * 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);
> + 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",
> + hdr->kernel_addr, DIV_ROUND_UP(hdr->kernel_size,
> 1024));
> + strncpy(andr_tmp_str, hdr->cmdline, ANDR_BOOT_ARGS_SIZE);
> + andr_tmp_str[ANDR_BOOT_ARGS_SIZE] = '\0';
> + if (strlen(andr_tmp_str)) {
> + printf("Kernel command line: %s\n", andr_tmp_str);
> + setenv("bootargs", andr_tmp_str);
> + }
> + if (hdr->ramdisk_size)
> + printf("RAM disk load addr 0x%08x size %u KiB\n",
> + hdr->ramdisk_addr,
> + DIV_ROUND_UP(hdr->ramdisk_size, 1024));
> +
> + if (os_data) {
> + *os_data = (ulong)hdr;
> + *os_data += hdr->page_size;
> + }
> + if (os_len)
> + *os_len = hdr->kernel_size;
> + return 0;
> +}
> +
> +int android_image_check_header(const struct andr_img_hdr *hdr)
> +{
> + return memcmp(ANDR_BOOT_MAGIC, hdr->magic,
> ANDR_BOOT_MAGIC_SIZE); +}
> +
> +ulong android_image_get_end(const struct andr_img_hdr *hdr)
> +{
> + u32 size = 0;
> + /*
> + * The header takes a full page, the remaining components
> are aligned
> + * on page boundary
> + */
> + size += hdr->page_size;
> + size += ALIGN(hdr->kernel_size, hdr->page_size);
> + size += ALIGN(hdr->ramdisk_size, hdr->page_size);
> + size += ALIGN(hdr->second_size, hdr->page_size);
> +
> + return size;
> +}
> +
> +ulong android_image_get_kload(const struct andr_img_hdr *hdr)
> +{
> + return hdr->kernel_addr;
> +}
> +
> +int andriod_image_get_ramdisk(const struct andr_img_hdr *hdr,
> + ulong *rd_data, ulong *rd_len)
> +{
> + if (!hdr->ramdisk_size)
> + return -1;
> + *rd_data = (unsigned long)hdr;
> + *rd_data += hdr->page_size;
> + *rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
> +
> + *rd_len = hdr->ramdisk_size;
> + return 0;
> +}
> diff --git a/common/image.c b/common/image.c
> index afbf806..b6063f6 100644
> --- a/common/image.c
> +++ b/common/image.c
> @@ -676,10 +676,12 @@ int genimg_get_format(const void *img_addr)
> if (image_check_magic(hdr))
> format = IMAGE_FORMAT_LEGACY;
> #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
> - else {
> - if (fdt_check_header(img_addr) == 0)
> - format = IMAGE_FORMAT_FIT;
> - }
> + else if (fdt_check_header(img_addr) == 0)
> + format = IMAGE_FORMAT_FIT;
> +#endif
> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
> + else if (android_image_check_header(img_addr) == 0)
> + format = IMAGE_FORMAT_ANDROID;
> #endif
>
> return format;
> @@ -949,7 +951,15 @@ int boot_get_ramdisk(int argc, char * const
> argv[], bootm_headers_t *images, (ulong)images->legacy_hdr_os);
>
> image_multi_getimg(images->legacy_hdr_os, 1,
> &rd_data, &rd_len);
> - } else {
> + }
> +#ifdef CONFIG_ANDROID_BOOT_IMAGE
> + else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID)
> &&
> + (!andriod_image_get_ramdisk((void
> *)images->os.start,
> + &rd_data, &rd_len))) {
> + /* empty */
> + }
> +#endif
> + else {
> /*
> * no initrd image
> */
> diff --git a/include/android_image.h b/include/android_image.h
> new file mode 100644
> index 0000000..094d60a
> --- /dev/null
> +++ b/include/android_image.h
> @@ -0,0 +1,69 @@
> +/*
> + * This is from the Android Project,
> + * Repository:
> https://android.googlesource.com/platform/bootable/bootloader/legacy
> + * File: include/boot/bootimg.h
> + * Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
> + *
> + * Copyright (C) 2008 The Android Open Source Project
> + *
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +
> +#ifndef _ANDROID_IMAGE_H_
> +#define _ANDROID_IMAGE_H_
> +
> +#define ANDR_BOOT_MAGIC "ANDROID!"
> +#define ANDR_BOOT_MAGIC_SIZE 8
> +#define ANDR_BOOT_NAME_SIZE 16
> +#define ANDR_BOOT_ARGS_SIZE 512
> +
> +struct andr_img_hdr {
> + char magic[ANDR_BOOT_MAGIC_SIZE];
> +
> + u32 kernel_size; /* size in bytes */
> + u32 kernel_addr; /* physical load addr */
> +
> + u32 ramdisk_size; /* size in bytes */
> + u32 ramdisk_addr; /* physical load addr */
> +
> + u32 second_size; /* size in bytes */
> + u32 second_addr; /* physical load addr */
> +
> + u32 tags_addr; /* physical addr for kernel
> tags */
> + u32 page_size; /* flash page size we assume */
> + u32 unused[2]; /* future expansion: should be
> 0 */ +
> + char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
> +
> + char cmdline[ANDR_BOOT_ARGS_SIZE];
> +
> + u32 id[8]; /* timestamp / checksum / sha1 / etc */
> +};
> +
> +/*
> + * +-----------------+
> + * | boot header | 1 page
> + * +-----------------+
> + * | kernel | n pages
> + * +-----------------+
> + * | ramdisk | m pages
> + * +-----------------+
> + * | second stage | o pages
> + * +-----------------+
> + *
> + * n = (kernel_size + page_size - 1) / page_size
> + * m = (ramdisk_size + page_size - 1) / page_size
> + * o = (second_size + page_size - 1) / page_size
> + *
> + * 0. all entities are page_size aligned in flash
> + * 1. kernel and ramdisk are required (size != 0)
> + * 2. second is optional (second_size == 0 -> no second)
> + * 3. load each element (kernel, ramdisk, second) at
> + * the specified physical address (kernel_addr, etc)
> + * 4. prepare tags at tag_addr. kernel_args[] is
> + * appended to the kernel commandline in the tags.
> + * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
> + * 6. if second_size != 0: jump to second_addr
> + * else: jump to kernel_addr
> + */
> +#endif
> diff --git a/include/image.h b/include/image.h
> index 6afd57b..b123860 100644
> --- a/include/image.h
> +++ b/include/image.h
> @@ -403,6 +403,7 @@ enum fit_load_op {
> #define IMAGE_FORMAT_INVALID 0x00
> #define IMAGE_FORMAT_LEGACY 0x01 /* legacy
> image_header based format */ #define IMAGE_FORMAT_FIT
> 0x02 /* new, libfdt based format */ +#define
> IMAGE_FORMAT_ANDROID 0x03 /* Android boot image */
> int genimg_get_format(const void *img_addr);
> int genimg_has_config(bootm_headers_t *images);
> @@ -996,4 +997,16 @@ static inline int
> fit_image_check_target_arch(const void *fdt, int node) #endif /*
> CONFIG_FIT_VERBOSE */ #endif /* CONFIG_FIT */
>
> +#if defined(CONFIG_ANDROID_BOOT_IMAGE)
> +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,
> + ulong *os_data, ulong *os_len);
> +int andriod_image_get_ramdisk(const struct andr_img_hdr *hdr,
> + ulong *rd_data, ulong *rd_len);
> +ulong android_image_get_end(const struct andr_img_hdr *hdr);
> +ulong android_image_get_kload(const struct andr_img_hdr *hdr);
> +
> +#endif /* CONFIG_ANDROID_BOOT_IMAGE */
> +
> #endif /* __IMAGE_H__ */

Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>

--
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group