Cette page traite des optimisations que vous pouvez apporter à la mise en œuvre d'une superposition d'arborescence d'appareils (DTO). décrit les restrictions concernant la superposition du nœud racine et explique comment configurer des superpositions compressées dans l'image DTBO. Il fournit également des exemples les instructions d'implémentation et le code requis.
Ligne de commande du noyau
La ligne de commande du noyau d'origine dans l'arborescence de périphériques (DT) se trouve dans le
Nœud chosen/bootargs
. Le bootloader doit concaténer ceci
emplacement avec d'autres sources de la ligne de commande du noyau:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
DTO ne peut pas concaténer les valeurs de la DT principale et du DT superposé. Par conséquent,
vous devez placer la ligne de commande
du noyau du DT principal dans
chosen/bootargs
et la ligne de commande du noyau
de la DT superposée dans
chosen/bootargs_ext
Le bootloader peut ensuite concaténer
et de transmettre le résultat au noyau.
main.dts | superposition.dts |
---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; |
/dts-v1/; /plugin/; &chosen { bootargs_ext = "..."; }; |
Libufdt
Bien que les dernières
libfdt
prend en charge DTO, est-il recommandé d'utiliser libufdt
pour implémenter DTO
(source AOSP à l'adresse
platform/system/libufdt
).
libufdt
crée une véritable arborescence (arborescence d'appareils non aplatie,
ou ufdt) de l'arborescence des appareils aplatis (FDT), afin d'améliorer
fusion de deux fichiers .dtb
de O(N2) à O(N), où N est le
le nombre de nœuds dans l'arborescence.
Tests de performances
Lors des tests internes de Google, avec libufdt
sur 2405
Avec .dtb
et 283 nœuds de transfert de données .dtbo
, vous obtenez des tailles de fichiers de
70 618 et 8 566 octets après la compilation. Par rapport à une
DTO
implémentation transférée à partir de FreeBSD (environnement d'exécution de 124 ms), libufdt
La durée d'exécution de DTO est de 10 ms.
Les tests de performance des appareils Pixel ont comparé libufdt
et
libfdt
L'effet du nombre de nœuds de base est similaire, mais inclut
les différences suivantes:
- 500 opérations de superposition (ajout ou remplacement) s'appliquent 6 à 8 fois différence
- 1 000 opérations de superposition (ajout ou remplacement) ont lieu 8 à 10 fois différence
Exemple avec le nombre d'ajouts défini sur X:
Figure 1 : Le nombre d'ajouts est X.
Exemple avec le nombre de remplacement défini sur X:
Figure 2. Nombre de remplacements : X.
libufdt
est développé avec des données et des API libfdt
.
différentes. Lorsque vous utilisez libufdt
, vous devez inclure et associer
libfdt
(toutefois, dans votre code, vous pouvez utiliser la libfdt
API pour utiliser le ciblage par niveau d'appareil.
API libufdt DTO
Voici la principale API pour les organisations de trafic de drogue dans 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);
Le paramètre main_fdt_header
est la DT principale et
overlay_fdt
est le tampon contenant le contenu d'une
.dtbo
. La valeur renvoyée est un nouveau tampon contenant le
DT fusionné (ou null
en cas d'erreur). Le transfert de données fusionné est mis en forme.
dans FDT, que vous pouvez transmettre
au noyau lors de son démarrage.
Le nouveau tampon de la valeur renvoyée est créé par dto_malloc()
,
que vous devez implémenter lors du portage de libufdt
dans le bootloader.
Pour obtenir des exemples d'implémentations, consultez
sysdeps/libufdt_sysdeps_*.c
Restrictions concernant les nœuds racines
Vous ne pouvez pas superposer un nouveau nœud ou une nouvelle propriété dans le nœud racine du DT principal. car les opérations de superposition reposent sur des étiquettes. Comme la DT principale doit définir une et que le transfert de données de superposition attribue des étiquettes aux nœuds, vous ne peut pas attribuer d'étiquette au nœud racine (et ne peut donc pas se superposer au nœud racine du nœud).
Les fournisseurs de SoC doivent définir la capacité de superposition de la DT principale ; Les ODM/OEM peuvent uniquement
ajouter ou remplacer des nœuds avec des étiquettes définies par le fournisseur du SoC. En tant que
une solution de contournement, vous pouvez définir un nœud odm
sous
nœud racine dans le transfert de données de base, permettant à tous les nœuds ODM dans le transfert de données de superposition d'ajouter de nouveaux nœuds.
Vous pouvez aussi placer tous les nœuds liés au SoC dans le DT de base dans un
soc
sous le nœud racine, comme décrit ci-dessous:
main.dts | superposition.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 { ... }; ... }; |
Utiliser des superpositions compressées
Android 9 permet désormais d'utiliser des superpositions compressées. dans l'image DTBO lors de l'utilisation de la version 1 de l'en-tête du tableau de transfert de données. Lorsque vous utilisez l'en-tête DTBO v1, les quatre bits les moins significatifs du champ des indicateurs dans dt_table_entry indiquent le format de compression de l'entrée de transfert de données.
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 */ };
Actuellement, les compressions zlib
et gzip
sont acceptées.
enum dt_compression_info { NO_COMPRESSION, ZLIB_COMPRESSION, GZIP_COMPRESSION };
Android 9 prend en charge les tests compressés
des superpositions au test VtsFirmwareDtboVerification
pour vous aider
vérifier l'exactitude de l'application superposée.
Exemple d'implémentation DTO
Les instructions suivantes vous guident à travers un exemple d'implémentation de DTO
avec libufdt
(exemple de code ci-dessous).
Exemples d'instructions pour les DTO
- Incluez les bibliothèques. Pour utiliser
libufdt
, incluezlibfdt
pour les structures de données et les API:#include <libfdt.h> #include <ufdt_overlay.h>
- Chargez la DT principale et la DT superposée. Charger
.dtb
et.dtbo
du stockage en mémoire (les étapes exactes dépendent de votre conception). À ce stade, Vous devriez obtenir un tampon et une taille de.dtb
/.dtbo
:main_size = my_load_main_dtb(main_buf, main_buf_size)
overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
- Superposez les DT:
<ph type="x-smartling-placeholder">
- </ph>
- Utilisez
ufdt_install_blob()
afin d'obtenir l'en-tête FDT pour la DT principale:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- Appeler
ufdt_apply_overlay()
vers DTO pour obtenir un transfert de données fusionné dans FDT format:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size);
- Utilisez
merged_fdt
pour obtenir la taille dedtc_totalsize()
:merged_fdt_size = dtc_totalsize(merged_fdt);
- Transmettez le DT fusionné pour démarrer le noyau:
my_kernel_entry(0, machine_type, merged_fdt);
- Utilisez
Exemple de code 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); }