Questa pagina illustra le ottimizzazioni che puoi apportare all'implementazione dell'overlay di Device Tree (DTO), descrive le limitazioni relative all'overlay del nodo radice e spiega come configurare gli overlay compressi nell'immagine DTBO. Fornisce anche istruzioni e codice di implementazione di esempio.
Riga di comando del kernel
La riga di comando del kernel originale in Device Tree (DT) si trova nel
chosen/bootargs nodo. Il bootloader deve concatenare questa
posizione con altre origini della riga di comando del kernel:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
DTO non può concatenare i valori di DT principale e DT overlay, quindi
devi inserire la riga di comando del kernel di DT principale in
chosen/bootargs e la riga di comando del kernel di DT overlay in
chosen/bootargs_ext. Il bootloader può quindi concatenare queste
posizioni e passare il risultato al kernel.
| main.dts | overlay.dts |
|---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; |
/dts-v1/;
/plugin/;
&chosen {
bootargs_ext = "...";
}; |
libufdt
Sebbene l'ultima versione
libfdt
supporti DTO, è consigliabile utilizzare libufdt per implementare DTO
(origine AOSP in
platform/system/libufdt).
libufdt crea una struttura ad albero reale (Device Tree non appiattito,
o ufdt) dal Device Tree appiattito (FDT), quindi può migliorare l'
unione di due file .dtb da O(N2) a O(N), dove N è il
numero di nodi nell'albero.
Test del rendimento
Nei test interni di Google, l'utilizzo di libufdt su 2405
.dtb e 283 .dtbo nodi DT comporta dimensioni dei file di
70.618 e 8.566 byte dopo la compilazione. Rispetto a un'
DTO
implementazione trasferita da FreeBSD (runtime di 124 ms), libufdt
il runtime DTO è di 10 ms.
I test del rendimento per i dispositivi Pixel hanno confrontato libufdt e
libfdt. L'effetto del numero di nodi di base è simile, ma include
le seguenti differenze:
- 500 operazioni di overlay (aggiunta o override) hanno una differenza di tempo da 6 a 8 volte
- 1000 operazioni di overlay (aggiunta o override) hanno una differenza di tempo da 8 a 10 volte
Esempio con il conteggio di aggiunta impostato su X:

Figura 1. Il conteggio di aggiunta è X.
Esempio con il conteggio di override impostato su X:

Figura 2. Il conteggio di override è X.
libufdt è sviluppato con alcune libfdt API e strutture di dati. Quando utilizzi libufdt, devi includere e collegare
libfdt (tuttavia, nel codice puoi utilizzare l'API libfdt
per operare su DTB o DTBO).
API DTO libufdt
L'API principale per DTO in libufdt è la seguente:
struct fdt_header *ufdt_apply_overlay(
struct fdt_header *main_fdt_header,
size_t main_fdt_size,
void *overlay_fdt,
size_t overlay_size);
Il parametro main_fdt_header è il DT principale e
overlay_fdt è il buffer contenente i contenuti di un
.dtbo file. Il valore restituito è un nuovo buffer contenente il
DT unito (o null in caso di errore). Il DT unito è formattato
in FDT, che puoi passare al kernel all'avvio.
Il nuovo buffer dal valore restituito viene creato da dto_malloc(),
che devi implementare quando trasferisci libufdt nel bootloader.
Per le implementazioni di riferimento, consulta
sysdeps/libufdt_sysdeps_*.c.
Limitazioni del nodo radice
Non puoi sovrapporre un nuovo nodo o una nuova proprietà al nodo radice di DT principale perché le operazioni di overlay si basano sulle etichette. Poiché il DT principale deve definire un' etichetta e il DT overlay assegna le etichette ai nodi da sovrapporre, non puoi assegnare un'etichetta al nodo radice (e quindi non puoi sovrapporre il nodo radice ).
I fornitori di SoC devono definire la capacità di overlay di DT principale; gli ODM/OEM possono solo
aggiungere o sostituire i nodi con le etichette definite dal fornitore di SoC. Come
soluzione alternativa, puoi definire un odm nodo sotto il
nodo radice in DT di base, consentendo a tutti i nodi ODM in DT overlay di aggiungere nuovi nodi.
In alternativa, puoi inserire tutti i nodi correlati a SoC in DT di base in un
soc nodo sotto il nodo radice, come descritto di seguito:
| 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 { ... }; ... }; |
Utilizzare overlay compressi
Android 9 aggiunge il supporto per l'utilizzo di overlay compressi nell'immagine DTBO quando si utilizza la versione 1 dell'intestazione della tabella DT. Quando si utilizza l'intestazione DTBO v1, i quattro bit meno significativi del campo dei flag in dt_table_entry indicano il formato di compressione della voce 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 */ };
Al momento sono supportate le compressioni zlib e gzip.
enum dt_compression_info { NO_COMPRESSION, ZLIB_COMPRESSION, GZIP_COMPRESSION };
Android 9 aggiunge il supporto per il test degli overlay compressi
al test VtsFirmwareDtboVerification per aiutarti
a verificare la correttezza dell'app di overlay.
Esempio di implementazione DTO
Le seguenti istruzioni ti guidano attraverso un'implementazione di esempio di DTO
con libufdt (codice campione di seguito).
Istruzioni DTO di esempio
- Includi le librerie. Per utilizzare
libufdt, includilibfdtper le strutture di dati e le API:#include <libfdt.h> #include <ufdt_overlay.h>
- Carica DT principale e DT overlay. Carica
.dtbe.dtbodallo spazio di archiviazione in memoria (i passaggi esatti dipendono dalla tua progettazione). A questo punto, dovresti avere il buffer e le dimensioni di.dtb/.dtbo:main_size = my_load_main_dtb(main_buf, main_buf_size)
overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
- Sovrapponi i DT:
- Utilizza
ufdt_install_blob()per ottenere l'intestazione FDT per DT principale:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- Chiama
ufdt_apply_overlay()per DTO per ottenere un DT unito in formato FDT format:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size); - Utilizza
merged_fdtper ottenere le dimensioni didtc_totalsize():merged_fdt_size = dtc_totalsize(merged_fdt);
- Passa il DT unito per avviare il kernel:
my_kernel_entry(0, machine_type, merged_fdt);
- Utilizza
Codice DTO di esempio
#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); }