O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Otimizando DTOs

Esta página discute as otimizações que você pode fazer em sua implementação de DTO, descreve as restrições contra a sobreposição do nó raiz e detalha como configurar sobreposições compactadas na imagem DTBO. Ele também fornece instruções e código de implementação de amostra.

Linha de comando do kernel

A linha de comando do kernel original na árvore de dispositivo está localizado no chosen/bootargs nó. O bootloader deve concatenar este local com outras fontes de linha de comando do kernel:

/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};

DTO não pode valores concatenar da principal DT e sobreposição DT, por isso você deve colocar a linha de comando do kernel do DT principal chosen/bootargs ea linha de comando do kernel da sobreposição DT em chosen/bootargs_ext . O bootloader pode então concatenar esses locais e passar o resultado para o kernel.

main.dts overlay.dts
/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};
/dts-v1/;
/plugin/;

&chosen {
  bootargs_ext = "...";
};

libufdt

Enquanto o mais recente libfdt suporta DTO, é recomendado o uso de libufdt para implementar DTO (fonte AOSP na platform/system/libufdt ). libufdt constrói uma estrutura de árvore real (árvore dispositivo un-achatada, ou ufdt) a partir da árvore dispositivo achatada (FDT), de modo que pode melhorar a fusão dos dois .dtb ficheiros a partir de O (N 2) a O (N), onde N é o número de nós na árvore.

Teste de performance

Em testes internos do Google, usando libufdt em 2405 .dtb e 283 .dtbo DT nós resulta em tamanhos de 70,618 e 8,566 bytes após a compilação de arquivo. Em comparação com uma aplicação DTO portado do FreeBSD (124 ms de tempo de execução), libufdt DTO de tempo de execução é de 10 ms.

O teste de desempenho de dispositivos de pixel comparado libufdt e libfdt . O efeito do número de nós de base é semelhante, mas inclui as seguintes diferenças:

  • 500 operações de sobreposição (acrescentar ou substituir) têm uma diferença de tempo de 6x a 8x
  • 1.000 operações de sobreposição (anexar ou substituir) têm uma diferença de tempo de 8x a 10x

Exemplo com adição de contagem definida como X:

Figura 1. Appending contagem é X

Exemplo com contagem de substituição definida como X:

Figura 2. Substituindo contagem é X

libufdt é desenvolvido com alguns libfdt APIs e estruturas de dados. Ao usar libufdt , você deve incluir e ligação libfdt (no entanto, em seu código, você pode usar o libfdt API para operar DTB ou DTBO).

API libufdt DTO

A principal API para DTO em libufdt é a seguinte:

struct fdt_header *ufdt_apply_overlay(
        struct fdt_header *main_fdt_header,
        size_t main_fdt_size,
        void *overlay_fdt,
        size_t overlay_size);

O parâmetro main_fdt_header é o principal DT e overlay_fdt é o tampão que contém o conteúdo de um .dtbo arquivo. O valor de retorno é um novo tamp contendo o DT fundiu (ou null em caso de erro). O DT mesclado é formatado em FDT, que você pode passar para o kernel ao iniciar o kernel.

O novo tampão a partir do valor de retorno é criado por dto_malloc() , que você deve implementar ao portar libufdt em bootloader. Para implementações de referência, consulte sysdeps/libufdt_sysdeps_*.c .

Restrições do nó raiz

Você não pode sobrepor um novo nó ou propriedade no nó raiz do DT principal porque as operações de sobreposição dependem de rótulos. Como o DT principal deve definir um rótulo e o DT de sobreposição atribui os nós a serem sobrepostos com rótulos, você não pode dar um rótulo para o nó raiz (e, portanto, não pode sobrepor o nó raiz).

Os fornecedores de SoC devem definir a capacidade de sobreposição do DT principal; ODM / OEMs só podem anexar ou substituir nós com rótulos definidos pelo fornecedor SoC. Como solução alternativa, você pode definir um odm nó sob o nó raiz na base de DT, permitindo que todos os nós ODM em sobreposição DT para adicionar novos nós. Alternativamente, você pode colocar todos os nós relacionados com o SoC na base DT em um soc nó sob o nó raiz conforme descrito abaixo:

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 {
        ...
    };
    ...
};

Usando sobreposições compactadas

O Android 9 adiciona suporte para o uso de sobreposições compactadas na imagem DTBO ao usar a versão 1 do cabeçalho da tabela da árvore do dispositivo. Ao usar DTBO cabeçalho v1, os quatro bits menos significativos do campo bandeiras em dt_table_entry indicar o formato de compressão da entrada 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 */
};

Atualmente, zlib e gzip compressões são suportados.

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

Android 9 adiciona suporte para testar sobreposições comprimido ao VtsFirmwareDtboVerification teste para ajudá-lo a verificar a regularidade do pedido de sobreposição.

Exemplo de implementação de DTO

As instruções a seguir orientá-lo através de uma implementação de exemplo de DTO com libufdt (código de exemplo abaixo).

Instruções de amostra de DTO

  1. Inclui bibliotecas. Para uso libufdt , incluem libfdt para estruturas de dados e APIs:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
    
  2. Carregue o DT principal e o DT de sobreposição. Carga .dtb e .dtbo do armazenamento na memória (etapas exatas dependem do seu design). Neste ponto, você deve ter o buffer e tamanho 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. Sobreponha os DTs:
    1. Use ufdt_install_blob() para obter o cabeçalho FDT para DT principal:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
      
    2. Chamada ufdt_apply_overlay() para DTO para obter uma fundiu DT em formato FDT:
      merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                      overlay_buf, overlay_size);
      
    3. Use merged_fdt para obter o tamanho de dtc_totalsize() :
      merged_fdt_size = dtc_totalsize(merged_fdt);
      
    4. Passe o fundiu DT de iniciar o kernel:
      my_kernel_entry(0, machine_type, merged_fdt);
      

Amostra de código 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);
}