أقسام التشغيل الخاصة بالمورّد

قدّم نظام التشغيل Android 11 مفهوم "صورة النواة العامة" (GKI). لتفعيل إمكانية تشغيل أي جهاز باستخدام GKI، يمكن لأجهزة Android 11 استخدام الإصدار 3 من عنوان صورة التشغيل. في الإصدار 3، يتم استبعاد جميع المعلومات الخاصة بمورّد معيّن من القسم boot ونقلها إلى قسم vendor_boot جديد. يجب أن يتوافق جهاز ARM64 الذي يعمل بالإصدار 11 من نظام التشغيل Android على نواة Linux 5.4 مع القسم vendor_boot وتنسيق القسم boot المعدَّل لاجتياز الاختبار باستخدام GKI.

يمكن لأجهزة Android 12 استخدام الإصدار 4 من عنوان صورة التمهيد، الذي يتيح تضمين العديد من أقراص ramdisk الخاصة بالمورّد في القسم vendor_boot. يتم ربط أجزاء متعددة من ramdisk الخاص بالمورّد بعضها ببعض في قسم ramdisk الخاص بالمورّد. يُستخدَم جدول ramdisk خاص بالمورّد لوصف تخطيط قسم ramdisk الخاص بالمورّد والبيانات الوصفية لكل جزء من ramdisk الخاص بالمورّد.

بنية القسم

يتم تقسيم قسم التمهيد الخاص بالمورّد إلى قسمَين A/B باستخدام ميزة "التقسيم الافتراضي A/B"، كما تتم حمايته من خلال ميزة "التمهيد الآمن" في Android.

الإصدار 3

يتألف القسم من عنوان وملف ramdisk خاص بالمورّد ورمز ثنائي كبير لشجرة الأجهزة (DTB).

القسم عدد الصفحات
عنوان التشغيل الخاص بالمورّد (عدد الصفحات) n = (2112 + 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

الإصدار 4

يتألف القسم من عنوان وقسم مساحة التخزين المؤقت للذاكرة العشوائية الخاصة بالمورّد (الذي يتألف من جميع أجزاء مساحة التخزين المؤقت للذاكرة العشوائية الخاصة بالمورّد، والتي تم ربطها ببعضها البعض) وكتلة شجرة الأجهزة (DTB) وجدول مساحة التخزين المؤقت للذاكرة العشوائية الخاصة بالمورّد.

القسم عدد الصفحات
عنوان التشغيل الخاص بالمورّد (عدد الصفحات) 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
جدول 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 تحتوي أقراص RAM على مراجع للاسترداد. يجب أن يحمّل برنامج الإقلاع هذه الملفات في الذاكرة عند بدء التشغيل في وضع الاسترداد.
    • تحتوي مساحات التخزين المؤقت للذاكرة العشوائية (ramdisk) في VENDOR_RAMDISK_TYPE_DLKM على وحدات ديناميكية قابلة للتحميل في النواة.
  • ramdisk_name هو اسم فريد لقرص RAM.
  • board_id هو متجه لمعرّفات الأجهزة المحدّدة من المورّد.

توافُق برنامج الإقلاع

بما أنّ قسم vendor_boot يحتوي على معلومات (مثل حجم صفحة الفلاش والنواة وعناوين تحميل ramdisk وDTB نفسه) كانت متوفّرة سابقًا في قسم boot، يجب أن يتمكّن برنامج التشغيل من الوصول إلى قسمَي boot وvendor_boot للحصول على بيانات كافية لإكمال عملية التشغيل.

يجب أن يحمّل برنامج الإقلاع قرص RAM العام في الذاكرة فورًا بعد قرص RAM الخاص بالمورّد (تتيح تنسيقات CPIO وGzip وlz4 هذا النوع من التسلسل). لا تضبط محاذاة الصفحة لصورة ramdisk العامة أو تُدرِج أي مساحة أخرى بينها وبين نهاية ramdisk المورّد في الذاكرة. بعد أن يفك النواة، يستخرج الملف المتسلسل إلى initramfs، ما يؤدي إلى بنية ملفات عبارة عن قرص RAM عام مضاف إلى بنية ملفات قرص RAM الخاص بالمورّد.

بما أنّه يتم ربط ramdisk العام وramdisk المورّد، يجب أن يكونا بالتنسيق نفسه. تستخدم صورة التمهيد GKI قرصًا RAM عامًا مضغوطًا بتنسيق lz4، لذا يجب أن يستخدم الجهاز المتوافق مع GKI قرص RAM خاصًا بالمورّد مضغوطًا بتنسيق lz4. يظهر أدناه إعدادات هذه الميزة.

تم توضيح متطلبات برنامج الإقلاع اللازمة لتوفير إمكانية استخدام bootconfig في مقالة تنفيذ Bootconfig.

أقراص RAM متعددة خاصة بالمورّدين (الإصدار 4)

باستخدام الإصدار 4 من عنوان صورة التمهيد، يمكن لبرنامج التحميل اختيار مجموعة فرعية أو جميع أقراص RAM الخاصة بالمورّد لتحميلها كـ initramfs أثناء وقت التمهيد. يحتوي جدول ramdisk الخاص بالمورّد على البيانات الوصفية لكل ramdisk، ويمكن أن يساعد برنامج التشغيل في تحديد ramdisk التي سيتم تحميلها. يمكن لبرنامج التحميل تحديد ترتيب تحميل أقراص RAM الخاصة بالمورّدين المحدّدين، شرط أن يتم تحميل قرص RAM العام آخر مرة.

على سبيل المثال، يمكن لبرنامج التحميل التمهيدي عدم تحميل ramdisk البائع من النوع VENDOR_RAMDISK_TYPE_RECOVERY أثناء عملية التشغيل العادية للحفاظ على الموارد، وبالتالي يتم تحميل ramdisk البائع من النوع VENDOR_RAMDISK_TYPE_PLATFORM وVENDOR_RAMDISK_TYPE_DLKM فقط في الذاكرة. من ناحية أخرى، يتم تحميل أقراص ذاكرة الوصول العشوائي الخاصة بالمورّد من النوع VENDOR_RAMDISK_TYPE_PLATFORM وVENDOR_RAMDISK_TYPE_RECOVERY وVENDOR_RAMDISK_TYPE_DLKM في الذاكرة عند التشغيل في وضع الاسترداد.

بدلاً من ذلك، يمكن لبرنامج الإقلاع تجاهل جدول vendor ramdisk وتحميل قسم vendor ramdisk بالكامل. ويكون لهذا التأثير التأثير نفسه الناتج عن تحميل جميع أجزاء ramdisk الخاصة بالمورّدين في القسم vendor_boot.

إنشاء تطبيق دعم

لتنفيذ ميزة إمكانية تشغيل الجهاز من خلال البائع:

  • اضبط قيمة BOARD_BOOT_HEADER_VERSION على 3 أو أكبر.

  • اضبط BOARD_RAMDISK_USE_LZ4 على true إذا كان جهازك متوافقًا مع GKI أو إذا كان يستخدم قرصًا عامًا مضغوطًا بتنسيق 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).

لتضمين ملفات 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 إذا لم يتم تحديدها بشكل آخر.

لإنشاء موارد الاسترداد كقرص RAM مستقل 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 "تلقائي" يحتوي على دليل DLKM baz وبقية الملفات في $(TARGET_VENDOR_RAMDISK_OUT). أما الثاني فهو dlkm_foobar ramdisk، الذي يحتوي على أدلة DLKM foo وbar، ويتم ضبط --ramdisk_type تلقائيًا على DLKM.