พาร์ติชันสำหรับเริ่มระบบของผู้จำหน่าย

Android 11 นำเสนอแนวคิดของ Generic Kernel Image (GKI) เพื่อเปิดใช้งานการบูทอุปกรณ์ตามอำเภอใจอย่างง่ายดายด้วย GKI อุปกรณ์ Android 11 สามารถใช้ส่วนหัวอิมเมจสำหรับบูตเวอร์ชัน 3 ในเวอร์ชัน 3 ข้อมูลเฉพาะของผู้จำหน่ายทั้งหมดจะถูกแยกออกจากพาร์ติชั่น boot และย้ายไปยังพาร์ติ vendor_boot ใหม่ อุปกรณ์ ARM64 ที่เปิดใช้ Android 11 บนเคอร์เนล Linux 5.4 จะต้องรองรับพาร์ติชัน vendor_boot และรูปแบบพาร์ติชัน boot ที่อัปเดตแล้วจึงจะผ่านการทดสอบกับ GKI

อุปกรณ์ Android 12 สามารถใช้ส่วนหัวอิมเมจสำหรับบูตเวอร์ชัน 4 ซึ่งรองรับการรวม ramdisks ของผู้จำหน่ายหลายรายในพาร์ติชัน vendor_boot แฟรกเมนต์ ramdisk ของผู้จำหน่ายหลายรายถูกต่อกันในส่วน ramdisk ของผู้จำหน่าย ตาราง ramdisk ของผู้ขายใช้เพื่ออธิบายโครงร่างของส่วน ramdisk ของผู้ขายและข้อมูลเมตาของแฟรกเมนต์ ramdisk ของผู้ขายแต่ละราย

โครงสร้างพาร์ติชั่น

พาร์ติชันสำหรับเริ่มระบบของผู้ขายเป็น A/B ที่มี A/B เสมือนและได้รับการป้องกันโดย Android Verified Boot

เวอร์ชัน 3

พาร์ติชั่นประกอบด้วยส่วนหัว ramdisk ของผู้จำหน่าย และ device tree blob (DTB)

ส่วน เลขหน้า
ส่วนหัวการบูตของผู้จัดจำหน่าย (หน้า n) n = (2112 + page_size - 1) / page_size
ผู้จำหน่าย ramdisk (หน้า) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (หน้า) p = (dtb_size + page_size - 1) / page_size

เวอร์ชัน 4

