Partitions de démarrage du fournisseur

Android 11 a introduit le concept de noyau générique Image (GKI). Pour pouvoir démarrer un appareil arbitraire avec GKI, Android 11 appareils peuvent utiliser la version 3 de l'en-tête de l'image de démarrage. Dans version 3, toutes les informations spécifiques au fournisseur sont exclues de la boot et les a replacés dans une nouvelle partition vendor_boot. Un appareil ARM64 avec Android 11 sur un noyau Linux 5.4 doit prennent en charge la partition vendor_boot et le format de partition boot mis à jour pour réussir les tests avec GKI.

Les appareils Android 12 peuvent utiliser la version 4 de l'en-tête de l'image de démarrage, qui permet d'inclure les ramdisks de plusieurs fournisseurs dans vendor_boot partition. Plusieurs fragments ramdisk sont concaténés les uns après les autres dans la section « ramdisk du fournisseur ». Une table ramdisk du fournisseur est utilisée pour décrire disposition de la section ramdisk du fournisseur et des métadonnées de chaque fournisseur Fragment.

Structure de la partition

La partition de démarrage du fournisseur effectue des tests A/B avec A/B virtuelle et est protégée par Android. Démarrage validé.

Version 3

La partition se compose d'un en-tête, du ramdisk du fournisseur et du blob de l'arborescence des appareils. (DTB).

Section Nombre de pages
En-tête de démarrage fournisseur (n pages) n = (2112 + page_size - 1) / page_size
Ramdisk du fournisseur (o pages) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (p pages) p = (dtb_size + page_size - 1) / page_size

Version 4

La partition comprend un en-tête, la section ramdisk du fournisseur (composée de tous les fragments ramdisk du fournisseur, concaténés), le blob de l'arborescence d'appareils (DTB) et le la table ramdisk du fournisseur.

Section Nombre de pages
En-tête de démarrage fournisseur (n pages) n = (2128 + page_size - 1) / page_size
Fragments ramdisk du fournisseur (pages o) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (p pages) p = (dtb_size + page_size - 1) / page_size
Table ramdisk du fournisseur (q pages) q = (vendor_ramdisk_table_size + page_size - 1) / page_size
Bootconfig (pages r) r = (bootconfig_size + page_size - 1) / page_size

En-tête de démarrage fournisseur

L'en-tête de la partition de démarrage du fournisseur est principalement constitué de données transféré depuis le en-tête de l'image de démarrage. Il contient également des informations sur le fournisseur ramdisk.

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 est la taille totale de tous les fragments ramdisk du fournisseur.
  • ramdisk_type indique le type de ramdisk. Les valeurs possibles sont les suivantes:
    • VENDOR_RAMDISK_TYPE_NONE indique que la valeur n'est pas spécifiée.
    • Les disques RAM VENDOR_RAMDISK_TYPE_PLATFORM contiennent des bits spécifiques à la plate-forme. Le bootloader doit toujours les charger en mémoire.
    • Les disques RAM VENDOR_RAMDISK_TYPE_RECOVERY contiennent des ressources de récupération. La le bootloader doit les charger en mémoire lors du démarrage de la récupération.
    • VENDOR_RAMDISK_TYPE_DLKM disque RAM contient un noyau chargeable dynamique modules.
  • ramdisk_name est un nom unique de ramdisk.
  • board_id est un vecteur d'identifiants matériels définis par le fournisseur.

Compatibilité avec le bootloader

Comme la partition de démarrage du fournisseur contient des informations (telles que la taille de la page Flash, le noyau, les adresses de chargement ramdisk, le DTB lui-même) qui existait auparavant dans le de démarrage, le bootloader doit accéder à la fois au démarrage et au démarrage du fournisseur d'avoir suffisamment de données pour terminer le démarrage.

Le bootloader doit charger le ramdisk générique dans la mémoire immédiatement après le fournisseur ramdisk (les formats CPIO, Gzip et lz4 acceptent ce type de concaténation). N'alignez pas la page sur l'image ramdisk générique et n'introduisez pas autre espace entre lui et la fin du ramdisk du fournisseur en mémoire. Après le le noyau décompresse, il extrait le fichier concaténé dans un initramfs, ce qui se traduit par une structure de fichiers qui est un ramdisk générique superposé la structure des fichiers ramdisk du fournisseur.

Comme le ramdisk générique et le ramdisk du fournisseur sont concaténés, ils doivent se trouver dans au même format. L'image de démarrage GKI utilise un ramdisk générique compressé au format lz4, un appareil compatible avec GKI doit utiliser un ramdisk du fournisseur compressé lz4. La est présentée ci-dessous.

Les exigences du bootloader pour la prise en charge de bootconfig sont expliquées dans Implémentation Bootconfig :

