Boot-Partitionen des Herstellers

Mit Android 11 wurde das Konzept des Generic Kernel Image (GKI) eingeführt. Um das einfache Booten eines beliebigen Geräts mit dem GKI zu ermöglichen, können Android 11-Geräte den Boot-Image-Header Version 3 verwenden. In Version 3 werden alle herstellerspezifischen Informationen aus der boot Partition herausgenommen und in eine neue vendor_boot Partition verschoben. Ein ARM64-Gerät, das mit Android 11 auf dem Linux-Kernel 5.4 gestartet wird, muss die vendor_boot Partition und das aktualisierte boot Partitionsformat unterstützen, um den Test mit dem GKI zu bestehen.

Android 12-Geräte können den Boot-Image-Header Version 4 verwenden, der die Aufnahme mehrerer Hersteller-Ramdisks in die vendor_boot Partition unterstützt. Mehrere Hersteller-Ramdisk-Fragmente werden im Abschnitt „Vendor Ramdisk“ nacheinander verkettet. Eine Vendor-Ramdisk-Tabelle wird verwendet, um das Layout des Vendor-Ramdisk-Abschnitts und die Metadaten jedes Vendor-Ramdisk-Fragments zu beschreiben.

Partitionsstruktur

Die Boot-Partition des Anbieters ist A/B-fähig mit virtuellem A/B und durch Android Verified Boot geschützt.

Version 3

Die Partition besteht aus einem Header, der Vendor-Ramdisk und dem Device Tree Blob (DTB).

Abschnitt Seitenzahl
Boot-Header des Anbieters (n Seiten) n = (2112 + page_size - 1) / page_size
Hersteller-Ramdisk (o Seiten) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (p Seiten) p = (dtb_size + page_size - 1) / page_size

Version 4

Die Partition besteht aus einem Header, dem Vendor-Ramdisk-Abschnitt (bestehend aus allen Vendor-Ramdisk-Fragmenten, verkettet), dem Device Tree Blob (DTB) und der Vendor-Ramdisk-Tabelle.

Abschnitt Seitenzahl
Boot-Header des Anbieters (n Seiten) n = (2128 + page_size - 1) / page_size
Ramdisk-Fragmente des Anbieters (o Seiten) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (p Seiten) p = (dtb_size + page_size - 1) / page_size
Anbieter-Ramdisk-Tabelle (q Seiten) q = (vendor_ramdisk_table_size + page_size - 1) / page_size
Bootconfig (r Seiten) r = (bootconfig_size + page_size - 1) / page_size

Boot-Header des Anbieters

Der Inhalt des Hersteller-Boot-Partitionsheaders besteht hauptsächlich aus Daten, die aus dem Boot-Image-Header dorthin verschoben wurden. Es enthält auch Informationen über die Ramdisk des Herstellers.

Version 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 */

};

Version 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 ist die Gesamtgröße aller Ramdisk-Fragmente des Anbieters.
  • ramdisk_type bezeichnet den Typ der Ramdisk, mögliche Werte sind:
    • VENDOR_RAMDISK_TYPE_NONE gibt an, dass der Wert nicht angegeben ist.
    • VENDOR_RAMDISK_TYPE_PLATFORM Ramdisks enthalten plattformspezifische Bits. Der Bootloader muss diese immer in den Speicher laden.
    • VENDOR_RAMDISK_TYPE_RECOVERY Ramdisks enthalten Wiederherstellungsressourcen. Der Bootloader muss diese beim Booten in die Wiederherstellung in den Speicher laden.
    • VENDOR_RAMDISK_TYPE_DLKM Ramdisks enthalten dynamisch ladbare Kernelmodule.
  • ramdisk_name ist ein eindeutiger Name der Ramdisk.
  • board_id ist ein Vektor von vom Hersteller definierten Hardware-IDs.

Bootloader-Unterstützung

Da die Boot-Partition des Anbieters Informationen (z. B. Flash-Seitengröße, Kernel, Ramdisk-Ladeadressen, DTB selbst) enthält, die zuvor in der Boot-Partition vorhanden waren, muss der Bootloader sowohl auf die Boot-Partition als auch auf die Boot-Partition des Anbieters zugreifen, um über genügend Daten zum Abschließen des Bootvorgangs zu verfügen .

Der Bootloader muss die generische Ramdisk unmittelbar nach der Hersteller-Ramdisk in den Speicher laden (die Formate CPIO, Gzip und LZ4 unterstützen diese Art der Verkettung). Führen Sie keine Seitenausrichtung des generischen Ramdisk-Images durch und fügen Sie keinen anderen Leerraum zwischen ihm und dem Ende der Hersteller-Ramdisk im Speicher ein. Nachdem der Kernel dekomprimiert wurde, extrahiert er die verkettete Datei in ein initramfs , was zu einer Dateistruktur führt, die eine generische Ramdisk ist, die der Ramdisk-Dateistruktur des Anbieters überlagert ist.

Da die generische Ramdisk und die Hersteller-Ramdisk verkettet werden, müssen sie dasselbe Format haben. Das GKI-Boot-Image verwendet eine lz4-komprimierte generische Ramdisk. Daher muss ein GKI-kompatibles Gerät eine lz4-komprimierte Ramdisk eines Herstellers verwenden. Die Konfiguration hierfür ist unten dargestellt.

Die Bootloader-Anforderungen zur Unterstützung von Bootconfig werden auf der Seite „Implementieren von Bootconfig“ erläutert.

