diff mbox series

[v3,3/9] cmd: abootimg: Add abootimg command

Message ID 20191224195455.31836-4-semen.protsenko@linaro.org
State Changes Requested, archived
Delegated to: Lokesh Vutla
Headers show
Series am57xx: Implement Android 10 boot flow | expand

Commit Message

Sam Protsenko Dec. 24, 2019, 7:54 p.m. UTC
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 <semen.protsenko@linaro.org>
---
 cmd/Kconfig    |   8 ++
 cmd/Makefile   |   1 +
 cmd/abootimg.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 251 insertions(+)
 create mode 100644 cmd/abootimg.c

Comments

Eugeniu Rosca Jan. 5, 2020, 8:38 p.m. UTC | #1
Hi,

With below nits, I have provided the Reviewed-by/Tested-by signatures.

On Tue, Dec 24, 2019 at 09:54:49PM +0200, Sam Protsenko wrote:
> 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"

FWIW, 'scripted manner' is more common, as suggested by Ngram:
https://tinyurl.com/rck3ysj

> diff --git a/cmd/abootimg.c b/cmd/abootimg.c
> +static int abootimg_get_dtb_by_index(int argc, char * const argv[])
> +{
> +	u32 num;
> +	char *endp;
> +	ulong addr;
> +	u32 size;
> +
> +	if (argc < 1 || argc > 3)
> +		return CMD_RET_USAGE;
> +
> +	num = simple_strtoul(argv[0] + strlen("--index="), &endp, 0);
> +	if (*endp != '\0') {
> +		printf("Error: Wrong num\n");
> +		return CMD_RET_FAILURE;
> +	}

The way '--index=' option is processed right now results in below
inconsistencies:

=> abootimg get dtb --index=0
1980
 `- expected output

=> abootimg get dtb --index=
1980
 `- unexpected output (expected error)

=> abootimg get dtb --index=0 --index=1
=>
 `- unexpected output (expected error)

> +U_BOOT_CMD(
> +	abootimg, CONFIG_SYS_MAXARGS, 0, do_abootimg,
> +	"manipulate Android Boot Image",
> +	"addr <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=<num> [addr_var [size_var]]\n"
> +	"    - get address and size (hex) of DT blob in the image by index\n"
> +	"      <num>: 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\n"

[minor] Superfluous blank line at the end of help.

Apart from the above, testing two Android v2 images containing the
DTB in so called "concat" and DTBO formats didn't reveal any issues.

Reviewed-by: Eugeniu Rosca <erosca@de.adit-jv.com>
Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com>
Simon Glass Jan. 8, 2020, 5:39 p.m. UTC | #2
On Tue, 24 Dec 2019 at 12:55, Sam Protsenko <semen.protsenko@linaro.org> wrote:
>
> 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 <semen.protsenko@linaro.org>
> ---
>  cmd/Kconfig    |   8 ++
>  cmd/Makefile   |   1 +
>  cmd/abootimg.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 251 insertions(+)
>  create mode 100644 cmd/abootimg.c

Reviewed-by: Simon Glass <sjg@chromium.org>

Can we have a test please?
diff mbox series

Patch

diff --git a/cmd/Kconfig b/cmd/Kconfig
index f63adbdc3a..e25ac7ee57 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -356,6 +356,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 c17ee20b25..8ccd8c7b87 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 0000000000..d4675c275b
--- /dev/null
+++ b/cmd/abootimg.c
@@ -0,0 +1,242 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Linaro Ltd.
+ * Sam Protsenko <semen.protsenko@linaro.org>
+ */
+
+#include <android_image.h>
+#include <common.h>
+#include <mapmem.h>
+
+#define abootimg_addr() (_abootimg_addr == -1 ? 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[])
+{
+	u32 num;
+	char *endp;
+	ulong addr;
+	u32 size;
+
+	if (argc < 1 || argc > 3)
+		return CMD_RET_USAGE;
+
+	num = simple_strtoul(argv[0] + strlen("--index="), &endp, 0);
+	if (*endp != '\0') {
+		printf("Error: Wrong 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 {
+		env_set_hex(argv[1], addr);
+		if (argc == 3)
+			env_set_hex(argv[2], size);
+	}
+
+	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 <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=<num> [addr_var [size_var]]\n"
+	"    - get address and size (hex) of DT blob in the image by index\n"
+	"      <num>: 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\n"
+);