Auf dieser Seite werden Optimierungen besprochen, die Sie an Ihrer DTO-Implementierung vornehmen können, Einschränkungen gegen die Überlagerung des Stammknotens beschrieben und detailliert beschrieben, wie komprimierte Überlagerungen im DTBO-Image konfiguriert werden. Es enthält außerdem Beispiele für Implementierungsanweisungen und Code.
Kernel-Befehlszeile
Die ursprüngliche Kernel-Befehlszeile im Gerätebaum befindet sich im Knoten chosen/bootargs
. Der Bootloader muss diesen Speicherort mit anderen Quellen der Kernel-Befehlszeile verketten:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
DTO kann keine Werte aus Haupt-DT und Overlay-DT verketten, daher müssen Sie die Kernel-Befehlszeile des Haupt-DT in chosen/bootargs
und die Kernel-Befehlszeile des Overlay-DT in chosen/bootargs_ext
einfügen. Der Bootloader kann diese Speicherorte dann verketten und das Ergebnis an den Kernel übergeben.
main.dts | overlay.dts |
---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; | /dts-v1/; /plugin/; &chosen { bootargs_ext = "..."; }; |
libufdt
Während die neueste libfdt
DTO unterstützt, wird empfohlen, libufdt
zur Implementierung von DTO zu verwenden (AOSP-Quelle unter platform/system/libufdt
). libufdt
erstellt aus dem Flattened Device Tree (FDT) eine echte Baumstruktur (Un-Flattened Device Tree oder ufdt ), sodass die Zusammenführung zweier .dtb
Dateien von O(N 2 ) nach O(N) verbessert werden kann, wobei N ist die Anzahl der Knoten im Baum.
Leistungstest
In internen Tests von Google führt die Verwendung libufdt
auf 2405 .dtb
und 283 .dtbo
DT-Knoten zu Dateigrößen von 70.618 und 8.566 Bytes nach der Kompilierung. Im Vergleich zu einer von FreeBSD portierten DTO-Implementierung (124 ms Laufzeit) beträgt die DTO-Laufzeit libufdt
10 ms.
Leistungstests für Pixel-Geräte verglichen libufdt
und libfdt
. Der Effekt der Anzahl der Basisknoten ist ähnlich, weist jedoch die folgenden Unterschiede auf:
- 500 Overlay-Vorgänge (Anhängen oder Überschreiben) haben einen 6- bis 8-fachen Zeitunterschied
- 1000 Overlay-Vorgänge (Anhängen oder Überschreiben) haben einen 8- bis 10-fachen Zeitunterschied
Beispiel mit auf X gesetzter Anhängeanzahl:
Beispiel mit auf X gesetzter überschreibender Anzahl:
libufdt
wird mit einigen libfdt
APIs und Datenstrukturen entwickelt. Wenn Sie libufdt
verwenden, müssen Sie libfdt
einschließen und verknüpfen (Sie können jedoch in Ihrem Code die libfdt
API verwenden, um DTB oder DTBO zu betreiben).
libufdt DTO-API
Die Haupt-API für DTO in libufdt
lautet wie folgt:
struct fdt_header *ufdt_apply_overlay( struct fdt_header *main_fdt_header, size_t main_fdt_size, void *overlay_fdt, size_t overlay_size);
Der Parameter main_fdt_header
ist der Haupt-DT und overlay_fdt
ist der Puffer, der den Inhalt einer .dtbo
Datei enthält. Der Rückgabewert ist ein neuer Puffer, der den zusammengeführten DT enthält (oder null
im Fehlerfall). Der zusammengeführte DT wird in FDT formatiert, das Sie beim Starten des Kernels an den Kernel übergeben können.
Der neue Puffer aus dem Rückgabewert wird von dto_malloc()
erstellt, was Sie beim Portieren libufdt
in den Bootloader implementieren sollten. Referenzimplementierungen finden Sie unter sysdeps/libufdt_sysdeps_*.c
.
Einschränkungen für Root-Knoten
Sie können einen neuen Knoten oder eine neue Eigenschaft nicht über den Stammknoten des Haupt-DT legen, da Überlagerungsvorgänge auf Beschriftungen basieren. Da das Haupt-DT eine Beschriftung definieren muss und die Overlay-DT die Knoten zuweist, die mit Beschriftungen überlagert werden sollen, können Sie keine Beschriftung für den Wurzelknoten vergeben (und daher den Wurzelknoten nicht überlagern).
SoC-Anbieter müssen die Overlay-Fähigkeit des Haupt-DT definieren; ODM/OEMs können Knoten nur mit vom SoC-Anbieter definierten Labels anhängen oder überschreiben. Um dieses Problem zu umgehen, können Sie einen odm
Knoten unter dem Stammknoten im Basis-DT definieren, sodass alle ODM-Knoten im Overlay-DT neue Knoten hinzufügen können. Alternativ können Sie alle SoC-bezogenen Knoten im Basis-DT wie unten beschrieben in einem soc
Knoten unter dem Stammknoten platzieren:
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 { ... }; ... }; |
Verwendung komprimierter Overlays
Android 9 fügt Unterstützung für die Verwendung komprimierter Overlays im DTBO-Bild hinzu, wenn Version 1 des Gerätebaumtabellenheaders verwendet wird. Bei Verwendung des DTBO-Headers v1 geben die vier niedrigstwertigen Bits des Flags-Felds in dt_table_entry das Komprimierungsformat des DT-Eintrags an.
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 */ };
Derzeit werden zlib
und gzip
Komprimierungen unterstützt.
enum dt_compression_info { NO_COMPRESSION, ZLIB_COMPRESSION, GZIP_COMPRESSION };
Android 9 fügt dem VtsFirmwareDtboVerification
Test Unterstützung für das Testen komprimierter Overlays hinzu, um Ihnen bei der Überprüfung der Richtigkeit der Overlay-Anwendung zu helfen.
Beispiel-DTO-Implementierung
Die folgenden Anweisungen führen Sie durch eine Beispielimplementierung von DTO mit libufdt
(Beispielcode unten).
Beispiel-DTO-Anweisungen
- Beziehen Sie Bibliotheken ein. Um
libufdt
zu verwenden, schließen Sielibfdt
für Datenstrukturen und APIs ein:#include <libfdt.h> #include <ufdt_overlay.h>
- Haupt-BMK und Overlay-BMK laden. Laden Sie
.dtb
und.dtbo
vom Speicher in den Speicher (die genauen Schritte hängen von Ihrem Design ab). Zu diesem Zeitpunkt sollten Sie über den Puffer und die Größe von.dtb
/.dtbo
verfügen:main_size = my_load_main_dtb(main_buf, main_buf_size)
overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
- Überlagern Sie die DTs:
- Verwenden Sie
ufdt_install_blob()
, um den FDT-Header für den Haupt-DT zu erhalten:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- Rufen Sie
ufdt_apply_overlay()
für DTO auf, um einen zusammengeführten DT im FDT-Format zu erhalten:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size);
- Verwenden Sie
merged_fdt
, um die Größe vondtc_totalsize()
zu erhalten:merged_fdt_size = dtc_totalsize(merged_fdt);
- Übergeben Sie den zusammengeführten DT, um den Kernel zu starten:
my_kernel_entry(0, machine_type, merged_fdt);
- Verwenden Sie
Beispiel-DTO-Code
#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); }