Mehrere Hersteller-Ramdisks (Version 4)

Mit der Boot-Image-Header-Version 4 kann der Bootloader entweder eine Teilmenge oder alle Ramdisks des Herstellers auswählen, die während des Bootens als initramfs geladen werden sollen. Die Hersteller-Ramdisk-Tabelle enthält die Metadaten jeder Ramdisk und kann dem Bootloader bei der Entscheidung helfen, welche Ramdisk geladen werden soll. Der Bootloader kann die Reihenfolge zum Laden der ausgewählten Hersteller-Ramdisk festlegen, solange die generische Ramdisk zuletzt geladen wird.

Beispielsweise kann der Bootloader das Laden von Hersteller-Ramdisks vom Typ VENDOR_RAMDISK_TYPE_RECOVERY während des normalen Startvorgangs auslassen, um Ressourcen zu sparen, sodass nur Hersteller-Ramdisks vom Typ VENDOR_RAMDISK_TYPE_PLATFORM und VENDOR_RAMDISK_TYPE_DLKM in den Speicher geladen werden. Andererseits werden Hersteller-Ramdisks vom Typ VENDOR_RAMDISK_TYPE_PLATFORM , VENDOR_RAMDISK_TYPE_RECOVERY und VENDOR_RAMDISK_TYPE_DLKM beim Booten im Wiederherstellungsmodus in den Speicher geladen.

Alternativ kann der Bootloader die Vendor-Ramdisk-Tabelle ignorieren und den gesamten Vendor-Ramdisk-Abschnitt laden. Dies hat den gleichen Effekt wie das Laden aller Vendor-Ramdisk-Fragmente in der vendor_boot Partition.

Unterstützung aufbauen

So implementieren Sie Hersteller-Boot-Unterstützung für ein Gerät:

  • Setzen Sie BOARD_BOOT_HEADER_VERSION auf 3 oder höher.

  • Setzen Sie BOARD_RAMDISK_USE_LZ4 auf true , wenn Ihr Gerät GKI-kompatibel ist oder ansonsten eine lz4-komprimierte generische Ramdisk verwendet.

  • Stellen Sie BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE auf eine geeignete Größe für Ihr Gerät ein und berücksichtigen Sie dabei die Kernelmodule, die auf der Ramdisk des Anbieters gespeichert werden müssen.

  • Aktualisieren Sie AB_OTA_PARTITIONS so, dass es vendor_boot und alle herstellerspezifischen Listen von OTA-Partitionen auf dem Gerät enthält.

  • Kopieren Sie fstab Ihres Geräts nach /first_stage_ramdisk in der vendor_boot Partition, nicht in die boot Partition. Zum Beispiel $(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM) .

So schließen Sie mehrere Hersteller-Ramdisks in vendor_boot ein:

  • Setzen Sie BOARD_BOOT_HEADER_VERSION auf 4 .
  • Legen Sie BOARD_VENDOR_RAMDISK_FRAGMENTS auf eine Liste logischer Hersteller-Ramdisk-Fragmentnamen fest, die in vendor_boot enthalten sein sollen.

  • Um eine vorgefertigte Hersteller-Ramdisk hinzuzufügen, legen Sie BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT auf den vorgefertigten Dateipfad fest.

  • Um eine DLKM-Anbieter-Ramdisk hinzuzufügen, legen Sie BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).KERNEL_MODULE_DIRS auf die Liste der einzuschließenden Kernelmodulverzeichnisse fest.

  • Legen Sie BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).MKBOOTIMG_ARGS auf mkbootimg Argumente fest. Dies sind die Argumente --board_id[0-15] und --ramdisk_type für das Ramdisk-Fragment des Anbieters. Für DLKM-Anbieter-Ramdisk wäre der Standardwert --ramdisk_type DLKM wenn nicht anders angegeben.

So erstellen Sie Wiederherstellungsressourcen als eigenständige recovery Ramdisk in vendor_boot :

  • Setzen Sie BOARD_BOOT_HEADER_VERSION auf 4 .
  • Setzen Sie BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT auf true .
  • Setzen Sie BOARD_INCLUDE_RECOVERY_RAMDISK_IN_VENDOR_BOOT auf true .
  • Dadurch wird ein Hersteller-Ramdisk-Fragment hinzugefügt, dessen ramdisk_name recovery und ramdisk_type VENDOR_RAMDISK_TYPE_RECOVERY ist. Die Ramdisk enthält dann alle Wiederherstellungsdateien, bei denen es sich um Dateien handelt, die unter $(TARGET_RECOVERY_ROOT_OUT) installiert sind.

mkbootimg Argumente

Streit Beschreibung
--ramdisk_type Der Typ der Ramdisk kann NONE , PLATFORM , RECOVERY oder DLKM sein.
--board_id[0-15] Geben Sie den Vektor board_id an, der Standardwert ist 0 .

Nachfolgend finden Sie eine Beispielkonfiguration:

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

Der resultierende vendor_boot würde zwei Vendor-Ramdisk-Fragmente enthalten. Die erste ist die „Standard“-Ramdisk, die das DLKM-Verzeichnis baz und die restlichen Dateien in $(TARGET_VENDOR_RAMDISK_OUT) enthält. Die zweite ist die dlkm_foobar Ramdisk, die die DLKM-Verzeichnisse foo und bar enthält, und --ramdisk_type ist standardmäßig DLKM .