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

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

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

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

Загрузочный раздел поставщика защищен 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

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

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

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

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

Версия 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 поставщика.
  • ramdisk_type обозначает тип ramdisk, возможные значения:
    • VENDOR_RAMDISK_TYPE_NONE указывает, что значение не указано.
    • VENDOR_RAMDISK_TYPE_PLATFORM ramdisks содержат биты, специфичные для платформы. Загрузчик всегда должен загружать их в память.
    • VENDOR_RAMDISK_TYPE_RECOVERY ramdisks содержат ресурсы восстановления. Загрузчик должен загрузить их в память при загрузке в режим восстановления.
    • Виртуальные диски VENDOR_RAMDISK_TYPE_DLKM содержат динамически загружаемые модули ядра.
  • ramdisk_name — уникальное имя ramdisk.
  • board_id — это вектор идентификаторов оборудования, определенных поставщиком.

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

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

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

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

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

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

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

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

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

Поддержка сборки

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

  • Установите BOARD_BOOT_HEADER_VERSION на значение 3 или больше.

  • Установите BOARD_RAMDISK_USE_LZ4 в true , если ваше устройство совместимо с GKI или если оно использует универсальный RAM-диск, сжатый с помощью LZ4.

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

  • Обновите 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 список имен логических фрагментов RAM-диска поставщика, которые необходимо включить в vendor_boot .

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

  • Чтобы добавить ramdisk поставщика 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 для фрагмента ramdisk поставщика. Для ramdisk поставщика DLKM --ramdisk_type по умолчанию будет DLKM , если не указано иное.

Чтобы создать ресурсы восстановления как автономный RAM-диск 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 поставщика, ramdisk_name которого — recovery , а ramdisk_typeVENDOR_RAMDISK_TYPE_RECOVERY . Затем ramdisk содержит все файлы восстановления, которые являются файлами, установленными в $(TARGET_RECOVERY_ROOT_OUT) .

Аргументы mkbootimg

Аргумент Описание
--ramdisk_type Тип RAM-диска может быть 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 будет содержать два фрагмента ramdisk поставщика. Первый из них — это ramdisk «по умолчанию», который содержит каталог DLKM baz и остальные файлы в $(TARGET_VENDOR_RAMDISK_OUT) . Второй — это ramdisk dlkm_foobar , который содержит каталоги DLKM foo и bar , а --ramdisk_type по умолчанию — DLKM .