All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/6] Android A/B Bootloader support
       [not found] <a74b3d5e65b4bf5c2edca98bba9e678be762ebe7>
@ 2017-04-02  8:49 ` Alex Deymo
  2017-04-02  8:49   ` [U-Boot] [PATCH 1/6] image: Update include/android_image.h Alex Deymo
  2017-04-19  8:42   ` [U-Boot] [PATCH 0/6] Android A/B Bootloader support Kever Yang
  0 siblings, 2 replies; 20+ messages in thread
From: Alex Deymo @ 2017-04-02  8:49 UTC (permalink / raw)
  To: u-boot

An "Android Bootloader" has a lot of requirements about how it should
behave which Android partners must implement. In particular, the new
A/B updates [1] added more requirements and flows to the bootloader
which are not common, on top of the existing flows.

For example, a few uncommon requirements include:
* Lookup in the BCB (boot control block) whether a "recovery" message
  is stored. This is used by the recovery environment when applying a
  multi-stage update in the legacy update model (recovery reboots to
  recovery again) and for interrumpted factory-reset (a reboot during
  the factory reset should continue to reboot into factory reset until
  it is done).
* A new "repair" mode. In the A/B model, when none of the slots is
  bootable, the device would boot into repair mode, which is often the
  same as "bootloader" mode (fastboot).
* Recovery as root: In newer version of AOSP, it is possible to mount
  the system image as / without an initramfs, which then frees up the
  initramfs in the "boot" partition to hold the "recovery" initramfs.
  This is the default for new devices and required for the A/B setup.

This patchset updates the Android-related headers and introduces new
commands to boot a recent Android build. This work is based on the
bootloader used in the Raspberry Pi in Android Things and extensively
tested there.

[1] https://source.android.com/devices/tech/ota/ab_updates.html


Alex Deymo (6):
  image: Update include/android_image.h
  image: Implement a function to load Android Images.
  cmd: Add 'load_android' command to load Android images.
  disk: Return the partition number in part_get_info_by_name()
  Initial support for the Android Bootloader flow
  cmd: Add "boot_android" command.

 README                               |  25 ++-
 cmd/Kconfig                          |  19 ++
 cmd/Makefile                         |   2 +
 cmd/boot_android.c                   | 126 +++++++++++++
 cmd/load_android.c                   |  56 ++++++
 common/Kconfig                       |  19 ++
 common/Makefile                      |   1 +
 common/android_bootloader.c          | 350 +++++++++++++++++++++++++++++++++++
 common/fb_mmc.c                      |   6 +-
 common/image-android.c               |  60 ++++++
 disk/part.c                          |   2 +-
 include/android_bootloader.h         |  48 +++++
 include/android_bootloader_message.h | 174 +++++++++++++++++
 include/android_image.h              |  24 ++-
 include/image.h                      |  19 ++
 include/part.h                       |   3 +-
 16 files changed, 920 insertions(+), 14 deletions(-)
 create mode 100644 cmd/boot_android.c
 create mode 100644 cmd/load_android.c
 create mode 100644 common/android_bootloader.c
 create mode 100644 include/android_bootloader.h
 create mode 100644 include/android_bootloader_message.h

-- 
2.12.2.564.g063fe858b8-goog

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 1/6] image: Update include/android_image.h
  2017-04-02  8:49 ` [U-Boot] [PATCH 0/6] Android A/B Bootloader support Alex Deymo
@ 2017-04-02  8:49   ` Alex Deymo
  2017-04-02  8:49     ` [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images Alex Deymo
                       ` (2 more replies)
  2017-04-19  8:42   ` [U-Boot] [PATCH 0/6] Android A/B Bootloader support Kever Yang
  1 sibling, 3 replies; 20+ messages in thread
From: Alex Deymo @ 2017-04-02  8:49 UTC (permalink / raw)
  To: u-boot

Update the Android image header format to the latest version published
in AOSP. The original code moved to a new repository, so this patch also
updates the reference to that path.

Signed-off-by: Alex Deymo <deymo@google.com>
---
 common/image-android.c  |  9 +++++++++
 include/android_image.h | 24 +++++++++++++++++++-----
 2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/common/image-android.c b/common/image-android.c
index ee03b96aaa..c668407817 100644
--- a/common/image-android.c
+++ b/common/image-android.c
@@ -161,6 +161,9 @@ int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
 void android_print_contents(const struct andr_img_hdr *hdr)
 {
 	const char * const p = IMAGE_INDENT_STRING;
+	/* os_version = ver << 11 | lvl */
+	u32 os_ver = hdr->os_version >> 11;
+	u32 os_lvl = hdr->os_version & ((1U << 11) - 1);
 
 	printf("%skernel size:      %x\n", p, hdr->kernel_size);
 	printf("%skernel address:   %x\n", p, hdr->kernel_addr);
@@ -170,6 +173,12 @@ void android_print_contents(const struct andr_img_hdr *hdr)
 	printf("%ssecond address:   %x\n", p, hdr->second_addr);
 	printf("%stags address:     %x\n", p, hdr->tags_addr);
 	printf("%spage size:        %x\n", p, hdr->page_size);
+	/* ver = A << 14 | B << 7 | C         (7 bits for each of A, B, C)
+	 * lvl = ((Y - 2000) & 127) << 4 | M  (7 bits for Y, 4 bits for M) */
+	printf("%sos_version:       %x (ver: %u.%u.%u, level: %u.%u)\n",
+	       p, hdr->os_version,
+	       (os_ver >> 7) & 0x7F, (os_ver >> 14) & 0x7F, os_ver & 0x7F,
+	       (os_lvl >> 4) + 2000, os_lvl & 0x0F);
 	printf("%sname:             %s\n", p, hdr->name);
 	printf("%scmdline:          %s\n", p, hdr->cmdline);
 }
diff --git a/include/android_image.h b/include/android_image.h
index 094d60afe8..dfd4d9d72c 100644
--- a/include/android_image.h
+++ b/include/android_image.h
@@ -1,8 +1,8 @@
 /*
  * This is from the Android Project,
- * Repository: https://android.googlesource.com/platform/bootable/bootloader/legacy
- * File: include/boot/bootimg.h
- * Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
+ * Repository: https://android.googlesource.com/platform/system/core/
+ * File: mkbootimg/bootimg.h
+ * Commit: d162828814b08ada310846a33205befb69ef5799
  *
  * Copyright (C) 2008 The Android Open Source Project
  *
@@ -12,10 +12,13 @@
 #ifndef _ANDROID_IMAGE_H_
 #define _ANDROID_IMAGE_H_
 
+typedef struct andr_img_hdr andr_img_hdr;
+
 #define ANDR_BOOT_MAGIC "ANDROID!"
 #define ANDR_BOOT_MAGIC_SIZE 8
 #define ANDR_BOOT_NAME_SIZE 16
 #define ANDR_BOOT_ARGS_SIZE 512
+#define ANDR_BOOT_EXTRA_ARGS_SIZE 1024
 
 struct andr_img_hdr {
 	char magic[ANDR_BOOT_MAGIC_SIZE];
@@ -31,14 +34,25 @@ struct andr_img_hdr {
 
 	u32 tags_addr;		/* physical addr for kernel tags */
 	u32 page_size;		/* flash page size we assume */
-	u32 unused[2];		/* future expansion: should be 0 */
+	u32 unused;		/* reserved for future expansion: MUST be 0 */
+
+	/* operating system version and security patch level; for
+	 * version "A.B.C" and patch level "Y-M-D":
+	 * ver = A << 14 | B << 7 | C         (7 bits for each of A, B, C)
+	 * lvl = ((Y - 2000) & 127) << 4 | M  (7 bits for Y, 4 bits for M)
+	 * os_version = ver << 11 | lvl */
+	u32 os_version;
 
 	char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
 
 	char cmdline[ANDR_BOOT_ARGS_SIZE];
 
 	u32 id[8]; /* timestamp / checksum / sha1 / etc */
-};
+
+	/* Supplemental command line data; kept here to maintain
+	 * binary compatibility with older versions of mkbootimg */
+	char extra_cmdline[ANDR_BOOT_EXTRA_ARGS_SIZE];
+} __attribute__((packed));
 
 /*
  * +-----------------+
-- 
2.12.2.564.g063fe858b8-goog

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images.
  2017-04-02  8:49   ` [U-Boot] [PATCH 1/6] image: Update include/android_image.h Alex Deymo
@ 2017-04-02  8:49     ` Alex Deymo
  2017-04-02  8:49       ` [U-Boot] [PATCH 3/6] cmd: Add 'load_android' command to load Android images Alex Deymo
  2017-04-06 22:42       ` [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images Simon Glass
  2017-04-06 22:42     ` [U-Boot] [PATCH 1/6] image: Update include/android_image.h Simon Glass
  2017-05-12 17:18     ` [U-Boot] [U-Boot,1/6] " Tom Rini
  2 siblings, 2 replies; 20+ messages in thread
From: Alex Deymo @ 2017-04-02  8:49 UTC (permalink / raw)
  To: u-boot

This patch implements the logic needed to load an Android boot image
from storage, since the size and kernel address in Android images is
defined in its header.

Signed-off-by: Alex Deymo <deymo@google.com>
---
 common/image-android.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/image.h        | 19 +++++++++++++++++++
 2 files changed, 70 insertions(+)

diff --git a/common/image-android.c b/common/image-android.c
index c668407817..f040f5b400 100644
--- a/common/image-android.c
+++ b/common/image-android.c
@@ -8,6 +8,7 @@
 #include <image.h>
 #include <android_image.h>
 #include <malloc.h>
+#include <mapmem.h>
 #include <errno.h>
 
 #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR	0x10008000
@@ -146,6 +147,56 @@ int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
 	return 0;
 }
 
+long android_image_load(struct blk_desc *dev_desc,
+			const disk_partition_t *part_info,
+			unsigned long load_address,
+			unsigned long max_size) {
+	void *buf;
+	long blk_cnt, blk_read = 0;
+
+	if (max_size < part_info->blksz)
+		return -1;
+
+	/* We don't know the size of the Android image before reading the header
+	 * so we don't limit the size of the mapped memory.
+	 */
+	buf = map_sysmem(load_address, 0 /* size */);
+
+	/* Read the Android header first and then read the rest. */
+	if (blk_dread(dev_desc, part_info->start, 1, buf) != 1)
+		blk_read = -1;
+
+	if (!blk_read && android_image_check_header(buf) != 0) {
+		printf("** Invalid Android Image header **\n");
+		blk_read = -1;
+	}
+	if (!blk_read) {
+		blk_cnt = (android_image_get_end(buf) - (ulong)buf +
+			   part_info->blksz - 1) / part_info->blksz;
+		if (blk_cnt * part_info->blksz > max_size) {
+			debug("Android Image too big (%lu bytes, max %lu)\n",
+			      android_image_get_end(buf) - (ulong)buf,
+			      max_size);
+			blk_read = -1;
+		} else {
+			debug("Loading Android Image (%lu blocks) to 0x%lx... ",
+			      blk_cnt, load_address);
+			blk_read = blk_dread(dev_desc, part_info->start,
+					     blk_cnt, buf);
+		}
+	}
+
+	unmap_sysmem(buf);
+	if (blk_read < 0)
+		return blk_read;
+
+	debug("%lu blocks read: %s\n",
+	      blk_read, (blk_read == blk_cnt) ? "OK" : "ERROR");
+	if (blk_read != blk_cnt)
+		return -1;
+	return blk_read;
+}
+
 #if !defined(CONFIG_SPL_BUILD)
 /**
  * android_print_contents - prints out the contents of the Android format image
diff --git a/include/image.h b/include/image.h
index 2372518960..de448a9a01 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1241,6 +1241,25 @@ ulong android_image_get_end(const struct andr_img_hdr *hdr);
 ulong android_image_get_kload(const struct andr_img_hdr *hdr);
 void android_print_contents(const struct andr_img_hdr *hdr);
 
+/** android_image_load - Load an Android Image from storage.
+ *
+ * Load an Android Image based on the header size in the storage. Return the
+ * number of bytes read from storage, which could be bigger than the actual
+ * Android Image as described in the header size. In case of error reading the
+ * image or if the image size needed to be read from disk is bigger than the
+ * the passed |max_size| a negative number is returned.
+ *
+ * @dev_desc:		The device where to read the image from
+ * @part_info:		The partition in |dev_desc| where to read the image from
+ * @load_address:	The address where the image will be loaded
+ * @max_size:		The maximum loaded size, in bytes
+ * @return the number of bytes read or a negative number in case of error.
+ */
+long android_image_load(struct blk_desc *dev_desc,
+			const disk_partition_t *part_info,
+			unsigned long load_address,
+			unsigned long max_size);
+
 #endif /* CONFIG_ANDROID_BOOT_IMAGE */
 
 /**
-- 
2.12.2.564.g063fe858b8-goog

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 3/6] cmd: Add 'load_android' command to load Android images.
  2017-04-02  8:49     ` [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images Alex Deymo
@ 2017-04-02  8:49       ` Alex Deymo
  2017-04-02  8:49         ` [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name() Alex Deymo
  2017-04-06 22:42         ` [U-Boot] [PATCH 3/6] cmd: Add 'load_android' command to load Android images Simon Glass
  2017-04-06 22:42       ` [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images Simon Glass
  1 sibling, 2 replies; 20+ messages in thread
From: Alex Deymo @ 2017-04-02  8:49 UTC (permalink / raw)
  To: u-boot

Android kernel images include a header that specifies addresses and
kernel size. This patch adds a command to load these images from
storage without specifying the size or address of them, and parsing
them from the header instead.
---
 cmd/Kconfig        |  9 +++++++++
 cmd/Makefile       |  1 +
 cmd/load_android.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+)
 create mode 100644 cmd/load_android.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 25e3b783a8..87a445d269 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -422,6 +422,15 @@ config CMD_LOADS
 	help
 	  Load an S-Record file over serial line
 
+config CMD_LOAD_ANDROID
+	bool "load_android"
+	default n
+	depends on ANDROID_BOOT_IMAGE
+	help
+	  Load an Android Boot image from storage. The Android Boot images
+	  define the size and kernel address on the header, which are used by
+	  this command.
+
 config CMD_FLASH
 	bool "flinfo, erase, protect"
 	default y
diff --git a/cmd/Makefile b/cmd/Makefile
index f13bb8c11e..2f75dab040 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_CMD_LDRINFO) += ldrinfo.o
 obj-$(CONFIG_LED_STATUS_CMD) += led.o
 obj-$(CONFIG_CMD_LICENSE) += license.o
 obj-y += load.o
+obj-$(CONFIG_CMD_LOAD_ANDROID) += load_android.o
 obj-$(CONFIG_LOGBUFFER) += log.o
 obj-$(CONFIG_ID_EEPROM) += mac.o
 obj-$(CONFIG_CMD_MD5SUM) += md5sum.o
diff --git a/cmd/load_android.c b/cmd/load_android.c
new file mode 100644
index 0000000000..b9f3b1b372
--- /dev/null
+++ b/cmd/load_android.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <common.h>
+#include <command.h>
+
+static int do_load_android(cmd_tbl_t *cmdtp, int flag, int argc,
+			   char * const argv[])
+{
+	int boot_partition;
+	unsigned long load_address;
+	char *addr_arg_endp, *addr_str;
+	struct blk_desc *dev_desc;
+	disk_partition_t part_info;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+	if (argc > 4)
+		return CMD_RET_USAGE;
+
+	if (argc >= 4) {
+		load_address = simple_strtoul(argv[3], &addr_arg_endp, 16);
+		if (addr_arg_endp == argv[3] || *addr_arg_endp != '\0')
+			return CMD_RET_USAGE;
+	} else {
+		addr_str = getenv("loadaddr");
+		if (addr_str != NULL)
+			load_address = simple_strtoul(addr_str, NULL, 16);
+		else
+			load_address = CONFIG_SYS_LOAD_ADDR;
+	}
+
+	boot_partition = blk_get_device_part_str(argv[1],
+						 (argc >= 3) ? argv[2] : NULL,
+						 &dev_desc, &part_info, 1);
+	if (boot_partition < 0)
+		return CMD_RET_FAILURE;
+
+	if (android_image_load(dev_desc, &part_info, load_address, -1UL) < 0) {
+		printf("Error loading Android Image from %s %d:%d to 0x%lx.\n",
+		       argv[1], dev_desc->devnum, boot_partition, load_address);
+		return CMD_RET_FAILURE;
+	}
+	return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+	load_android, 4, 0, do_load_android,
+	"load Android Boot image from storage.",
+	"<interface> [<dev[:part]> [<addr>]]\n"
+	"    - Load a binary Android Boot image from the partition 'part' on\n"
+	"      device type 'interface' instance 'dev' to address 'addr'."
+);
-- 
2.12.2.564.g063fe858b8-goog

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name()
  2017-04-02  8:49       ` [U-Boot] [PATCH 3/6] cmd: Add 'load_android' command to load Android images Alex Deymo
@ 2017-04-02  8:49         ` Alex Deymo
  2017-04-02  8:49           ` [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow Alex Deymo
                             ` (2 more replies)
  2017-04-06 22:42         ` [U-Boot] [PATCH 3/6] cmd: Add 'load_android' command to load Android images Simon Glass
  1 sibling, 3 replies; 20+ messages in thread
From: Alex Deymo @ 2017-04-02  8:49 UTC (permalink / raw)
  To: u-boot

Similar to what blk_get_device_part_str() does, this patch makes
part_get_info_by_name() return the partition number in case of a match.
This is useful when the partition number is needed and not just the
descriptor.

Signed-off-by: Alex Deymo <deymo@google.com>
---
 common/fb_mmc.c | 6 +++---
 disk/part.c     | 2 +-
 include/part.h  | 3 ++-
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/common/fb_mmc.c b/common/fb_mmc.c
index 6cc113d825..866982e41c 100644
--- a/common/fb_mmc.c
+++ b/common/fb_mmc.c
@@ -37,7 +37,7 @@ static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc,
 	int ret;
 
 	ret = part_get_info_by_name(dev_desc, name, info);
-	if (ret) {
+	if (ret < 0) {
 		/* strlen("fastboot_partition_alias_") + 32(part_name) + 1 */
 		char env_alias_name[25 + 32 + 1];
 		char *aliased_part_name;
