Android 11 引入了通用核心映像 (GKI) 的概念。為了能夠使用 GKI 輕鬆啟動任意設備,Android 11 設備可以使用啟動映像標頭版本 3。在版本 3 中,所有供應商特定資訊均從boot
分區中提取出來,並重新定位到新的vendor_boot
分區中。在 5.4 Linux 核心上啟動 Android 11 的 ARM64 裝置必須支援vendor_boot
分割區和更新的boot
分割區格式才能通過 GKI 測試。
Android 12 裝置可以使用啟動映像標頭版本 4,該版本支援在vendor_boot
分割區中包含多個供應商 ramdisk。多個供應商 ramdisk 片段在供應商 ramdisk 部分中依序串聯。供應商 ramdisk 表用於描述供應商 ramdisk 部分的佈局以及每個供應商 ramdisk 片段的元資料。
隔間結構
供應商啟動分區採用虛擬 A/B 進行 A/B 處理,並受 Android 驗證啟動保護。
版本3
此分區由標頭、供應商 ramdisk 和設備樹 blob (DTB) 組成。
部分 | 頁數 |
---|---|
供應商引導標頭(n 頁) | n = (2112 + page_size - 1) / page_size |
供應商 ramdisk(o 頁) | o = (vendor_ramdisk_size + page_size - 1) / page_size |
DTB(頁數) | p = (dtb_size + page_size - 1) / page_size |
版本4
此分區由標頭、供應商 ramdisk 部分(由所有供應商 ramdisk 片段連接而成)、設備樹 blob (DTB) 和供應商 ramdisk 表組成。
部分 | 頁數 |
---|---|
供應商引導標頭(n 頁) | n = (2128 + page_size - 1) / page_size |
供應商 ramdisk 碎片(o 頁) | o = (vendor_ramdisk_size + page_size - 1) / page_size |
DTB(頁數) | p = (dtb_size + page_size - 1) / page_size |
供應商 ramdisk 表(q 頁) | q = (vendor_ramdisk_table_size + page_size - 1) / page_size |
Bootconfig(r 頁) | r = (bootconfig_size + page_size - 1) / page_size |
供應商引導標頭
供應商引導分區標頭的內容主要由從引導映像標頭重新定位到那裡的資料組成。它還包含有關供應商 ramdisk 的資訊。
版本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
是所有供應商 ramdisk 片段的總大小。 -
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
是供應商定義的硬體標識符的向量。
引導程式支持
由於供應商引導分區包含先前存在於引導分區中的資訊(例如快閃記憶體頁大小、核心、ramdisk 載入位址、DTB 本身),因此引導程式必須存取引導分割區和供應商引導分割區,以獲得足夠的資料來完成引導。
引導程式必須在供應商 ramdisk 之後立即將通用 ramdisk 載入到記憶體中(CPIO、Gzip 和 lz4 格式支援這種類型的串聯)。不要對通用 ramdisk 映像進行頁面對齊,也不要在其與記憶體中供應商 ramdisk 的末尾之間引入任何其他空間。核心解壓縮後,會將串聯檔案提取到initramfs
中,從而產生一個檔案結構,該檔案結構是覆蓋在供應商 ramdisk 檔案結構上的通用 ramdisk。
由於通用 ramdisk 和供應商 ramdisk 是串聯的,因此它們必須採用相同的格式。 GKI 啟動映像檔使用 lz4 壓縮的通用 ramdisk,因此符合 GKI 的裝置必須使用 lz4 壓縮的供應商 ramdisk。其配置如下所示。
支援 bootconfig 的引導程式要求在實作 Bootconfig頁面上進行了說明。
多個供應商 ramdisk(版本 4)
使用引導映像標頭版本 4,引導程式可以選擇供應商 ramdisk 的子集或全部在引導期間作為initramfs
載入。供應商 ramdisk 表包含每個 ramdisk 的元數據,可以幫助引導程式決定要載入哪些 ramdisk。引導程式可以決定載入所選供應商 ramdisk 的順序,只要最後載入通用 ramdisk 即可。
例如,引導程式可以在正常開機期間省略載入類型為VENDOR_RAMDISK_TYPE_RECOVERY
的供應商 ramdis,以節省資源,因此僅將類型為VENDOR_RAMDISK_TYPE_PLATFORM
和VENDOR_RAMDISK_TYPE_DLKM
的供應商 ramdis 載入到記憶體中。另一方面,當啟動到復原模式時,類型為VENDOR_RAMDISK_TYPE_PLATFORM
、 VENDOR_RAMDISK_TYPE_RECOVERY
和VENDOR_RAMDISK_TYPE_DLKM
的供應商 ramdisk 會載入到記憶體中。
或者,引導程式可以忽略供應商 ramdisk 表並載入整個供應商 ramdisk 部分。這與載入供應商vendor_boot
分割區中的所有供應商 ramdisk 片段具有相同的效果。
建立支持
要實現設備的供應商引導支援:
將
BOARD_BOOT_HEADER_VERSION
設定為3
或更大。如果您的裝置符合 GKI 標準,或使用 lz4 壓縮的通用 ramdisk,請將
BOARD_RAMDISK_USE_LZ4
設為true
。將
BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE
設定為適合您裝置的大小,並考慮必須位於供應商 ramdisk 上的核心模組。更新
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
中的邏輯供應商 ramdisk 片段名稱清單。若要新增預先建置的供應商 ramdisk,請將
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT
設定為預先建置的檔案路徑。若要新增 DLKM 供應商 ramdisk,請將
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).KERNEL_MODULE_DIRS
設定為要包含的核心模組目錄清單。將
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).MKBOOTIMG_ARGS
設定為mkbootimg
參數。這些是供應商 ramdisk 片段的--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
。 - 這會增加一個供應商 ramdisk 片段,其
ramdisk_name
為recovery
,ramdisk_type
為VENDOR_RAMDISK_TYPE_RECOVERY
。然後,ramdisk 包含所有復原文件,這些文件是安裝在$(TARGET_RECOVERY_ROOT_OUT)
下的文件。
mkbootimg
參數
爭論 | 描述 |
---|---|
--ramdisk_type | ramdisk 的類型可以是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
。