پارتیشن بوت فروشنده

اندروید ۱۱ مفهوم تصویر هسته عمومی (GKI) را معرفی کرد. برای فعال کردن بوت شدن یک دستگاه دلخواه با GKI، دستگاه‌های اندروید ۱۱ می‌توانند از هدر تصویر بوت نسخه ۳ استفاده کنند. در نسخه ۳، تمام اطلاعات خاص فروشنده از پارتیشن boot حذف شده و به یک پارتیشن جدید vendor_boot منتقل می‌شوند. یک دستگاه ARM64 که با اندروید ۱۱ روی هسته لینوکس ۵.۴ راه‌اندازی می‌شود، باید از پارتیشن vendor_boot و فرمت پارتیشن boot به‌روزرسانی‌شده پشتیبانی کند تا آزمایش با GKI را با موفقیت پشت سر بگذارد.

دستگاه‌های اندروید ۱۲ می‌توانند از هدر تصویر بوت نسخه ۴ استفاده کنند که از گنجاندن چندین ramdisk از شرکت‌های مختلف در پارتیشن vendor_boot پشتیبانی می‌کند. چندین قطعه ramdisk از شرکت‌های مختلف، یکی پس از دیگری در بخش ramdisk از شرکت‌های مختلف به هم متصل می‌شوند. یک جدول ramdisk از شرکت‌های مختلف برای توصیف طرح‌بندی بخش ramdisk از شرکت‌های مختلف و فراداده‌های هر قطعه ramdisk از شرکت‌های مختلف استفاده می‌شود.

ساختار پارتیشن

پارتیشن بوت فروشنده با A/B مجازی A/B-ed شده و توسط Android Verified Boot محافظت می‌شود.

نسخه ۳

این پارتیشن شامل یک هدر، ramdisk فروشنده و قطعه درخت دستگاه (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

نسخه ۴

این پارتیشن شامل یک هدر، بخش ramdisk فروشنده (شامل تمام قطعات ramdisk فروشنده، به هم پیوسته)، لکه درخت دستگاه (DTB) و جدول ramdisk فروشنده است.

بخش تعداد صفحات
سربرگ بوت فروشنده (n صفحه) n = (2128 + page_size - 1) / page_size
قطعات رم‌دیسک فروشنده (o صفحه) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (صفحه‌ها) p = (dtb_size + page_size - 1) / page_size
جدول رم‌دیسک فروشنده (q صفحه) q = (vendor_ramdisk_table_size + page_size - 1) / page_size
پیکربندی بوت (صفحات r) r = (bootconfig_size + page_size - 1) / page_size

هدر بوت فروشنده

محتویات هدر پارتیشن بوت فروشنده عمدتاً شامل داده‌هایی است که از هدر تصویر بوت به آنجا منتقل شده‌اند. همچنین حاوی اطلاعاتی در مورد رم‌دیسک فروشنده است.

نسخه ۳

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 */

};

نسخه ۴

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_name نام منحصر به فرد ramdisk است.
  • board_id از شناسه‌های سخت‌افزاری تعریف‌شده توسط فروشنده است.

پشتیبانی از بوت لودر

از آنجا که پارتیشن بوت فروشنده حاوی اطلاعاتی (مانند اندازه صفحه فلش، هسته، آدرس‌های بارگذاری رم‌دیسک، خود DTB) است که قبلاً در پارتیشن بوت وجود داشته است، بوت‌لودر باید به هر دو پارتیشن بوت و بوت فروشنده دسترسی داشته باشد تا داده‌های کافی برای تکمیل بوت داشته باشد.

بوت لودر باید ramdisk عمومی را بلافاصله پس از ramdisk فروشنده در حافظه بارگذاری کند (فرمت‌های CPIO، Gzip و lz4 از این نوع الحاق پشتیبانی می‌کنند). تصویر ramdisk عمومی را صفحه بندی نکنید یا هیچ فاصله دیگری بین آن و انتهای ramdisk فروشنده در حافظه قرار ندهید. پس از اینکه هسته از حالت فشرده خارج شد، فایل الحاق شده را در یک initramfs استخراج می‌کند، که منجر به ساختار فایلی می‌شود که یک ramdisk عمومی است که روی ساختار فایل ramdisk فروشنده قرار گرفته است.

از آنجا که ramdisk عمومی و ramdisk فروشنده به هم متصل می‌شوند، باید فرمت یکسانی داشته باشند. تصویر بوت GKI از یک ramdisk عمومی فشرده‌شده با lz4 استفاده می‌کند، بنابراین دستگاهی که با GKI سازگار است باید از یک ramdisk فروشنده فشرده‌شده با lz4 استفاده کند. پیکربندی این مورد در زیر نشان داده شده است.

الزامات بوت لودر برای پشتیبانی از bootconfig در Implement Bootconfig توضیح داده شده است.

رم‌دیسک‌های چندفروشنده‌ای (نسخه ۴)

با هدر تصویر بوت نسخه ۴، بوت‌لودر می‌تواند یک زیرمجموعه یا تمام ramdiskهای فروشنده را برای بارگذاری به عنوان 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 مربوط به vendor را نادیده بگیرد و کل بخش ramdisk مربوط به vendor را بارگذاری کند. این کار همان تأثیر بارگذاری تمام قطعات ramdisk مربوط به vendor در پارتیشن vendor_boot دارد.

پشتیبانی ایجاد کنید

برای پیاده‌سازی پشتیبانی بوت فروشنده برای یک دستگاه:

  • مقدار BOARD_BOOT_HEADER_VERSION روی 3 یا بیشتر تنظیم کنید.

  • اگر دستگاه شما با GKI سازگار است، یا اگر از یک ramdisk عمومی فشرده‌شده با lz4 استفاده می‌کند، BOARD_RAMDISK_USE_LZ4 را روی true تنظیم کنید.

  • با توجه به ماژول‌های هسته که باید روی ramdisk سازنده قرار گیرند، اندازه BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE را روی اندازه مناسب برای دستگاه خود تنظیم کنید.

  • 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) .

برای گنجاندن چندین ramdisk از فروشندگان مختلف در 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 و 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 مربوط به vendor خواهد بود. اولی ramdisk "پیش‌فرض" است که شامل دایرکتوری DLKM baz و بقیه فایل‌های موجود در $(TARGET_VENDOR_RAMDISK_OUT) می‌شود. دومی dlkm_foobar ramdisk است که شامل دایرکتوری‌های DLKM به foo و bar است و --ramdisk_type به طور پیش‌فرض روی DLKM تنظیم شده است.