หน้านี้กล่าวถึงการปรับให้เหมาะสมที่คุณสามารถทำได้กับการใช้งาน DTO ของคุณ อธิบายข้อจำกัดในการซ้อนทับโหนดรูท และรายละเอียดวิธีกำหนดค่าการซ้อนทับที่บีบอัดในอิมเมจ DTBO นอกจากนี้ยังมีคำแนะนำและโค้ดการใช้งานตัวอย่างอีกด้วย
บรรทัดคำสั่งเคอร์เนล
บรรทัดคำสั่งเคอร์เนลดั้งเดิมในแผนผังอุปกรณ์อยู่ในโหนด chosen/bootargs
bootloader ต้องเชื่อมตำแหน่งนี้เข้ากับแหล่งอื่นของบรรทัดคำสั่งเคอร์เนล:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
DTO ไม่สามารถ เชื่อมค่าจาก DT หลักและโอเวอร์เลย์ DT ได้ ดังนั้นคุณต้องใส่บรรทัดคำสั่งเคอร์เนลของ DT หลักใน chosen/bootargs
และบรรทัดคำสั่งเคอร์เนลของ Overlay 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(N 2 ) ถึง O(N) โดยที่ N คือจำนวนโหนดในแผนผัง
การทดสอบประสิทธิภาพ
ในการทดสอบภายในของ Google การใช้ libufdt
บนโหนด 2405 .dtb
และ 283 .dtbo
DT จะทำให้ไฟล์มีขนาด 70,618 และ 8,566 ไบต์หลังจากการคอมไพล์ เมื่อเปรียบเทียบกับ การใช้งาน DTO ที่ย้ายจาก FreeBSD (รันไทม์ 124 ms) รันไทม์ libufdt
DTO คือ 10 ms
การทดสอบประสิทธิภาพสำหรับอุปกรณ์ Pixel เปรียบเทียบ libufdt
และ libfdt
จำนวนของเอฟเฟกต์โหนดฐานจะใกล้เคียงกัน แต่รวมถึงความแตกต่างดังต่อไปนี้:
- การดำเนินการซ้อนทับ 500 รายการ (ผนวกหรือแทนที่) มีความแตกต่างของเวลา 6x ถึง 8x
- การดำเนินการซ้อนทับ 1,000 ครั้ง (ผนวกหรือแทนที่) มีความแตกต่างของเวลา 8x ถึง 10x
ตัวอย่างที่ตั้งค่าการนับต่อท้ายเป็น X:
ตัวอย่างที่มีการแทนที่การนับที่ตั้งค่าเป็น X:
libufdt
ได้รับการพัฒนาด้วย libfdt
API และโครงสร้างข้อมูลบางตัว เมื่อใช้ 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 เมื่อใช้เวอร์ชัน 1 ของส่วนหัวตารางแผนผังอุปกรณ์ เมื่อใช้ส่วนหัว DTBO 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' will be 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()
ไปที่ 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); }