این صفحه درباره بهینهسازیهایی که میتوانید در پیادهسازی رونهاد درخت دستگاه (DTO) انجام دهید بحث میکند، محدودیتهای مربوط به رونهاد کردن گره ریشه را شرح میدهد، و جزئیات نحوه پیکربندی رونهادهای فشرده در تصویر DTBO را ارائه میدهد. همچنین دستورالعملها و کد پیادهسازی نمونه را ارائه میدهد.
خط فرمان هسته
خط فرمان هسته اصلی در درخت دستگاه (DT) در گره
chosen/bootargs قرار دارد. راهانداز باید این مکان را با منابع دیگر خط فرمان هسته پیوند دهد:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
DTO نمیتواند مقادیر را از DT اصلی و DT همپوشانی بههم متصل کند، بنابراین
باید خط فرمان هسته DT اصلی را در
chosen/bootargs و خط فرمان هسته DT همپوشانی را در
chosen/bootargs_ext قرار دهید. سپس «راهانداز» میتواند این مکانها را بههم متصل کند
و نتیجه را به هسته منتقل کند.
| main.dts | overlay.dts |
|---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; |
/dts-v1/;
/plugin/;
&chosen {
bootargs_ext = "...";
}; |
libufdt
While the latest
libfdt
supports DTO, is it recommended to use libufdt to implement DTO
(AOSP source at
platform/system/libufdt).
libufdt builds a real tree structure (un-flattened device tree,
or ufdt) from the flattened device tree (FDT), so it can improve the
merging of two .dtb files from O(N2) to O(N), where N is the
number of nodes in the tree.
آزمایش عملکرد
در آزمایش داخلی Google، استفاده از libufdt در 2405
.dtb و 283 .dtbo گره DT منجر به اندازه فایل
۷۰٬۶۱۸ و ۸٬۵۶۶ بایت پساز کامپایل میشود. درمقایسه با
پیادهسازی
DTO منتقلشده از FreeBSD (زمان اجرای ۱۲۴ میلیثانیه)، libufdt
زمان اجرای DTO ۱۰ میلیثانیه است.
آزمایش عملکرد برای دستگاههای Pixel در مقایسه با libufdt و
libfdt. تعداد گرههای پایه اثر مشابه است، اما شامل
تفاوتهای زیر است:
- ۵۰۰ عملیات رونهاد (الحاق یا ملغی کردن) ۶ تا ۸ برابر تفاوت زمانی دارد
- ۱۰۰۰ عملیات همپوشانی (افزودن یا لغو) ۸ تا ۱۰ برابر تفاوت زمانی دارند
مثال با تعداد پیوست تنظیمشده روی X:

شکل ۱. تعداد پیوستها X است.
مثال با تعداد لغو تنظیمشده روی X:

شکل ۲. تعداد لغو X است.
libufdt با برخیاز دادهها و
ساختارهای میانای برنامهسازی کاربردی libfdt توسعه یافته است. هنگام استفاده از libufdt، باید libfdt را اضافه و پیوند دهید (بااینحال، در کدتان میتوانید از libfdt
API برای عملکرد DTB یا DTBO استفاده کنید).
libufdt DTO API
میانای برنامهسازی کاربردی اصلی برای DTO در 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 است. مقدار برگشتی یک بافر جدید حاوی DT ادغامشده است (یا null درصورت بروز خطا). DT ادغامشده در قالب FDT است که میتوانید هنگام شروع هسته به هسته منتقل کنید.
بافر جدید از مقدار برگشتی توسط dto_malloc() ایجاد میشود،
که باید هنگام انتقال libufdt به بارکننده آن را پیادهسازی کنید.
برای پیادهسازیهای مرجع، به
sysdeps/libufdt_sysdeps_*.c مراجعه کنید.
محدودیتهای گره ریشه
نمیتوانید گره یا دارایی جدیدی را روی گره ریشه DT اصلی رونهاد کنید زیرا عملیات رونهاد به برچسبها متکی است. ازآنجاییکه DT اصلی باید برچسبی را تعریف کند و DT رونهاد گرههایی را که باید با برچسبها رونهاد شوند اختصاص میدهد، نمیتوانید برای گره ریشه برچسبی ارائه دهید (و بنابراین نمیتوانید گره ریشه را رونهاد کنید).
فروشندگان SoC باید قابلیت رونهاد کردن DT اصلی را تعریف کنند؛ شرکتهای ODM/OEM فقط میتوانند گرهها را با برچسبهای تعریفشده توسط فروشنده SoC
پیوست یا ملغی کنند. بهعنوان
راهحل، میتوانید گره odm را زیر
گره ریشه در DT پایه تعریف کنید، تا همه گرههای ODM در DT همپوشان بتوانند گرههای جدید اضافه کنند.
یا میتوانید همه گرههای مربوط به SoC را در DT پایه در گره 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 هنگام استفاده از نسخه ۱ سرصفحه جدول DT، از استفاده از رونهادهای فشرده در تصویر DTBO پشتیبانی میکند. هنگام استفاده از DTBO header v1، چهار بیت کمارزش فیلد پرچمها در 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>
- «جدول دادههای» اصلی و رونهاد «جدول دادهها» را بار کنید.
.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);
- پوشاندن DTها:
- از
ufdt_install_blob()برای دریافت سرایند FDT برای DT اصلی استفاده کنید:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- برای دریافت DT ادغامشده در قالب FDT
، با
ufdt_apply_overlay()به DTO تماس بگیرید:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size); - برای دریافت اندازه
dtc_totalsize()ازmerged_fdtاستفاده کنید:merged_fdt_size = dtc_totalsize(merged_fdt);
- DT ادغامشده را برای شروع هسته ارسال کنید:
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); }