ב-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, שתומכת בהכללת כמה דיסקים של זיכרון RAM של ספקים במחיצה vendor_boot
. מספר קטעי ramdisk של ספקים מחוברים זה לזה ברצף בקטע של ה-ramdisk של הספק. טבלת RAMDisk של ספק משמשת לתיאור הפריסה של הקטע של RAMDisk של הספק והמטא-נתונים של כל קטע של RAMDisk של הספק.
מבנה המחיצות
מחיצה האתחול של הספק מוגדרת כמחיצה A/B עם A/B וירטואלי ומוגנת על ידי Android Verified Boot.
גרסה 3
המחיצה מורכבת מכותרת, מ-ramdisk של הספק ומ-blob של עץ המכשיר (DTB).
קטע | מספר הדפים |
---|---|
כותרת האתחול של הספק (n דפים) | n = (2112 + page_size - 1) / page_size |
Vendor ramdisk (o pages) | 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 |
קטעי ramdisk של ספק (o דפים) | o = (vendor_ramdisk_size + page_size - 1) / page_size |
DTB (p דפים) | p = (dtb_size + page_size - 1) / page_size |
טבלת Vendor 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
מציין את הסוג של דיסק ה-RAM. הערכים האפשריים הם:- הערך
VENDOR_RAMDISK_TYPE_NONE
מציין שהערך לא צוין. VENDOR_RAMDISK_TYPE_PLATFORM
דיסקים של זיכרון RAM מכילים ביטים ספציפיים לפלטפורמה. מנהל האתחול תמיד צריך לטעון אותם לזיכרון.- דיסקים מסוג
VENDOR_RAMDISK_TYPE_RECOVERY
מכילים משאבי שחזור. מנהל האתחול צריך לטעון אותם לזיכרון כשמפעילים את המכשיר במצב שחזור. VENDOR_RAMDISK_TYPE_DLKM
דיסקים של זיכרון RAM מכילים מודולים דינמיים של ליבה שניתנים לטעינה.
- הערך
ramdisk_name
הוא שם ייחודי של דיסק ה-RAM.board_id
הוא וקטור של מזהים של חומרה שהוגדרו על ידי הספק.
תמיכה בתוכנת אתחול
מכיוון שמחיצה לאתחול של הספק מכילה מידע (כמו גודל דף הפלאש, הליבה, כתובות הטעינה של דיסק ה-RAM, ה-DTB עצמו) שהיה קיים בעבר במחיצה לאתחול, מנהל האתחול צריך לגשת גם למחיצה לאתחול וגם למחיצה לאתחול של הספק כדי שיהיה לו מספיק נתונים כדי להשלים את האתחול.
תוכנת האתחול צריכה לטעון את ה-ramdisk הגנרי לזיכרון מיד אחרי ה-ramdisk של הספק (הפורמטים CPIO, Gzip ו-lz4 תומכים בסוג הזה של שרשור). אין לבצע התאמה לדף של קובץ האימג' הגנרי של ה-RAMdisk או להוסיף רווח כלשהו בינו לבין סוף ה-RAMdisk של הספק בזיכרון. אחרי שהמעבד מבצע את הדחיסה, הוא מחלץ את הקובץ המקושר לקובץ initramfs
, וכתוצאה מכך נוצר מבנה קבצים של דיסק אחסון RAM (ramdisk) גנרי שמשולב במבנה הקבצים של דיסק האחסון ה-ramdisk של הספק.
מאחר שה-ramdisk הגנרי וה-ramdisk של הספק מקושרים, הם צריכים להיות באותו פורמט. קובץ האימג' של GKI לטעינה משתמש ב-ramdisk גנרי בלחץ lz4, ולכן במכשיר שתואם ל-GKI צריך להשתמש ב-ramdisk של ספק בלחץ lz4. ההגדרה של זה מוצגת בהמשך.
הדרישות של תוכנת האתחול לתמיכה ב-bootconfig מפורטות במאמר הטמעת Bootconfig.
מספר דיסקים של RAM של ספקים שונים (גרסה 4)
בכותרת של קובץ האימג' של האתחול בגרסה 4, מנהל האתחול יכול לבחור קבוצת משנה או את כל הדיסקים הווירטואליים של המכשיר לטעינה בתור initramfs
במהלך האתחול. טבלת ה-ramdisk של הספק מכילה את המטא-נתונים של כל ה-ramdisk, והיא יכולה לעזור למחולל האתחול להחליט אילו ramdisk לטעון. מנהל האתחול יכול לקבוע את הסדר שבו נטענים דיסקי ה-RAMdisk של הספקים שנבחרו, כל עוד דיסק ה-RAMdisk הגנרי נטען אחרון.
לדוגמה, כדי לחסוך במשאבים, מנהל האתחול יכול להשמיט את הטעינה של דיסקים זמניים של ספקים מסוג VENDOR_RAMDISK_TYPE_RECOVERY
במהלך אתחול רגיל, כך שרק דיסקים זמניים של ספקים מסוג VENDOR_RAMDISK_TYPE_PLATFORM
ו-VENDOR_RAMDISK_TYPE_DLKM
נטענים בזיכרון. לעומת זאת, דיסקים מסוג VENDOR_RAMDISK_TYPE_PLATFORM
, VENDOR_RAMDISK_TYPE_RECOVERY
ו-VENDOR_RAMDISK_TYPE_DLKM
של ספקים נטענים בזיכרון בזמן האתחול למצב שחזור.
לחלופין, תוכנת האתחול יכולה להתעלם מטבלת ה-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)
.
כדי לכלול כמה דיסקים של זיכרון RAM של ספקים ב-vendor_boot
:
- מגדירים את
BOARD_BOOT_HEADER_VERSION
לערך4
. מגדירים את
BOARD_VENDOR_RAMDISK_FRAGMENTS
כרשימה של שמות של קטעי ramdisk לוגיים של הספק שצריך לכלול ב-vendor_boot
.כדי להוסיף דיסק RAM מובנה של ספק, מגדירים את
BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT
לנתיב המובנה.כדי להוסיף דיסק RAM של ספק 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
. - הפעולה הזו מוסיפה קטע של דיסק RAM של ספק, שבו הערך של
ramdisk_name
הואrecovery
ו-ramdisk_type
הואVENDOR_RAMDISK_TYPE_RECOVERY
. לאחר מכן, דיסק ה-RAM מכיל את כל קובצי השחזור, שהם קבצים שמותקנים בתיקייה$(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 של הספק. הראשון הוא דיסק ה-RAM שמוגדר כברירת מחדל, שמכיל את ספריית DLKM baz
ואת שאר הקבצים ב-$(TARGET_VENDOR_RAMDISK_OUT)
. השני הוא דיסק ה-RAM dlkm_foobar
, שמכיל את הספריות DLKM foo
ו-bar
, והערך שמוגדר כברירת מחדל ל---ramdisk_type
הוא DLKM
.