หน้านี้จะกล่าวถึงการเพิ่มประสิทธิภาพที่คุณทำได้กับการติดตั้งใช้งาน Device Tree Overlay (DTO) อธิบายข้อจำกัดในการซ้อนทับโหนดรูท และให้รายละเอียดเกี่ยวกับวิธี กำหนดค่าการซ้อนทับที่บีบอัดในอิมเมจ DTBO นอกจากนี้ ยังมีตัวอย่าง วิธีการติดตั้งใช้งานและโค้ดด้วย
บรรทัดคำสั่งเคอร์เนล
บรรทัดคำสั่งเคอร์เนลเดิมใน Device Tree (DT) จะอยู่ในโหนด
chosen/bootargs
Bootloader ต้องต่อตำแหน่งนี้
กับแหล่งที่มาอื่นๆ ของบรรทัดคำสั่งเคอร์เนล
/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
เวอร์ชันล่าสุด
libfdt
จะรองรับ DTO แต่เราขอแนะนำให้ใช้ libufdt
เพื่อใช้ DTO
(แหล่งที่มาของ AOSP ที่
platform/system/libufdt
)
libufdt
สร้างโครงสร้างแบบต้นไม้จริง (Device Tree ที่ไม่ได้ Flatten หรือ ufdt) จาก Device Tree ที่ Flatten (FDT) จึงช่วยปรับปรุง
การผสานไฟล์ .dtb
2 ไฟล์จาก 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 เท่า
- การดำเนินการซ้อนทับ (ต่อท้ายหรือลบล้าง) 1,000 รายการใช้เวลาต่างกัน 8-10 เท่า
ตัวอย่างที่มีการตั้งค่าการต่อท้ายจำนวนเป็น X
รูปที่ 1 การต่อท้ายจำนวนคือ X
ตัวอย่างที่มีการตั้งค่าการลบล้างจำนวนเป็น X
รูปที่ 2 การลบล้างจำนวนคือ X
libufdt
พัฒนาขึ้นด้วย API และโครงสร้างข้อมูลlibfdt
บางส่วน
เมื่อใช้ libufdt
คุณต้องรวมและลิงก์ libfdt
(อย่างไรก็ตาม ในโค้ด คุณสามารถใช้ libfdt
API เพื่อดำเนินการ DTB หรือ DTBO ได้)
libufdt DTO API
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
ไปยัง Bootloader
ดูการติดตั้งใช้งานอ้างอิงได้ที่
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 เพิ่มการรองรับการใช้การวางซ้อนที่บีบอัด ในรูปภาพ DTBO เมื่อใช้ส่วนหัวของตาราง DT เวอร์ชัน 1 เมื่อใช้ส่วนหัว DTBO v1 บิตที่มีนัยสำคัญน้อยที่สุด 4 บิตของฟิลด์แฟล็ก ใน 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);
- ซ้อนทับ DT ดังนี้
- ใช้
ufdt_install_blob()
เพื่อรับส่วนหัว FDT สำหรับ DT หลักmain_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- โทรหา
ufdt_apply_overlay()
เพื่อรับ DT ที่ผสานรวมในรูปแบบ FDTmerged_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); }