From patchwork Mon May 5 20:08:09 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rob Herring X-Patchwork-Id: 345868 X-Patchwork-Delegate: marek.vasut@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 23F68140F8D for ; Tue, 6 May 2014 06:08:48 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D12434B9B5; Mon, 5 May 2014 22:08:45 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id tL4K1efwIrNf; Mon, 5 May 2014 22:08:45 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 7BB8C4B97D; Mon, 5 May 2014 22:08:34 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 3DA444B914 for ; Mon, 5 May 2014 22:08:30 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id BIir37Wn54cW for ; Mon, 5 May 2014 22:08:26 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-ob0-f173.google.com (mail-ob0-f173.google.com [209.85.214.173]) by theia.denx.de (Postfix) with ESMTPS id 523D54B90A for ; Mon, 5 May 2014 22:08:22 +0200 (CEST) Received: by mail-ob0-f173.google.com with SMTP id wm4so5804871obc.18 for ; Mon, 05 May 2014 13:08:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=7JVgRvnlAd7txz9456nJ+NfLGnJdt/z3ZY1eS8+FjRk=; b=TqfIC+XXQmhzWuF7PJ8iwc1zzh8v4iIYuAgF5i/dpTOsuHm8cev+6H/RlVCvV9Th3r /nJ6zc/6z+QRq20g4KHIEfGhqM3wXRtNIw18cKt51czqbQZ6sP/dAZ86nHbkYmXEkd74 4ZbT5CUlLN/qwFVYv1MRd6MNLTqIG1BIMaoLGBYpHo2tEL7VPrS1OdUbNFzacg/MHnPp H6jbocvD63nZDi1iP5D8+q7qP/QHy40HsBMEa5FuXT0dQoGTfaVQ5+1llS8Z/N6rpLAd pgv90RMnRXgy4v2b1TqgKp8eGXBTgl0N3qOVDxvXtLi/gLJmode/tYhX2zg6q5BzDxCG MQxg== X-Received: by 10.182.78.100 with SMTP id a4mr5116170obx.56.1399320501263; Mon, 05 May 2014 13:08:21 -0700 (PDT) Received: from localhost.localdomain (72-48-77-163.dyn.grandenetworks.net. [72.48.77.163]) by mx.google.com with ESMTPSA id zc8sm21468422obc.1.2014.05.05.13.08.19 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 05 May 2014 13:08:20 -0700 (PDT) From: Rob Herring To: u-boot@lists.denx.de, Lukasz Majewski , Marek Vasut , Wolfgang Denk , Tom Rini Date: Mon, 5 May 2014 15:08:09 -0500 Message-Id: <1399320491-9089-2-git-send-email-robherring2@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1399320491-9089-1-git-send-email-robherring2@gmail.com> References: <1397829272-22266-1-git-send-email-robherring2@gmail.com> <1399320491-9089-1-git-send-email-robherring2@gmail.com> Cc: Rob Herring Subject: [U-Boot] [PATCH v5 1/3] image: add support for Android's boot image format X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de From: Sebastian Siewior 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 Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Rob Herring Reviewed-by: Tom Rini Reviewed-by: Lukasz Majewski --- 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 7c853ae..bfcb466 100644 --- a/common/Makefile +++ b/common/Makefile @@ -237,6 +237,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 c243a5b..993b906 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -222,6 +222,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { const void *os_hdr; + bool ep_found = false; /* get kernel image header, start address and length */ os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, @@ -274,6 +275,18 @@ 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; + ep_found = true; + + 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 (!ep_found) { 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..6ded7e2 --- /dev/null +++ b/common/image-android.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011 Sebastian Andrzej Siewior + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +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 android_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 9c6bec5..7ff27d7 100644 --- a/common/image.c +++ b/common/image.c @@ -659,10 +659,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; @@ -932,7 +934,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) && + (!android_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 2508d7d..e1f9297 100644 --- a/include/image.h +++ b/include/image.h @@ -412,6 +412,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); @@ -1030,4 +1031,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 android_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__ */