Android A/B Bootloader support
A message that is not in the archive (sent off-list or not yet received): a74b3d5e65b4bf5c2edca98bba9e678be762ebe7
cover Android A/B Bootloader support
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
Signature · 1 line
2.12.2.564.g063fe858b8-goog
PATCH 1/6 image: Update include/android_image.h
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.
--- common/image-android.c | 9 +++++++++ include/android_image.h | 24 +++++++++++++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-)
common/image-android.c +9 -0
@@ -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); }
include/android_image.h +19 -5
@@ -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));/* * +-----------------+
Signature · 1 line
2.12.2.564.g063fe858b8-goog
PATCH 2/6 image: Implement a function to load Android Images.
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.
--- common/image-android.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/image.h | 19 +++++++++++++++++++ 2 files changed, 70 insertions(+)
common/image-android.c +51 -0
@@ -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
include/image.h +19 -0
@@ -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 */ /**
Signature · 1 line
2.12.2.564.g063fe858b8-goog
PATCH 3/6 cmd: Add 'load_android' command to load Android images.
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
cmd/Kconfig +9 -0
@@ -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
cmd/Makefile +1 -0
@@ -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
cmd/load_android.c new file +56 -0
56 lines not on this page · raw message
Signature · 1 line
2.12.2.564.g063fe858b8-goog
PATCH 4/6 disk: Return the partition number in part_get_info_by_name()
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.
--- common/fb_mmc.c | 6 +++--- disk/part.c | 2 +- include/part.h | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-)
common/fb_mmc.c +3 -3
@@ -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 ;
disk/part.c +1 -1
@@ -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; } } }
include/part.h +2 -1
@@ -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);
Signature · 1 line
2.12.2.564.g063fe858b8-goog
PATCH 5/6 Initial support for the Android Bootloader flow
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.
--- 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
README +15 -4
@@ -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
common/Kconfig +19 -0
@@ -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
common/Makefile +1 -0
@@ -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
common/android_bootloader.c new file +350 -0
350 lines not on this page · raw message
include/android_bootloader.h new file +48 -0
48 lines not on this page · raw message
include/android_bootloader_message.h new file +174 -0
174 lines not on this page · raw message
Signature · 1 line
2.12.2.564.g063fe858b8-goog
PATCH 6/6 cmd: Add "boot_android" command.
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.
--- 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
README +6 -0
@@ -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
cmd/Kconfig +10 -0
@@ -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
cmd/Makefile +1 -0
@@ -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
cmd/boot_android.c new file +126 -0
126 lines not on this page · raw message
Signature · 1 line
2.12.2.564.g063fe858b8-goog
PATCH 6/6 cmd: Add "boot_android" command.
Hi Alex,
Quoted 4 lines
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
Quoted 223 lines
Test: Booted a rpi3 build with Android Things.
Signed-off-by Alex Deymo <[email protected]>--- README | 6 +++ cmd/Kconfig | 10 +++++ cmd/Makefile | 1 + cmd/boot_android.c | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644
cmd/boot_android.cREADME +2
-0@@ -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" whichexecutes the
README +1
-0+ Android Bootloader flow. Enabling
CONFIG_CMD_FASTBOOTisREADME +1
-0+ recommended to support the Android Fastboot protocolas part
README +2
-0+ of the bootloader. + CONFIG_ANDROID_BOOTLOADER This enables support for the Android bootloaderflow. Android devices can boot in normal mode, recovery mode or bootloader diff --git a/cmd/Kconfig b/cmd/Kconfig index
87a445d269..c4c22464b1100644cmd/Kconfig +0
-0@@ -431,6 +431,16 @@ config CMD_LOAD_ANDROID define the size and kernel address on the header, whichare used by this command.
cmd/Kconfig +6
-0+config CMD_BOOT_ANDROID + bool "boot_android" + default n + depends on ANDROID_BOOTLOADER + help + Performs the Android Bootloader boot flow, loading theappropriate
cmd/Kconfig +1
-0+ Android image (normal kernel, recovery kernel or"bootloader" mode)
cmd/Kconfig +1
-0+ and booting it. The boot mode is determined by thecontents of the
cmd/Kconfig +2
-0+ Android Bootloader Message. + config CMD_FLASH bool "flinfo, erase, protect" default ycmd/Makefile +1
-0@@ -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.ocmd/boot_android.c new file +12
-0@@ -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, setsdev_descandpart_infoaccordingly with the
+ * information of the partition with the givenpartition_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
+ */cmd/boot_android.c new file +26
-0+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) {
cmd/boot_android.c new file +1
-0+ printf("Could not find \"%s\" partition\n",
part_str);cmd/boot_android.c new file +23
-0+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);cmd/boot_android.c new file +1
-0+ if (addr_arg_endp == argv[4] || *addr_arg_endp !='\0')
cmd/boot_android.c new file +5
-0+return CMD_RET_USAGE ; + }else { + addr_str =getenv ("loadaddr" ); +if (addr_str) + load_address = simple_strtoul(addr_str,NULL, 16);
cmd/boot_android.c new file +9
-0+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,cmd/boot_android.c new file +1
-0+ &dev_desc, &part_info) <0) {
cmd/boot_android.c new file +1
-0+/* Couldn't lookup by name from mmc, try looking up the
cmd/boot_android.c new file +3
-0+* partition description directly. +*/ + if (blk_get_device_part_str(misc_part_iface,
misc_part_desc,cmd/boot_android.c new file +1
-0+ &dev_desc, &part_info,1) < 0) {
cmd/boot_android.c new file +7
-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],
cmd/boot_android.c new file +12
-0+ 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"
cmd/boot_android.c new file +1
-0+ " - Load the Boot Control Block (BCB) from the partition'part' on\n"
cmd/boot_android.c new file +1
-0+ " device type 'interface' instance 'dev' to determinethe boot\n"
cmd/boot_android.c new file +2
-0+" mode, and load and execute the appropriate kernel.\n" + " In normal and recovery mode, the kernel will beloaded from\n"
cmd/boot_android.c new file +1
-0+ " the corresponding \"boot\" partition. In bootloadermode, the\n"
cmd/boot_android.c new file +1
-0+ " command defined in the \"fastbootcmd\" variable willbe\n"
cmd/boot_android.c new file +2
-0+" executed.\n" + " On Android devices with multiple slots, the pass'slot' is\n"
cmd/boot_android.c new file +1
-0+ " used to load the appropriate kernel. The standardslot names\n"
cmd/boot_android.c new file +2
-0+" are 'a' and 'b'.\n" + " - If 'part_name' is passed, preceded with a ; insteadof :, the\n"
cmd/boot_android.c new file +1
-0+ " partition name whose label is 'part_name' will belooked up in\n"
cmd/boot_android.c new file +1
-0+ " the partition table. This is commonly the \"misc\"
Quoted 1 line
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
PATCH 5/6 Initial support for the Android Bootloader flow
In reply to Alex DeymoHi Alex,
Quoted 20 lines · Alex Deymo
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 asandroid_bootloader_message.hwith 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_BOOTin 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.
Quoted 4 lines
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.
Quoted 13 lines
Signed-off-by Alex Deymo <[email protected]>--- 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
README The following options need to be configured: · line 1487
Quoted 10 lines
README +2
-0@@ -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).
README The following options need to be configured: · line 1499
Quoted 12 lines
README +12
-0+ 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.
Quoted 65 lines
README +1
-4+ - 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 forcommon/Kconfig +19
-0@@ -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_Rcommon/Makefile +1
-0@@ -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.ocommon/android_bootloader.c new file +2
-0@@ -0,0 +1,350 @@ +/* +* Copyright (C) 2016 The Android Open Source Project
common/android_bootloader.c line 12
Quoted 10 lines
common/android_bootloader.c new file +10
-0+* +* 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"
common/android_bootloader.c line 21
Quoted 9 lines
common/android_bootloader.c new file +9
-0+ +#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
common/android_bootloader.c line 23
Quoted 2 lines
common/android_bootloader.c new file +2
-0+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?
common/android_bootloader.c line 29
Quoted 6 lines
common/android_bootloader.c new file +6
-0+{ +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.
common/android_bootloader.c line 37
Quoted 8 lines
common/android_bootloader.c new file +8
-0+ } + +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
Quoted 25 lines
common/android_bootloader.c new file +25
-0+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(
common/android_bootloader.c line 72
Quoted 10 lines
common/android_bootloader.c new file +10
-0+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
* ...
*/
Quoted 39 lines
common/android_bootloader.c new file +39
-0+ 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) {
common/android_bootloader.c line 121
Quoted 10 lines
common/android_bootloader.c new file +10
-0+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 */
Quoted 54 lines
common/android_bootloader.c new file +54
-0+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)
common/android_bootloader.c
Quoted 10 lines
common/android_bootloader.c new file +10
-0+{ +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.
Quoted 8 lines
common/android_bootloader.c new file +8
-0+if (ret) + ret[0 ] ='\0' ; +return ret; + } + + ret =malloc (joined_len); + current = ret; +if (!ret)
common/android_bootloader.c line 203
Quoted 10 lines
common/android_bootloader.c new file +10
-0+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
common/android_bootloader.c line 208
Quoted 5 lines
common/android_bootloader.c new file +5
-0+ current[-1 ] ='\0' ; +return ret; +} + +/** android_assemble_cmdline - Assemble the command line to pass to the kernel
Please add args
Quoted 148 lines
common/android_bootloader.c new file +142
-0+* @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 ; +}include/android_bootloader.h new file +0
-0
include/android_bootloader.h line 10
Quoted 10 lines
include/android_bootloader.h new file +10
-0@@ -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.
Quoted 23 lines
include/android_bootloader.h new file +23
-0+ +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
include/android_bootloader.h line 43
Quoted 10 lines
include/android_bootloader.h new file +10
-0+* 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.
Quoted 86 lines
include/android_bootloader.h new file +5
-0+const disk_partition_t *misc_part_info, + const char *slot, + unsigned long kernel_address); + +#endif /* __ANDROID_BOOTLOADER_H */ include/android_bootloader_message.h new file +75
-0@@ -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];
include/android_bootloader_message.h line 85
Quoted 10 lines
include/android_bootloader_message.h new file +10
-0+}; + +/** +* 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
Quoted 28 lines
include/android_bootloader_message.h new file +28
-0+ +/** +* 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).
include/android_bootloader_message.h line 123
Quoted 10 lines
include/android_bootloader_message.h new file +10
-0+*/ +#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.
Quoted 52 lines
include/android_bootloader_message.h new file +51
-1+/* 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 */ --
Quoted 2 lines
2.12.2.564.g063fe858b8-goog
Regards,
Simon
PATCH 4/6 disk: Return the partition number in part_get_info_by_name()
In reply to Alex DeymoQuoted 11 lines · Alex Deymo
Similar to what
blk_get_device_part_str()does, this patch makespart_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 <[email protected]>--- common/fb_mmc.c | 6 +++--- disk/part.c | 2 +- include/part.h | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-)
PATCH 4/6 disk: Return the partition number in part_get_info_by_name()
In reply to Alex DeymoQuoted 7 lines · Alex Deymo
Similar to what
blk_get_device_part_str()does, this patch makespart_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 <[email protected]>Reviewed-by Simon Glass <[email protected]>
Applied to u-boot/master, thanks!
Signature · 8 lines
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>
PATCH 3/6 cmd: Add 'load_android' command to load Android images.
In reply to Alex DeymoHi Alex,
Quoted 10 lines · Alex Deymo
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
PATCH 2/6 image: Implement a function to load Android Images.
In reply to Alex DeymoHi Alex,
Quoted 23 lines · Alex Deymo
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 <[email protected]>--- common/image-android.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/image.h | 19 +++++++++++++++++++ 2 files changed, 70 insertions(+)common/image-android.c +1
-0@@ -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
common/image-android.c int android_image_get_ramdisk(const struct andr_img_hdr *hdr, · line 150
Quoted 4 lines
common/image-android.c +1
-0@@ -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?
common/image-android.c int android_image_get_ramdisk(const struct andr_img_hdr *hdr, · line 160
Quoted 10 lines
common/image-android.c +10
-0+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 ...
* ...
*/
common/image-android.c int android_image_get_ramdisk(const struct andr_img_hdr *hdr, · line 163
Quoted 3 lines
common/image-android.c +3
-0+* 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.
common/image-android.c int android_image_get_ramdisk(const struct andr_img_hdr *hdr, · line 167
Quoted 4 lines
common/image-android.c +4
-0+ +/* 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.
common/image-android.c int android_image_get_ramdisk(const struct andr_img_hdr *hdr, · line 171
Quoted 4 lines
common/image-android.c +4
-0+ +if (!blk_read &&android_image_check_header (buf) !=0 ) { +printf ("** Invalid Android Image header **\n" ); + blk_read =-1 ;
-EINVAL perhaps?
Quoted 36 lines
common/image-android.c +28
-0+ } +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 include/image.h +0
-0
include/image.h ulong android_image_get_end(const struct andr_img_hdr *hdr); · line 1250
Quoted 10 lines
include/image.h +7
-0@@ -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.
include/image.h ulong android_image_get_end(const struct andr_img_hdr *hdr); · line 1256
Quoted 6 lines
include/image.h +6
-0+* +* @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?
Quoted 10 lines
include/image.h +6
-1+*/ +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 */ /** --
Quoted 2 lines
2.12.2.564.g063fe858b8-goog
Regards,
Simon
PATCH 1/6 image: Update include/android_image.h
In reply to Alex DeymoQuoted 9 lines · Alex Deymo
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 <[email protected]>--- common/image-android.c | 9 +++++++++ include/android_image.h | 24 +++++++++++++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-)
PATCH 1/6 image: Update include/android_image.h
In reply to Alex DeymoQuoted 6 lines · Alex Deymo
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 <[email protected]>Reviewed-by Simon Glass <[email protected]>
Applied to u-boot/master, thanks!
Signature · 8 lines
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>
cover Android A/B Bootloader support
In reply to Alex DeymoHi 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
Quoted 59 lines · Alex Deymo
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: Updateinclude/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 inpart_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 100644cmd/load_android.c
create mode 100644common/android_bootloader.ccreate mode 100644include/android_bootloader.hcreate mode 100644include/android_bootloader_message.h