Disques RAM de plusieurs fournisseurs (version 4)

Avec la version 4 de l'en-tête de l'image de démarrage, le bootloader peut sélectionner un sous-ensemble ou tous les ramdisks du fournisseur à charger en tant que initramfs lors du démarrage. La La table ramdisk du fournisseur contient les métadonnées de chaque disque ramdisk et peut aider à bootloader pour décider des ramdisks à charger. Le bootloader peut décider l'ordre de chargement des ramdisks du fournisseur sélectionné, à condition que le ramdisk générique soit chargé en dernier.

Par exemple, le bootloader peut omettre le chargement des disques RAM du fournisseur de type VENDOR_RAMDISK_TYPE_RECOVERY au démarrage normal pour préserver les ressources. Ainsi, les ramdisks de fournisseur de type VENDOR_RAMDISK_TYPE_PLATFORM et Les VENDOR_RAMDISK_TYPE_DLKM sont chargés dans la mémoire. D'un autre côté, le fournisseur Disques RAM de type VENDOR_RAMDISK_TYPE_PLATFORM, VENDOR_RAMDISK_TYPE_RECOVERY et VENDOR_RAMDISK_TYPE_DLKM sont chargés en mémoire lors du démarrage .

Le bootloader peut également ignorer la table ramdisk du fournisseur et charger toute la section ramdisk du fournisseur. Cela a le même effet que de charger les fragments ramdisk du fournisseur dans la partition vendor_boot.

Assistance pour la compilation

Pour implémenter la prise en charge du démarrage par le fournisseur sur un appareil:

  • Définissez BOARD_BOOT_HEADER_VERSION sur 3 ou une valeur supérieure.

  • Définissez BOARD_RAMDISK_USE_LZ4 sur true si votre appareil est compatible GKI, ou si il utilise sinon un ramdisk générique compressé lz4.

  • Définissez BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE sur une taille adaptée à votre appareil, en tenant compte des modules du noyau qui doivent être placés sur le fournisseur ramdisk.

  • Mettez à jour AB_OTA_PARTITIONS pour inclure vendor_boot et tout autre fournisseur spécifique. des listes de partitions OTA sur l'appareil.

  • Copiez votre appareil fstab dans /first_stage_ramdisk dans le vendor_boot et non boot. Exemple : $(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM).

Pour inclure plusieurs disques RAM de fournisseur dans vendor_boot:

  • Définissez BOARD_BOOT_HEADER_VERSION sur 4.
  • Définir BOARD_VENDOR_RAMDISK_FRAGMENTS sur une liste de fournisseurs logiques ramdisk noms de fragments à inclure dans vendor_boot.

  • Pour ajouter un ramdisk prédéfini de fournisseur, définissez BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT à la valeur prédéfinie chemin d'accès.

  • Pour ajouter un ramdisk du fournisseur DLKM, définissez BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).KERNEL_MODULE_DIRS jusqu'à liste des répertoires du module du noyau à inclure.

  • Définir BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).MKBOOTIMG_ARGS sur mkbootimg arguments. Il s'agit des --board_id[0-15] et des --ramdisk_type pour le fragment ramdisk du fournisseur. Pour le fournisseur DLKM ramdisk, S'il n'est pas spécifié, la valeur par défaut --ramdisk_type est DLKM.

Pour créer des ressources de récupération en tant que ramdisk recovery autonome dans vendor_boot:

  • Définissez BOARD_BOOT_HEADER_VERSION sur 4.
  • Définissez BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT sur true.
  • Définissez BOARD_INCLUDE_RECOVERY_RAMDISK_IN_VENDOR_BOOT sur true.
  • Cette opération ajoute un fragment ramdisk du fournisseur dont le champ ramdisk_name est recovery, et ramdisk_type est VENDOR_RAMDISK_TYPE_RECOVERY. Le ramdisk contient alors tous les fichiers de récupération, qui sont des fichiers installés sous $(TARGET_RECOVERY_ROOT_OUT)

Arguments mkbootimg

Argument Description
--ramdisk_type Le type de ramdisk peut être NONE, PLATFORM, RECOVERY ou DLKM.
--board_id[0-15] Spécifiez le vecteur board_id. La valeur par défaut est 0.

Voici un exemple de configuration:

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

Le vendor_boot résultant contiendrait deux fragments ramdisk du fournisseur. La le premier est le paramètre "par défaut" ramdisk, qui contient le répertoire DLKM baz ; le reste des fichiers dans $(TARGET_VENDOR_RAMDISK_OUT). Le deuxième est le dlkm_foobar : ramdisk, qui contient les répertoires DLKM foo et bar ; la valeur par défaut de --ramdisk_type est DLKM.