Trang này thảo luận về những cách tối ưu hoá mà bạn có thể thực hiện cho việc triển khai lớp phủ cây thiết bị (DTO), mô tả các hạn chế đối với việc che phủ nút gốc và chi tiết cách định cấu hình lớp phủ nén trong hình ảnh DTBO. Công cụ này cũng cung cấp các mẫu mã và hướng dẫn triển khai.
Dòng lệnh kernel
Dòng lệnh kernel ban đầu trong cây thiết bị (DT) nằm trong
Nút chosen/bootargs
. Trình tải khởi động phải nối thuộc tính này với nhau
vị trí bằng các nguồn khác của dòng lệnh kernel:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
DTO không thể nối các giá trị từ DT chính và lớp phủ DT, vì vậy
bạn phải đặt dòng lệnh kernel của DT chính vào
chosen/bootargs
và dòng lệnh nhân của lớp phủ DT trong
chosen/bootargs_ext
. Sau đó, trình tải khởi động có thể nối các thông số này
vị trí và truyền kết quả đến nhân.
main.dts | lớp phủ.dts |
---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; |
/dts-v1/; /plugin/; &chosen { bootargs_ext = "..."; }; |
libufdt
Trong khi những giá trị mới nhất
libfdt
hỗ trợ DTO, bạn nên sử dụng libufdt
để triển khai DTO
(Nguồn AOSP (Dự án nguồn mở Android) tại
platform/system/libufdt
).
libufdt
xây dựng một cấu trúc cây thực (cây thiết bị không được làm phẳng,
hoặc ufdt) từ cây thiết bị đã làm phẳng (FDT), nhờ đó, công cụ này có thể cải thiện
hợp nhất hai tệp .dtb
từ O(N2) với O(N, trong đó N là phần tử
số nút trong cây.
Kiểm thử hiệu suất
Trong thử nghiệm nội bộ của Google, sử dụng libufdt
trên 2405
.dtb
và 283 .dtbo
nút DT dẫn đến kích thước tệp là
70.618 và 8.566 byte sau khi biên dịch. So với
Quản lý hoạt động kỹ thuật số
triển khai được chuyển từ FreeBSD (thời gian chạy 124 mili giây), libufdt
Thời gian chạy DTO là 10 mili giây.
Kết quả kiểm tra hiệu suất cho thiết bị Pixel so sánh libufdt
và
libfdt
. Số lượng nút cơ sở hiệu ứng tương tự nhau, nhưng bao gồm
những điểm khác biệt sau:
- 500 thao tác lớp phủ (nối hoặc ghi đè) hoạt động có thời gian gấp 6 đến 8 lần mức chênh lệch
- 1000 thao tác lớp phủ (nối hoặc ghi đè) có thời gian từ 8 đến 10 lần mức chênh lệch
Ví dụ về số lượng thêm được đặt thành X:
Hình 1. Số lượng đang thêm là X.
Ví dụ về trường hợp số lượng ghi đè được đặt thành X:
Hình 2. Số lượng ghi đè là X.
libufdt
được phát triển bằng một số API và dữ liệu libfdt
cấu trúc. Khi sử dụng libufdt
, bạn phải bao gồm và liên kết
libfdt
(tuy nhiên, trong mã của mình, bạn có thể sử dụng libfdt
API để vận hành DTB hoặc DTBO).
API DTO libufdt
Sau đây là API chính cho DTO trong 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);
Tham số main_fdt_header
là DT chính và
overlay_fdt
là vùng đệm chứa nội dung của
.dtbo
. Giá trị trả về là một vùng đệm mới có chứa
DT hợp nhất (hoặc null
trong trường hợp xảy ra lỗi). DT hợp nhất đã được định dạng
trong FDT. Bạn có thể truyền URL này đến hạt nhân khi khởi động hạt nhân.
Vùng đệm mới từ giá trị trả về do dto_malloc()
tạo,
mà bạn nên triển khai khi chuyển libufdt
vào trình tải khởi động.
Để biết cách triển khai tài liệu tham khảo, hãy tham khảo
sysdeps/libufdt_sysdeps_*.c
.
Các hạn chế đối với nút gốc
Bạn không thể phủ một nút hoặc thuộc tính mới vào nút gốc của DT chính bởi vì các thao tác lớp phủ đều dựa vào nhãn. Vì DT chính phải xác định và lớp phủ DT sẽ gán các nút cần phủ nhãn, bạn không thể cung cấp nhãn cho nút gốc (và do đó không thể phủ lên nút gốc nút).
Nhà cung cấp hệ thống SoC phải xác định khả năng bao phủ của DT chính; ODM/OEM chỉ có thể
thêm hoặc ghi đè các nút có nhãn do nhà cung cấp SoC xác định. Là một
để giải quyết sự cố này, bạn có thể xác định nút odm
trong
nút gốc trong DT cơ sở, cho phép tất cả các nút ODM trong DT lớp phủ để thêm các nút mới.
Ngoài ra, bạn có thể đặt tất cả các nút liên quan đến SoC trong DT cơ sở vào một
Nút soc
bên dưới nút gốc như mô tả bên dưới:
main.dts | lớp phủ.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 { ... }; ... }; |
Dùng lớp phủ nén
Android 9 hỗ trợ thêm việc sử dụng lớp phủ nén trong hình ảnh DTBO khi sử dụng phiên bản 1 của tiêu đề bảng DT. Khi sử dụng tiêu đề DTBO v1, 4 bit có ý nghĩa nhỏ nhất của trường cờ trong dt_table_entry cho biết định dạng nén của mục nhập 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 */ };
Hiện tại, chúng tôi hỗ trợ định dạng nén zlib
và gzip
.
enum dt_compression_info { NO_COMPRESSION, ZLIB_COMPRESSION, GZIP_COMPRESSION };
Android 9 bổ sung tính năng hỗ trợ cho việc kiểm thử tệp nén
lớp phủ cho thử nghiệm VtsFirmwareDtboVerification
để giúp bạn
xác minh tính chính xác của ứng dụng lớp phủ.
Triển khai DTO mẫu
Các hướng dẫn sau đây sẽ hướng dẫn bạn một ví dụ về cách triển khai DTO
với libufdt
(mã mẫu bên dưới).
Hướng dẫn mẫu về DTO
- Bao gồm thư viện. Để sử dụng
libufdt
, hãy thêmlibfdt
cho cấu trúc dữ liệu và API:#include <libfdt.h> #include <ufdt_overlay.h>
- Tải DT chính và lớp phủ DT. Tải
.dtb
và.dtbo
từ dung lượng lưu trữ sang bộ nhớ (các bước chính xác tuỳ thuộc vào thiết kế của bạn). Tại thời điểm này, bạn sẽ có vùng đệm và dung lượng.dtb
/.dtbo
:main_size = my_load_main_dtb(main_buf, main_buf_size)
overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
- Lớp phủ DT:
- Sử dụng
ufdt_install_blob()
để lấy tiêu đề FDT cho DT chính:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- Gọi
ufdt_apply_overlay()
đến DTO để lấy DT đã hợp nhất trong FDT định dạng:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size);
- Sử dụng
merged_fdt
để lấy kích thước củadtc_totalsize()
:merged_fdt_size = dtc_totalsize(merged_fdt);
- Truyền DT đã hợp nhất để khởi động nhân:
my_kernel_entry(0, machine_type, merged_fdt);
- Sử dụng
Mã DTO mẫu
#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); }