Partycje rozruchowe dostawcy

Android 11 wprowadził koncepcję ogólnego obrazu jądra (GKI). Aby umożliwić uruchamianie dowolnego urządzenia za pomocą GKI, urządzenia z Androidem 11 mogą używać nagłówka obrazu rozruchowego w wersji 3. W wersji 3 wszystkie informacje specyficzne dla dostawcy są wyodrębnione z boot partycji i przeniesione do nowej partycji vendor_boot. Urządzenie ARM64 z Androidem 11 i jądrem Linux 5.4 musi obsługiwać partycję vendor_boot oraz zaktualizowany format partycji boot, aby przejść testy z GKI.

Urządzenia z Androidem 12 mogą używać nagłówka obrazu rozruchowego w wersji 4, który umożliwia umieszczanie wielu dysków RAM dostawcy w partycji vendor_boot. Wiele fragmentów dysku RAM dostawcy jest łączonych jeden po drugim w sekcji dysku RAM dostawcy. Tabela dysku RAM dostawcy służy do opisywania układu sekcji dysku RAM dostawcy i metadanych każdego fragmentu dysku RAM dostawcy.

Struktura partycji

Partycja rozruchowa dostawcy jest podzielona na partycje A/B z wirtualnymi partycjami A/B i chroniona przez weryfikację podczas uruchamiania Androida.

Wersja 3

Partycja składa się z nagłówka, dysku RAM dostawcy i obiektu drzewa urządzenia (DTB).

Sekcja Liczba stron
Nagłówek rozruchowy dostawcy (n stron) n = (2112 + page_size - 1) / page_size
Dysk RAM dostawcy (o stron) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (p stron) p = (dtb_size + page_size - 1) / page_size

Wersja 4

Partycja składa się z nagłówka, sekcji dysku RAM dostawcy (zawierającej wszystkie połączone fragmenty dysku RAM dostawcy), obiektu drzewa urządzenia (DTB) i tabeli dysku RAM dostawcy.

Sekcja Liczba stron
Nagłówek rozruchowy dostawcy (n stron) n = (2128 + page_size - 1) / page_size
Fragmenty dysku RAM dostawcy (o stron) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (p stron) p = (dtb_size + page_size - 1) / page_size
Tabela dysku RAM dostawcy (q stron) q = (vendor_ramdisk_table_size + page_size - 1) / page_size
Bootconfig (r stron) r = (bootconfig_size + page_size - 1) / page_size

Nagłówek rozruchowy dostawcy

Zawartość nagłówka partycji rozruchowej dostawcy składa się głównie z danych , które zostały przeniesione z nagłówka obrazu rozruchowego. Zawiera też informacje o dysku RAM dostawcy.

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

};

Wersja 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 to łączny rozmiar wszystkich fragmentów dysku RAM dostawcy.
  • ramdisk_type oznacza typ dysku RAM. Możliwe wartości:
    • VENDOR_RAMDISK_TYPE_NONE oznacza, że wartość nie jest określona.
    • VENDOR_RAMDISK_TYPE_PLATFORM dyski RAM zawierają bity specyficzne dla platformy. Program rozruchowy musi zawsze ładować je do pamięci.
    • VENDOR_RAMDISK_TYPE_RECOVERY dyski RAM zawierają zasoby odzyskiwania. Program rozruchowy musi ładować je do pamięci podczas uruchamiania w trybie odzyskiwania.
    • VENDOR_RAMDISK_TYPE_DLKM dyski RAM zawierają dynamicznie ładowane moduły jądra.
  • ramdisk_name to unikalna nazwa dysku RAM.
  • board_id to wektor identyfikatorów sprzętu zdefiniowanych przez dostawcę.

Obsługa programu rozruchowego

Ponieważ partycja rozruchowa dostawcy zawiera informacje (takie jak rozmiar strony flash, jądro, adresy ładowania dysku RAM, sam DTB), które wcześniej znajdowały się w partycji rozruchowej, program rozruchowy musi mieć dostęp zarówno do partycji rozruchowej, jak i do partycji rozruchowej dostawcy, aby mieć wystarczającą ilość danych do ukończenia uruchamiania.

Program rozruchowy musi załadować ogólny dysk RAM do pamięci bezpośrednio po dysku RAM dostawcy (formaty CPIO, Gzip i lz4 obsługują ten typ łączenia). Nie wyrównuj obrazu ogólnego dysku RAM do strony ani nie wprowadzaj żadnych innych spacji między nim a końcem dysku RAM dostawcy w pamięci. Po dekompresji jądro wyodrębnia połączony plik do initramfs, co powoduje powstanie struktury plików, która jest ogólnym dyskiem RAM nałożonym na strukturę plików dysku RAM dostawcy.

Ponieważ ogólny dysk RAM i dysk RAM dostawcy są łączone, muszą być w tym samym formacie. Obraz rozruchowy GKI używa ogólnego dysku RAM skompresowanego za pomocą lz4, więc urządzenie zgodne z GKI musi używać dysku RAM dostawcy skompresowanego za pomocą lz4. Konfiguracja jest pokazana poniżej.

