Android 11 wprowadził koncepcję 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 można było przeprowadzić testy w GKI, urządzenie ARM64 z Androidem 11 z jądrem systemu Linux 5.4 musi obsługiwać partycję vendor_boot
i zaktualizowany format partycji boot
.
Urządzenia z Androidem 12 mogą używać nagłówka 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 bloba drzewa urządzenia (DTB).
Sekcja | Liczba stron |
---|---|
Nagłówek uruchamiania dostawcy (n stron) | n = (2112 + page_size - 1) / page_size |
Plik Ramdisk dostawcy (strony O) | 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 ramdisk (o strony) | o = (vendor_ramdisk_size + page_size - 1) / page_size |
DTB (strony: p) | p = (dtb_size + page_size - 1) / page_size |
Tabela ramdisk dostawcy (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 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
określa typ dysku ramdy. Możliwe wartości to:VENDOR_RAMDISK_TYPE_NONE
oznacza, że wartość jest nieokreś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
Ramdysk zawiera 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
Partycja rozruchowa dostawcy zawiera informacje (takie jak rozmiar strony w formacie Flash, jądro, adresy wczytywanego dysku RAM czy plik DTB), które istniały wcześniej w partycji rozruchowej, więc program rozruchowy musi mieć dostęp zarówno do partycji rozruchowej, jak i od dostawcy, aby mieć wystarczającą ilość danych do zakoń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 GKI używa ogólnego pliku ramdysk skompresowanego za pomocą lz4, więc urządzenie zgodne z GKI musi używać pliku ramdysk skompresowanego za pomocą lz4. Konfiguracja tego ustawienia jest pokazana poniżej.
Wymagania dotyczące programu rozruchowego związane z obsługą rozruchu zostały opisane w artykule Implementowanie konfiguracji rozruchowej.
Ramdiski 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 tylko ostatnio wczytany będzie ogólny ramdisk.
Program rozruchowy może na przykład podczas normalnego rozruchu pomijać wczytywanie dysków RAM dostawcy typu VENDOR_RAMDISK_TYPE_RECOVERY
, aby oszczędzać zasoby. W rezultacie do pamięci wczytywane są tylko dyski RAM dostawców typu VENDOR_RAMDISK_TYPE_PLATFORM
i VENDOR_RAMDISK_TYPE_DLKM
. Z drugiej strony podczas uruchamiania w trybie przywracania do pamięci są wczytywane dyski Ramdy dostawcy typu VENDOR_RAMDISK_TYPE_PLATFORM
, VENDOR_RAMDISK_TYPE_RECOVERY
i VENDOR_RAMDISK_TYPE_DLKM
.
Alternatywnie bootloader może 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 dostawcy.Skopiuj urządzenie
fstab
do/first_stage_ramdisk
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 fragmentów dysków Ramdisk dostawcy logicznych, 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ć dysk ramdisk dostawcy DLKM, ustaw
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).KERNEL_MODULE_DIRS
na listę katalogów modułu jądra, które chcesz uwzględnić.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
. Ramdysk zawiera wtedy wszystkie pliki przywracania, czyli pliki zainstalowane w systemie$(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
.