供應商啟動分區

Android 11 導入了一般核心的概念 圖片 (GKI)。如何使用 GKI (Android) 啟動任意裝置 有 11 部裝置可以使用第 3 版啟動映像檔標頭。於 第 3 版時,所有供應商相關資訊都會納入 boot 並移至新的 vendor_boot 分區中。擁有 ARM64 裝置 在 5.4 Linux 核心上透過 Android 11 啟動,必須 支援 vendor_boot 分區,以及更新後的 boot 分區格式, 通過 GKI 測試

Android 12 裝置可以使用第 4 版啟動映像檔標頭。 可在 vendor_boot 中加入多個供應商 ramdisks 多個供應商的 ramdisk 片段依序串連 位於供應商 ramdisk 部分中供應商 ramdisk 資料表可用來描述 廠商 ramdisk 區段的版面配置,以及每個供應商 ramdisk 的中繼資料 片段。

分區結構

供應商啟動分區是以虛擬 A/B 為基礎的 A/B 版本,並受到 Android 保護 驗證開機程序。

版本 3

分區包含標頭、供應商 ramdisk 和裝置樹狀結構 blob (DTB)。

章節 頁數
供應商啟動標頭 (n 頁) n = (2112 + page_size - 1) / page_size
供應商 ramdisk (多頁) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (p 頁) p = (dtb_size + page_size - 1) / page_size

版本 4

分區包含標頭、廠商 ramdisk 區段 (由 所有供應商的 ramdisk 片段 (串連)、裝置樹狀結構 blob (DTB) 以及 供應商 ramdisk 資料表。

章節 頁數
供應商啟動標頭 (n 頁) n = (2128 + page_size - 1) / page_size
供應商 ramdisk 片段 (數頁) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (p 頁) 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 ramdisks 包含平台專屬的位元。 系統啟動載入程式一律必須將這些值載入記憶體。
    • VENDOR_RAMDISK_TYPE_RECOVERY 個 ramdisks 包含復原資源。 開機進入復原程序時,系統啟動載入程式必須在記憶體中載入這些元件。
    • VENDOR_RAMDISK_TYPE_DLKM 個 ramdisks 包含動態載入的核心 模組。
  • ramdisk_name 是 ramdisk 的唯一名稱。
  • board_id 是供應商定義的硬體 ID 向量。

系統啟動載入程式支援

由於廠商啟動分區包含某些資訊 (例如 Flash 網頁大小、 核心、ramdisk 負載位址、DTB 本身), 系統啟動載入程式必須同時存取開機和廠商開機 多個分區中的資料,足以完成啟動作業。

系統啟動載入程式必須在呼叫以下事件後立即將一般 ramdisk 載入記憶體 廠商 ramdisk (CPIO、Gzip 和 lz4 格式都支援這類 串連)。請勿對齊一般 ramdisk 映像檔,也不要引入任何 與廠商 ramdisk 結尾之間的其他空間在 核心解壓縮後,就會將串連的檔案擷取至 initramfs, 這樣就會形成一個檔案結構,也就是 一組一般的 RAM 磁碟 供應商 ramdisk 檔案結構。

由於一般 ramdisk 和供應商 ramdisk 串連,因此它們必須 相同格式GKI 開機映像檔使用的是 lz4 壓縮的一般 ramdisk 技術,因此 符合 GKI 規範的裝置必須使用採用 lz4 壓縮的供應商 ramdisk 格式。 相關設定如下

如要瞭解支援開機設定的系統啟動載入程式需求,請參閱 導入 Bootconfig

多個供應商 ramdisks (第 4 版)

使用第 4 版開機映像檔標頭時,系統啟動載入程式可以選取一部分或 開機時載入的所有供應商 ramdisk 做為 initramfs。 供應商 ramdisk 資料表內含每個 ramdisk 的中繼資料,有助於 系統啟動載入程式,用於決定要載入哪個 ramdisk。系統啟動載入程式可決定 載入所選供應商 ramdisks,但前提是 上次載入

舉例來說,系統啟動載入程式可以省略「類型」類型的載入廠商 ramdisks 在一般啟動期間執行 VENDOR_RAMDISK_TYPE_RECOVERY 以節省資源,因此僅限 供應商 ramdisks,類型為 VENDOR_RAMDISK_TYPE_PLATFORMVENDOR_RAMDISK_TYPE_DLKM 會載入記憶體。另一方面 VENDOR_RAMDISK_TYPE_PLATFORM 類型的 ramdisks,VENDOR_RAMDISK_TYPE_RECOVERYVENDOR_RAMDISK_TYPE_DLKM 會在啟動進入復原程序時載入記憶體 模式。

或者,系統啟動載入程式可以忽略供應商 ramdisk 資料表,並載入 整個供應商 ramdisk 欄位這與載入 vendor_boot 分區中的廠商 ramdisk 片段。

建構支援

如何為裝置實作廠商啟動支援:

  • 請將 BOARD_BOOT_HEADER_VERSION 設為 3 以上。

  • 如果您的裝置符合 GKI 規定,或是裝置符合 GKI 規定,請將 BOARD_RAMDISK_USE_LZ4 設為 true 如果沒有,就會使用 lz4 壓縮的泛型 RAM。

  • 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 中加入多個供應商 ramdisks:

  • BOARD_BOOT_HEADER_VERSION 設為 4
  • BOARD_VENDOR_RAMDISK_FRAGMENTS 設為邏輯供應商 ramdisk 清單 要包含在 vendor_boot 中的片段名稱。

  • 如要新增預先建構的供應商 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 引數。這些是--board_id[0-15]--ramdisk_type 供應商 ramdisk 片段的引數。如果是 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_namerecoveryramdisk_typeVENDOR_RAMDISK_TYPE_RECOVERY。然後 ramdisk 會包含 所有復原檔案,這些檔案會安裝在 $(TARGET_RECOVERY_ROOT_OUT)

mkbootimg 引數

引數 說明
--ramdisk_type ramdisk 的類型可能是 NONEPLATFORMRECOVERYDLKM
--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 目錄 foobar,以及 --ramdisk_type 預設為 DLKM