Wymagania dotyczące programu rozruchowego w zakresie obsługi bootconfig są opisane w sekcji Implementowanie bootconfig.

Wiele dysków RAM dostawcy (wersja 4)

W przypadku nagłówka obrazu rozruchowego w wersji 4 program rozruchowy może wybrać podzbiór lub wszystkie dyski RAM dostawcy do załadowania jako initramfs podczas uruchamiania. Tabela dysku RAM dostawcy zawiera metadane każdego dysku RAM i może pomóc programowi rozruchowemu w podjęciu decyzji, które dyski RAM należy załadować. Program rozruchowy może zdecydować o kolejności ładowania wybranych dysków RAM dostawcy, o ile ogólny dysk RAM zostanie załadowany jako ostatni.

Na przykład program rozruchowy może pominąć ładowanie dysków RAM dostawcy typu VENDOR_RAMDISK_TYPE_RECOVERY podczas normalnego uruchamiania, aby oszczędzać zasoby. W takim przypadku do pamięci są ładowane tylko dyski RAM dostawcy typu VENDOR_RAMDISK_TYPE_PLATFORM i VENDOR_RAMDISK_TYPE_DLKM. Z drugiej strony, podczas uruchamiania w trybie odzyskiwania do pamięci są ładowane dyski RAM dostawcy typu VENDOR_RAMDISK_TYPE_PLATFORM, VENDOR_RAMDISK_TYPE_RECOVERY i VENDOR_RAMDISK_TYPE_DLKM.

Program rozruchowy może też zignorować tabelę dysku RAM dostawcy i załadować całą sekcję dysku RAM dostawcy. Ma to taki sam efekt jak załadowanie wszystkich fragmentów dysku RAM dostawcy w partycji vendor_boot.

Obsługa kompilacji

Aby zaimplementować obsługę rozruchu dostawcy na urządzeniu:

  • Ustaw BOARD_BOOT_HEADER_VERSION na 3 lub wyższą.

  • Jeśli Twoje urządzenie jest zgodne z GKI lub używa ogólnego dysku RAM skompresowanego za pomocą lz4, ustaw BOARD_RAMDISK_USE_LZ4 na true.

  • Ustaw BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE na odpowiedni rozmiar dla Twojego urządzenia, biorąc pod uwagę moduły jądra, które muszą znajdować się na dysku RAM dostawcy.

  • Zaktualizuj AB_OTA_PARTITIONS, aby uwzględnić vendor_boot i wszelkie listy partycji OTA specyficzne dla dostawcy na urządzeniu.

  • Skopiuj fstab urządzenia do /first_stage_ramdisk w partycji vendor_boot, a nie w partycji boot. Na przykład $(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM).

Aby uwzględnić wiele dysków RAM dostawcy w vendor_boot:

  • Ustaw BOARD_BOOT_HEADER_VERSION na 4.
  • Ustaw BOARD_VENDOR_RAMDISK_FRAGMENTS na listę logicznych nazw fragmentów dysku RAM dostawcy, które mają być uwzględnione w vendor_boot.

  • Aby dodać wstępnie skompilowany dysk RAM dostawcy, ustaw BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT na ścieżkę wstępnie skompilowanego dysku.

  • Aby dodać dysk RAM dostawcy DLKM, ustaw BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).KERNEL_MODULE_DIRS na listę katalogów modułów jądra, które mają być uwzględnione.

  • Ustaw BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).MKBOOTIMG_ARGS na argumenty mkbootimg. Są to argumenty --board_id[0-15] i --ramdisk_type dla fragmentu dysku RAM dostawcy. W przypadku dysku RAM dostawcy DLKM domyślna wartość --ramdisk_type to DLKM, jeśli nie określono inaczej.

Aby skompilować zasoby odzyskiwania jako samodzielny dysk RAM recovery w vendor_boot:

  • Ustaw BOARD_BOOT_HEADER_VERSION na 4.
  • Ustaw BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT na true.
  • Ustaw BOARD_INCLUDE_RECOVERY_RAMDISK_IN_VENDOR_BOOT na true.
  • Spowoduje to dodanie fragmentu dysku RAM dostawcy, którego ramdisk_name to recovery, a ramdisk_type to VENDOR_RAMDISK_TYPE_RECOVERY. Dysk RAM będzie wtedy zawierać wszystkie pliki odzyskiwania, czyli pliki zainstalowane w $(TARGET_RECOVERY_ROOT_OUT).

Argumenty mkbootimg

Argument Opis
--ramdisk_type Typ dysku RAM. Może to być jedna z tych wartości: NONE, PLATFORM, RECOVERY lub DLKM.
--board_id[0-15] Określ wektor board_id. Domyślnie jest to 0.

Oto przykład konfiguracji:

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

Wynikowy vendor_boot będzie zawierać 2 fragmenty dysku RAM dostawcy. Pierwszy to dysk RAM „default”, który zawiera katalog DLKM baz i pozostałe pliki w $(TARGET_VENDOR_RAMDISK_OUT). Drugi to dlkm_foobar dysk RAM, który zawiera katalogi DLKM foo i bar, a --ramdisk_type domyślnie ma wartość DLKM.