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 ซึ่งรองรับการรวม ramdisk ของผู้จำหน่ายหลายรายการในพาร์ติชัน 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 หน้า) | o = (vendor_ramdisk_size + page_size - 1) / page_size |
DTB (หน้า) | p = (dtb_size + page_size - 1) / page_size |
เวอร์ชัน 4
พาร์ติชันประกอบด้วยส่วนหัว ส่วน ramdisk ของผู้ขาย (ประกอบด้วยแฟรกเมนต์ ramdisk ของผู้ขายทั้งหมด เชื่อมต่อกัน) Device tree 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
มีบิตเฉพาะของแพลตฟอร์ม bootloader ต้องโหลดสิ่งเหล่านี้ลงในหน่วยความจำเสมอ -
VENDOR_RAMDISK_TYPE_RECOVERY
มีทรัพยากรการกู้คืน bootloader ต้องโหลดสิ่งเหล่านี้ลงในหน่วยความจำเมื่อบูตเข้าสู่การกู้คืน -
VENDOR_RAMDISK_TYPE_DLKM
มีโมดูลเคอร์เนลที่โหลดได้แบบไดนามิก
-
-
ramdisk_name
เป็นชื่อเฉพาะของ ramdisk -
board_id
เป็นเวกเตอร์ของตัวระบุฮาร์ดแวร์ที่กำหนดโดยผู้ขาย
รองรับ Bootloader
เนื่องจากพาร์ติชันสำหรับบูตของผู้ขายมีข้อมูล (เช่น ขนาดหน้าแฟลช, เคอร์เนล, ที่อยู่โหลด ramdisk, ตัว DTB เอง) ที่มีอยู่ก่อนหน้านี้ในพาร์ติชันสำหรับบูต bootloader ต้องเข้าถึงทั้งพาร์ติชันสำหรับบูตและของผู้จำหน่ายเพื่อให้มีข้อมูลเพียงพอในการบูตให้เสร็จสมบูรณ์ .
bootloader ต้องโหลด ramdisk ทั่วไปลงในหน่วยความจำ ทันที ตามหลัง ramdisk ของผู้จำหน่าย (รูปแบบ CPIO, Gzip และ lz4 รองรับการต่อข้อมูลประเภทนี้) ห้ามจัดหน้าอิมเมจ ramdisk ทั่วไปหรือใส่ช่องว่างอื่นใดระหว่างมันกับส่วนท้ายของ ramdisk ของผู้ขายในหน่วยความจำ หลังจากคลายการบีบอัดเคอร์เนลแล้ว เคอร์เนลจะแยกไฟล์ที่ต่อกันออกเป็น initramfs
ซึ่งส่งผลให้โครงสร้างไฟล์เป็น ramdisk ทั่วไปที่วางทับบนโครงสร้างไฟล์ ramdisk ของผู้ขาย
เนื่องจาก ramdisk ทั่วไปและ ramdisk ของผู้ขายเชื่อมต่อกัน จึงต้องอยู่ในรูปแบบเดียวกัน อิมเมจสำหรับบูต GKI ใช้แรมดิสก์ทั่วไปที่บีบอัดด้วย lz4 ดังนั้นอุปกรณ์ที่สอดคล้องกับ GKI จะต้องใช้แรมดิสก์ของผู้จำหน่ายที่บีบอัดด้วย lz4 การกำหนดค่าสำหรับสิ่งนี้แสดงไว้ด้านล่าง
ข้อกำหนด bootloader สำหรับการสนับสนุน bootconfig มีอธิบายไว้ในหน้า Implementing Bootconfig
ramdisk ของผู้จำหน่ายหลายราย (เวอร์ชัน 4)
ด้วยส่วนหัวอิมเมจสำหรับบูตเวอร์ชัน 4 bootloader สามารถเลือกชุดย่อยหรือ ramdisk ของผู้จำหน่ายทั้งหมดเพื่อโหลดเป็น initramfs
ระหว่างเวลาบูต ตาราง ramdisk ของผู้จำหน่ายมีข้อมูลเมตาของ ramdisk แต่ละตัว และสามารถช่วยเหลือ bootloader ในการตัดสินใจว่าจะโหลด ramdisk ตัวใด bootloader สามารถเลือกลำดับในการโหลด ramdisk ของผู้จำหน่ายที่เลือก ตราบใดที่ ramdisk ทั่วไปถูกโหลดครั้งสุดท้าย
ตัวอย่างเช่น bootloader สามารถละเว้นการโหลด ramdisks ของผู้ขายประเภท VENDOR_RAMDISK_TYPE_RECOVERY
ระหว่างการบูตปกติเพื่อประหยัดทรัพยากร ดังนั้นเฉพาะ ramdisks ของผู้ขายประเภท VENDOR_RAMDISK_TYPE_PLATFORM
และ VENDOR_RAMDISK_TYPE_DLKM
เท่านั้นที่โหลดลงในหน่วยความจำ ในทางกลับกัน ramdisk ของผู้ขายประเภท 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 ของผู้ขายสองรายการ อันแรกคือแรมดิสก์ "เริ่มต้น" ซึ่งมีไดเร็กทอรี DLKM baz
และไฟล์ที่เหลือใน $(TARGET_VENDOR_RAMDISK_OUT)
อันที่สองคือ dlkm_foobar
ramdisk ซึ่งมีไดเร็กทอรี DLKM foo
และ bar
และ --ramdisk_type
เริ่มต้นเป็น DLKM