Boot Image Header Versioning

Boot Image Header Versioning

Starting in Android 9, the boot image header contains a field to indicate the header version. The bootloader must check this header version field and parse the header accordingly. Versioning the boot image header allows future modifications to the header while maintaining backward compatibility.

All devices launching with Android 9 must use a boot header version of 1.

Boot image header changes

In the legacy boot image header (shown below), the unused field will be converted to a header version field for devices launching with Android 9.

struct boot_img_hdr
{
    uint8_t magic[BOOT_MAGIC_SIZE];
    uint32_t kernel_size;  /* size in bytes */
    uint32_t kernel_addr;  /* physical load addr */

    uint32_t ramdisk_size; /* size in bytes */
    uint32_t ramdisk_addr; /* physical load addr */

    uint32_t second_size;  /* size in bytes */
    uint32_t second_addr;  /* physical load addr */

    uint32_t tags_addr;    /* physical addr for kernel tags */
    uint32_t page_size;    /* flash page size we assume */
    uint32_t unused;
    uint32_t os_version;
    uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
    uint8_t cmdline[BOOT_ARGS_SIZE];
    uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
    uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
};

Devices launched before Android 9 using the legacy boot image header are considered as using a boot image header version of 0. All devices launching with Android 9 must use the following structure for the boot image header with the header version set to 1:

struct boot_img_hdr
{
    uint8_t magic[BOOT_MAGIC_SIZE];
    uint32_t kernel_size;  /* size in bytes */
    uint32_t kernel_addr;  /* physical load addr */

    uint32_t ramdisk_size; /* size in bytes */
    uint32_t ramdisk_addr; /* physical load addr */

    uint32_t second_size;  /* size in bytes */
    uint32_t second_addr;  /* physical load addr */

    uint32_t tags_addr;    /* physical addr for kernel tags */
    uint32_t page_size;    /* flash page size we assume */
    uint32_t header_version;
    uint32_t os_version;
    uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
    uint8_t cmdline[BOOT_ARGS_SIZE];
    uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
    uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
    uint32_t recovery_dtbo_size;   /* size of recovery dtbo image */
    uint64_t recovery_dtbo_offset; /* offset in boot image */
    uint32_t header_size;   /* size of boot image header in bytes */
};

The header_size field contains the size of the boot image header. If the boot image header version is set to 1, the id field contains the SHA1 digest for the recovery_dtbo section of the boot image in addition to the kernel, ramdisk. and second sections. For details on the recovery_dtbo_size and recovery_dtbo_offset fields, refer to Including DTBO in Recovery for Non-A/B Devices.

Implementation

The mkbootimg tool that creates boot images adds the following arguments to support the new boot image header:

Argument Description
header_version Sets the boot image header version.
recovery_dtbo Path to the recovery DTBO image to be included in the recovery image.

The device BoardConfig.mk uses the config BOARD_MKBOOTIMG_ARGS to add header version to the other board-specific arguments of mkbootimg. For example:

  BOARD_MKBOOTIMG_ARGS := --ramdisk_offset $(BOARD_RAMDISK_OFFSET) --tags_offset $(BOARD_KERNEL_TAGS_OFFSET) --header_version $(BOARD_BOOTIMG_HEADER_VERSION)

The Android build system uses the BoardConfig variable BOARD_PREBUILT_DTBOIMAGE to set the argument recovery_dtbo of mkbootimg tool during the creation of recovery image.

For details on the Android Open Source Project (AOSP) changes, review the associated changelists for boot image header versioning.

Validation

For all devices launching with Android 9, the Vendor Test Suite (VTS) checks the format of the boot/recovery image to ensure the boot image header uses version 1.