В 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_type
—VENDOR_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
.