From 5efbed3b272b2b8b6bfa1e8317801f1637eeec88 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 11 Apr 2012 07:42:34 +0200 Subject: [PATCH] arm: add Android boot image support The Android Image contains 3 components and params - kernel - initrd - second stage (optional) - tags addr - bootargs In fast boot the initrd is mandatory, in barebox we are less restrictive use the initrd only if present add to env params: aimage_noverwrite_bootargs Disable overwrite of the bootargs with the one present in aimage aimage_noverwrite_tags Disable overwrite of the tags addr with the one present in aimage Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Magnus Damm Signed-off-by: Sascha Hauer --- arch/arm/lib/bootm.c | 147 +++++++++++++++++++++++++++++++++++++++++++ commands/Kconfig | 7 +++ include/aimage.h | 74 ++++++++++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 include/aimage.h diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index defc89b7f..ac83ec7a3 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -231,12 +232,158 @@ static struct image_handler barebox_handler = { .filetype = filetype_arm_barebox, }; +#include + +static int aimage_load_resource(int fd, struct resource *r, void* buf, int ps) +{ + int ret; + void *image = (void *)r->start; + unsigned to_read = ps - r->size % ps; + + ret = read_full(fd, image, r->size); + if (ret < 0) + return ret; + + ret = read_full(fd, buf, to_read); + if (ret < 0) + printf("could not read dummy %d\n", to_read); + + return ret; +} + +static int do_bootm_aimage(struct image_data *data) +{ + struct resource *snd_stage_res; + int fd, ret; + struct android_header __header, *header; + void *buf; + int to_read; + struct android_header_comp *cmp; + + fd = open(data->os_file, O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + header = &__header; + ret = read(fd, header, sizeof(*header)); + if (ret < sizeof(*header)) { + printf("could not read %s\n", data->os_file); + goto err_out; + } + + printf("Android Image for '%s'\n", header->name); + + /* + * As on tftp we do not support lseek and we will just have to seek + * for the size of a page - 1 max just buffer instead to read to dummy + * data + */ + buf = xmalloc(header->page_size); + + to_read = header->page_size - sizeof(*header); + ret = read_full(fd, buf, to_read); + if (ret < 0) { + printf("could not read dummy %d from %s\n", to_read, data->os_file); + goto err_out; + } + + cmp = &header->kernel; + data->os_res = request_sdram_region("akernel", cmp->load_addr, cmp->size); + if (!data->os_res) { + ret = -ENOMEM; + goto err_out; + } + + ret = aimage_load_resource(fd, data->os_res, buf, header->page_size); + if (ret < 0) { + perror("could not read kernel"); + goto err_out; + } + + /* + * fastboot always expect a ramdisk + * in barebox we can be less restrictive + */ + cmp = &header->ramdisk; + if (cmp->size) { + data->initrd_res = request_sdram_region("ainitrd", cmp->load_addr, cmp->size); + if (!data->initrd_res) { + ret = -ENOMEM; + goto err_out; + } + + ret = aimage_load_resource(fd, data->initrd_res, buf, header->page_size); + if (ret < 0) { + perror("could not read initrd"); + goto err_out; + } + } + + if (!getenv("aimage_noverwrite_bootargs")) + setenv("bootargs", header->cmdline); + + if (!getenv("aimage_noverwrite_tags")) + armlinux_set_bootparams((void*)header->tags_addr); + + if (data->oftree) { + ret = of_fix_tree(data->oftree); + if (ret) + goto err_out; + } + + cmp = &header->second_stage; + if (cmp->size) { + void (*second)(void); + + snd_stage_res = request_sdram_region("asecond", cmp->load_addr, cmp->size); + if (!snd_stage_res) { + ret = -ENOMEM; + goto err_out; + } + + ret = aimage_load_resource(fd, snd_stage_res, buf, header->page_size); + if (ret < 0) { + perror("could not read initrd"); + goto err_out; + } + + second = (void*)snd_stage_res->start; + shutdown_barebox(); + + second(); + + reset_cpu(0); + } + + return __do_bootm_linux(data, 0); + +err_out: + close(fd); + + return ret; +} + +static struct image_handler aimage_handler = { + .name = "ARM Android Image", + .bootm = do_bootm_aimage, + .filetype = filetype_aimage, +}; + +#ifdef CONFIG_CMD_BOOTM_AIMAGE +BAREBOX_MAGICVAR(aimage_noverwrite_bootargs, "Disable overwrite of the bootargs with the one present in aimage"); +BAREBOX_MAGICVAR(aimage_noverwrite_tags, "Disable overwrite of the tags addr with the one present in aimage"); +#endif + static int armlinux_register_image_handler(void) { register_image_handler(&barebox_handler); register_image_handler(&uimage_handler); register_image_handler(&rawimage_handler); register_image_handler(&zimage_handler); + if (IS_BUILTIN(CONFIG_CMD_BOOTM_AIMAGE)) + register_image_handler(&aimage_handler); return 0; } diff --git a/commands/Kconfig b/commands/Kconfig index d7fdf04cf..49a56ca2f 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -359,6 +359,13 @@ config CMD_BOOTM_OFTREE_UIMAGE Support using oftree uImages. Without this only raw oftree blobs can be used. +config CMD_BOOTM_AIMAGE + bool + prompt "bootm Android image support" + depends on CMD_BOOTM && ARM + help + Support using Android Images. + config CMD_UIMAGE tristate prompt "uimage" diff --git a/include/aimage.h b/include/aimage.h new file mode 100644 index 000000000..9702b7d35 --- /dev/null +++ b/include/aimage.h @@ -0,0 +1,74 @@ +/* + * (C) Copyright 2011 Jean-Christhophe PLAGNIOL-VILLARD + * + * Android boot image + * + * Under GPLv2 only + */ + +#ifndef __AIMAGE_H__ +#define __AIMAGE_H__ + +#define BOOT_MAGIC "ANDROID!" +#define BOOT_MAGIC_SIZE 8 +#define BOOT_NAME_SIZE 16 +#define BOOT_ARGS_SIZE 512 + +struct android_header_comp +{ + unsigned size; + unsigned load_addr; +}; + +struct android_header +{ + u8 magic[BOOT_MAGIC_SIZE]; + + struct android_header_comp kernel; + + struct android_header_comp ramdisk; + + struct android_header_comp second_stage; + + /* physical addr for kernel tags */ + unsigned tags_addr; + /* flash page size we assume */ + unsigned page_size; + /* future expansion: should be 0 */ + unsigned unused[2]; + + unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ + + unsigned char cmdline[BOOT_ARGS_SIZE]; + + unsigned 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 /* __AIMAGE_H__ */