Загрузочные разделы производителя

В Android 11 появилась концепция универсального образа ядра (GKI). Чтобы обеспечить загрузку произвольного устройства с помощью GKI, устройства Android 11 могут использовать заголовок загрузочного образа версии 3. В версии 3 вся информация, специфичная для поставщика, выносится из boot раздела и перемещается в новый vendor_boot . Устройство ARM64, запускаемое с Android 11 на ядре Linux 5.4, должно поддерживать vendor_boot и обновленный формат boot раздела, чтобы пройти тестирование с помощью GKI.

Устройства Android 12 могут использовать заголовок загрузочного образа версии 4, который поддерживает включение нескольких виртуальных дисков поставщиков в vendor_boot . Несколько фрагментов виртуального диска поставщика объединяются один за другим в разделе виртуального диска поставщика. Таблица виртуального диска поставщика используется для описания структуры раздела виртуального диска поставщика и метаданных каждого фрагмента виртуального диска поставщика.

Структура разделов

Загрузочный раздел поставщика имеет класс A/B с виртуальным A/B и защищен Android Verified Boot.

Версия 3

Раздел состоит из заголовка, виртуального диска поставщика и объекта дерева устройств (DTB).

Раздел Количество страниц
Загрузочный заголовок поставщика (n страниц) n = (2112 + page_size - 1) / page_size
RAM-диск поставщика (о страниц) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (стр.) p = (dtb_size + page_size - 1) / page_size

Версия 4

Раздел состоит из заголовка, раздела виртуального диска поставщика (состоящего из всех объединенных фрагментов виртуального диска поставщика), объекта дерева устройств (DTB) и таблицы виртуального диска поставщика.

Раздел Количество страниц
Загрузочный заголовок поставщика (n страниц) n = (2128 + page_size - 1) / page_size
Фрагменты виртуального диска поставщика (o страниц) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (стр.) p = (dtb_size + page_size - 1) / page_size
Таблица виртуального диска поставщика (q страниц) q = (vendor_ramdisk_table_size + page_size - 1) / page_size
Bootconfig (r страниц) r = (bootconfig_size + page_size - 1) / page_size

Загрузочный заголовок поставщика

Содержимое заголовка загрузочного раздела поставщика состоит в основном из данных, которые были перемещены туда из заголовка загрузочного образа . Он также содержит информацию об виртуальном диске поставщика.

Версия 3

struct vendor_boot_img_hdr_v3
{
#define VENDOR_BOOT_MAGIC_SIZE 8
    uint8_t magic[VENDOR_BOOT_MAGIC_SIZE];
    uint32_t header_version;
    uint32_t page_size;           /* flash page size we assume */

    uint32_t kernel_addr;         /* physical load addr */
    uint32_t ramdisk_addr;        /* physical load addr */

    uint32_t vendor_ramdisk_size; /* size in bytes */

#define VENDOR_BOOT_ARGS_SIZE 2048
    uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE];

    uint32_t tags_addr;           /* physical addr for kernel tags */

#define VENDOR_BOOT_NAME_SIZE 16
    uint8_t name[VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */
    uint32_t header_size;         /* size of vendor boot image header in
                                   * bytes */
    uint32_t dtb_size;            /* size of dtb image */
    uint64_t dtb_addr;            /* physical load address */

};

Версия 4

struct vendor_boot_img_hdr_v4
{
#define VENDOR_BOOT_MAGIC_SIZE 8
    uint8_t magic[VENDOR_BOOT_MAGIC_SIZE];
    uint32_t header_version;
    uint32_t page_size;           /* flash page size we assume */

    uint32_t kernel_addr;         /* physical load addr */
    uint32_t ramdisk_addr;        /* physical load addr */

    uint32_t vendor_ramdisk_size; /* size in bytes */

#define VENDOR_BOOT_ARGS_SIZE 2048
    uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE];

    uint32_t tags_addr;           /* physical addr for kernel tags */

