[U-Boot] [PATCH 5/6] Initial support for the Android Bootloader flow

Simon Glass sjg at chromium.org
Sun Apr 9 19:27:12 UTC 2017


Hi Alex,

On 2 April 2017 at 02:49, Alex Deymo <deymo at 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 at 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


More information about the U-Boot mailing list