diff mbox

[U-Boot,6/6] cmd: Add "boot_android" command.

Message ID 20170402084952.5102-7-deymo@google.com
State Changes Requested
Delegated to: Tom Rini
Headers show

Commit Message

Alex Deymo April 2, 2017, 8:49 a.m. UTC
The new "boot_android" command simply executes the Android Bootloader
flow. This receives the location (interface, dev, partition) of the
Android "misc" partition which is then used to lookup and infer the
kernel and system images that should be booted from the passed slot.

Test: Booted a rpi3 build with Android Things.
Signed-off-by: Alex Deymo <deymo@google.com>
---
 README             |   6 +++
 cmd/Kconfig        |  10 +++++
 cmd/Makefile       |   1 +
 cmd/boot_android.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 143 insertions(+)
 create mode 100644 cmd/boot_android.c

Comments

Lukasz Majewski April 4, 2017, 2:46 p.m. UTC | #1
Hi Alex,

> The new "boot_android" command simply executes the Android Bootloader
> flow. This receives the location (interface, dev, partition) of the
> Android "misc" partition which is then used to lookup and infer the
> kernel and system images that should be booted from the passed slot.

I'm just wondering if it would be possible to modify/extend 'bootm'
command to boot this android image instead of introducing two extra
commands - namely "load_android" and "boot_android"?

Then we could use "load" command to load the android image as is and
then bootm, which would recognize it (I suppose that android image
header allows this) and boot?

Best regards,
Ɓukasz Majewski

