Android 11 導入了通用核心映像檔 (GKI) 的概念。如要使用 GKI 啟動任意裝置,Android 11 裝置可以使用啟動映像檔標頭版本 3。在第 3 版中,所有廠商專屬資訊都會從 boot
分區中排除,並重新移至新的 vendor_boot
分區。搭載 Android 11 的 ARM64 裝置 (使用 5.4 Linux 核心啟動) 必須支援 vendor_boot
分割區和更新的 boot
分割區格式,才能通過 GKI 測試。
Android 12 裝置可以使用啟動映像檔標頭版本 4,支援在 vendor_boot
分區中加入多個供應商 ramdisk。多個供應商 RAM 磁碟片段會依序串連在供應商 RAM 磁碟區段中。供應商 RAM 磁碟表用於描述供應商 RAM 磁碟區段的版面配置,以及每個供應商 RAM 磁碟片段的中繼資料。
分區結構
供應商啟動磁碟分割區會透過虛擬 A/B 分割區進行 A/B 分割,並受到 Android 驗證開機程序保護。
版本 3
這個分割區包含標頭、供應商 RAM 磁碟和裝置樹狀結構 Blob (DTB)。
小節 | 頁數 |
---|---|
供應商啟動標頭 (n 頁) | n = (2112 + page_size - 1) / page_size |
供應商 RAM 磁碟 (o 頁面) | o = (vendor_ramdisk_size + page_size - 1) / page_size |
DTB (p 頁面) | p = (dtb_size + page_size - 1) / page_size |
版本 4
這個分割區包含標頭、供應商 RAM 磁碟區段 (由所有供應商 RAM 磁碟片段串連而成)、裝置樹狀結構 Blob (DTB) 和供應商 RAM 磁碟表。
小節 | 頁數 |
---|---|
供應商啟動標頭 (n 頁) | n = (2128 + page_size - 1) / page_size |
供應商 RAM 磁碟片段 (o 頁面) | o = (vendor_ramdisk_size + page_size - 1) / page_size |
DTB (p 頁面) | p = (dtb_size + page_size - 1) / page_size |
供應商 RAM 磁碟表 (q 頁) | q = (vendor_ramdisk_table_size + page_size - 1) / page_size |
Bootconfig (r 頁面) | r = (bootconfig_size + page_size - 1) / page_size |
供應商啟動標頭
供應商啟動磁碟分割區標頭的內容主要包含從啟動映像檔標頭重新定位的資料。其中也包含供應商 RAM 磁碟的相關資訊。
版本 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 */
};
版本 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
是所有供應商 RAM 磁碟片段的總大小。ramdisk_type
表示 ramdisk 的類型,可能的值包括:VENDOR_RAMDISK_TYPE_NONE
表示值未指定。VENDOR_RAMDISK_TYPE_PLATFORM
ramdisk 包含平台專屬位元。系統啟動載入程式一律會將這些項目載入記憶體。VENDOR_RAMDISK_TYPE_RECOVERY
ramdisk 包含復原資源。啟動進入復原模式時,系統啟動載入程式必須將這些項目載入記憶體。VENDOR_RAMDISK_TYPE_DLKM
ramdisk 包含可動態載入的核心模組。
ramdisk_name
是 ramdisk 的專屬名稱。board_id
是供應商定義的硬體 ID 向量。
系統啟動載入程式支援
由於供應商啟動磁碟分割區包含先前位於啟動磁碟分割區的資訊 (例如快閃頁面大小、核心、RAM 磁碟載入位址、DTB 本身),因此開機載入程式必須存取啟動和供應商啟動磁碟分割區,才能取得足夠的資料來完成開機。
開機載入器必須在供應商 RAM 磁碟 (CPIO、Gzip 和 lz4 格式支援這類串連) 之後立即將通用 RAM 磁碟載入記憶體。請勿將一般 ramdisk 映像檔對齊頁面,或在記憶體中,於該映像檔與供應商 ramdisk 結尾之間加入任何其他空間。核心解壓縮後,會將串連的檔案解壓縮至 initramfs
,產生一般 RAM 磁碟疊加在供應商 RAM 磁碟檔案結構上的檔案結構。
由於一般 ramdisk 和供應商 ramdisk 會串連在一起,因此格式必須相同。GKI 開機映像檔使用 lz4 壓縮的通用 RAM 磁碟,因此符合 GKI 規範的裝置必須使用 lz4 壓縮的供應商 RAM 磁碟。相關設定如下所示。
如要瞭解支援 Bootconfig 的系統啟動載入程式需求,請參閱「實作 Bootconfig」。
多個供應商 ramdisk (版本 4)
使用開機映像檔標頭版本 4 時,開機載入器可以選取部分或所有供應商 RAM 磁碟,在開機時載入為 initramfs
。供應商 RAM 磁碟表包含每個 RAM 磁碟的中繼資料,可協助開機載入器決定要載入哪些 RAM 磁碟。只要最後載入通用 ramdisk,開機載入器就能決定載入所選供應商 ramdisk 的順序。
舉例來說,系統啟動載入程式可以在正常啟動期間省略載入 VENDOR_RAMDISK_TYPE_RECOVERY
類型的供應商 RAM 磁碟,以節省資源,因此只有 VENDOR_RAMDISK_TYPE_PLATFORM
和 VENDOR_RAMDISK_TYPE_DLKM
類型的供應商 RAM 磁碟會載入記憶體。另一方面,當啟動進入復原模式時,類型為 VENDOR_RAMDISK_TYPE_PLATFORM
、VENDOR_RAMDISK_TYPE_RECOVERY
和 VENDOR_RAMDISK_TYPE_DLKM
的供應商 ramdisk 會載入記憶體。
或者,系統啟動載入程式可以忽略供應商 RAM 磁碟表,並載入整個供應商 RAM 磁碟區段。這與在 vendor_boot
分區中載入所有供應商 RAM 磁碟片段的效果相同。
建立支援
如要為裝置實作廠商啟動支援功能,請按照下列步驟操作:
將
BOARD_BOOT_HEADER_VERSION
設為3
以上。如果裝置符合 GKI 規範,或使用 lz4 壓縮的通用 RAM 磁碟,請將
BOARD_RAMDISK_USE_LZ4
設為true
。考量必須放在供應商 RAM 磁碟上的核心模組,將
BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE
設為適合裝置的大小。更新
AB_OTA_PARTITIONS
,加入vendor_boot
和裝置上任何供應商專屬的 OTA 分區清單。將裝置
fstab
複製到vendor_boot
分割區的/first_stage_ramdisk
,而非boot
分割區。例如:$(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM)
。
如要在 vendor_boot
中加入多個供應商 ramdisk:
- 將
BOARD_BOOT_HEADER_VERSION
設為4
。 將
BOARD_VENDOR_RAMDISK_FRAGMENTS
設為要納入vendor_boot
的邏輯供應商 RAM 磁碟片段名稱清單。如要新增預先建構的供應商 RAM 磁碟,請將
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT
設為預先建構的路徑。如要新增 DLKM 供應商 RAM 磁碟,請將
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).KERNEL_MODULE_DIRS
設為要納入的 Kernel 模組目錄清單。將
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).MKBOOTIMG_ARGS
設為mkbootimg
引數。這些是供應商 RAM 磁碟片段的--board_id[0-15]
和--ramdisk_type
引數。如果是 DLKM 供應商 ramdisk,如未另行指定,預設--ramdisk_type
會是DLKM
。
如要在 vendor_boot
中將復原資源建構為獨立的 recovery
ramdisk,請執行下列操作:
- 將
BOARD_BOOT_HEADER_VERSION
設為4
。 - 將
BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT
設為true
。 - 將
BOARD_INCLUDE_RECOVERY_RAMDISK_IN_VENDOR_BOOT
設為true
。 - 這樣就會新增供應商 RAM 磁碟片段,其
ramdisk_name
為recovery
,ramdisk_type
為VENDOR_RAMDISK_TYPE_RECOVERY
。ramdisk 隨後會包含所有復原檔案,也就是安裝在$(TARGET_RECOVERY_ROOT_OUT)
下的檔案。
mkbootimg 引數
引數 | 說明 |
---|---|
--ramdisk_type |
RAM 磁碟類型,可以是 NONE 、PLATFORM 、RECOVERY 或 DLKM 。
|
--board_id[0-15] |
指定 board_id 向量,預設為 0 。 |
以下為設定範例:
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
產生的 vendor_boot
會包含兩個供應商 ramdisk 片段。第一個是「預設」ramdisk,其中包含 DLKM 目錄 baz
和 $(TARGET_VENDOR_RAMDISK_OUT)
中的其餘檔案。第二個是 dlkm_foobar
ramdisk,其中包含 DLKM 目錄 foo
和 bar
,而 --ramdisk_type
預設為 DLKM
。