تتناول هذه الصفحة التحسينات التي يمكنك إجراؤها على تنفيذ تراكب شجرة الأجهزة (DTO)، وتوضّح القيود المفروضة على تراكب العقدة الجذر، وتفصّل كيفية ضبط التراكبات المضغوطة في صورة DTBO. ويوفّر أيضًا عيّنات من تعليمات التنفيذ والرمز البرمجي.
سطر أوامر النواة
يقع سطر أوامر النواة الأصلي في شجرة الأجهزة (DT) ضمن العقدة chosen/bootargs
. يجب أن يدمج برنامج التحميل هذا الموقع الجغرافي مع مصادر أخرى لسطر أوامر النواة:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
لا يمكن لملف DTO دمج القيم من ملف DT الرئيسي وملف DT المتراكب، لذا عليك وضع سطر أوامر النواة لملف DT الرئيسي في chosen/bootargs
وسطر أوامر النواة لملف DT المتراكب في chosen/bootargs_ext
. يمكن لبرنامج Bootloader بعد ذلك ربط هذه المواقع الجغرافية وتمرير النتيجة إلى النواة.
main.dts | overlay.dts |
---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; |
/dts-v1/; /plugin/; &chosen { bootargs_ext = "..."; }; |
libufdt
على الرغم من أنّ أحدث إصدار من
libfdt
يتوافق مع DTO، ننصح باستخدام libufdt
لتنفيذ DTO
(مصدر AOSP على
platform/system/libufdt
).
يبني libufdt
بنية شجرة حقيقية (شجرة أجهزة غير مسطّحة،
أو ufdt) من شجرة الأجهزة المسطّحة (FDT)، وبالتالي يمكنه تحسين
دمج ملفَي .dtb
من O(N2) إلى O(N)، حيث N هو
عدد العُقد في الشجرة.
اختبار الأداء
في الاختبارات الداخلية التي أجرتها Google، يؤدي استخدام libufdt
على 2405
.dtb
و283 عقدة .dtbo
DT إلى أحجام ملفات تبلغ
70,618 و8,566 بايت بعد التجميع. بالمقارنة مع تنفيذ DTO تم نقله من FreeBSD (وقت التشغيل 124 ملي ثانية)، يبلغ وقت تشغيل libufdt
DTO 10 ملي ثانية.
اختبار الأداء على أجهزة Pixel مقارنةً بـ libufdt
وlibfdt
تتشابه تأثيرات عدد العُقد الأساسية، ولكنها تتضمّن الاختلافات التالية:
- تتضمّن 500 عملية تراكب (إضافة أو تجاهل) فرقًا في الوقت يتراوح بين 6 و8 أضعاف
- تتضمّن 1000 عملية تراكب (إلحاق أو تجاهل) فرقًا في الوقت يتراوح بين 8 و10 أضعاف
مثال مع ضبط عدد الإلحاقات على X:
الشكل 1. عدد عمليات الإلحاق هو X.
مثال مع ضبط عدد عمليات الإلغاء على X:
الشكل 2. عدد عمليات التجاوز هو X.
تم تطوير libufdt
باستخدام بعض واجهات برمجة التطبيقات libfdt
وهياكل البيانات. عند استخدام libufdt
، يجب تضمين libfdt
وإضافة رابط إليه (مع ذلك، يمكنك استخدام واجهة برمجة التطبيقات libfdt
في الرمز البرمجي لتشغيل DTB أو DTBO).
libufdt DTO API
في ما يلي واجهة برمجة التطبيقات الرئيسية لتحويل البيانات إلى كائنات نقل البيانات في libufdt
:
struct fdt_header *ufdt_apply_overlay( struct fdt_header *main_fdt_header, size_t main_fdt_size, void *overlay_fdt, size_t overlay_size);
المَعلمة main_fdt_header
هي DT الرئيسية، وoverlay_fdt
هي المخزن المؤقت الذي يحتوي على محتويات ملف .dtbo
. قيمة العرض هي مخزن مؤقت جديد يحتوي على
البيانات المدمجة (أو null
في حال حدوث خطأ). يتم تنسيق شجرة الأجهزة المدمجة
في شجرة الأجهزة المسطّحة، ويمكنك تمريرها إلى النواة عند بدء تشغيل النواة.
يتم إنشاء المخزن المؤقت الجديد من قيمة الإرجاع بواسطة dto_malloc()
،
التي يجب تنفيذها عند نقل libufdt
إلى برنامج التحميل.
للاطّلاع على عمليات التنفيذ المرجعية، يُرجى الرجوع إلى
sysdeps/libufdt_sysdeps_*.c
.
القيود المفروضة على العقدة الأساسية
لا يمكنك إضافة عقدة أو سمة جديدة إلى العقدة الجذرية في شجرة البيانات الرئيسية لأنّ عمليات الإضافة تعتمد على التصنيفات. بما أنّ جدول البيانات الرئيسي يجب أن يحدّد تصنيفًا، ويحدّد جدول البيانات المتراكب العُقد التي سيتم تراكبها مع التصنيفات، لا يمكنك تقديم تصنيف للعقدة الجذر (وبالتالي لا يمكنك تراكب العقدة الجذر).
على مورّدي المنظومة على الرقاقة (SoC) تحديد إمكانية التراكب في شجرة الأجهزة الرئيسية، ولا يمكن للمصنّعين الأصليين للأجهزة أو مصنّعي التصميم الأصليين سوى إضافة أو تجاهل العُقد التي تحمل التصنيفات المحدّدة من قِبل مورّد المنظومة على الرقاقة. كحلّ بديل، يمكنك تحديد عقدة odm
ضمن عقدة الجذر في شجرة الأجهزة الأساسية، ما يتيح لجميع عقد ODM في شجرة الأجهزة المتراكبة إضافة عقد جديدة.
بدلاً من ذلك، يمكنك وضع جميع العُقد ذات الصلة بنظام SoC في شجرة الجهاز الأساسية ضمن العقدة soc
ضمن العقدة الجذر كما هو موضّح أدناه:
main.dts | overlay.dts |
---|---|
/dts-v1/; / { compatible = "corp,bar"; ... chosen: chosen { bootargs = "..."; }; /* nodes for all soc nodes */ soc { ... soc_device@0: soc_device@0 { compatible = "corp,bar"; ... }; ... }; odm: odm { /* reserved for overlay by odm */ }; }; |
/dts-v1/; /plugin/; / { }; &chosen { bootargs_ex = "..."; }; &odm { odm_device@0 { ... }; ... }; |
استخدام المحتوى المركّب المضغوط
يضيف نظام التشغيل Android 9 إمكانية استخدام تراكبات مضغوطة في صورة DTBO عند استخدام الإصدار 1 من عنوان جدول DT. عند استخدام الإصدار 1 من عنوان DTBO، تشير وحدات البت الأربع الأقل أهمية في حقل العلامات في dt_table_entry إلى تنسيق الضغط الخاص بإدخال DT.
struct dt_table_entry_v1 { uint32_t dt_size; uint32_t dt_offset; /* offset from head of dt_table_header */ uint32_t id; /* optional, must be zero if unused */ uint32_t rev; /* optional, must be zero if unused */ uint32_t flags; /* For version 1 of dt_table_header, the 4 least significant bits of 'flags' are used to indicate the compression format of the DT entry as per the enum 'dt_compression_info' */ uint32_t custom[3]; /* optional, must be zero if unused */ };
في الوقت الحالي، يمكن استخدام ضغط zlib
وgzip
.
enum dt_compression_info { NO_COMPRESSION, ZLIB_COMPRESSION, GZIP_COMPRESSION };
يضيف نظام التشغيل Android 9 إمكانية اختبار التراكبات المضغوطة إلى اختبار VtsFirmwareDtboVerification
لمساعدتك في التحقّق من صحة تطبيق التراكب.
نموذج لتنفيذ DTO
ترشدك التعليمات التالية خلال عملية تنفيذ نموذجية لـ DTO باستخدام libufdt
(الرمز النموذجي أدناه).
مثال على تعليمات DTO
- تضمين المكتبات لاستخدام
libufdt
، عليك تضمينlibfdt
لبُنى البيانات وواجهات برمجة التطبيقات:#include <libfdt.h> #include <ufdt_overlay.h>
- حمِّل جدول بيانات DT الرئيسي وجدول بيانات DT المتراكب. حمِّل
.dtb
و.dtbo
من مساحة التخزين إلى الذاكرة (تعتمد الخطوات الدقيقة على تصميمك). في هذه المرحلة، يجب أن يتوفّر لديك المخزن المؤقت وحجم.dtb
/.dtbo
:main_size = my_load_main_dtb(main_buf, main_buf_size)
overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
- تراكب أنواع البيانات:
- استخدِم
ufdt_install_blob()
للحصول على عنوان FDT لـ DT الرئيسي:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- اتّصِل بالرقم
ufdt_apply_overlay()
لطلب دمج DT في FDT بالتنسيق التالي:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size);
- استخدِم
merged_fdt
للحصول على حجمdtc_totalsize()
:merged_fdt_size = dtc_totalsize(merged_fdt);
- مرِّر شجرة الأجهزة المدمجة لبدء تشغيل النواة:
my_kernel_entry(0, machine_type, merged_fdt);
- استخدِم
نموذج رمز DTO
#include <libfdt.h> #include <ufdt_overlay.h> … { struct fdt_header *main_fdt_header; struct fdt_header *merged_fdt; /* load main dtb into memory and get the size */ main_size = my_load_main_dtb(main_buf, main_buf_size); /* load overlay dtb into memory and get the size */ overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size); /* overlay */ main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size; merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size); merged_fdt_size = dtc_totalsize(merged_fdt); /* pass to kernel */ my_kernel_entry(0, machine_type, merged_fdt); }