> 
> Test: Booted a rpi3 build with Android Things.
> Signed-off-by: Alex Deymo <deymo@google.com>
> ---
>  README             |   6 +++
>  cmd/Kconfig        |  10 +++++
>  cmd/Makefile       |   1 +
>  cmd/boot_android.c | 126
> +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files
> changed, 143 insertions(+) create mode 100644 cmd/boot_android.c
> 
> diff --git a/README b/README
> index 384cc6aabb..5f62e14d94 100644
> --- a/README
> +++ b/README
> @@ -1484,6 +1484,12 @@ The following options need to be configured:
>  		sending again an USB request to the device.
>  
>  - Android Bootloader support:
> +		CONFIG_CMD_BOOT_ANDROID
> +		This enables the command "boot_android" which
> executes the
> +		Android Bootloader flow. Enabling
> CONFIG_CMD_FASTBOOT is
> +		recommended to support the Android Fastboot protocol
> as part
> +		of the bootloader.
> +
>  		CONFIG_ANDROID_BOOTLOADER
>  		This enables support for the Android bootloader
> flow. Android devices can boot in normal mode, recovery mode or
> bootloader diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 87a445d269..c4c22464b1 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -431,6 +431,16 @@ config CMD_LOAD_ANDROID
>  	  define the size and kernel address on the header, which
> are used by this command.
>  
> +config CMD_BOOT_ANDROID
> +	bool "boot_android"
> +	default n
> +	depends on ANDROID_BOOTLOADER
> +	help
> +	  Performs the Android Bootloader boot flow, loading the
> appropriate
> +	  Android image (normal kernel, recovery kernel or
> "bootloader" mode)
> +	  and booting it. The boot mode is determined by the
> contents of the
> +	  Android Bootloader Message.
> +
>  config CMD_FLASH
>  	bool "flinfo, erase, protect"
>  	default y
> diff --git a/cmd/Makefile b/cmd/Makefile
> index 2f75dab040..348cf75386 100644
> --- a/cmd/Makefile
> +++ b/cmd/Makefile
> @@ -22,6 +22,7 @@ obj-$(CONFIG_CMD_BDI) += bdinfo.o
>  obj-$(CONFIG_CMD_BEDBUG) += bedbug.o
>  obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o
>  obj-$(CONFIG_CMD_BMP) += bmp.o
> +obj-$(CONFIG_CMD_BOOT_ANDROID) += boot_android.o
>  obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o
>  obj-$(CONFIG_CMD_BOOTMENU) += bootmenu.o
>  obj-$(CONFIG_CMD_BOOTLDR) += bootldr.o
> diff --git a/cmd/boot_android.c b/cmd/boot_android.c
> new file mode 100644
> index 0000000000..067d9c7637
> --- /dev/null
> +++ b/cmd/boot_android.c
> @@ -0,0 +1,126 @@
> +/*
> + * Copyright (C) 2016 The Android Open Source Project
> + *
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +
> +#include <android_bootloader.h>
> +#include <common.h>
> +#include <command.h>
> +
> +/**
> + * part_get_info_by_dev_and_name - Parse a device number and
> partition name
> + * string in the form of "device_num;partition_name", for example
> "0;misc".
> + * If the partition is found, sets dev_desc and part_info
> accordingly with the
> + * information of the partition with the given partition_name.
> + *
> + * @dev_iface:		Device interface.
> + * @dev_part_str:	Input string argument, like "0;misc".
> + * @dev_desc:		Place to put the device description
> pointer.
> + * @part_info:		Place to put the partition information.
> + * @return 0 on success, or -1 on error
> + */
> +static int part_get_info_by_dev_and_name(const char *dev_iface,
> +					 const char *dev_part_str,
> +					 struct blk_desc **dev_desc,
> +					 disk_partition_t *part_info)
> +{
> +	char *ep;
> +	const char *part_str;
> +	int dev_num;
> +
> +	part_str = strchr(dev_part_str, ';');
> +	if (!part_str)
> +		return -1;
> +
> +	dev_num = simple_strtoul(dev_part_str, &ep, 16);
> +	if (ep != part_str) {
> +		/* Not all the first part before the ; was parsed. */
> +		return -1;
> +	}
> +	part_str++;
> +
> +	*dev_desc = blk_get_dev(dev_iface, dev_num);
> +	if (!*dev_desc) {
> +		printf("Could not find %s %d\n", dev_iface, dev_num);
> +		return -1;
> +	}
> +	if (part_get_info_by_name(*dev_desc, part_str, part_info) <
> 0) {
> +		printf("Could not find \"%s\" partition\n",
> part_str);
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +static int do_boot_android(cmd_tbl_t *cmdtp, int flag, int argc,
> +			   char * const argv[])
> +{
> +	unsigned long load_address;
> +	int ret = CMD_RET_SUCCESS;
> +	char *addr_arg_endp, *addr_str;
> +	struct blk_desc *dev_desc;
> +	disk_partition_t part_info;
> +	const char *misc_part_iface;
> +	const char *misc_part_desc;
> +
> +	if (argc < 4)
> +		return CMD_RET_USAGE;
> +	if (argc > 5)
> +		return CMD_RET_USAGE;
> +
> +	if (argc >= 5) {
> +		load_address = simple_strtoul(argv[4],
> &addr_arg_endp, 16);
> +		if (addr_arg_endp == argv[4] || *addr_arg_endp !=
> '\0')
> +			return CMD_RET_USAGE;
> +	} else {
> +		addr_str = getenv("loadaddr");
> +		if (addr_str)
> +			load_address = simple_strtoul(addr_str,
> NULL, 16);
> +		else
> +			load_address = CONFIG_SYS_LOAD_ADDR;
> +	}
> +
> +	/* Lookup the "misc" partition from argv[1] and argv[2] */
> +	misc_part_iface = argv[1];
> +	misc_part_desc = argv[2];
> +	/* Split the part_name if passed as "$dev_num;part_name". */
> +	if (part_get_info_by_dev_and_name(misc_part_iface,
> misc_part_desc,
> +					  &dev_desc, &part_info) <
> 0) {
> +		/* Couldn't lookup by name from mmc, try looking up
> the
> +		 * partition description directly.
> +		 */
> +		if (blk_get_device_part_str(misc_part_iface,
> misc_part_desc,
> +					    &dev_desc, &part_info,
> 1) < 0) {
> +			printf("Couldn't find partition %s %s\n",
> +			       misc_part_iface, misc_part_desc);
> +			return CMD_RET_FAILURE;
> +		}
> +	}
> +
> +	ret = android_bootloader_boot_flow(dev_desc, &part_info,
> argv[3],
> +					   load_address);
> +	if (ret < 0) {
> +		printf("Android boot failed, error %d.\n", ret);
> +		return CMD_RET_FAILURE;
> +	}
> +	return CMD_RET_SUCCESS;
> +}
> +
> +U_BOOT_CMD(
> +	boot_android, 5, 0, do_boot_android,
> +	"Execute the Android Bootloader flow.",
> +	"<interface> <dev[:part|;part_name]> <slot>
> [<kernel_addr>]\n"
> +	"    - Load the Boot Control Block (BCB) from the partition
> 'part' on\n"
> +	"      device type 'interface' instance 'dev' to determine
> the boot\n"
> +	"      mode, and load and execute the appropriate kernel.\n"
> +	"      In normal and recovery mode, the kernel will be
> loaded from\n"
> +	"      the corresponding \"boot\" partition. In bootloader
> mode, the\n"
> +	"      command defined in the \"fastbootcmd\" variable will
> be\n"
> +	"      executed.\n"
> +	"      On Android devices with multiple slots, the pass
> 'slot' is\n"
> +	"      used to load the appropriate kernel. The standard
> slot names\n"
> +	"      are 'a' and 'b'.\n"
> +	"    - If 'part_name' is passed, preceded with a ; instead
> of :, the\n"
> +	"      partition name whose label is 'part_name' will be
> looked up in\n"
> +	"      the partition table. This is commonly the \"misc\"
> partition.\n" +);




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
diff mbox

Patch

diff --git a/README b/README
index 384cc6aabb..5f62e14d94 100644
--- a/README
+++ b/README
@@ -1484,6 +1484,12 @@  The following options need to be configured:
 		sending again an USB request to the device.
 
 - Android Bootloader support:
+		CONFIG_CMD_BOOT_ANDROID
+		This enables the command "boot_android" which executes the
+		Android Bootloader flow. Enabling CONFIG_CMD_FASTBOOT is
+		recommended to support the Android Fastboot protocol as part
+		of the bootloader.
+
 		CONFIG_ANDROID_BOOTLOADER
 		This enables support for the Android bootloader flow. Android
 		devices can boot in normal mode, recovery mode or bootloader
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 87a445d269..c4c22464b1 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -431,6 +431,16 @@  config CMD_LOAD_ANDROID
 	  define the size and kernel address on the header, which are used by
 	  this command.
 
+config CMD_BOOT_ANDROID
+	bool "boot_android"
+	default n
+	depends on ANDROID_BOOTLOADER
+	help
+	  Performs the Android Bootloader boot flow, loading the appropriate
+	  Android image (normal kernel, recovery kernel or "bootloader" mode)
+	  and booting it. The boot mode is determined by the contents of the
+	  Android Bootloader Message.
+
 config CMD_FLASH
 	bool "flinfo, erase, protect"
 	default y
diff --git a/cmd/Makefile b/cmd/Makefile
index 2f75dab040..348cf75386 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -22,6 +22,7 @@  obj-$(CONFIG_CMD_BDI) += bdinfo.o
 obj-$(CONFIG_CMD_BEDBUG) += bedbug.o
 obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o
 obj-$(CONFIG_CMD_BMP) += bmp.o
+obj-$(CONFIG_CMD_BOOT_ANDROID) += boot_android.o
 obj-$(CONFIG_CMD_BOOTEFI) += bootefi.o
 obj-$(CONFIG_CMD_BOOTMENU) += bootmenu.o
 obj-$(CONFIG_CMD_BOOTLDR) += bootldr.o
diff --git a/cmd/boot_android.c b/cmd/boot_android.c
new file mode 100644
index 0000000000..067d9c7637
--- /dev/null
+++ b/cmd/boot_android.c
@@ -0,0 +1,126 @@ 
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <android_bootloader.h>
+#include <common.h>
+#include <command.h>
+
+/**
+ * part_get_info_by_dev_and_name - Parse a device number and partition name
+ * string in the form of "device_num;partition_name", for example "0;misc".
+ * If the partition is found, sets dev_desc and part_info accordingly with the
+ * information of the partition with the given partition_name.
+ *
+ * @dev_iface:		Device interface.
+ * @dev_part_str:	Input string argument, like "0;misc".
+ * @dev_desc:		Place to put the device description pointer.
+ * @part_info:		Place to put the partition information.
+ * @return 0 on success, or -1 on error
+ */
+static int part_get_info_by_dev_and_name(const char *dev_iface,
+					 const char *dev_part_str,
+					 struct blk_desc **dev_desc,
+					 disk_partition_t *part_info)
+{
+	char *ep;
+	const char *part_str;
+	int dev_num;
+
+	part_str = strchr(dev_part_str, ';');
+	if (!part_str)
+		return -1;
+
+	dev_num = simple_strtoul(dev_part_str, &ep, 16);
+	if (ep != part_str) {
+		/* Not all the first part before the ; was parsed. */
+		return -1;
+	}
+	part_str++;
+
+	*dev_desc = blk_get_dev(dev_iface, dev_num);
+	if (!*dev_desc) {
+		printf("Could not find %s %d\n", dev_iface, dev_num);
+		return -1;
+	}
+	if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) {
+		printf("Could not find \"%s\" partition\n", part_str);
+		return -1;
+	}
+	return 0;
+}
+
+static int do_boot_android(cmd_tbl_t *cmdtp, int flag, int argc,
+			   char * const argv[])
+{
+	unsigned long load_address;
+	int ret = CMD_RET_SUCCESS;
+	char *addr_arg_endp, *addr_str;
+	struct blk_desc *dev_desc;
+	disk_partition_t part_info;
+	const char *misc_part_iface;
+	const char *misc_part_desc;
+
+	if (argc < 4)
+		return CMD_RET_USAGE;
+	if (argc > 5)
+		return CMD_RET_USAGE;
+
+	if (argc >= 5) {
+		load_address = simple_strtoul(argv[4], &addr_arg_endp, 16);
+		if (addr_arg_endp == argv[4] || *addr_arg_endp != '\0')
+			return CMD_RET_USAGE;
+	} else {
+		addr_str = getenv("loadaddr");
+		if (addr_str)
+			load_address = simple_strtoul(addr_str, NULL, 16);
+		else
+			load_address = CONFIG_SYS_LOAD_ADDR;
+	}
+
+	/* Lookup the "misc" partition from argv[1] and argv[2] */
+	misc_part_iface = argv[1];
+	misc_part_desc = argv[2];
+	/* Split the part_name if passed as "$dev_num;part_name". */
+	if (part_get_info_by_dev_and_name(misc_part_iface, misc_part_desc,
+					  &dev_desc, &part_info) < 0) {
+		/* Couldn't lookup by name from mmc, try looking up the
+		 * partition description directly.
+		 */
+		if (blk_get_device_part_str(misc_part_iface, misc_part_desc,
+					    &dev_desc, &part_info, 1) < 0) {
+			printf("Couldn't find partition %s %s\n",
+			       misc_part_iface, misc_part_desc);
+			return CMD_RET_FAILURE;
+		}
+	}
+
+	ret = android_bootloader_boot_flow(dev_desc, &part_info, argv[3],
+					   load_address);
+	if (ret < 0) {
+		printf("Android boot failed, error %d.\n", ret);
+		return CMD_RET_FAILURE;
+	}
+	return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+	boot_android, 5, 0, do_boot_android,
+	"Execute the Android Bootloader flow.",
+	"<interface> <dev[:part|;part_name]> <slot> [<kernel_addr>]\n"
+	"    - Load the Boot Control Block (BCB) from the partition 'part' on\n"
+	"      device type 'interface' instance 'dev' to determine the boot\n"
+	"      mode, and load and execute the appropriate kernel.\n"
+	"      In normal and recovery mode, the kernel will be loaded from\n"
+	"      the corresponding \"boot\" partition. In bootloader mode, the\n"
+	"      command defined in the \"fastbootcmd\" variable will be\n"
+	"      executed.\n"
+	"      On Android devices with multiple slots, the pass 'slot' is\n"
+	"      used to load the appropriate kernel. The standard slot names\n"
+	"      are 'a' and 'b'.\n"
+	"    - If 'part_name' is passed, preceded with a ; instead of :, the\n"
+	"      partition name whose label is 'part_name' will be looked up in\n"
+	"      the partition table. This is commonly the \"misc\" partition.\n"
+);