From 94f6d0d1bd602ffa520e5676177e770fcfe8472f Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Fri, 24 Jan 2020 17:53:42 +0200 Subject: [PATCH] cmd: abootimg: Add abootimg command This command can be used to extract fields and image payloads from Android Boot Image. It can be used for example to implement boot flow where dtb is taken from boot.img (as v2 incorporated dtb inside of boot.img). Using this command, one can obtain needed dtb blob from boot.img in scripting manner, and then apply needed dtbo's (from "dtbo" partition) on top of that, providing then the resulting image to bootm command in order to boot the Android. Also right now this command has the sub-command to get an address and size of recovery dtbo from recovery image (for non-A/B devices only, see [1,2] for details). It can be tested like this: => mmc dev 1 => part start mmc 1 boot_a boot_start => part size mmc 1 boot_a boot_size => mmc read $loadaddr $boot_start $boot_size => abootimg get ver => abootimg dump dtb [1] https://source.android.com/devices/bootloader/boot-image-header [2] https://source.android.com/devices/architecture/dto/partitions Signed-off-by: Sam Protsenko Signed-off-by: Lokesh Vutla --- cmd/Kconfig | 8 ++ cmd/Makefile | 1 + cmd/abootimg.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 cmd/abootimg.c diff --git a/cmd/Kconfig b/cmd/Kconfig index 6e1efaaf85d..4734da17fed 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -386,6 +386,14 @@ config CMD_ADTIMG files should be merged in one dtb further, which needs to be passed to the kernel, as part of a boot process. +config CMD_ABOOTIMG + bool "abootimg" + depends on ANDROID_BOOT_IMAGE + help + Android Boot Image manipulation commands. Allows one to extract + images contained in boot.img, like kernel, ramdisk, dtb, etc, and + obtain corresponding meta-information from boot.img. + config CMD_ELF bool "bootelf, bootvx" default y diff --git a/cmd/Makefile b/cmd/Makefile index 4f29b72c695..f1dd513a4b4 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -48,6 +48,7 @@ ifdef CONFIG_POST obj-$(CONFIG_CMD_DIAG) += diag.o endif obj-$(CONFIG_CMD_ADTIMG) += adtimg.o +obj-$(CONFIG_CMD_ABOOTIMG) += abootimg.o obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o diff --git a/cmd/abootimg.c b/cmd/abootimg.c new file mode 100644 index 00000000000..670bcb3aaa8 --- /dev/null +++ b/cmd/abootimg.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2020 + * Sam Protsenko + */ + +#include +#include +#include + +#define abootimg_addr() \ + (_abootimg_addr == -1 ? image_load_addr : _abootimg_addr) + +/* Please use abootimg_addr() macro to obtain the boot image address */ +static ulong _abootimg_addr = -1; + +static int abootimg_get_ver(int argc, char * const argv[]) +{ + const struct andr_img_hdr *hdr; + int res = CMD_RET_SUCCESS; + + if (argc > 1) + return CMD_RET_USAGE; + + hdr = map_sysmem(abootimg_addr(), sizeof(*hdr)); + if (android_image_check_header(hdr)) { + printf("Error: Boot Image header is incorrect\n"); + res = CMD_RET_FAILURE; + goto exit; + } + + if (argc == 0) + printf("%u\n", hdr->header_version); + else + env_set_ulong(argv[0], hdr->header_version); + +exit: + unmap_sysmem(hdr); + return res; +} + +static int abootimg_get_recovery_dtbo(int argc, char * const argv[]) +{ + ulong addr; + u32 size; + + if (argc > 2) + return CMD_RET_USAGE; + + if (!android_image_get_dtbo(abootimg_addr(), &addr, &size)) + return CMD_RET_FAILURE; + + if (argc == 0) { + printf("%lx\n", addr); + } else { + env_set_hex(argv[0], addr); + if (argc == 2) + env_set_hex(argv[1], size); + } + + return CMD_RET_SUCCESS; +} + +static int abootimg_get_dtb_load_addr(int argc, char * const argv[]) +{ + const struct andr_img_hdr *hdr; + int res = CMD_RET_SUCCESS; + + if (argc > 1) + return CMD_RET_USAGE; + + hdr = map_sysmem(abootimg_addr(), sizeof(*hdr)); + if (android_image_check_header(hdr)) { + printf("Error: Boot Image header is incorrect\n"); + res = CMD_RET_FAILURE; + goto exit; + } + + if (hdr->header_version < 2) { + printf("Error: header_version must be >= 2 for this\n"); + res = CMD_RET_FAILURE; + goto exit; + } + + if (argc == 0) + printf("%lx\n", (ulong)hdr->dtb_addr); + else + env_set_hex(argv[0], (ulong)hdr->dtb_addr); + +exit: + unmap_sysmem(hdr); + return res; +} + +static int abootimg_get_dtb_by_index(int argc, char * const argv[]) +{ + const char *index_str; + u32 num; + char *endp; + ulong addr; + u32 size; + + if (argc < 1 || argc > 3) + return CMD_RET_USAGE; + + index_str = argv[0] + strlen("--index="); + if (index_str[0] == '\0') { + printf("Error: Wrong index num\n"); + return CMD_RET_FAILURE; + } + + num = simple_strtoul(index_str, &endp, 0); + if (*endp != '\0') { + printf("Error: Wrong index num\n"); + return CMD_RET_FAILURE; + } + + if (!android_image_get_dtb_by_index(abootimg_addr(), num, + &addr, &size)) { + return CMD_RET_FAILURE; + } + + if (argc == 1) { + printf("%lx\n", addr); + } else { + if (env_set_hex(argv[1], addr)) { + printf("Error: Can't set [addr_var]\n"); + return CMD_RET_FAILURE; + } + + if (argc == 3) { + if (env_set_hex(argv[2], size)) { + printf("Error: Can't set [size_var]\n"); + return CMD_RET_FAILURE; + } + } + } + + return CMD_RET_SUCCESS; +} + +static int abootimg_get_dtb(int argc, char * const argv[]) +{ + if (argc < 1) + return CMD_RET_USAGE; + + if (strstr(argv[0], "--index=")) + return abootimg_get_dtb_by_index(argc, argv); + + return CMD_RET_USAGE; +} + +static int do_abootimg_addr(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + char *endp; + ulong img_addr; + + if (argc != 2) + return CMD_RET_USAGE; + + img_addr = simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0') { + printf("Error: Wrong image address\n"); + return CMD_RET_FAILURE; + } + + _abootimg_addr = img_addr; + return CMD_RET_SUCCESS; +} + +static int do_abootimg_get(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + const char *param; + + if (argc < 2) + return CMD_RET_USAGE; + + param = argv[1]; + argc -= 2; + argv += 2; + if (!strcmp(param, "ver")) + return abootimg_get_ver(argc, argv); + else if (!strcmp(param, "recovery_dtbo")) + return abootimg_get_recovery_dtbo(argc, argv); + else if (!strcmp(param, "dtb_load_addr")) + return abootimg_get_dtb_load_addr(argc, argv); + else if (!strcmp(param, "dtb")) + return abootimg_get_dtb(argc, argv); + + return CMD_RET_USAGE; +} + +static int do_abootimg_dump(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + if (argc != 2) + return CMD_RET_USAGE; + + if (!strcmp(argv[1], "dtb")) { + if (android_image_print_dtb_contents(abootimg_addr())) + return CMD_RET_FAILURE; + } else { + return CMD_RET_USAGE; + } + + return CMD_RET_SUCCESS; +} + +static cmd_tbl_t cmd_abootimg_sub[] = { + U_BOOT_CMD_MKENT(addr, 2, 1, do_abootimg_addr, "", ""), + U_BOOT_CMD_MKENT(dump, 2, 1, do_abootimg_dump, "", ""), + U_BOOT_CMD_MKENT(get, 5, 1, do_abootimg_get, "", ""), +}; + +static int do_abootimg(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + cmd_tbl_t *cp; + + cp = find_cmd_tbl(argv[1], cmd_abootimg_sub, + ARRAY_SIZE(cmd_abootimg_sub)); + + /* Strip off leading 'abootimg' command argument */ + argc--; + argv++; + + if (!cp || argc > cp->maxargs) + return CMD_RET_USAGE; + if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) + return CMD_RET_SUCCESS; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD( + abootimg, CONFIG_SYS_MAXARGS, 0, do_abootimg, + "manipulate Android Boot Image", + "addr \n" + " - set the address in RAM where boot image is located\n" + " ($loadaddr is used by default)\n" + "abootimg dump dtb\n" + " - print info for all DT blobs in DTB area\n" + "abootimg get ver [varname]\n" + " - get header version\n" + "abootimg get recovery_dtbo [addr_var [size_var]]\n" + " - get address and size (hex) of recovery DTBO area in the image\n" + " [addr_var]: variable name to contain DTBO area address\n" + " [size_var]: variable name to contain DTBO area size\n" + "abootimg get dtb_load_addr [varname]\n" + " - get load address (hex) of DTB, from image header\n" + "abootimg get dtb --index= [addr_var [size_var]]\n" + " - get address and size (hex) of DT blob in the image by index\n" + " : index number of desired DT blob in DTB area\n" + " [addr_var]: variable name to contain DT blob address\n" + " [size_var]: variable name to contain DT blob size" +);