בדף הזה מפורטות האופטימיזציות שאתם יכולים לבצע בהטמעת שכבת-העל של עץ המכשיר (DTO), הסבר על הגבלות מפני שכבות-על של צומת השורש ופרטים איך להגדיר שכבות-על דחוסות בתמונה של DTBO. הוא גם מספק דוגמה את ההוראות להטמעה ואת הקוד.
שורת הפקודה בליבה (Kernel)
שורת הפקודה המקורית של הליבה בעץ המכשיר (DT) ממוקמת
צומת chosen/bootargs
. תוכנת האתחול צריכה לשרשר את המחרוזת
המיקום שלו עם מקורות אחרים של שורת הפקודה בליבה (kernel):
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
ל-DTO לא ניתן לשרשר ערכים מה-DT הראשי ומשכבת ה-DT, כך
צריך להכניס את שורת הפקודה הבסיסית (kernel) של ה-DT הראשי
chosen/bootargs
ושורת הפקודה בליבה של שכבת-העל DT
chosen/bootargs_ext
עכשיו תוכנת האתחול יכולה לשרשר את
מיקומים ומעבירים את התוצאה לליבה.
Main.dts | שכבת-על.dts |
---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; |
/dts-v1/; /plugin/; &chosen { bootargs_ext = "..."; }; |
ליבופט
אומנם הגרסה העדכנית ביותר
libfdt
תומך ב-DTO, האם מומלץ להשתמש ב-libufdt
כדי להטמיע DTO
(מקור AOSP ב-
platform/system/libufdt
).
libufdt
בונה מבנה עץ אמיתי (עץ מכשיר לא שטוח,
או ufdt) מעץ המכשיר השטוחה (FDT), כדי שהוא יכול לשפר
מיזוג של שני קובצי .dtb
מ-O(N2) ל-O(N), כאשר N הוא
מספר הצמתים בעץ.
בדיקת ביצועים
בבדיקה הפנימית של Google, באמצעות libufdt
בתאריך 2405
צמתי DT של .dtbo
ו-.dtb
ו-283 מובילים לגודל הקבצים של הקבצים
70,618 ו-8,566 בייטים לאחר הידור. בהשוואה למדד
DTO
הטמעה נויד מ-FreeBSD (זמן ריצה של 124 אלפיות שנייה), libufdt
זמן הריצה של DTO הוא 10 אלפיות השנייה.
בדיקות הביצועים במכשירי Pixel בהשוואה ל-libufdt
ול-
libfdt
. ההשפעה של מספר צמתים הבסיסיים דומה אבל כוללת
את ההבדלים הבאים:
- 500 פעולות של שכבת-על (הוספה או שינוי מברירת המחדל) מקבלות פי 6 עד פי 8 הפרש
- לפעולות של 1,000 שכבת-על (צירוף או שינוי מברירת המחדל) יש זמן של פי 8 עד פי 10 הפרש
דוגמה שבה הספירה מצורפת מוגדרת ל-X:
איור 1. המספר שמצורף הוא X.
דוגמה עם ערך עקיפה מוגדר ל-X:
איור 2. הספירה לשינוי היא X.
האפליקציה libufdt
פותחה עם כמה ממשקי API ונתונים של libfdt
מבנים. כשמשתמשים ב-libufdt
, צריך לכלול ולקשר
libfdt
(עם זאת, בקוד שלכם אפשר להשתמש ברכיב libfdt
API להפעלת DTB או DTBO).
ממשק API של 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 בשכבת-העל מקצה את הצמתים לשכבת-על של תוויות, לא ניתן להוסיף תווית לצומת הרמה הבסיסית (root) (ולכן לא ניתן ליצור שכבת-על של הרמה הבסיסית (root) ).
ספקי SoC חייבים להגדיר את יכולת היצירה של שכבות-על של השידור הראשי. יצרני ציוד מקורי (ODM)/יצרני ציוד מקורי יכולים (OEM) בלבד
להוסיף או לשנות צמתים עם תוויות שהוגדרו על ידי ספק ה-SoC. בתור
כפתרון זמני, אפשר להגדיר צומת odm
מתחת
צומת הרמה הבסיסית (root) ב-DT הבסיסי, הפעלת כל צומתי ה-ODM בשכבת-העל של DT כדי להוסיף צמתים חדשים.
לחלופין, אפשר להכניס את כל הצמתים שקשורים ל-SoC ב-DT הבסיסי לתוך
צומת soc
מתחת לצומת של הרמה הבסיסית (root), כפי שמתואר בהמשך:
Main.dts | שכבת-על.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. כשמשתמשים בכותרת DTBO גרסה 1, ארבע הביטים המינימליים ביותר של שדה הדגלים ב-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
למבני נתונים ולממשקי API:#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()
אל DTO כדי לקבל 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);
- מעבירים את ה-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); }