#define VENDOR_BOOT_NAME_SIZE 16
    uint8_t name[VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */
    uint32_t header_size;         /* size of vendor boot image header in
                                   * bytes */
    uint32_t dtb_size;            /* size of dtb image */
    uint64_t dtb_addr;            /* physical load address */

    uint32_t vendor_ramdisk_table_size; /* size in bytes for the vendor ramdisk table */
    uint32_t vendor_ramdisk_table_entry_num; /* number of entries in the vendor ramdisk table */
    uint32_t vendor_ramdisk_table_entry_size; /* size in bytes for a vendor ramdisk table entry */
    uint32_t bootconfig_size; /* size in bytes for the bootconfig section */
};

#define VENDOR_RAMDISK_TYPE_NONE 0
#define VENDOR_RAMDISK_TYPE_PLATFORM 1
#define VENDOR_RAMDISK_TYPE_RECOVERY 2
#define VENDOR_RAMDISK_TYPE_DLKM 3

struct vendor_ramdisk_table_entry_v4
{
    uint32_t ramdisk_size; /* size in bytes for the ramdisk image */
    uint32_t ramdisk_offset; /* offset to the ramdisk image in vendor ramdisk section */
    uint32_t ramdisk_type; /* type of the ramdisk */
#define VENDOR_RAMDISK_NAME_SIZE 32
    uint8_t ramdisk_name[VENDOR_RAMDISK_NAME_SIZE]; /* asciiz ramdisk name */

#define VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE 16
    // Hardware identifiers describing the board, soc or platform which this
    // ramdisk is intended to be loaded on.
    uint32_t board_id[VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE];
};
  • vendor_ramdisk_size — общий размер всех фрагментов виртуального диска поставщика.
  • ramdisk_type обозначает тип виртуального диска, возможные значения:
    • VENDOR_RAMDISK_TYPE_NONE указывает, что значение не указано.
    • RAM-диски VENDOR_RAMDISK_TYPE_PLATFORM содержат биты, специфичные для платформы. Загрузчик всегда должен загружать их в память.
    • RAM-диски VENDOR_RAMDISK_TYPE_RECOVERY содержат ресурсы восстановления. Загрузчик должен загрузить их в память при загрузке в рекавери.
    • RAM-диски VENDOR_RAMDISK_TYPE_DLKM содержат динамически загружаемые модули ядра.
  • ramdisk_name — уникальное имя виртуального диска.
  • board_id — это вектор идентификаторов оборудования, определенных поставщиком.

Поддержка загрузчика

Поскольку загрузочный раздел поставщика содержит информацию (например, размер флэш-страницы, ядро, адреса загрузки виртуального диска, сам DTB), которая ранее существовала в загрузочном разделе, загрузчик должен получить доступ как к загрузочному разделу, так и к загрузочному разделу поставщика, чтобы иметь достаточно данных для завершения загрузки. .

Загрузчик должен загрузить общий виртуальный диск в память сразу после виртуального диска поставщика (форматы CPIO, Gzip и lz4 поддерживают этот тип конкатенации). Не выравнивайте по страницам общий образ виртуального диска и не вводите какое-либо другое пространство между ним и концом виртуального диска поставщика в памяти. После распаковки ядра оно извлекает объединенный файл в initramfs , в результате чего получается файловая структура, представляющая собой общий виртуальный диск, наложенный на файловую структуру виртуального диска поставщика.

Поскольку общий виртуальный диск и виртуальный диск поставщика объединяются, они должны быть в одном формате. Загрузочный образ GKI использует общий виртуальный диск, сжатый lz4, поэтому устройство, совместимое с GKI, должно использовать виртуальный диск поставщика, сжатый lz4. Конфигурация для этого показана ниже.

Требования к загрузчику для поддержки bootconfig описаны в разделе «Реализация Bootconfig» .

Несколько виртуальных дисков поставщиков (версия 4)

С заголовком загрузочного образа версии 4 загрузчик может выбрать подмножество или все виртуальные диски поставщика для загрузки в качестве initramfs во время загрузки. Таблица виртуального диска поставщика содержит метаданные каждого виртуального диска и может помочь загрузчику решить, какие виртуальные диски загружать. Загрузчик может определить порядок загрузки виртуальных дисков выбранного поставщика, при условии, что общий виртуальный диск загружается последним.

