Android 11 wprowadził pojęcie Generic Kernel Image (GKI). Aby umożliwić uruchamianie dowolnego urządzenia za pomocą interfejsu GKI, urządzenia z Androidem 11 mogą używać nagłówka obrazu rozruchu w wersji 3. W wersji 3 wszystkie informacje o dostawcy są wykluczane z partycji boot
i przenoszone do nowej partycji vendor_boot
. Aby urządzenie ARM64 z Androidem 11 na jądrze Linux 5.4 mogło przejść testy GKI, musi obsługiwać partycję vendor_boot
i zaktualizowany format partycji boot
.
Urządzenia z Androidem 12 mogą używać nagłówka pliku obrazu rozruchowego w wersji 4, który obsługuje umieszczanie wielu dysków RAM dostawcy na partycji vendor_boot
. W sekcji dotyczącej ramdiska dostawcy wiele fragmentów ramdiska jest łączonych jeden po drugim. Tabela ramdisk dostawcy służy do opisania układu sekcji ramdisk dostawcy i metadanych każdego fragmentu ramdisk dostawcy.
Struktura partycji
Partycja rozruchu dostawcy jest skonfigurowana w trybie A/B z wirtualnym trybem A/B i chroniona przez funkcję Verified Boot w Androidzie.
Wersja 3
Partycja składa się z nagłówka, partycji RAM dostawcy i pliku danych drzewa urządzenia (DTB).
Sekcja | Liczba stron |
---|---|
Nagłówek uruchamiania dostawcy (n stron) | n = (2112 + page_size - 1) / page_size |
Dostawca ramdisk (o strony) | 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 dostawcy ramdisk (która zawiera wszystkie złączone fragmenty ramdisk dostawcy), pliku danych drzewa urządzenia (DTB) i tabeli ramdisk dostawcy.
Sekcja | Liczba stron |
---|---|
Nagłówek uruchamiania dostawcy (n stron) | n = (2128 + page_size - 1) / page_size |
Fragmenty dostawcy dotyczące dysku RAM (o strony) | o = (vendor_ramdisk_size + page_size - 1) / page_size |
DTB (p stron) | p = (dtb_size + page_size - 1) / page_size |
Tabela dostawcy dysku RAM (strony q) | q = (vendor_ramdisk_table_size + page_size - 1) / page_size |
Bootconfig (strony r) | r = (bootconfig_size + page_size - 1) / page_size |
Nagłówek uruchamiania dostawcy
Zawartość nagłówka partycji rozruchowej dostawcy składa się głównie z danych przeniesionych z nagłówka obrazu rozruchowego. Zawiera on również informacje o pamięci 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 to:VENDOR_RAMDISK_TYPE_NONE
oznacza, że wartość nie została określona.VENDOR_RAMDISK_TYPE_PLATFORM
Ramdiski zawierają bity specyficzne dla platformy. Program rozruchowy musi zawsze wczytywać je do pamięci.VENDOR_RAMDISK_TYPE_RECOVERY
Pamięci RAM zawierają zasoby odzyskiwania. Program rozruchowy musi załadować je do pamięci podczas uruchamiania trybu odzyskiwania.VENDOR_RAMDISK_TYPE_DLKM
Ramdiski zawierają dynamicznie ładowalne moduły jądra.
ramdisk_name
to unikalna nazwa dysku RAM.board_id
to wektor identyfikatorów sprzętowych zdefiniowanych przez dostawcę.
Obsługa programu rozruchowego
Ponieważ partycja rozruchu dostawcy zawiera informacje (takie jak rozmiar strony flash, jądro, adresy ładowania ramdisku, sam DTB), które wcześniej znajdowały się na partycji rozruchu, bootloader musi mieć dostęp do obu partycji rozruchu i partycji rozruchu dostawcy, aby mieć wystarczającą ilość danych do ukończenia rozruchu.
Program rozruchowy musi załadować do pamięci ogólny dysk RAM natychmiast po dysku RAM dostawcy (takie konkatenacje obsługują formaty CPIO, Gzip i lz4). Nie wyrównuj strony do ramki pliku ramdysk ogólny ani nie wprowadzaj żadnych innych odstępów między nim a końcem pliku ramdysk dostawcy w pamięci. Po zakończeniu procesu dekompresji jądra plik jest wyodrębniony z konkatenowanego pliku do initramfs
, co powoduje powstanie struktury plików, która jest ogólnym dyskiem ramowym nałożonym na strukturę pliku dysku ramowego dostawcy.
Ponieważ ogólny dysk RAM i dysk RAM dostawcy są łączone, muszą mieć ten sam format. Obraz rozruchowy GKI korzysta z ramdisku ogólnego skompresowanego za pomocą lz4, więc urządzenie zgodne z GKI musi używać ramdisku dostawcy skompresowanego za pomocą lz4. Konfiguracja tego ustawienia jest pokazana poniżej.
Wymagania dotyczące programu rozruchowego w przypadku obsługi pliku bootconfig są opisane w artykule Implementacja pliku Bootconfig.
Ramdisk wielu dostawców (wersja 4)
W przypadku nagłówka obrazu rozruchowego w wersji 4 bootloader może wybrać podzbiór lub wszystkie ramdysk dostawcy do załadowania jako initramfs
podczas rozruchu. Tabela vendor ramdisk zawiera metadane każdego dysku RAM i może pomóc programowi rozruchowemu w podejmowaniu decyzji, które dyski RAM mają być ładowane. Bootloader może decydować o kolejności wczytywania wybranych ramdysków dostawcy, o ile ostatnio wczytany jest ogólny ramdisk.
Na przykład program rozruchowy może pominąć wczytywanie pamięci RAM typu VENDOR_RAMDISK_TYPE_RECOVERY
podczas normalnego uruchamiania, aby oszczędzać zasoby. W pamięci są wczytywane tylko pamięci RAM typu VENDOR_RAMDISK_TYPE_PLATFORM
i VENDOR_RAMDISK_TYPE_DLKM
. Z drugiej strony, ramdysk dostawcy typu VENDOR_RAMDISK_TYPE_PLATFORM
, VENDOR_RAMDISK_TYPE_RECOVERY
i VENDOR_RAMDISK_TYPE_DLKM
jest ładowany do pamięci podczas uruchamiania w trybie odzyskiwania.
Bootloader może też zignorować tabelę ramdisk dostawcy i wczytać całą sekcję ramdisk dostawcy. Ma to taki sam efekt jak wczytywanie wszystkich fragmentów pamięci RAM dostarczyciela na partycji vendor_boot
.
Pomoc w budowaniu
Aby wdrożyć obsługę uruchamiania przez dostawcę na urządzeniu:
Ustaw wartość
BOARD_BOOT_HEADER_VERSION
na3
lub większą.Ustaw
BOARD_RAMDISK_USE_LZ4
natrue
, jeśli urządzenie jest zgodne z GKI lub używa ogólnego pliku wymiany z kompresją LZ4.Ustaw
BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE
na odpowiedni rozmiar dla urządzenia, biorąc pod uwagę moduły jądra, które muszą znajdować się na partycji RAM dostawcy.Zaktualizuj
AB_OTA_PARTITIONS
, aby uwzględnićvendor_boot
oraz wszelkie listy partycji OTA na urządzeniu, które są specyficzne dla danego producenta.Skopiuj urządzenie
fstab
do/first_stage_ramdisk
w partycjivendor_boot
, a nieboot
. Na przykład:$(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM)
.
Aby uwzględnić w vendor_boot
kilka dysków RAM od różnych dostawców:
- Ustaw
BOARD_BOOT_HEADER_VERSION
na4
. Ustaw
BOARD_VENDOR_RAMDISK_FRAGMENTS
na listę nazw logicznych fragmentów pliku ramdisk dostawcy, które mają być uwzględnione wvendor_boot
.Aby dodać gotowy obraz pamięci RAM od dostawcy, ustaw parametr
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT
na ścieżkę do gotowego obrazu.Aby dodać ramdisk dostawcy DLKM, ustaw
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).KERNEL_MODULE_DIRS
na liście katalogów modułów jądra, które mają być uwzględnione.Ustaw argumenty
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).MKBOOTIMG_ARGS
namkbootimg
. Są to argumenty--board_id[0-15]
i--ramdisk_type
dla fragmentu ramdisk dostawcy. W przypadku pamięci RAM dostawcy DLKM domyślna wartość--ramdisk_type
toDLKM
, jeśli nie zostanie określona inna wartość.
Aby utworzyć zasoby do przywracania jako samodzielny dysk RAM recovery
w vendor_boot
:
- Ustaw
BOARD_BOOT_HEADER_VERSION
na4
. - Ustaw
BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT
natrue
. - Ustaw
BOARD_INCLUDE_RECOVERY_RAMDISK_IN_VENDOR_BOOT
natrue
. - Dodaje fragment ramdisk dostawcy, którego
ramdisk_name
torecovery
, aramdisk_type
toVENDOR_RAMDISK_TYPE_RECOVERY
. Dysk RAM zawiera wszystkie pliki odzyskiwania, czyli pliki zainstalowane w katalogu$(TARGET_RECOVERY_ROOT_OUT)
.
Argumenty mkbootimg
Argument | Opis |
---|---|
--ramdisk_type |
Typ dysku RAM może być NONE , PLATFORM , RECOVERY lub DLKM .
|
--board_id[0-15] |
Określ wektor board_id , który domyślnie ma wartość 0 . |
Oto przykładowa konfiguracja:
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
Powstały vendor_boot
zawierałby 2 fragmenty ramdisk dostawcy. Pierwszy to „domyślny” dysk twardy w pamięci RAM, który zawiera katalog DLKM baz
oraz resztę plików w $(TARGET_VENDOR_RAMDISK_OUT)
. Drugim jest dysk RAM dlkm_foobar
, który zawiera katalogi DLKM foo
i bar
, a wartość domyślna --ramdisk_type
to DLKM
.