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

Lukasz Majewski l.majewski at samsung.com
Tue Apr 15 15:59:14 CEST 2014


Hi Rob,

> From: Sebastian Siewior <bigeasy at 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 at denx.de>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy at linutronix.de>
> Signed-off-by: Rob Herring <robh at 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 at 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 at samsung.com>

-- 
Best regards,

Lukasz Majewski

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


More information about the U-Boot mailing list