Например, загрузчик может не загружать виртуальные диски поставщика типа VENDOR_RAMDISK_TYPE_RECOVERY во время обычной загрузки для экономии ресурсов, поэтому в память загружаются только виртуальные диски поставщика типа VENDOR_RAMDISK_TYPE_PLATFORM и VENDOR_RAMDISK_TYPE_DLKM . С другой стороны, виртуальные диски производителя типа VENDOR_RAMDISK_TYPE_PLATFORM , VENDOR_RAMDISK_TYPE_RECOVERY и VENDOR_RAMDISK_TYPE_DLKM загружаются в память при загрузке в режиме восстановления.

Альтернативно, загрузчик может игнорировать таблицу виртуального диска поставщика и загружать весь раздел виртуального диска поставщика. Это имеет тот же эффект, что и загрузка всех фрагментов виртуального диска поставщика в vendor_boot .

Создайте поддержку

Чтобы реализовать поддержку загрузки устройства поставщиком:

  • Установите для BOARD_BOOT_HEADER_VERSION значение 3 или выше.

  • Установите для BOARD_RAMDISK_USE_LZ4 значение true , если ваше устройство совместимо с GKI или если оно иным образом использует общий виртуальный диск, сжатый lz4.

  • Установите для BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE размер, соответствующий вашему устройству, учитывая модули ядра, которые должны находиться на виртуальном диске поставщика.

  • Обновите AB_OTA_PARTITIONS , включив в vendor_boot и любые списки разделов OTA на устройстве, зависящие от поставщика.

  • Скопируйте fstab вашего устройства в /first_stage_ramdisk в vendor_boot , а не в boot раздел. Например, $(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM) .

Чтобы включить несколько виртуальных дисков поставщика vendor_boot :

  • Установите для BOARD_BOOT_HEADER_VERSION значение 4 .
  • Задайте для BOARD_VENDOR_RAMDISK_FRAGMENTS список имен фрагментов логического виртуального диска поставщика, которые будут включены vendor_boot .

  • Чтобы добавить предварительно созданный виртуальный диск поставщика, установите для BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT предварительно созданный путь.

  • Чтобы добавить виртуальный диск поставщика DLKM, установите BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).KERNEL_MODULE_DIRS в список каталогов модулей ядра, которые необходимо включить.

  • Установите для BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).MKBOOTIMG_ARGS аргументы mkbootimg . Это аргументы --board_id[0-15] и --ramdisk_type для фрагмента виртуального диска поставщика. Для виртуального диска поставщика DLKM значением по умолчанию --ramdisk_type будет DLKM , если не указано иное.

Чтобы создать ресурсы восстановления в виде отдельного виртуального диска recovery в vendor_boot :

  • Установите для BOARD_BOOT_HEADER_VERSION значение 4 .
  • Установите для BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT значение true .
  • Установите для BOARD_INCLUDE_RECOVERY_RAMDISK_IN_VENDOR_BOOT значение true .
  • При этом добавляется фрагмент виртуального диска поставщика, ramdisk_name которого — recovery , а ramdisk_typeVENDOR_RAMDISK_TYPE_RECOVERY . Затем виртуальный диск содержит все файлы восстановления, которые являются файлами, установленными в $(TARGET_RECOVERY_ROOT_OUT) .

аргументы mkbootimg

Аргумент Описание
--ramdisk_type Тип виртуального диска может быть одним из NONE , PLATFORM , RECOVERY или DLKM .
--board_id[0-15] Укажите вектор board_id , значение по умолчанию равное 0 .

Ниже приведен пример конфигурации:

BOARD_KERNEL_MODULE_DIRS := foo bar baz
BOARD_BOOT_HEADER_VERSION := 4
BOARD_VENDOR_RAMDISK_FRAGMENTS := dlkm_foobar
BOARD_VENDOR_RAMDISK_FRAGMENT.dlkm_foobar.KERNEL_MODULE_DIRS := foo bar
BOARD_VENDOR_RAMDISK_FRAGMENT.dlkm_foobar.MKBOOTIMG_ARGS := --board_id0 0xF00BA5 --board_id1 0xC0FFEE

Полученный vendor_boot будет содержать два фрагмента виртуального диска поставщика. Первый — это виртуальный диск «по умолчанию», который содержит каталог DLKM baz и остальные файлы в $(TARGET_VENDOR_RAMDISK_OUT) . Второй — это виртуальный диск dlkm_foobar , который содержит каталоги DLKM foo и bar , а --ramdisk_type по умолчанию имеет значение DLKM .