@@ -153,7 +153,7 @@ void fb_mmc_flash_write(const char *cmd, void *download_buffer,
 	}
 #endif
 
-	if (part_get_info_by_name_or_alias(dev_desc, cmd, &info)) {
+	if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) {
 		error("cannot find partition: '%s'\n", cmd);
 		fastboot_fail("cannot find partition");
 		return;
@@ -205,7 +205,7 @@ void fb_mmc_erase(const char *cmd)
 	}
 
 	ret = part_get_info_by_name_or_alias(dev_desc, cmd, &info);
-	if (ret) {
+	if (ret < 0) {
 		error("cannot find partition: '%s'", cmd);
 		fastboot_fail("cannot find partition");
 		return;
diff --git a/disk/part.c b/disk/part.c
index cd447024c0..491b02dc9c 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -635,7 +635,7 @@ int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
 			}
 			if (strcmp(name, (const char *)info->name) == 0) {
 				/* matched */
-				return 0;
+				return i;
 			}
 		}
 	}
diff --git a/include/part.h b/include/part.h
index b6d1b33167..83bce05a43 100644
--- a/include/part.h
+++ b/include/part.h
@@ -163,7 +163,8 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
  * @param gpt_name - the specified table entry name
  * @param info - returns the disk partition info
  *
- * @return - '0' on match, '-1' on no match, otherwise error
+ * @return - the partition number on match (starting on 1), -1 on no match,
+ * otherwise error
  */
 int part_get_info_by_name(struct blk_desc *dev_desc,
 			      const char *name, disk_partition_t *info);
