Android 11 introdujo el concepto de imagen genérica del kernel (GKI). Para habilitar el inicio fácil de un dispositivo arbitrario con GKI, los dispositivos con Android 11 pueden usar la versión 3 del encabezado de la imagen de inicio. En la versión 3, toda la información específica del proveedor se elimina de la partición de boot
y se reubica en una nueva partición de vendor_boot
. Un dispositivo ARM64 que se inicie con Android 11 en el kernel de Linux 5.4 debe ser compatible con la partición vendor_boot
y el formato de partición de boot
actualizado para pasar la prueba con GKI.
Los dispositivos con Android 12 pueden usar la versión 4 del encabezado de la imagen de arranque, que admite la inclusión de varios ramdisks de proveedores en la partición vendor_boot
. Varios fragmentos de ramdisk de proveedores se concatenan uno tras otro en la sección ramdisk de proveedores. Se utiliza una tabla ramdisk de proveedor para describir el diseño de la sección ramdisk de proveedor y los metadatos de cada fragmento de ramdisk de proveedor.
Estructura de partición
La partición de arranque del proveedor tiene A/B con A/B virtual y está protegida por Android Verified Boot.
Versión 3
La partición consta de un encabezado, el ramdisk del proveedor y el blob del árbol de dispositivos (DTB).
Sección | Número de páginas |
---|---|
Encabezado de arranque del proveedor (n páginas) | n = (2112 + page_size - 1) / page_size |
Ramdisk del proveedor (o páginas) | o = (vendor_ramdisk_size + page_size - 1) / page_size |
DTB (p páginas) | p = (dtb_size + page_size - 1) / page_size |
Versión 4
La partición consta de un encabezado, la sección ramdisk del proveedor (que consta de todos los fragmentos ramdisk del proveedor, concatenados), el blob del árbol del dispositivo (DTB) y la tabla ramdisk del proveedor.
Sección | Número de páginas |
---|---|
Encabezado de arranque del proveedor (n páginas) | n = (2128 + page_size - 1) / page_size |
Fragmentos de ramdisk del proveedor (o páginas) | o = (vendor_ramdisk_size + page_size - 1) / page_size |
DTB (p páginas) | p = (dtb_size + page_size - 1) / page_size |
Tabla ramdisk de proveedores (q páginas) | q = (vendor_ramdisk_table_size + page_size - 1) / page_size |
Bootconfig (páginas r) | r = (bootconfig_size + page_size - 1) / page_size |
Encabezado de arranque del proveedor
El contenido del encabezado de la partición de inicio del proveedor consta principalmente de datos que se han reubicado allí desde el encabezado de la imagen de inicio . También contiene información sobre el ramdisk del proveedor.
Versión 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 */
};
Versión 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
es el tamaño total de todos los fragmentos de ramdisk del proveedor. -
ramdisk_type
indica el tipo de ramdisk, los valores posibles son:-
VENDOR_RAMDISK_TYPE_NONE
indica que el valor no está especificado. -
VENDOR_RAMDISK_TYPE_PLATFORM
VENDOR_RAMDISK_TYPE_PLATFORM contienen bits específicos de la plataforma. El cargador de arranque siempre debe cargarlos en la memoria. -
VENDOR_RAMDISK_TYPE_RECOVERY
VENDOR_RAMDISK_TYPE_RECOVERY contienen recursos de recuperación. El gestor de arranque debe cargarlos en la memoria al iniciar la recuperación. -
VENDOR_RAMDISK_TYPE_DLKM
VENDOR_RAMDISK_TYPE_DLKM contienen módulos kernel cargables dinámicos.
-
-
ramdisk_name
es un nombre único del ramdisk. -
board_id
es un vector de identificadores de hardware definidos por el proveedor.
Soporte de cargador de arranque
Debido a que la partición de inicio del proveedor contiene información (como el tamaño de la página flash, el núcleo, las direcciones de carga del disco RAM, el propio DTB) que existía anteriormente en la partición de inicio, el cargador de inicio debe acceder tanto a la partición de inicio como a la del proveedor para tener suficientes datos para completar el inicio. .
El gestor de arranque debe cargar el ramdisk genérico en la memoria inmediatamente después del ramdisk del proveedor (los formatos CPIO, Gzip y lz4 admiten este tipo de concatenación). No alinee la página de la imagen ramdisk genérica ni introduzca ningún otro espacio entre ella y el final del ramdisk del proveedor en la memoria. Después de que el kernel se descomprime, extrae el archivo concatenado en un initramfs
, lo que da como resultado una estructura de archivo que es un ramdisk genérico superpuesto a la estructura de archivos ramdisk del proveedor.
Dado que el ramdisk genérico y el ramdisk del proveedor se concatenan, deben tener el mismo formato. La imagen de arranque de GKI usa un ramdisk genérico comprimido con lz4, por lo que un dispositivo compatible con GKI debe usar un ramdisk de proveedor comprimido con lz4. La configuración para esto se muestra a continuación.
Los requisitos del gestor de arranque para admitir bootconfig se explican en la página Implementación de Bootconfig .
Ramdisks de varios proveedores (versión 4)
Con la versión 4 del encabezado de la imagen de arranque, el gestor de arranque puede seleccionar un subconjunto o todos los ramdisks del proveedor para cargarlos como initramfs
durante el arranque. La tabla ramdisk del proveedor contiene los metadatos de cada ramdisk y puede ayudar al gestor de arranque a decidir qué ramdisks cargar. El gestor de arranque puede decidir el orden de carga de los ramdisks del proveedor seleccionado, siempre que el ramdisk genérico se cargue en último lugar.
Por ejemplo, el cargador de arranque puede omitir la carga de ramdisks de proveedores de tipo VENDOR_RAMDISK_TYPE_RECOVERY
durante el arranque normal para conservar recursos, por lo que solo se cargan en la memoria ramdisks de proveedores de tipo VENDOR_RAMDISK_TYPE_PLATFORM
y VENDOR_RAMDISK_TYPE_DLKM
. Por otro lado, los ramdisks de proveedores de tipo VENDOR_RAMDISK_TYPE_PLATFORM
, VENDOR_RAMDISK_TYPE_RECOVERY
y VENDOR_RAMDISK_TYPE_DLKM
se cargan en la memoria cuando se inicia en modo de recuperación.
Alternativamente, el gestor de arranque puede ignorar la tabla ramdisk del proveedor y cargar toda la sección ramdisk del proveedor. Esto tiene el mismo efecto que cargar todos los fragmentos de ramdisk de proveedor en la partición de vendor_boot
.
Construir soporte
Para implementar el soporte de arranque del proveedor para un dispositivo:
Establezca
BOARD_BOOT_HEADER_VERSION
en3
o más.Establezca
BOARD_RAMDISK_USE_LZ4
entrue
si su dispositivo es compatible con GKI, o si usa un ramdisk genérico comprimido con lz4.Establezca
BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE
en un tamaño adecuado para su dispositivo, teniendo en cuenta los módulos del núcleo que deben ir en el ramdisk del proveedor.Actualice
AB_OTA_PARTITIONS
para incluirvendor_boot
y cualquier lista de particiones OTA específicas del proveedor en el dispositivo.Copie su dispositivo
fstab
en/first_stage_ramdisk
vendor_boot
la partición de arranque_proveedor, no en la partición deboot
. Por ejemplo,$(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM)
.
Para incluir ramdisks de varios proveedores en vendor_boot
:
- Establezca
BOARD_BOOT_HEADER_VERSION
en4
. Establezca
BOARD_VENDOR_RAMDISK_FRAGMENTS
en una lista de nombres de fragmentos de ramdisk de proveedores lógicos que se incluirán envendor_boot
.Para agregar un ramdisk de proveedor prediseñado, establezca
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT
en la ruta del archivo prediseñado.Para agregar un ramdisk de proveedor DLKM, establezca
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).KERNEL_MODULE_DIRS
en la lista de directorios de módulos del núcleo que se incluirán.Establezca
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).MKBOOTIMG_ARGS
en argumentosmkbootimg
. Estos son los--board_id[0-15]
y--ramdisk_type
para el fragmento ramdisk del proveedor. Para el ramdisk del proveedor de DLKM, el--ramdisk_type
predeterminado seríaDLKM
si no se especifica lo contrario.
Para crear recursos de recuperación como un ramdisk de recovery
independiente en vendor_boot
:
- Establezca
BOARD_BOOT_HEADER_VERSION
en4
. - Establezca
BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT
entrue
. - Establezca
BOARD_INCLUDE_RECOVERY_RAMDISK_IN_VENDOR_BOOT
entrue
. - Esto agrega un fragmento ramdisk de proveedor cuyo
ramdisk_name
esrecovery
yramdisk_type
esVENDOR_RAMDISK_TYPE_RECOVERY
. El ramdisk luego contiene todos los archivos de recuperación, que son archivos instalados en$(TARGET_RECOVERY_ROOT_OUT)
.
argumentos mkbootimg
Argumento | Descripción |
---|---|
--ramdisk_type | El tipo de ramdisk puede ser NONE , PLATFORM , RECOVERY o DLKM . |
--board_id[0-15] | Especifique el vector board_id , el valor predeterminado es 0 . |
A continuación se muestra una configuración de ejemplo:
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
El vendor_boot
resultante contendría dos fragmentos ramdisk de proveedor. El primero es el ramdisk "predeterminado", que contiene el directorio baz
de DLKM y el resto de los archivos en $(TARGET_VENDOR_RAMDISK_OUT)
. El segundo es el ramdisk dlkm_foobar
, que contiene los directorios foo
y bar
de DLKM, y el valor predeterminado --ramdisk_type
es DLKM
.