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

Sebastian Andrzej Siewior bigeasy at linutronix.de
Tue Sep 20 16:02:01 CEST 2011


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.

Cc: Wolfgang Denk <wd at denx.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy at linutronix.de>
---
 common/cmd_bootm.c      |   87 +++++++++++++++++++++++++++++++++++++++++++++-
 common/image.c          |   17 +++++++++
 include/android_image.h |   89 +++++++++++++++++++++++++++++++++++++++++++++++
 include/image.h         |    4 ++
 4 files changed, 196 insertions(+), 1 deletions(-)
 create mode 100644 include/android_image.h

diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 272d879..ec9bf39 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -36,6 +36,7 @@
 #include <lmb.h>
 #include <linux/ctype.h>
 #include <asm/byteorder.h>
+#include <android_image.h>
 
 #if defined(CONFIG_CMD_USB)
 #include <usb.h>
@@ -211,10 +212,33 @@ static void bootm_start_lmb(void)
 #endif
 }
 
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+static u32 android_img_get_end(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;
+}
+
+static u32 android_img_get_kload(struct andr_img_hdr *hdr)
+{
+	return hdr->kernel_addr;
+}
+#endif
+
 static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	void		*os_hdr;
 	int		ret;
+	int		img_type;
 
 	memset ((void *)&images, 0, sizeof (images));
 	images.verify = getenv_yesno ("verify");
@@ -230,7 +254,8 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	}
 
 	/* get image parameters */
-	switch (genimg_get_format (os_hdr)) {
+	img_type = genimg_get_format(os_hdr);
+	switch (img_type) {
 	case IMAGE_FORMAT_LEGACY:
 		images.os.type = image_get_type (os_hdr);
 		images.os.comp = image_get_comp (os_hdr);
@@ -272,6 +297,16 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 		}
 		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.os.end = android_img_get_end(os_hdr);
+		images.os.load = android_img_get_kload(os_hdr);
+		break;
+#endif
 	default:
 		puts ("ERROR: unknown image format type!\n");
 		return 1;
@@ -289,6 +324,10 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 			return 1;
 		}
 #endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	} else if (img_type == IMAGE_FORMAT_ANDROID) {
+		images.ep = images.os.load;
+#endif
 	} else {
 		puts ("Could not find kernel entry point!\n");
 		return 1;
@@ -821,6 +860,36 @@ static int fit_check_kernel (const void *fit, int os_noffset, int verify)
 }
 #endif /* CONFIG_FIT */
 
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
+static int android_image_get_kernel(struct andr_img_hdr *hdr, int verify)
+{
+	/*
+	 * 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));
+	return 0;
+}
+#endif
+
 /**
  * boot_get_kernel - find kernel image
  * @os_data: pointer to a ulong variable, will hold os data start address
@@ -847,6 +916,9 @@ static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char * const
 	int		cfg_noffset;
 	int		os_noffset;
 #endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	struct andr_img_hdr *ahdr;
+#endif
 
 	/* find out kernel image address */
 	if (argc < 2) {
@@ -980,6 +1052,19 @@ static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char * const
 		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);
+		ahdr = (void *)img_addr;
+		if (android_image_get_kernel(ahdr, images->verify))
+			return NULL;
+
+		*os_data = img_addr;
+		*os_data += ahdr->page_size;
+		*os_len = ahdr->kernel_size;
+		images->ahdr = ahdr;
+		break;
+#endif
 	default:
 		printf ("Wrong Image Format for %s command\n", cmdtp->name);
 		show_boot_progress (-108);
diff --git a/common/image.c b/common/image.c
index 5eea2a1..12b3ec5 100644
--- a/common/image.c
+++ b/common/image.c
@@ -26,6 +26,7 @@
 #ifndef USE_HOSTCC
 #include <common.h>
 #include <watchdog.h>
+#include <android_image.h>
 
 #ifdef CONFIG_SHOW_BOOT_PROGRESS
 #include <status_led.h>
@@ -671,7 +672,14 @@ int genimg_get_format (void *img_addr)
 			format = IMAGE_FORMAT_FIT;
 	}
 #endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	else {
+		const struct andr_img_hdr *ahdr = img_addr;
 
+		if (!memcmp(ANDR_BOOT_MAGIC, ahdr->magic, ANDR_BOOT_MAGIC_SIZE))
+			format = IMAGE_FORMAT_ANDROID;
+	}
+#endif
 	return format;
 }
 
@@ -993,6 +1001,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);
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+		if (images->ahdr && images->ahdr->ramdisk_size) {
+			rd_data = (unsigned long) images->ahdr;
+			rd_data += images->ahdr->page_size;
+			rd_data += ALIGN(images->ahdr->kernel_size,
+					images->ahdr->page_size);
+			rd_len = images->ahdr->ramdisk_size;
+		}
+#endif
 	} else {
 		/*
 		 * no initrd image
diff --git a/include/android_image.h b/include/android_image.h
new file mode 100644
index 0000000..b231b66
--- /dev/null
+++ b/include/android_image.h
@@ -0,0 +1,89 @@
+/*
+ * This is from the Android Project,
+ * bootloader/legacy/include/boot/bootimg.h
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#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 {
+	u8 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 */
+
+	u8 name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
+
+	u8 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 352e4a0..4360d73 100644
--- a/include/image.h
+++ b/include/image.h
@@ -261,6 +261,9 @@ typedef struct bootm_headers {
 #ifdef CONFIG_LMB
 	struct lmb	lmb;		/* for memory mgmt */
 #endif
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+	struct andr_img_hdr	*ahdr;
+#endif
 } bootm_headers_t;
 
 /*
@@ -326,6 +329,7 @@ void genimg_print_size (uint32_t size);
 #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 (void *img_addr);
 int genimg_has_config (bootm_headers_t *images);
-- 
1.7.6.3



More information about the U-Boot mailing list