พาร์ติชันประกอบด้วยส่วนหัว ส่วน ramdisk ของผู้ขาย (ประกอบด้วยแฟรกเมนต์ ramdisk ของผู้ขายทั้งหมด ต่อกัน) หยดแผนผังอุปกรณ์ (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 มีบิตเฉพาะของแพลตฟอร์ม bootloader ต้องโหลดสิ่งเหล่านี้ลงในหน่วยความจำเสมอ
    • VENDOR_RAMDISK_TYPE_RECOVERY ramdisk มีทรัพยากรการกู้คืน bootloader ต้องโหลดสิ่งเหล่านี้ลงในหน่วยความจำเมื่อทำการบูทเข้าสู่การกู้คืน
    • VENDOR_RAMDISK_TYPE_DLKM ramdisk มีโมดูลเคอร์เนลที่โหลดได้แบบไดนามิก
  • ramdisk_name เป็นชื่อเฉพาะของ ramdisk
  • board_id เป็นเวกเตอร์ของตัวระบุฮาร์ดแวร์ที่ผู้ขายกำหนด

รองรับ Bootloader

เนื่องจากพาร์ติชันสำหรับเริ่มระบบของผู้ขายมีข้อมูล (เช่น ขนาดหน้าแฟลช, เคอร์เนล, ที่อยู่โหลด ramdisk, DTB เอง) ที่มีอยู่ก่อนหน้านี้ในพาร์ติชันสำหรับเริ่มระบบ ตัวโหลดบูตต้องเข้าถึงทั้งบูตพาร์ติชันและพาร์ติชันสำหรับเริ่มระบบของผู้ขายเพื่อให้มีข้อมูลเพียงพอในการบูตให้เสร็จสมบูรณ์ .

bootloader ต้องโหลด ramdisk ทั่วไปลงในหน่วยความจำ ทันที ตาม ramdisk ของผู้จำหน่าย (รูปแบบ CPIO, Gzip และ lz4 รองรับการต่อข้อมูลประเภทนี้) ห้ามจัดหน้าอิมเมจ ramdisk ทั่วไปหรือแนะนำช่องว่างอื่นระหว่างมันกับจุดสิ้นสุดของ ramdisk ของผู้จำหน่ายในหน่วยความจำ หลังจากที่เคอร์เนลคลายการบีบอัด มันจะแตกไฟล์ที่ต่อกันเป็น initramfs ซึ่งส่งผลให้โครงสร้างไฟล์เป็น ramdisk ทั่วไปที่ซ้อนทับบนโครงสร้างไฟล์ ramdisk ของผู้จำหน่าย

เนื่องจาก ramdisk ทั่วไปและ ramdisk ของผู้จำหน่ายได้รับการต่อกัน พวกเขาจึงต้องอยู่ในรูปแบบเดียวกัน อิมเมจสำหรับบูต GKI ใช้ ramdisk ทั่วไปที่บีบอัด lz4 ดังนั้นอุปกรณ์ที่สอดคล้องกับ GKI ต้องใช้ ramdisk ของผู้ขายที่บีบอัด lz4 การกำหนดค่าสำหรับสิ่งนี้แสดงอยู่ด้านล่าง

ข้อกำหนดของ bootloader สำหรับรองรับ bootconfig นั้นอธิบายไว้ในหน้า Implementing Bootconfig

ramdisks ของผู้ขายหลายราย (เวอร์ชัน 4)

ด้วยส่วนหัวของอิมเมจสำหรับบูตเวอร์ชัน 4 ตัวโหลดบูตสามารถเลือกชุดย่อยหรือ ramdisks ของผู้ขายทั้งหมดเพื่อโหลดเป็น initramfs ระหว่างเวลาบูต ตาราง ramdisk ของผู้ขายมีข้อมูลเมตาของแต่ละ ramdisk และสามารถช่วย bootloader ในการตัดสินใจว่าจะโหลด ramdisk ใด bootloader สามารถตัดสินใจลำดับที่จะโหลด ramdisk ของผู้จำหน่ายที่เลือก ตราบใดที่ ramdisk ทั่วไปโหลดอยู่ล่าสุด

ตัวอย่างเช่น ตัวโหลดบูตสามารถละเว้นการโหลด ramdisks ของผู้ขายประเภท VENDOR_RAMDISK_TYPE_RECOVERY ระหว่างการบูตปกติเพื่อประหยัดทรัพยากร ดังนั้นเฉพาะ ramdisks ของผู้ขายประเภท VENDOR_RAMDISK_TYPE_PLATFORM และ VENDOR_RAMDISK_TYPE_DLKM เท่านั้นที่โหลดลงในหน่วยความจำ ในทางกลับกัน ramdisks ของผู้ขายประเภท VENDOR_RAMDISK_TYPE_PLATFORM , VENDOR_RAMDISK_TYPE_RECOVERY และ VENDOR_RAMDISK_TYPE_DLKM จะถูกโหลดลงในหน่วยความจำเมื่อทำการบูทเข้าสู่โหมดการกู้คืน

อีกทางหนึ่งคือ bootloader สามารถละเว้นตาราง ramdisk ของผู้ขาย และโหลดส่วน ramdisk ของผู้ขายทั้งหมด สิ่งนี้มีผลเช่นเดียวกับการโหลดแฟรกเมนต์ ramdisk ของผู้ขายทั้งหมดในพาร์ติชัน vendor_boot

สร้างการสนับสนุน

ในการปรับใช้การรองรับการบู๊ตของผู้จำหน่ายสำหรับอุปกรณ์:

  • ตั้งค่า BOARD_BOOT_HEADER_VERSION เป็น 3 ขึ้นไป

  • ตั้งค่า BOARD_RAMDISK_USE_LZ4 true หากอุปกรณ์ของคุณเป็นไปตาม GKI หรือหากใช้ ramdisk ทั่วไปที่บีบอัด lz4

  • ตั้งค่า BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE ให้เป็นขนาดที่เหมาะสมสำหรับอุปกรณ์ของคุณ โดยพิจารณาจากโมดูลเคอร์เนลที่ต้องใช้กับ ramdisk ของผู้จำหน่าย

  • อัปเดต AB_OTA_PARTITIONS เพื่อรวม vendor_boot และรายการพาร์ติชัน OTA เฉพาะผู้จำหน่ายในอุปกรณ์

  • คัดลอกอุปกรณ์ fstab ของคุณไปที่ /first_stage_ramdisk ในพาร์ติชัน vendor_boot ไม่ใช่พาร์ติชัน boot ตัวอย่างเช่น $(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM)

ในการรวม ramdisks ของผู้ขายหลายรายใน vendor_boot :

  • ตั้งค่า BOARD_BOOT_HEADER_VERSION เป็น 4
  • ตั้งค่า BOARD_VENDOR_RAMDISK_FRAGMENTS เป็นรายการชื่อแฟรกเมนต์ ramdisk ของผู้จำหน่ายแบบลอจิคัลที่จะรวมอยู่ใน vendor_boot

  • ในการเพิ่ม ramdisk ของผู้จำหน่ายที่สร้างไว้ล่วงหน้า ให้ตั้งค่า BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT เป็นพาธไฟล์ที่สร้างไว้ล่วงหน้า

  • ในการเพิ่ม ramdisk ของผู้จำหน่าย DLKM ให้ตั้งค่า 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 ของผู้ขาย สำหรับ ramdisk ของผู้จำหน่าย DLKM ค่าเริ่มต้น --ramdisk_type จะเป็น DLKM หากไม่ได้ระบุไว้เป็นอย่างอื่น

ในการสร้างทรัพยากรการกู้คืนเป็น ramdisk recovery แบบสแตนด์อโลนใน vendor_boot :

  • ตั้งค่า 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 และ VENDOR_RAMDISK_TYPE_RECOVERY คือ ramdisk_type จากนั้น 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 "default" ซึ่งมีไดเร็กทอรี DLKM baz และไฟล์ที่เหลือใน $(TARGET_VENDOR_RAMDISK_OUT) อันที่สองคือ dlkm_foobar ramdisk ซึ่งมีไดเร็กทอรี DLKM foo และ bar และ --ramdisk_type ตั้งค่าเริ่มต้นเป็น DLKM