Optimisez les organisations de trafic de drogue

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) sont effectuées 8 fois à 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 transfert de données 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 superposer le 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 de la DT superposée 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

  1. Incluez les bibliothèques. Pour utiliser libufdt, incluez libfdt pour les structures de données et les API:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
    
  2. 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);
    
  3. Superposez les DT:
    1. 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;
      
    2. 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);
      
    3. Utilisez merged_fdt pour obtenir la taille de dtc_totalsize():
      merged_fdt_size = dtc_totalsize(merged_fdt);
      
    4. Transmettez le DT fusionné pour démarrer le noyau:
      my_kernel_entry(0, machine_type, merged_fdt);
      

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);
}