diff --git a/common/Makefile b/common/Makefile index 7c853ae442..bfcb4664b7 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 c243a5bd78..993b906c70 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, @@ -273,6 +274,18 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, return 1; } 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"); @@ -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; } @@ -1001,6 +1014,14 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, images->fit_uname_cfg = fit_uname_config; 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); diff --git a/common/image-android.c b/common/image-android.c new file mode 100644 index 0000000000..6ded7e2c97 --- /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 9c6bec5b76..7ff27d75c3 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 0000000000..094d60afe8 --- /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 2508d7d243..e1f92979a4 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__ */