-- 
2.12.2.564.g063fe858b8-goog

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow
  2017-04-02  8:49         ` [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name() Alex Deymo
@ 2017-04-02  8:49           ` Alex Deymo
  2017-04-02  8:49             ` [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command Alex Deymo
  2017-04-09 19:27             ` [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow Simon Glass
  2017-04-06 22:42           ` [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name() Simon Glass
  2017-05-12 17:18           ` [U-Boot] [U-Boot, " Tom Rini
  2 siblings, 2 replies; 20+ messages in thread
From: Alex Deymo @ 2017-04-02  8:49 UTC (permalink / raw)
  To: u-boot

An Android Bootloader must comply with certain boot modes and change
the kernel command line accordingly. This patch introduces the Android
boot mode concept which determines whether the device should boot to
one of the following:
 * recovery: which should boot to the recovery image,
 * bootloader: which should boot to the "bootloader" (fastboot) and
 * normal: which should boot to the system image.

The boot mode is determined in part by the Boot Control Block (BCB)
which is stored at the beginning of the "misc" partition. The BCB
is defined in the "bootloader_message.h" file in AOSP, now copied
here as android_bootloader_message.h with minor modifications.

This patch implements the basic boot flow that loads and boots an
Android kernel image assuming an A/B device which implies that it uses
boot as recovery (BOARD_USES_RECOVERY_AS_BOOT in the BoardConfig.mk).
This means that the recovery image shares the same kernel with the
normal boot system image, but stores the recovery image as a ramdisk
which is not used in normal mode.

Among the limitations, this patch doesn't implement the A/B slot
selection, it only boots from the provided slot.

Test: Booted a rpi3 with this flow.
Signed-off-by: Alex Deymo <deymo@google.com>
---
 README                               |  19 +-
 common/Kconfig                       |  19 ++
 common/Makefile                      |   1 +
 common/android_bootloader.c          | 350 +++++++++++++++++++++++++++++++++++
 include/android_bootloader.h         |  48 +++++
 include/android_bootloader_message.h | 174 +++++++++++++++++
 6 files changed, 607 insertions(+), 4 deletions(-)
 create mode 100644 common/android_bootloader.c
 create mode 100644 include/android_bootloader.h
 create mode 100644 include/android_bootloader_message.h

diff --git a/README b/README
index aa907ced8a..384cc6aabb 100644
--- a/README
+++ b/README
@@ -1483,6 +1483,21 @@ The following options need to be configured:
 		entering dfuMANIFEST state. Host waits this timeout, before
 		sending again an USB request to the device.
 
+- Android Bootloader support:
+		CONFIG_ANDROID_BOOTLOADER
+		This enables support for the Android bootloader flow. Android
+		devices can boot in normal mode, recovery mode or bootloader
+		mode. The normal mode is the most common boot mode, but
+		recovery mode is often used to perform factory reset and OTA
+		(over-the-air) updates in the legacy updater. Also it is
+		possible for an Android system to request a reboot to the
+		"bootloader", which often means reboot to fastboot but may also
+		include a UI with a menu.
+
+		CONFIG_ANDROID_BOOT_IMAGE
+		This enables support for booting images which use the Android
+		image format header.
+
 - USB Device Android Fastboot support:
 		CONFIG_USB_FUNCTION_FASTBOOT
 		This enables the USB part of the fastboot gadget
@@ -1494,10 +1509,6 @@ The following options need to be configured:
 		used on Android devices.
 		See doc/README.android-fastboot for more information.
 
-		CONFIG_ANDROID_BOOT_IMAGE
-		This enables support for booting images which use the Android
-		image format header.
-
 		CONFIG_FASTBOOT_BUF_ADDR
 		The fastboot protocol requires a large memory buffer for
 		downloads. Define this to the starting RAM address to use for
diff --git a/common/Kconfig b/common/Kconfig
index 8f73c8f757..47e2ffa3d6 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -393,6 +393,25 @@ config DISPLAY_BOARDINFO
 	  when U-Boot starts up. The board function checkboard() is called
 	  to do this.
 
+config ANDROID_BOOTLOADER
+	bool "Support for Android Bootloader boot flow"
+	default n
+	depends on ANDROID_BOOT_IMAGE
+	help
+	  If enabled, adds support to boot an Android device following the
+	  Android Bootloader boot flow. This flow requires an Android Bootloader
+	  to handle the Android Bootloader Message stored in the Boot Control
+	  Block (BCB), normally in the "misc" partition of an Android device.
+	  The BCB is used to determine the boot mode of the device (normal mode,
+	  recovery mode or bootloader mode) and, if enabled, the slot to boot
+	  from in devices with multiple boot slots (A/B devices).
+
+config ANDROID_BOOT_IMAGE
+	bool "Enable support for Android Boot Images"
+	help
+	  This enables support for booting images which use the Android
+	  image format header.
+
 menu "Start-up hooks"
 
 config ARCH_EARLY_INIT_R
diff --git a/common/Makefile b/common/Makefile
index 86225f1564..9de0a77063 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -147,6 +147,7 @@ endif
 obj-$(CONFIG_CMD_IDE) += ide.o
 obj-y += image.o
 obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
+obj-$(CONFIG_ANDROID_BOOTLOADER) += android_bootloader.o
 obj-$(CONFIG_$(SPL_)OF_LIBFDT) += image-fdt.o
 obj-$(CONFIG_$(SPL_)FIT) += image-fit.o
 obj-$(CONFIG_$(SPL_)FIT_SIGNATURE) += image-sig.o
diff --git a/common/android_bootloader.c b/common/android_bootloader.c
new file mode 100644
index 0000000000..6656311ee3
--- /dev/null
+++ b/common/android_bootloader.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <android_bootloader.h>
+#include <android_bootloader_message.h>
+
+#include <cli.h>
+#include <common.h>
+#include <malloc.h>
+
+#define ANDROID_PARTITION_BOOT "boot"
+#define ANDROID_PARTITION_SYSTEM "system"
+
+#define ANDROID_ARG_SLOT_SUFFIX "androidboot.slot_suffix="
+#define ANDROID_ARG_ROOT "root="
+
+static int android_bootloader_message_load(
+	struct blk_desc *dev_desc,
+	const disk_partition_t *part_info,
+	struct android_bootloader_message *message)
+{
+	ulong message_blocks = sizeof(struct android_bootloader_message) /
+	    part_info->blksz;
+	if (message_blocks > part_info->size) {
+		printf("misc partition too small.\n");
+		return -1;
+	}
+
+	if (blk_dread(dev_desc, part_info->start, message_blocks, message) !=
+	    message_blocks) {
+		printf("Could not read from misc partition\n");
+		return -1;
+	}
+	debug("ANDROID: Loaded BCB, %lu blocks.\n", message_blocks);
+	return 0;
+}
+
+static int android_bootloader_message_write(
+	struct blk_desc *dev_desc,
+	const disk_partition_t *part_info,
+	struct android_bootloader_message *message)
+{
+	ulong message_blocks = sizeof(struct android_bootloader_message) /
+	    part_info->blksz;
+	if (message_blocks > part_info->size) {
+		printf("misc partition too small.\n");
+		return -1;
+	}
+
+	if (blk_dwrite(dev_desc, part_info->start, message_blocks, message) !=
+	    message_blocks) {
+		printf("Could not write to misc partition\n");
+		return -1;
+	}
+	debug("ANDROID: Wrote new BCB, %lu blocks.\n", message_blocks);
+	return 0;
+}
+
+static enum android_boot_mode android_bootloader_load_and_clear_mode(
+	struct blk_desc *dev_desc,
+	const disk_partition_t *misc_part_info)
+{
+	struct android_bootloader_message bcb;
+
+#ifdef CONFIG_FASTBOOT
+	char *bootloader_str;
+
+	/* Check for message from bootloader stored in RAM from a previous boot.
+	 */
+	bootloader_str = (char *)CONFIG_FASTBOOT_BUF_ADDR;
+	if (!strcmp("reboot-bootloader", bootloader_str)) {
+		bootloader_str[0] = '\0';
+		return ANDROID_BOOT_MODE_BOOTLOADER;
+	}
+#endif
+
+	/* Check and update the BCB message if needed. */
+	if (android_bootloader_message_load(dev_desc, misc_part_info, &bcb) <
+	    0) {
+		printf("WARNING: Unable to load the BCB.\n");
+		return ANDROID_BOOT_MODE_NORMAL;
+	}
+
+	if (!strcmp("bootonce-bootloader", bcb.command)) {
+		/* Erase the message in the BCB since this value should be used
+		 * only once.
+		 */
+		memset(bcb.command, 0, sizeof(bcb.command));
+		android_bootloader_message_write(dev_desc, misc_part_info,
+						 &bcb);
+		return ANDROID_BOOT_MODE_BOOTLOADER;
+	}
+
+	if (!strcmp("boot-recovery", bcb.command))
+		return ANDROID_BOOT_MODE_RECOVERY;
+
+	return ANDROID_BOOT_MODE_NORMAL;
+}
+
+/**
+ * Return the reboot reason string for the passed boot mode.
+ *
+ * @param mode	The Android Boot mode.
+ * @return a pointer to the reboot reason string for mode.
+ */
+static const char *android_boot_mode_str(enum android_boot_mode mode)
+{
+	switch (mode) {
+	case ANDROID_BOOT_MODE_NORMAL:
+		return "(none)";
+	case ANDROID_BOOT_MODE_RECOVERY:
+		return "recovery";
+	case ANDROID_BOOT_MODE_BOOTLOADER:
+		return "bootloader";
+	}
+	return NULL;
+}
+
+static int android_part_get_info_by_name_suffix(struct blk_desc *dev_desc,
+						const char *base_name,
+						const char *slot_suffix,
+						disk_partition_t *part_info)
+{
+	char *part_name;
+	int part_num;
+	size_t part_name_len;
+
+	part_name_len = strlen(base_name) + 1;
+	if (slot_suffix)
+		part_name_len += strlen(slot_suffix);
+	part_name = malloc(part_name_len);
+	if (!part_name)
+		return -1;
+	strcpy(part_name, base_name);
+	if (slot_suffix)
+		strcat(part_name, slot_suffix);
+
+	part_num = part_get_info_by_name(dev_desc, part_name, part_info);
+	if (part_num < 0) {
+		debug("ANDROID: Could not find partition \"%s\"\n", part_name);
+		part_num = -1;
+	}
+
+	free(part_name);
+	return part_num;
+}
+
+static int android_bootloader_boot_bootloader(void)
+{
+	const char *fastboot_cmd = getenv("fastbootcmd");
+
+	if (fastboot_cmd)
+		return run_command(fastboot_cmd, CMD_FLAG_ENV);
+	return -1;
+}
+
+static int android_bootloader_boot_kernel(unsigned long kernel_address)
+{
+	char kernel_addr_str[12];
+	char *fdt_addr = getenv("fdt_addr");
+	char *bootm_args[] = { "bootm", kernel_addr_str, "-", fdt_addr, NULL };
+
+	sprintf(kernel_addr_str, "0x%lx", kernel_address);
+
+	printf("Booting kernel at %s with fdt@%s...\n\n\n",
+	       kernel_addr_str, fdt_addr);
+	do_bootm(NULL, 0, 4, bootm_args);
+
+	return -1;
+}
+
+static char *strjoin(const char **chunks, char separator)
+{
+	int len, joined_len = 0;
+	char *ret, *current;
+	const char **p;
+
+	for (p = chunks; *p; p++)
+		joined_len += strlen(*p) + 1;
+
+	if (!joined_len) {
+		ret = malloc(1);
+		if (ret)
+			ret[0] = '\0';
+		return ret;
+	}
+
+	ret = malloc(joined_len);
+	current = ret;
+	if (!ret)
+		return ret;
+
+	for (p = chunks; *p; p++) {
+		len = strlen(*p);
+		memcpy(current, *p, len);
+		current += len;
+		*current = separator;
+		current++;
+	}
+	/* Replace the last separator by a \0. */
+	current[-1] = '\0';
+	return ret;
+}
+
+/** android_assemble_cmdline - Assemble the command line to pass to the kernel
+ * @return a newly allocated string
+ */
+static char *android_assemble_cmdline(const char *slot_suffix,
+				      const char *extra_args)
+{
+	const char *cmdline_chunks[16];
+	const char **current_chunk = cmdline_chunks;
+	char *env_cmdline, *cmdline, *rootdev_input;
+	char *allocated_suffix = NULL;
+	char *allocated_rootdev = NULL;
+	unsigned long rootdev_len;
+
+	env_cmdline = getenv("bootargs");
+	if (env_cmdline)
+		*(current_chunk++) = env_cmdline;
+
+	/* The |slot_suffix| needs to be passed to the kernel to know what
+	 * slot to boot from.
+	 */
+	if (slot_suffix) {
+		allocated_suffix = malloc(strlen(ANDROID_ARG_SLOT_SUFFIX) +
+					  strlen(slot_suffix));
+		strcpy(allocated_suffix, ANDROID_ARG_SLOT_SUFFIX);
+		strcat(allocated_suffix, slot_suffix);
+		*(current_chunk++) = allocated_suffix;
+	}
+
+	rootdev_input = getenv("android_rootdev");
+	if (rootdev_input) {
+		rootdev_len = strlen(ANDROID_ARG_ROOT) + CONFIG_SYS_CBSIZE + 1;
+		allocated_rootdev = malloc(rootdev_len);
+		strcpy(allocated_rootdev, ANDROID_ARG_ROOT);
+		cli_simple_process_macros(rootdev_input,
+					  allocated_rootdev +
+					  strlen(ANDROID_ARG_ROOT));
+		/* Make sure that the string is null-terminated since the
+		 * previous could not copy to the end of the input string if it
+		 * is too big.
+		 */
+		allocated_rootdev[rootdev_len - 1] = '\0';
+		*(current_chunk++) = allocated_rootdev;
+	}
+
+	if (extra_args)
+		*(current_chunk++) = extra_args;
+
+	*(current_chunk++) = NULL;
+	cmdline = strjoin(cmdline_chunks, ' ');
+	free(allocated_suffix);
+	free(allocated_rootdev);
+	return cmdline;
+}
+
+int android_bootloader_boot_flow(struct blk_desc *dev_desc,
+				 const disk_partition_t *misc_part_info,
+				 const char *slot,
+				 unsigned long kernel_address)
+{
+	enum android_boot_mode mode;
+	disk_partition_t boot_part_info;
+	disk_partition_t system_part_info;
+	int boot_part_num, system_part_num;
+	int ret;
+	char *command_line;
+	char slot_suffix[3];
+	const char *mode_cmdline = NULL;
+
+	/* Determine the boot mode and clear its value for the next boot if
+	 * needed.
+	 */
+	mode = android_bootloader_load_and_clear_mode(dev_desc, misc_part_info);
+	printf("ANDROID: reboot reason: \"%s\"\n", android_boot_mode_str(mode));
+
+	switch (mode) {
+	case ANDROID_BOOT_MODE_NORMAL:
+		/* In normal mode, we load the kernel from "boot" but append
+		 * "skip_initramfs" to the cmdline to make it ignore the
+		 * recovery initramfs in the boot partition.
+		 */
+		mode_cmdline = "skip_initramfs";
+		break;
+	case ANDROID_BOOT_MODE_RECOVERY:
+		/* In recovery mode we still boot the kernel from "boot" but
+		 * don't skip the initramfs so it boots to recovery.
+		 */
+		break;
+	case ANDROID_BOOT_MODE_BOOTLOADER:
+		/* Bootloader mode enters fastboot. If this operation fails we
+		 * simply return since we can't recover from this situation by
+		 * switching to another slot.
+		 */
+		return android_bootloader_boot_bootloader();
+	}
+
+	slot_suffix[0] = '\0';
+	if (slot && slot[0]) {
+		slot_suffix[0] = '_';
+		slot_suffix[1] = slot[0];
+		slot_suffix[2] = '\0';
+	}
+
+	/* Load the kernel from the desired "boot" partition. */
+	boot_part_num =
+	    android_part_get_info_by_name_suffix(dev_desc,
+						 ANDROID_PARTITION_BOOT,
+						 slot_suffix, &boot_part_info);
+	if (boot_part_num < 0)
+		return -1;
+	debug("ANDROID: Loading kernel from \"%s\", partition %d.\n",
+	      boot_part_info.name, boot_part_num);
+
+	system_part_num =
+	    android_part_get_info_by_name_suffix(dev_desc,
+						 ANDROID_PARTITION_SYSTEM,
+						 slot_suffix,
+						 &system_part_info);
+	if (system_part_num < 0)
+		return -1;
+	debug("ANDROID: Using system image from \"%s\", partition %d.\n",
+	      system_part_info.name, system_part_num);
+
+	ret = android_image_load(dev_desc, &boot_part_info, kernel_address,
+				 -1UL);
+	if (ret < 0)
+		return ret;
+
+	/* Set Android root variables. */
+	setenv_ulong("android_root_devnum", dev_desc->devnum);
+	setenv_ulong("android_root_partnum", system_part_num);
+	setenv("android_slotsufix", slot_suffix);
+
+	/* Assemble the command line */
+	command_line = android_assemble_cmdline(slot_suffix, mode_cmdline);
+	setenv("bootargs", command_line);
+
+	debug("ANDROID: bootargs: \"%s\"\n", command_line);
+
+	android_bootloader_boot_kernel(kernel_address);
+
+	/* TODO: If the kernel doesn't boot mark the selected slot as bad. */
+	return -1;
+}
diff --git a/include/android_bootloader.h b/include/android_bootloader.h
new file mode 100644
index 0000000000..ddf6d76f64
--- /dev/null
+++ b/include/android_bootloader.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __ANDROID_BOOTLOADER_H
+#define __ANDROID_BOOTLOADER_H
+
+#include <common.h>
+
+enum android_boot_mode {
+	ANDROID_BOOT_MODE_NORMAL = 0,
+
+	/* "recovery" mode is triggered by the "reboot recovery" command or
+	 * equivalent adb/fastboot command. It can also be triggered by writing
+	 * "boot-recovery" in the BCB message. This mode should boot the
+	 * recovery kernel.
+	 */
+	ANDROID_BOOT_MODE_RECOVERY,
+
+	/* "bootloader" mode is triggered by the "reboot bootloader" command or
+	 * equivalent adb/fastboot command. It can also be triggered by writing
+	 * "bootonce-bootloader" in the BCB message. This mode should boot into
+	 * fastboot.
+	 */
+	ANDROID_BOOT_MODE_BOOTLOADER,
+};
+
+/** android_bootloader_boot_flow - Execute the Android Bootloader Flow.
+ * 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. On success it doesn't return.
+ *
+ * @dev_desc:		device where to load the kernel and system to boot from.
+ * @misc_part_info:	the "misc" partition descriptor in 'dev_desc'.
+ * @slot:		the boot slot to boot from.
+ * @kernel_address:	address where to load the kernel if needed.
+ *
+ * @return a negative number in case of error, otherwise it doesn't return.
+ */
+int android_bootloader_boot_flow(struct blk_desc *dev_desc,
+				 const disk_partition_t *misc_part_info,
+				 const char *slot,
+				 unsigned long kernel_address);
+
+#endif  /* __ANDROID_BOOTLOADER_H */
diff --git a/include/android_bootloader_message.h b/include/android_bootloader_message.h
new file mode 100644
index 0000000000..2c2142dc6f
--- /dev/null
+++ b/include/android_bootloader_message.h
@@ -0,0 +1,174 @@
+/*
+ * This is from the Android Project,
+ * Repository: https://android.googlesource.com/platform/bootable/recovery/
+ * File: bootloader_message/include/bootloader_message/bootloader_message.h
+ * Commit: 8b309f6970ab3b7c53cc529c51a2cb44e1c7a7e1
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __ANDROID_BOOTLOADER_MESSAGE_H
+#define __ANDROID_BOOTLOADER_MESSAGE_H
+
+/* compiler.h defines the types that otherwise are included from stdint.h and
+ * stddef.h
+ */
+#include <compiler.h>
+
+/* Spaces used by misc partition are as below:
+ * 0   - 2K     Bootloader Message
+ * 2K  - 16K    Used by Vendor's bootloader (the 2K - 4K range may be optionally used
+ *              as bootloader_message_ab struct)
+ * 16K - 64K    Used by uncrypt and recovery to store wipe_package for A/B devices
+ * Note that these offsets are admitted by bootloader,recovery and uncrypt, so they
+ * are not configurable without changing all of them.
+ */
+static const size_t ANDROID_BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0;
+static const size_t ANDROID_WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;
+
+/* Bootloader Message (2-KiB)
+ *
+ * This structure describes the content of a block in flash
+ * that is used for recovery and the bootloader to talk to
+ * each other.
+ *
+ * The command field is updated by linux when it wants to
+ * reboot into recovery or to update radio or bootloader firmware.
+ * It is also updated by the bootloader when firmware update
+ * is complete (to boot into recovery for any final cleanup)
+ *
+ * The status field is written by the bootloader after the
+ * completion of an "update-radio" or "update-hboot" command.
+ *
+ * The recovery field is only written by linux and used
+ * for the system to send a message to recovery or the
+ * other way around.
+ *
+ * The stage field is written by packages which restart themselves
+ * multiple times, so that the UI can reflect which invocation of the
+ * package it is.  If the value is of the format "#/#" (eg, "1/3"),
+ * the UI will add a simple indicator of that status.
+ *
+ * We used to have slot_suffix field for A/B boot control metadata in
+ * this struct, which gets unintentionally cleared by recovery or
+ * uncrypt. Move it into struct bootloader_message_ab to avoid the
+ * issue.
+ */
+struct android_bootloader_message {
+    char command[32];
+    char status[32];
+    char recovery[768];
+
+    /* The 'recovery' field used to be 1024 bytes.  It has only ever
+     * been used to store the recovery command line, so 768 bytes
+     * should be plenty.  We carve off the last 256 bytes to store the
+     * stage string (for multistage packages) and possible future
+     * expansion. */
+    char stage[32];
+
+    /* The 'reserved' field used to be 224 bytes when it was initially
+     * carved off from the 1024-byte recovery field. Bump it up to
+     * 1184-byte so that the entire bootloader_message struct rounds up
+     * to 2048-byte. */
+    char reserved[1184];
+};
+
+/**
+ * We must be cautious when changing the bootloader_message struct size,
+ * because A/B-specific fields may end up with different offsets.
+ */
+#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
+static_assert(sizeof(struct android_bootloader_message) == 2048,
+              "struct bootloader_message size changes, which may break A/B devices");
+#endif
+
+/**
+ * The A/B-specific bootloader message structure (4-KiB).
+ *
+ * We separate A/B boot control metadata from the regular bootloader
+ * message struct and keep it here. Everything that's A/B-specific
+ * stays after struct bootloader_message, which should be managed by
+ * the A/B-bootloader or boot control HAL.
+ *
+ * The slot_suffix field is used for A/B implementations where the
+ * bootloader does not set the androidboot.ro.boot.slot_suffix kernel
+ * commandline parameter. This is used by fs_mgr to mount /system and
+ * other partitions with the slotselect flag set in fstab. A/B
+ * implementations are free to use all 32 bytes and may store private
+ * data past the first NUL-byte in this field. It is encouraged, but
+ * not mandatory, to use 'struct bootloader_control' described below.
+ */
+struct android_bootloader_message_ab {
+    struct android_bootloader_message message;
+    char slot_suffix[32];
+
+    /* Round up the entire struct to 4096-byte. */
+    char reserved[2016];
+};
+
+/**
+ * Be cautious about the struct size change, in case we put anything post
+ * bootloader_message_ab struct (b/29159185).
+ */
+#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
+static_assert(sizeof(struct android_bootloader_message_ab) == 4096,
+              "struct bootloader_message_ab size changes");
+#endif
+
+#define ANDROID_BOOT_CTRL_MAGIC   0x42414342 /* Bootloader Control AB */
+#define ANDROID_BOOT_CTRL_VERSION 1
+
+struct android_slot_metadata {
+    /* Slot priority with 15 meaning highest priority, 1 lowest
+     * priority and 0 the slot is unbootable. */
+    uint8_t priority : 4;
+    /* Number of times left attempting to boot this slot. */
+    uint8_t tries_remaining : 3;
+    /* 1 if this slot has booted successfully, 0 otherwise. */
+    uint8_t successful_boot : 1;
+    /* 1 if this slot is corrupted from a dm-verity corruption, 0 */
+    /* otherwise. */
+    uint8_t verity_corrupted : 1;
+    /* Reserved for further use. */
+    uint8_t reserved : 7;
+} __attribute__((packed));
+
+/* Bootloader Control AB
+ *
+ * This struct can be used to manage A/B metadata. It is designed to
+ * be put in the 'slot_suffix' field of the 'bootloader_message'
+ * structure described above. It is encouraged to use the
+ * 'bootloader_control' structure to store the A/B metadata, but not
+ * mandatory.
+ */
+struct android_bootloader_control {
+    /* NUL terminated active slot suffix. */
+    char slot_suffix[4];
+    /* Bootloader Control AB magic number (see BOOT_CTRL_MAGIC). */
+    uint32_t magic;
+    /* Version of struct being used (see BOOT_CTRL_VERSION). */
+    uint8_t version;
+    /* Number of slots being managed. */
+    uint8_t nb_slot : 3;
+    /* Number of times left attempting to boot recovery. */
+    uint8_t recovery_tries_remaining : 3;
+    /* Ensure 4-bytes alignment for slot_info field. */
+    uint8_t reserved0[2];
+    /* Per-slot information.  Up to 4 slots. */
+    struct android_slot_metadata slot_info[4];
+    /* Reserved for further use. */
+    uint8_t reserved1[8];
+    /* CRC32 of all 28 bytes preceding this field (little endian
+     * format). */
+    uint32_t crc32_le;
+} __attribute__((packed));
+
+#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
+static_assert(sizeof(struct android_bootloader_control) ==
+              sizeof(((struct android_bootloader_message_ab *)0)->slot_suffix),
+              "struct bootloader_control has wrong size");
+#endif
+
+#endif  /* __ANDROID_BOOTLOADER_MESSAGE_H */
-- 
2.12.2.564.g063fe858b8-goog

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command.
  2017-04-02  8:49           ` [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow Alex Deymo
@ 2017-04-02  8:49             ` Alex Deymo
  2017-04-04 14:46               ` Lukasz Majewski
  2017-04-09 19:27             ` [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow Simon Glass
  1 sibling, 1 reply; 20+ messages in thread
From: Alex Deymo @ 2017-04-02  8:49 UTC (permalink / raw)
  To: u-boot

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

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"
+);
-- 
2.12.2.564.g063fe858b8-goog

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command.
  2017-04-02  8:49             ` [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command Alex Deymo
@ 2017-04-04 14:46               ` Lukasz Majewski
  0 siblings, 0 replies; 20+ messages in thread
From: Lukasz Majewski @ 2017-04-04 14:46 UTC (permalink / raw)
  To: u-boot

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="windows-1254", Size: 7734 bytes --]

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 at denx.de

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 1/6] image: Update include/android_image.h
  2017-04-02  8:49   ` [U-Boot] [PATCH 1/6] image: Update include/android_image.h Alex Deymo
  2017-04-02  8:49     ` [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images Alex Deymo
@ 2017-04-06 22:42     ` Simon Glass
  2017-05-12 17:18     ` [U-Boot] [U-Boot,1/6] " Tom Rini
  2 siblings, 0 replies; 20+ messages in thread
From: Simon Glass @ 2017-04-06 22:42 UTC (permalink / raw)
  To: u-boot

On 2 April 2017 at 02:49, Alex Deymo <deymo@google.com> wrote:
> Update the Android image header format to the latest version published
> in AOSP. The original code moved to a new repository, so this patch also
> updates the reference to that path.
>
> Signed-off-by: Alex Deymo <deymo@google.com>
> ---
>  common/image-android.c  |  9 +++++++++
>  include/android_image.h | 24 +++++++++++++++++++-----
>  2 files changed, 28 insertions(+), 5 deletions(-)

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

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images.
  2017-04-02  8:49     ` [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images Alex Deymo
  2017-04-02  8:49       ` [U-Boot] [PATCH 3/6] cmd: Add 'load_android' command to load Android images Alex Deymo
@ 2017-04-06 22:42       ` Simon Glass
  1 sibling, 0 replies; 20+ messages in thread
From: Simon Glass @ 2017-04-06 22:42 UTC (permalink / raw)
  To: u-boot

Hi Alex,

On 2 April 2017 at 02:49, Alex Deymo <deymo@google.com> wrote:
> This patch implements the logic needed to load an Android boot image
> from storage, since the size and kernel address in Android images is
> defined in its header.
>
> Signed-off-by: Alex Deymo <deymo@google.com>
> ---
>  common/image-android.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/image.h        | 19 +++++++++++++++++++
>  2 files changed, 70 insertions(+)
>
> diff --git a/common/image-android.c b/common/image-android.c
> index c668407817..f040f5b400 100644
> --- a/common/image-android.c
> +++ b/common/image-android.c
> @@ -8,6 +8,7 @@
>  #include <image.h>
>  #include <android_image.h>
>  #include <malloc.h>
> +#include <mapmem.h>
>  #include <errno.h>
>
>  #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR      0x10008000
> @@ -146,6 +147,56 @@ int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
>         return 0;
>  }
>
> +long android_image_load(struct blk_desc *dev_desc,

Can you pass a udevice * instead of dev_desc?

> +                       const disk_partition_t *part_info,
> +                       unsigned long load_address,
> +                       unsigned long max_size) {
> +       void *buf;
> +       long blk_cnt, blk_read = 0;
> +
> +       if (max_size < part_info->blksz)
> +               return -1;
> +
> +       /* We don't know the size of the Android image before reading the header

Comment style:

/*
 * We don't know ...
 * ...
 */

> +        * so we don't limit the size of the mapped memory.
> +        */
> +       buf = map_sysmem(load_address, 0 /* size */);

This is fine, or you could provide a guess here, since there really
isn't any mapping going on. You could use max_size, for example.

> +
> +       /* Read the Android header first and then read the rest. */
> +       if (blk_dread(dev_desc, part_info->start, 1, buf) != 1)
> +               blk_read = -1;

This should be blk_read(). Unfortunately that function is not defined.
It should call the device's read() method. Can you add a patch to
define this function for read/write/erase/select_hwpart? See pch.h for
an example of how this is done in the header file.

That way you can get a proper error number.
> +
> +       if (!blk_read && android_image_check_header(buf) != 0) {
> +               printf("** Invalid Android Image header **\n");
> +               blk_read = -1;

-EINVAL perhaps?

> +       }
> +       if (!blk_read) {
> +               blk_cnt = (android_image_get_end(buf) - (ulong)buf +
> +                          part_info->blksz - 1) / part_info->blksz;
> +               if (blk_cnt * part_info->blksz > max_size) {
> +                       debug("Android Image too big (%lu bytes, max %lu)\n",
> +                             android_image_get_end(buf) - (ulong)buf,
> +                             max_size);
> +                       blk_read = -1;
> +               } else {
> +                       debug("Loading Android Image (%lu blocks) to 0x%lx... ",
> +                             blk_cnt, load_address);
> +                       blk_read = blk_dread(dev_desc, part_info->start,
> +                                            blk_cnt, buf);
> +               }
> +       }
> +
> +       unmap_sysmem(buf);
> +       if (blk_read < 0)
> +               return blk_read;
> +
> +       debug("%lu blocks read: %s\n",
> +             blk_read, (blk_read == blk_cnt) ? "OK" : "ERROR");
> +       if (blk_read != blk_cnt)
> +               return -1;
> +       return blk_read;
> +}
> +
>  #if !defined(CONFIG_SPL_BUILD)
>  /**
>   * android_print_contents - prints out the contents of the Android format image
> diff --git a/include/image.h b/include/image.h
> index 2372518960..de448a9a01 100644
> --- a/include/image.h
> +++ b/include/image.h
> @@ -1241,6 +1241,25 @@ ulong android_image_get_end(const struct andr_img_hdr *hdr);
>  ulong android_image_get_kload(const struct andr_img_hdr *hdr);
>  void android_print_contents(const struct andr_img_hdr *hdr);
>
> +/** android_image_load - Load an Android Image from storage.
> + *
> + * Load an Android Image based on the header size in the storage. Return the
> + * number of bytes read from storage, which could be bigger than the actual
> + * Android Image as described in the header size. In case of error reading the
> + * image or if the image size needed to be read from disk is bigger than the
> + * the passed |max_size| a negative number is returned.

We normally do @max_size in U-Boot.

> + *
> + * @dev_desc:          The device where to read the image from
> + * @part_info:         The partition in |dev_desc| where to read the image from
> + * @load_address:      The address where the image will be loaded
> + * @max_size:          The maximum loaded size, in bytes
> + * @return the number of bytes read or a negative number in case of error.

Is it bytes or blocks?

> + */
> +long android_image_load(struct blk_desc *dev_desc,
> +                       const disk_partition_t *part_info,
> +                       unsigned long load_address,
> +                       unsigned long max_size);
> +
>  #endif /* CONFIG_ANDROID_BOOT_IMAGE */
>
>  /**
> --
> 2.12.2.564.g063fe858b8-goog
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 3/6] cmd: Add 'load_android' command to load Android images.
  2017-04-02  8:49       ` [U-Boot] [PATCH 3/6] cmd: Add 'load_android' command to load Android images Alex Deymo
  2017-04-02  8:49         ` [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name() Alex Deymo
@ 2017-04-06 22:42         ` Simon Glass
  1 sibling, 0 replies; 20+ messages in thread
From: Simon Glass @ 2017-04-06 22:42 UTC (permalink / raw)
  To: u-boot

Hi Alex,

On 2 April 2017 at 02:49, Alex Deymo <deymo@google.com> wrote:
> Android kernel images include a header that specifies addresses and
> kernel size. This patch adds a command to load these images from
> storage without specifying the size or address of them, and parsing
> them from the header instead.
> ---
>  cmd/Kconfig        |  9 +++++++++
>  cmd/Makefile       |  1 +
>  cmd/load_android.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 66 insertions(+)
>  create mode 100644 cmd/load_android.c

We normally use bootm for this. Can the header not be detected? If it
can be, you could use genimg_get_format() and avoid needing a new
command.

Regards,
SImon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name()
  2017-04-02  8:49         ` [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name() Alex Deymo
  2017-04-02  8:49           ` [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow Alex Deymo
@ 2017-04-06 22:42           ` Simon Glass
  2017-05-12 17:18           ` [U-Boot] [U-Boot, " Tom Rini
  2 siblings, 0 replies; 20+ messages in thread
From: Simon Glass @ 2017-04-06 22:42 UTC (permalink / raw)
  To: u-boot

On 2 April 2017 at 02:49, Alex Deymo <deymo@google.com> wrote:
> Similar to what blk_get_device_part_str() does, this patch makes
> part_get_info_by_name() return the partition number in case of a match.
> This is useful when the partition number is needed and not just the
> descriptor.
>
> Signed-off-by: Alex Deymo <deymo@google.com>
> ---
>  common/fb_mmc.c | 6 +++---
>  disk/part.c     | 2 +-
>  include/part.h  | 3 ++-
>  3 files changed, 6 insertions(+), 5 deletions(-)

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

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow
  2017-04-02  8:49           ` [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow Alex Deymo
  2017-04-02  8:49             ` [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command Alex Deymo
@ 2017-04-09 19:27             ` Simon Glass
  1 sibling, 0 replies; 20+ messages in thread
From: Simon Glass @ 2017-04-09 19:27 UTC (permalink / raw)
  To: u-boot

Hi Alex,

On 2 April 2017 at 02:49, Alex Deymo <deymo@google.com> wrote:
> An Android Bootloader must comply with certain boot modes and change
> the kernel command line accordingly. This patch introduces the Android
> boot mode concept which determines whether the device should boot to
> one of the following:
>  * recovery: which should boot to the recovery image,
>  * bootloader: which should boot to the "bootloader" (fastboot) and
>  * normal: which should boot to the system image.
>
> The boot mode is determined in part by the Boot Control Block (BCB)
> which is stored at the beginning of the "misc" partition. The BCB
> is defined in the "bootloader_message.h" file in AOSP, now copied
> here as android_bootloader_message.h with minor modifications.
>
> This patch implements the basic boot flow that loads and boots an
> Android kernel image assuming an A/B device which implies that it uses
> boot as recovery (BOARD_USES_RECOVERY_AS_BOOT in the BoardConfig.mk).
> This means that the recovery image shares the same kernel with the
> normal boot system image, but stores the recovery image as a ramdisk
> which is not used in normal mode.
>
> Among the limitations, this patch doesn't implement the A/B slot
> selection, it only boots from the provided slot.
>
> Test: Booted a rpi3 with this flow.

Could we have a sandbox test for this? Set test_vboot.py for an example.

> Signed-off-by: Alex Deymo <deymo@google.com>
> ---
>  README                               |  19 +-
>  common/Kconfig                       |  19 ++
>  common/Makefile                      |   1 +
>  common/android_bootloader.c          | 350 +++++++++++++++++++++++++++++++++++
>  include/android_bootloader.h         |  48 +++++
>  include/android_bootloader_message.h | 174 +++++++++++++++++
>  6 files changed, 607 insertions(+), 4 deletions(-)
>  create mode 100644 common/android_bootloader.c
>  create mode 100644 include/android_bootloader.h
>  create mode 100644 include/android_bootloader_messa.ge.h
>

This looks pretty clean so most of my comments are style-related

> diff --git a/README b/README
> index aa907ced8a..384cc6aabb 100644
> --- a/README
> +++ b/README
> @@ -1483,6 +1483,21 @@ The following options need to be configured:
>                 entering dfuMANIFEST state. Host waits this timeout, before
>                 sending again an USB request to the device.
>
> +- Android Bootloader support:
> +               CONFIG_ANDROID_BOOTLOADER

This name seems slightly off to me. Isn't this adding Android boot
support to and existing bootloader? Perhaps CONFIG_ANDROID_BOOT? Also
I'm not quite sure what is different between this and
CONFIG_ANDROID_BOOT_IMAGE. Does this new boot method have a name by
itself? (assuming it is a boot method).

> +               This enables support for the Android bootloader flow. Android
> +               devices can boot in normal mode, recovery mode or bootloader
> +               mode. The normal mode is the most common boot mode, but
> +               recovery mode is often used to perform factory reset and OTA
> +               (over-the-air) updates in the legacy updater. Also it is
> +               possible for an Android system to request a reboot to the
> +               "bootloader", which often means reboot to fastboot but may also
> +               include a UI with a menu.
> +
> +               CONFIG_ANDROID_BOOT_IMAGE
> +               This enables support for booting images which use the Android
> +               image format header.

I think it is enough to put this documentation in Kconfig. It might be
useful for have a separate README for the boot flow description.

> +
>  - USB Device Android Fastboot support:
>                 CONFIG_USB_FUNCTION_FASTBOOT
>                 This enables the USB part of the fastboot gadget
> @@ -1494,10 +1509,6 @@ The following options need to be configured:
>                 used on Android devices.
>                 See doc/README.android-fastboot for more information.
>
> -               CONFIG_ANDROID_BOOT_IMAGE
> -               This enables support for booting images which use the Android
> -               image format header.
> -
>                 CONFIG_FASTBOOT_BUF_ADDR
>                 The fastboot protocol requires a large memory buffer for
>                 downloads. Define this to the starting RAM address to use for
> diff --git a/common/Kconfig b/common/Kconfig
> index 8f73c8f757..47e2ffa3d6 100644
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -393,6 +393,25 @@ config DISPLAY_BOARDINFO
>           when U-Boot starts up. The board function checkboard() is called
>           to do this.
>
> +config ANDROID_BOOTLOADER
> +       bool "Support for Android Bootloader boot flow"
> +       default n
> +       depends on ANDROID_BOOT_IMAGE
> +       help
> +         If enabled, adds support to boot an Android device following the
> +         Android Bootloader boot flow. This flow requires an Android Bootloader
> +         to handle the Android Bootloader Message stored in the Boot Control
> +         Block (BCB), normally in the "misc" partition of an Android device.
> +         The BCB is used to determine the boot mode of the device (normal mode,
> +         recovery mode or bootloader mode) and, if enabled, the slot to boot
> +         from in devices with multiple boot slots (A/B devices).
> +
> +config ANDROID_BOOT_IMAGE
> +       bool "Enable support for Android Boot Images"
> +       help
> +         This enables support for booting images which use the Android
> +         image format header.
> +
>  menu "Start-up hooks"
>
>  config ARCH_EARLY_INIT_R
> diff --git a/common/Makefile b/common/Makefile
> index 86225f1564..9de0a77063 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -147,6 +147,7 @@ endif
>  obj-$(CONFIG_CMD_IDE) += ide.o
>  obj-y += image.o
>  obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
> +obj-$(CONFIG_ANDROID_BOOTLOADER) += android_bootloader.o
>  obj-$(CONFIG_$(SPL_)OF_LIBFDT) += image-fdt.o
>  obj-$(CONFIG_$(SPL_)FIT) += image-fit.o
>  obj-$(CONFIG_$(SPL_)FIT_SIGNATURE) += image-sig.o
> diff --git a/common/android_bootloader.c b/common/android_bootloader.c
> new file mode 100644
> index 0000000000..6656311ee3
> --- /dev/null
> +++ b/common/android_bootloader.c
> @@ -0,0 +1,350 @@
> +/*
> + * Copyright (C) 2016 The Android Open Source Project
> + *
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +
> +#include <android_bootloader.h>
> +#include <android_bootloader_message.h>
> +
> +#include <cli.h>
> +#include <common.h>
> +#include <malloc.h>

common.h always goes first. See

http://www.denx.de/wiki/U-Boot/CodingStyle

under 'Include file order"

> +
> +#define ANDROID_PARTITION_BOOT "boot"
> +#define ANDROID_PARTITION_SYSTEM "system"
> +
> +#define ANDROID_ARG_SLOT_SUFFIX "androidboot.slot_suffix="
> +#define ANDROID_ARG_ROOT "root="
> +
> +static int android_bootloader_message_load(
> +       struct blk_desc *dev_desc,

Better to use struct udevice

> +       const disk_partition_t *part_info,
> +       struct android_bootloader_message *message)

The android_bootloader prefix is very long. Is there a sensible
abbreviation that could be used?

> +{
> +       ulong message_blocks = sizeof(struct android_bootloader_message) /
> +           part_info->blksz;
> +       if (message_blocks > part_info->size) {
> +               printf("misc partition too small.\n");
> +               return -1;

Please return real error numbers, like -ENOSPC, etc.

> +       }
> +
> +       if (blk_dread(dev_desc, part_info->start, message_blocks, message) !=
> +           message_blocks) {
> +               printf("Could not read from misc partition\n");
> +               return -1;
> +       }
> +       debug("ANDROID: Loaded BCB, %lu blocks.\n", message_blocks);

blank line before last return in a function

> +       return 0;
> +}
> +
> +static int android_bootloader_message_write(
> +       struct blk_desc *dev_desc,
> +       const disk_partition_t *part_info,
> +       struct android_bootloader_message *message)
> +{
> +       ulong message_blocks = sizeof(struct android_bootloader_message) /
> +           part_info->blksz;
> +       if (message_blocks > part_info->size) {
> +               printf("misc partition too small.\n");
> +               return -1;
> +       }
> +
> +       if (blk_dwrite(dev_desc, part_info->start, message_blocks, message) !=
> +           message_blocks) {
> +               printf("Could not write to misc partition\n");
> +               return -1;
> +       }
> +       debug("ANDROID: Wrote new BCB, %lu blocks.\n", message_blocks);
> +       return 0;
> +}
> +
> +static enum android_boot_mode android_bootloader_load_and_clear_mode(
> +       struct blk_desc *dev_desc,
> +       const disk_partition_t *misc_part_info)
> +{
> +       struct android_bootloader_message bcb;
> +
> +#ifdef CONFIG_FASTBOOT
> +       char *bootloader_str;
> +
> +       /* Check for message from bootloader stored in RAM from a previous boot.
> +        */

/*
 * multi-line comment starts here
 * ...
 */

> +       bootloader_str = (char *)CONFIG_FASTBOOT_BUF_ADDR;
> +       if (!strcmp("reboot-bootloader", bootloader_str)) {
> +               bootloader_str[0] = '\0';
> +               return ANDROID_BOOT_MODE_BOOTLOADER;
> +       }
> +#endif
> +
> +       /* Check and update the BCB message if needed. */
> +       if (android_bootloader_message_load(dev_desc, misc_part_info, &bcb) <
> +           0) {
> +               printf("WARNING: Unable to load the BCB.\n");
> +               return ANDROID_BOOT_MODE_NORMAL;
> +       }
> +
> +       if (!strcmp("bootonce-bootloader", bcb.command)) {
> +               /* Erase the message in the BCB since this value should be used
> +                * only once.
> +                */
> +               memset(bcb.command, 0, sizeof(bcb.command));
> +               android_bootloader_message_write(dev_desc, misc_part_info,
> +                                                &bcb);
> +               return ANDROID_BOOT_MODE_BOOTLOADER;
> +       }
> +
> +       if (!strcmp("boot-recovery", bcb.command))
> +               return ANDROID_BOOT_MODE_RECOVERY;
> +
> +       return ANDROID_BOOT_MODE_NORMAL;
> +}
> +
> +/**
> + * Return the reboot reason string for the passed boot mode.
> + *
> + * @param mode The Android Boot mode.
> + * @return a pointer to the reboot reason string for mode.
> + */
> +static const char *android_boot_mode_str(enum android_boot_mode mode)
> +{
> +       switch (mode) {
> +       case ANDROID_BOOT_MODE_NORMAL:
> +               return "(none)";
> +       case ANDROID_BOOT_MODE_RECOVERY:
> +               return "recovery";
> +       case ANDROID_BOOT_MODE_BOOTLOADER:
> +               return "bootloader";
> +       }
> +       return NULL;
> +}
> +

This could use a function comment.

/*
 * android_part_get_info_by_name_suffix() - short description
 *
 * @dev_desc: blah blah
 * ...
 * @return parition number found (> 0) or -ve error number
 */

> +static int android_part_get_info_by_name_suffix(struct blk_desc *dev_desc,
> +                                               const char *base_name,
> +                                               const char *slot_suffix,
> +                                               disk_partition_t *part_info)
> +{
> +       char *part_name;
> +       int part_num;
> +       size_t part_name_len;
> +
> +       part_name_len = strlen(base_name) + 1;
> +       if (slot_suffix)
> +               part_name_len += strlen(slot_suffix);
> +       part_name = malloc(part_name_len);
> +       if (!part_name)
> +               return -1;
> +       strcpy(part_name, base_name);
> +       if (slot_suffix)
> +               strcat(part_name, slot_suffix);
> +
> +       part_num = part_get_info_by_name(dev_desc, part_name, part_info);
> +       if (part_num < 0) {
> +               debug("ANDROID: Could not find partition \"%s\"\n", part_name);
> +               part_num = -1;
> +       }
> +
> +       free(part_name);
> +       return part_num;
> +}
> +
> +static int android_bootloader_boot_bootloader(void)
> +{
> +       const char *fastboot_cmd = getenv("fastbootcmd");
> +
> +       if (fastboot_cmd)
> +               return run_command(fastboot_cmd, CMD_FLAG_ENV);
> +       return -1;
> +}
> +
> +static int android_bootloader_boot_kernel(unsigned long kernel_address)
> +{
> +       char kernel_addr_str[12];
> +       char *fdt_addr = getenv("fdt_addr");
> +       char *bootm_args[] = { "bootm", kernel_addr_str, "-", fdt_addr, NULL };
> +
> +       sprintf(kernel_addr_str, "0x%lx", kernel_address);
> +
> +       printf("Booting kernel at %s with fdt at %s...\n\n\n",
> +              kernel_addr_str, fdt_addr);
> +       do_bootm(NULL, 0, 4, bootm_args);
> +
> +       return -1;
> +}
> +
> +static char *strjoin(const char **chunks, char separator)
> +{
> +       int len, joined_len = 0;
> +       char *ret, *current;
> +       const char **p;
> +
> +       for (p = chunks; *p; p++)
> +               joined_len += strlen(*p) + 1;
> +
> +       if (!joined_len) {
> +               ret = mallo=c(1);

calloc() would avoid the need for the next two lines if you like.

> +               if (ret)
> +                       ret[0] = '\0';
> +               return ret;
> +       }
> +
> +       ret = malloc(joined_len);
> +       current = ret;
> +       if (!ret)
> +               return ret;
> +
> +       for (p = chunks; *p; p++) {
> +               len = strlen(*p);
> +               memcpy(current, *p, len);
> +               current += len;
> +               *current = separator;
> +               current++;
> +       }
> +       /* Replace the last separator by a \0. */

Avoid . at end of comment

> +       current[-1] = '\0';
> +       return ret;
> +}
> +
> +/** android_assemble_cmdline - Assemble the command line to pass to the kernel

Please add args

> + * @return a newly allocated string
> + */
> +static char *android_assemble_cmdline(const char *slot_suffix,
> +                                     const char *extra_args)
> +{
> +       const char *cmdline_chunks[16];
> +       const char **current_chunk = cmdline_chunks;
> +       char *env_cmdline, *cmdline, *rootdev_input;
> +       char *allocated_suffix = NULL;
> +       char *allocated_rootdev = NULL;
> +       unsigned long rootdev_len;
> +
> +       env_cmdline = getenv("bootargs");
> +       if (env_cmdline)
> +               *(current_chunk++) = env_cmdline;
> +
> +       /* The |slot_suffix| needs to be passed to the kernel to know what
> +        * slot to boot from.
> +        */
> +       if (slot_suffix) {
> +               allocated_suffix = malloc(strlen(ANDROID_ARG_SLOT_SUFFIX) +
> +                                         strlen(slot_suffix));
> +               strcpy(allocated_suffix, ANDROID_ARG_SLOT_SUFFIX);
> +               strcat(allocated_suffix, slot_suffix);
> +               *(current_chunk++) = allocated_suffix;
> +       }
> +
> +       rootdev_input = getenv("android_rootdev");
> +       if (rootdev_input) {
> +               rootdev_len = strlen(ANDROID_ARG_ROOT) + CONFIG_SYS_CBSIZE + 1;
> +               allocated_rootdev = malloc(rootdev_len);
> +               strcpy(allocated_rootdev, ANDROID_ARG_ROOT);
> +               cli_simple_process_macros(rootdev_input,
> +                                         allocated_rootdev +
> +                                         strlen(ANDROID_ARG_ROOT));
> +               /* Make sure that the string is null-terminated since the
> +                * previous could not copy to the end of the input string if it
> +                * is too big.
> +                */
> +               allocated_rootdev[rootdev_len - 1] = '\0';
> +               *(current_chunk++) = allocated_rootdev;
> +       }
> +
> +       if (extra_args)
> +               *(current_chunk++) = extra_args;
> +
> +       *(current_chunk++) = NULL;
> +       cmdline = strjoin(cmdline_chunks, ' ');
> +       free(allocated_suffix);
> +       free(allocated_rootdev);
> +       return cmdline;
> +}
> +
> +int android_bootloader_boot_flow(struct blk_desc *dev_desc,
> +                                const disk_partition_t *misc_part_info,
> +                                const char *slot,
> +                                unsigned long kernel_address)
> +{
> +       enum android_boot_mode mode;
> +       disk_partition_t boot_part_info;
> +       disk_partition_t system_part_info;
> +       int boot_part_num, system_part_num;
> +       int ret;
> +       char *command_line;
> +       char slot_suffix[3];
> +       const char *mode_cmdline = NULL;
> +
> +       /* Determine the boot mode and clear its value for the next boot if
> +        * needed.
> +        */
> +       mode = android_bootloader_load_and_clear_mode(dev_desc, misc_part_info);
> +       printf("ANDROID: reboot reason: \"%s\"\n", android_boot_mode_str(mode));
> +
> +       switch (mode) {
> +       case ANDROID_BOOT_MODE_NORMAL:
> +               /* In normal mode, we load the kernel from "boot" but append
> +                * "skip_initramfs" to the cmdline to make it ignore the
> +                * recovery initramfs in the boot partition.
> +                */
> +               mode_cmdline = "skip_initramfs";
> +               break;
> +       case ANDROID_BOOT_MODE_RECOVERY:
> +               /* In recovery mode we still boot the kernel from "boot" but
> +                * don't skip the initramfs so it boots to recovery.
> +                */
> +               break;
> +       case ANDROID_BOOT_MODE_BOOTLOADER:
> +               /* Bootloader mode enters fastboot. If this operation fails we
> +                * simply return since we can't recover from this situation by
> +                * switching to another slot.
> +                */
> +               return android_bootloader_boot_bootloader();
> +       }
> +
> +       slot_suffix[0] = '\0';
> +       if (slot && slot[0]) {
> +               slot_suffix[0] = '_';
> +               slot_suffix[1] = slot[0];
> +               slot_suffix[2] = '\0';
> +       }
> +
> +       /* Load the kernel from the desired "boot" partition. */
> +       boot_part_num =
> +           android_part_get_info_by_name_suffix(dev_desc,
> +                                                ANDROID_PARTITION_BOOT,
> +                                                slot_suffix, &boot_part_info);
> +       if (boot_part_num < 0)
> +               return -1;
> +       debug("ANDROID: Loading kernel from \"%s\", partition %d.\n",
> +             boot_part_info.name, boot_part_num);
> +
> +       system_part_num =
> +           android_part_get_info_by_name_suffix(dev_desc,
> +                                                ANDROID_PARTITION_SYSTEM,
> +                                                slot_suffix,
> +                                                &system_part_info);
> +       if (system_part_num < 0)
> +               return -1;
> +       debug("ANDROID: Using system image from \"%s\", partition %d.\n",
> +             system_part_info.name, system_part_num);
> +
> +       ret = android_image_load(dev_desc, &boot_part_info, kernel_address,
> +                                -1UL);
> +       if (ret < 0)
> +               return ret;
> +
> +       /* Set Android root variables. */
> +       setenv_ulong("android_root_devnum", dev_desc->devnum);
> +       setenv_ulong("android_root_partnum", system_part_num);
> +       setenv("android_slotsufix", slot_suffix);
> +
> +       /* Assemble the command line */
> +       command_line = android_assemble_cmdline(slot_suffix, mode_cmdline);
> +       setenv("bootargs", command_line);
> +
> +       debug("ANDROID: bootargs: \"%s\"\n", command_line);
> +
> +       android_bootloader_boot_kernel(kernel_address);
> +
> +       /* TODO: If the kernel doesn't boot mark the selected slot as bad. */
> +       return -1;
> +}
> diff --git a/include/android_bootloader.h b/include/android_bootloader.h
> new file mode 100644
> index 0000000000..ddf6d76f64
> --- /dev/null
> +++ b/include/android_bootloader.h
> @@ -0,0 +1,48 @@
> +/*
> + * Copyright (C) 2016 The Android Open Source Project
> + *
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +
> +#ifndef __ANDROID_BOOTLOADER_H
> +#define __ANDROID_BOOTLOADER_H
> +
> +#include <common.h>

You should be able to drop this if you have common.h first in your
includes in .c files.

> +
> +enum android_boot_mode {
> +       ANDROID_BOOT_MODE_NORMAL = 0,
> +
> +       /* "recovery" mode is triggered by the "reboot recovery" command or
> +        * equivalent adb/fastboot command. It can also be triggered by writing
> +        * "boot-recovery" in the BCB message. This mode should boot the
> +        * recovery kernel.
> +        */
> +       ANDROID_BOOT_MODE_RECOVERY,
> +
> +       /* "bootloader" mode is triggered by the "reboot bootloader" command or
> +        * equivalent adb/fastboot command. It can also be triggered by writing
> +        * "bootonce-bootloader" in the BCB message. This mode should boot into
> +        * fastboot.
> +        */
> +       ANDROID_BOOT_MODE_BOOTLOADER,
> +};
> +
> +/** android_bootloader_boot_flow - Execute the Android Bootloader Flow.
> + * 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. On success it doesn't return.
> + *
> + * @dev_desc:          device where to load the kernel and system to boot from.
> + * @misc_part_info:    the "misc" partition descriptor in 'dev_desc'.
> + * @slot:              the boot slot to boot from.
> + * @kernel_address:    address where to load the kernel if needed.
> + *
> + * @return a negative number in case of error, otherwise it doesn't return.
> + */
> +int android_bootloader_boot_flow(struct blk_desc *dev_desc,

Particularly for an exported function like this, struct udevice * is better.

> +                                const disk_partition_t *misc_part_info,
> +                                const char *slot,
> +                                unsigned long kernel_address);
> +
> +#endif  /* __ANDROID_BOOTLOADER_H */
> diff --git a/include/android_bootloader_message.h b/include/android_bootloader_message.h
> new file mode 100644
> index 0000000000..2c2142dc6f
> --- /dev/null
> +++ b/include/android_bootloader_message.h
> @@ -0,0 +1,174 @@
> +/*
> + * This is from the Android Project,
> + * Repository: https://android.googlesource.com/platform/bootable/recovery/
> + * File: bootloader_message/include/bootloader_message/bootloader_message.h
> + * Commit: 8b309f6970ab3b7c53cc529c51a2cb44e1c7a7e1
> + *
> + * Copyright (C) 2008 The Android Open Source Project
> + *
> + * SPDX-License-Identifier: BSD-2-Clause
> + */
> +
> +#ifndef __ANDROID_BOOTLOADER_MESSAGE_H
> +#define __ANDROID_BOOTLOADER_MESSAGE_H
> +
> +/* compiler.h defines the types that otherwise are included from stdint.h and
> + * stddef.h
> + */
> +#include <compiler.h>
> +
> +/* Spaces used by misc partition are as below:
> + * 0   - 2K     Bootloader Message
> + * 2K  - 16K    Used by Vendor's bootloader (the 2K - 4K range may be optionally used
> + *              as bootloader_message_ab struct)
> + * 16K - 64K    Used by uncrypt and recovery to store wipe_package for A/B devices
> + * Note that these offsets are admitted by bootloader,recovery and uncrypt, so they
> + * are not configurable without changing all of them.
> + */
> +static const size_t ANDROID_BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0;
> +static const size_t ANDROID_WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;
> +
> +/* Bootloader Message (2-KiB)
> + *
> + * This structure describes the content of a block in flash
> + * that is used for recovery and the bootloader to talk to
> + * each other.
> + *
> + * The command field is updated by linux when it wants to
> + * reboot into recovery or to update radio or bootloader firmware.
> + * It is also updated by the bootloader when firmware update
> + * is complete (to boot into recovery for any final cleanup)
> + *
> + * The status field is written by the bootloader after the
> + * completion of an "update-radio" or "update-hboot" command.
> + *
> + * The recovery field is only written by linux and used
> + * for the system to send a message to recovery or the
> + * other way around.
> + *
> + * The stage field is written by packages which restart themselves
> + * multiple times, so that the UI can reflect which invocation of the
> + * package it is.  If the value is of the format "#/#" (eg, "1/3"),
> + * the UI will add a simple indicator of that status.
> + *
> + * We used to have slot_suffix field for A/B boot control metadata in
> + * this struct, which gets unintentionally cleared by recovery or
> + * uncrypt. Move it into struct bootloader_message_ab to avoid the
> + * issue.
> + */
> +struct android_bootloader_message {
> +    char command[32];
> +    char status[32];
> +    char recovery[768];
> +
> +    /* The 'recovery' field used to be 1024 bytes.  It has only ever
> +     * been used to store the recovery command line, so 768 bytes
> +     * should be plenty.  We carve off the last 256 bytes to store the
> +     * stage string (for multistage packages) and possible future
> +     * expansion. */
> +    char stage[32];
> +
> +    /* The 'reserved' field used to be 224 bytes when it was initially
> +     * carved off from the 1024-byte recovery field. Bump it up to
> +     * 1184-byte so that the entire bootloader_message struct rounds up
> +     * to 2048-byte. */
> +    char reserved[1184];
> +};
> +
> +/**
> + * We must be cautious when changing the bootloader_message struct size,
> + * because A/B-specific fields may end up with different offsets.
> + */
> +#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
> +static_assert(sizeof(struct android_bootloader_message) == 2048,
> +              "struct bootloader_message size changes, which may break A/B devices");
> +#endif

The check_member() macros might be useful here to avoid this #if

> +
> +/**
> + * The A/B-specific bootloader message structure (4-KiB).
> + *
> + * We separate A/B boot control metadata from the regular bootloader
> + * message struct and keep it here. Everything that's A/B-specific
> + * stays after struct bootloader_message, which should be managed by
> + * the A/B-bootloader or boot control HAL.
> + *
> + * The slot_suffix field is used for A/B implementations where the
> + * bootloader does not set the androidboot.ro.boot.slot_suffix kernel
> + * commandline parameter. This is used by fs_mgr to mount /system and
> + * other partitions with the slotselect flag set in fstab. A/B
> + * implementations are free to use all 32 bytes and may store private
> + * data past the first NUL-byte in this field. It is encouraged, but
> + * not mandatory, to use 'struct bootloader_control' described below.
> + */
> +struct android_bootloader_message_ab {
> +    struct android_bootloader_message message;
> +    char slot_suffix[32];
> +
> +    /* Round up the entire struct to 4096-byte. */
> +    char reserved[2016];
> +};
> +
> +/**
> + * Be cautious about the struct size change, in case we put anything post
> + * bootloader_message_ab struct (b/29159185).
> + */
> +#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
> +static_assert(sizeof(struct android_bootloader_message_ab) == 4096,
> +              "struct bootloader_message_ab size changes");
> +#endif
> +
> +#define ANDROID_BOOT_CTRL_MAGIC   0x42414342 /* Bootloader Control AB */
> +#define ANDROID_BOOT_CTRL_VERSION 1
> +
> +struct android_slot_metadata {

I think thee read better if you put the comments at the top. See for
example struct udevice.

> +    /* Slot priority with 15 meaning highest priority, 1 lowest
> +     * priority and 0 the slot is unbootable. */
> +    uint8_t priority : 4;
> +    /* Number of times left attempting to boot this slot. */
> +    uint8_t tries_remaining : 3;
> +    /* 1 if this slot has booted successfully, 0 otherwise. */
> +    uint8_t successful_boot : 1;
> +    /* 1 if this slot is corrupted from a dm-verity corruption, 0 */
> +    /* otherwise. */
> +    uint8_t verity_corrupted : 1;
> +    /* Reserved for further use. */
> +    uint8_t reserved : 7;
> +} __attribute__((packed));
> +
> +/* Bootloader Control AB
> + *
> + * This struct can be used to manage A/B metadata. It is designed to
> + * be put in the 'slot_suffix' field of the 'bootloader_message'
> + * structure described above. It is encouraged to use the
> + * 'bootloader_control' structure to store the A/B metadata, but not
> + * mandatory.
> + */
> +struct android_bootloader_control {
> +    /* NUL terminated active slot suffix. */
> +    char slot_suffix[4];
> +    /* Bootloader Control AB magic number (see BOOT_CTRL_MAGIC). */
> +    uint32_t magic;
> +    /* Version of struct being used (see BOOT_CTRL_VERSION). */
> +    uint8_t version;
> +    /* Number of slots being managed. */
> +    uint8_t nb_slot : 3;
> +    /* Number of times left attempting to boot recovery. */
> +    uint8_t recovery_tries_remaining : 3;
> +    /* Ensure 4-bytes alignment for slot_info field. */
> +    uint8_t reserved0[2];
> +    /* Per-slot information.  Up to 4 slots. */
> +    struct android_slot_metadata slot_info[4];
> +    /* Reserved for further use. */
> +    uint8_t reserved1[8];
> +    /* CRC32 of all 28 bytes preceding this field (little endian
> +     * format). */
> +    uint32_t crc32_le;
> +} __attribute__((packed));
> +
> +#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
> +static_assert(sizeof(struct android_bootloader_control) ==
> +              sizeof(((struct android_bootloader_message_ab *)0)->slot_suffix),
> +              "struct bootloader_control has wrong size");
> +#endif
> +
> +#endif  /* __ANDROID_BOOTLOADER_MESSAGE_H */
> --
> 2.12.2.564.g063fe858b8-goog
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 0/6] Android A/B Bootloader support
  2017-04-02  8:49 ` [U-Boot] [PATCH 0/6] Android A/B Bootloader support Alex Deymo
  2017-04-02  8:49   ` [U-Boot] [PATCH 1/6] image: Update include/android_image.h Alex Deymo
@ 2017-04-19  8:42   ` Kever Yang
  1 sibling, 0 replies; 20+ messages in thread
From: Kever Yang @ 2017-04-19  8:42 UTC (permalink / raw)
  To: u-boot

Hi Alex,


     It's great for this patch set which able to support full android 
boot flow,
there was no support for parse misc and enter recovery in U-Boot mainline.

     Do you have a public tree or more detail step by step document, I want
to test this patch set on my board.

Thanks,
- Kever
On 04/02/2017 04:49 PM, Alex Deymo wrote:
> An "Android Bootloader" has a lot of requirements about how it should
> behave which Android partners must implement. In particular, the new
> A/B updates [1] added more requirements and flows to the bootloader
> which are not common, on top of the existing flows.
>
> For example, a few uncommon requirements include:
> * Lookup in the BCB (boot control block) whether a "recovery" message
>    is stored. This is used by the recovery environment when applying a
>    multi-stage update in the legacy update model (recovery reboots to
>    recovery again) and for interrumpted factory-reset (a reboot during
>    the factory reset should continue to reboot into factory reset until
>    it is done).
> * A new "repair" mode. In the A/B model, when none of the slots is
>    bootable, the device would boot into repair mode, which is often the
>    same as "bootloader" mode (fastboot).
> * Recovery as root: In newer version of AOSP, it is possible to mount
>    the system image as / without an initramfs, which then frees up the
>    initramfs in the "boot" partition to hold the "recovery" initramfs.
>    This is the default for new devices and required for the A/B setup.
>
> This patchset updates the Android-related headers and introduces new
> commands to boot a recent Android build. This work is based on the
> bootloader used in the Raspberry Pi in Android Things and extensively
> tested there.
>
> [1] https://source.android.com/devices/tech/ota/ab_updates.html
>
>
> Alex Deymo (6):
>    image: Update include/android_image.h
>    image: Implement a function to load Android Images.
>    cmd: Add 'load_android' command to load Android images.
>    disk: Return the partition number in part_get_info_by_name()
>    Initial support for the Android Bootloader flow
>    cmd: Add "boot_android" command.
>
>   README                               |  25 ++-
>   cmd/Kconfig                          |  19 ++
>   cmd/Makefile                         |   2 +
>   cmd/boot_android.c                   | 126 +++++++++++++
>   cmd/load_android.c                   |  56 ++++++
>   common/Kconfig                       |  19 ++
>   common/Makefile                      |   1 +
>   common/android_bootloader.c          | 350 +++++++++++++++++++++++++++++++++++
>   common/fb_mmc.c                      |   6 +-
>   common/image-android.c               |  60 ++++++
>   disk/part.c                          |   2 +-
>   include/android_bootloader.h         |  48 +++++
>   include/android_bootloader_message.h | 174 +++++++++++++++++
>   include/android_image.h              |  24 ++-
>   include/image.h                      |  19 ++
>   include/part.h                       |   3 +-
>   16 files changed, 920 insertions(+), 14 deletions(-)
>   create mode 100644 cmd/boot_android.c
>   create mode 100644 cmd/load_android.c
>   create mode 100644 common/android_bootloader.c
>   create mode 100644 include/android_bootloader.h
>   create mode 100644 include/android_bootloader_message.h
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [U-Boot,1/6] image: Update include/android_image.h
  2017-04-02  8:49   ` [U-Boot] [PATCH 1/6] image: Update include/android_image.h Alex Deymo
  2017-04-02  8:49     ` [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images Alex Deymo
  2017-04-06 22:42     ` [U-Boot] [PATCH 1/6] image: Update include/android_image.h Simon Glass
@ 2017-05-12 17:18     ` Tom Rini
  2 siblings, 0 replies; 20+ messages in thread
From: Tom Rini @ 2017-05-12 17:18 UTC (permalink / raw)
  To: u-boot

On Sun, Apr 02, 2017 at 01:49:47AM -0700, Alex Deymo wrote:

> Update the Android image header format to the latest version published
> in AOSP. The original code moved to a new repository, so this patch also
> updates the reference to that path.
> 
> Signed-off-by: Alex Deymo <deymo@google.com>
> Reviewed-by: Simon Glass <sjg@chromium.org>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170512/056238e5/attachment.sig>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [U-Boot, 4/6] disk: Return the partition number in part_get_info_by_name()
  2017-04-02  8:49         ` [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name() Alex Deymo
  2017-04-02  8:49           ` [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow Alex Deymo
  2017-04-06 22:42           ` [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name() Simon Glass
@ 2017-05-12 17:18           ` Tom Rini
  2 siblings, 0 replies; 20+ messages in thread
From: Tom Rini @ 2017-05-12 17:18 UTC (permalink / raw)
  To: u-boot

On Sun, Apr 02, 2017 at 01:49:50AM -0700, Alex Deymo wrote:

> Similar to what blk_get_device_part_str() does, this patch makes
> part_get_info_by_name() return the partition number in case of a match.
> This is useful when the partition number is needed and not just the
> descriptor.
> 
> Signed-off-by: Alex Deymo <deymo@google.com>
> Reviewed-by: Simon Glass <sjg@chromium.org>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170512/3f06d140/attachment.sig>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command.
  2018-04-26 22:41   ` Stanislas BERTRAND
@ 2018-04-30 10:28     ` Alex Deymo
  0 siblings, 0 replies; 20+ messages in thread
From: Alex Deymo @ 2018-04-30 10:28 UTC (permalink / raw)
  To: u-boot

Regarding the boot_android command, U-Boot supports loading Android-format
kernel images to memory and booting them. That's not the main purpose of
boot_android, it actually does that by just calling bootm.

The part that U-Boot doesn't support is all the flows around booting an
Android device that are expected in AOSP. A big one is reading and honoring
the Boot Control Block (BCB), normally the first 4KiB of the "misc"
partition. See
https://android.googlesource.com/platform/bootable/recovery/+/master/bootloader_message/include/bootloader_message/bootloader_message.h
for a definition.

BCB is used for factory reset (from the Settings UI in Android), which will
write a message in the BCB saying "boot-recovery":
https://android.googlesource.com/platform/bootable/recovery/+/master/recovery.cpp#135

On boot, the bootloader must read the BCB and decide whether to boot the
normal kernel or instead boot to "recovery" mode. During the Factory Reset,
it is important that this is stored somewhere on the emmc, otherwise if you
just rely on a memory flag to tell the bootloader to boot to "recovery"
mode and complete the factory reset; a cold start boot might forget that
value. There are other cases where the bootloader should enter recovery,
for example when you run "boot recovery" from adb, or whit a multi-stage
non-A/B update (needs to reboot multiple times to recovery).

There's the "bootonce-bootloader" message too, in bootloader_message.cpp in
AOSP as well which tells to boot in bootloader mode (essentially, fastboot
mode), which can be triggered by "reboot bootloader" from userspace.
Deciding this means changing the kernel command line in the bootloader, so
that also must be done somewhere.

On top of that there's all the A/B logic flow, to decide which slot to boot
from; which is also defined in the bootloader_message.h, explained here:
https://source.android.com/devices/tech/ota/ab/ (See "Implementing A/B
Updates" too).

All this is what the boot_android command is taking care of. I'm sorry that
I don't have a better self-contained documentation link about this flow.

I should note that these flows are not *required* for all Android devices.
Android partners are free to use their own format for A/B metadata, not use
the AOSP "recovery" program/updates at all, and I think that even
"fastboot" is not mandatory for some devices (but I really don't know). Of
course, if you don't use this, you have to implement your own (updates, A/B
flow, factory reset...). That said, in my opinion if you take the latest
AOSP, U-Boot and kernel and put them together in a reasonable unlocked
device they should all work with these features and flows. You shouldn't
need to write code to make that work, just enable them, so that's why I
think U-Boot should have these Android-specific flows in it, given that it
already supports loading Android-format kernels.

Best regards,
Alex

2018-04-27 0:41 GMT+02:00 Stanislas BERTRAND <sbertrand@witekio.com>:

> Hi Sam,
>
> > Can I ask you some questions about this code?
> >  1. Do I understand correctly that this is just some old patch hanging
> > in mailing list [1]?
>
> Yes, it is from an old post to the mailing list.
>
> >  2. What is the motivation of adding this command? We already have
> > Android boot image support in bootm command, which we successfully use
> > in TI just by loading needed images to RAM and then passing them to
> > bootm, like this: [2].
>
> I am working to get a Android A/B System implementation on my board.
> I was looking to reuse existing implementation. Aiming to stay close to
> the mainline.
>
> The command boot_android performs the different loading and checks
> required before calling bootm.
>
> Like Alex mentioned [4], those patch series are not recent but it was good
> starting point of implementation.
> I had to perform some customization to have a functional boot flow adapted
> to my system ( Android 7.1.1, Linux 4.4.45, U-Boot 2017.0 ).
>
> I am not pushing to have this particular implementation mainline.
> However having a mainline implementation for Android A/B system,
> would be nice. I was giving feedback from my particular system usage.
>
> >  3. Can you provide more information about how this code works? And
> > probably show some relevant link from Android documentation where it
> > says about boot flow implemented here?
>
> >  [1] https://lists.denx.de/pipermail/u-boot/2017-April/285847.html
> > [2] http://git.denx.de/?p=u-boot.git;a=blob;f=include/
> environment/ti/boot.h;h=24b7783f88947db07480d814c798e5
> 1197c07ce2;hb=HEAD#l38
> <https://lists.denx.de/listinfo/u-boot>
> More information was posted by Alex in his original patch series [3].
>
> Alex, I did add loading of the FDT in the boot_android command. How did
> you load your at 'fdt_addr' ?
>

This was done for the raspberry pi and I was using the FDT that the
bootloader code in the Pi loads and assembles. This is so all the boot.txt
configs and overlays that people expect to work on the pi are used, plus
the cmdline.txt (u-boot.img would be a "kernel" for the rpi, which then
loads android). In that case, the "fdt_addr" is populated from the
board/raspberrypi/rpi/rpi.c, so all you need to do is to load it from
memory and change the FDT if needed. I wasn't loading it from emmc.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command.
  2018-04-26 19:06 ` Sam Protsenko
@ 2018-04-26 22:41   ` Stanislas BERTRAND
  2018-04-30 10:28     ` Alex Deymo
  0 siblings, 1 reply; 20+ messages in thread
From: Stanislas BERTRAND @ 2018-04-26 22:41 UTC (permalink / raw)
  To: u-boot

Hi Sam,


> Can I ask you some questions about this code?
>  1. Do I understand correctly that this is just some old patch hanging
> in mailing list [1]?

Yes, it is from an old post to the mailing list.

>  2. What is the motivation of adding this command? We already have
> Android boot image support in bootm command, which we successfully use
> in TI just by loading needed images to RAM and then passing them to
> bootm, like this: [2].

I am working to get a Android A/B System implementation on my board.
I was looking to reuse existing implementation. Aiming to stay close to the mainline.

The command boot_android performs the different loading and checks required before calling bootm.

Like Alex mentioned [4], those patch series are not recent but it was good starting point of implementation.
I had to perform some customization to have a functional boot flow adapted to my system ( Android 7.1.1, Linux 4.4.45, U-Boot 2017.0 ).

I am not pushing to have this particular implementation mainline.
However having a mainline implementation for Android A/B system,
would be nice. I was giving feedback from my particular system usage.

>  3. Can you provide more information about how this code works? And
> probably show some relevant link from Android documentation where it
> says about boot flow implemented here?

>  [1] https://lists.denx.de/pipermail/u-boot/2017-April/285847.html
> [2] http://git.denx.de/?p=u-boot.git;a=blob;f=include/environment/ti/boot.h;h=24b7783f88947db07480d814c798e51197c07ce2;hb=HEAD#l38
<https://lists.denx.de/listinfo/u-boot>
More information was posted by Alex in his original patch series [3].

Alex, I did add loading of the FDT in the boot_android command. How did you load your at 'fdt_addr' ?

<https://lists.denx.de/pipermail/u-boot/2018-April/325674.html>

Thanks,

[3] https://lists.denx.de/pipermail/u-boot/2017-April/285841.html
[4] https://lists.denx.de/pipermail/u-boot/2018-April/325674.html

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command.
  2018-04-19 17:21 [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command Stanislas BERTRAND
@ 2018-04-26 19:06 ` Sam Protsenko
  2018-04-26 22:41   ` Stanislas BERTRAND
  0 siblings, 1 reply; 20+ messages in thread
From: Sam Protsenko @ 2018-04-26 19:06 UTC (permalink / raw)
  To: u-boot

On 19 April 2018 at 20:21, Stanislas BERTRAND <sbertrand@witekio.com> wrote:
> Hi Alex,
>
> I used work available in https://android.googlesource.com/platform/external/u-boot/+/android-o-mr1-iot-preview-7.
> I selected the n-iot-preview-4 because it is U-Boot version 2017.01 which is compatible with TI U-Boot work.
>
> One quick feedback about the boot_android :
>
>> 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>

Hi Stanislas,

Can I ask you some questions about this code?
 1. Do I understand correctly that this is just some old patch hanging
in mailing list [1]?
 2. What is the motivation of adding this command? We already have
Android boot image support in bootm command, which we successfully use
in TI just by loading needed images to RAM and then passing them to
bootm, like this: [2].
 3. Can you provide more information about how this code works? And
probably show some relevant link from Android documentation where it
says about boot flow implemented here?

Thanks!

[1] https://lists.denx.de/pipermail/u-boot/2017-April/285847.html
[2] http://git.denx.de/?p=u-boot.git;a=blob;f=include/environment/ti/boot.h;h=24b7783f88947db07480d814c798e51197c07ce2;hb=HEAD#l38

>> ---
>>  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"
>
> The part name will be used to find the partition if `;` is used. `;` is the command delimiter
> for u-boot commands. When using it with the `boot` partition, the `boot` command would
> be executed and boot_android would return a failure.
>
> Could part number and part name be handle in software, if name lookup fails, try a
> number conversion.
>
>> +     "    - 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"
>> +);
>> --
>>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command.
@ 2018-04-19 17:21 Stanislas BERTRAND
  2018-04-26 19:06 ` Sam Protsenko
  0 siblings, 1 reply; 20+ messages in thread
From: Stanislas BERTRAND @ 2018-04-19 17:21 UTC (permalink / raw)
  To: u-boot

Hi Alex,

I used work available in https://android.googlesource.com/platform/external/u-boot/+/android-o-mr1-iot-preview-7.
I selected the n-iot-preview-4 because it is U-Boot version 2017.01 which is compatible with TI U-Boot work.

One quick feedback about the boot_android :

> 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
> 
> 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"

The part name will be used to find the partition if `;` is used. `;` is the command delimiter
for u-boot commands. When using it with the `boot` partition, the `boot` command would
be executed and boot_android would return a failure. 

Could part number and part name be handle in software, if name lookup fails, try a
number conversion.

> +	"    - 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"
> +);
> --
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2018-04-30 10:28 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <a74b3d5e65b4bf5c2edca98bba9e678be762ebe7>
2017-04-02  8:49 ` [U-Boot] [PATCH 0/6] Android A/B Bootloader support Alex Deymo
2017-04-02  8:49   ` [U-Boot] [PATCH 1/6] image: Update include/android_image.h Alex Deymo
2017-04-02  8:49     ` [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images Alex Deymo
2017-04-02  8:49       ` [U-Boot] [PATCH 3/6] cmd: Add 'load_android' command to load Android images Alex Deymo
2017-04-02  8:49         ` [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name() Alex Deymo
2017-04-02  8:49           ` [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow Alex Deymo
2017-04-02  8:49             ` [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command Alex Deymo
2017-04-04 14:46               ` Lukasz Majewski
2017-04-09 19:27             ` [U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow Simon Glass
2017-04-06 22:42           ` [U-Boot] [PATCH 4/6] disk: Return the partition number in part_get_info_by_name() Simon Glass
2017-05-12 17:18           ` [U-Boot] [U-Boot, " Tom Rini
2017-04-06 22:42         ` [U-Boot] [PATCH 3/6] cmd: Add 'load_android' command to load Android images Simon Glass
2017-04-06 22:42       ` [U-Boot] [PATCH 2/6] image: Implement a function to load Android Images Simon Glass
2017-04-06 22:42     ` [U-Boot] [PATCH 1/6] image: Update include/android_image.h Simon Glass
2017-05-12 17:18     ` [U-Boot] [U-Boot,1/6] " Tom Rini
2017-04-19  8:42   ` [U-Boot] [PATCH 0/6] Android A/B Bootloader support Kever Yang
2018-04-19 17:21 [U-Boot] [PATCH 6/6] cmd: Add "boot_android" command Stanislas BERTRAND
2018-04-26 19:06 ` Sam Protsenko
2018-04-26 22:41   ` Stanislas BERTRAND
2018-04-30 10:28     ` Alex Deymo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.