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

В 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 . Несколько фрагментов образов оперативной памяти от разных производителей объединяются один за другим в разделе vendor_boot. Для описания структуры раздела vendor_boot и метаданных каждого фрагмента образов оперативной памяти используется таблица vendor_boot.

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

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

Версия 3

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

Раздел Количество страниц
Заголовочный файл загрузки поставщика (n страниц) n = (2112 + page_size - 1) / page_size
Vendor ramdisk (o pages) 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 = (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 pages) 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 указывает на то, что значение не определено.
    • VENDOR_RAMDISK_TYPE_PLATFORM это виртуальные диски в оперативной памяти, содержащие биты, специфичные для конкретной платформы. Загрузчик всегда должен загружать их в память.
    • VENDOR_RAMDISK_TYPE_RECOVERY это виртуальные диски в оперативной памяти, содержащие ресурсы восстановления. Загрузчик должен загрузить их в память при загрузке в режим восстановления.
    • VENDOR_RAMDISK_TYPE_DLKM это виртуальные диски, содержащие динамически загружаемые модули ядра.
  • ramdisk_name — это уникальное имя виртуального диска в оперативной памяти.
  • board_id — это вектор идентификаторов оборудования, определенных производителем.

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

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

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

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

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

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

аргументы mkbootimg

Аргумент Описание
--ramdisk_type Тип образа ramdisk может быть одним из следующих: 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 .