Questa pagina illustra le ottimizzazioni che puoi apportare all'implementazione dell'overlay ad albero dei dispositivi (DTO), descrive le limitazioni alla sovrapposizione del nodo principale e descrive nel dettaglio come configurare overlay compressi nell'immagine DTBO. Fornisce anche esempi le istruzioni e il codice per l'implementazione.
Riga di comando kernel
La riga di comando originale del kernel nella struttura ad albero dei dispositivi (DT) si trova nella
chosen/bootargs
nodo. Il bootloader deve concatenare questa impostazione
con altre origini della riga di comando del kernel:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
Un DTO non può concatenare i valori del DT principale e del DT sovrapposto, perciò
devi inserire la riga di comando del kernel del DT principale
chosen/bootargs
e la riga di comando kernel del DT overlay in
chosen/bootargs_ext
. Il bootloader può quindi concatenare questi
più posizioni e passare il risultato al kernel.
main.dts | overlay.dts |
---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; |
/dts-v1/; /plugin/; &chosen { bootargs_ext = "..."; }; |
Libufdt
Anche se l'ultima versione
libfdt
supporta DTO, si consiglia di utilizzare libufdt
per implementare DTO
(Sorgente AOSP in
platform/system/libufdt
).
libufdt
crea una vera struttura ad albero (albero dei dispositivi non appiattito,
o ufdt) dalla struttura ad albero dei dispositivi bidimensionali (FDT), in modo da poter migliorare
unione di due file .dtb
da O(N2) a O(N), dove N è
di nodi nell'albero.
Test delle prestazioni
Nei test interni di Google, utilizzando libufdt
su 2405
.dtb
e 283 .dtbo
nodi DT generano dimensioni di file pari a
70.618 e 8.566 byte dopo la compilazione. Confrontato con un
DTO
implementazione portata da FreeBSD (124 ms di runtime), libufdt
Il tempo di esecuzione del DTO è di 10 ms.
I test delle prestazioni per i dispositivi Pixel hanno confrontato libufdt
e
libfdt
. L'effetto del numero di nodi base è simile, ma include
le seguenti differenze:
- 500 operazioni di sovrapposizione (aggiunta o override) tempi da 6 a 8x differenza
- 1000 operazioni di overlay (aggiunta o override) tempi da 8 a 10 volte differenza
Esempio con conteggio aggiunto impostato su X:
Figura 1. Il conteggio aggiunto è X.
Esempio con conteggio per l'override impostato su X:
Figura 2. Il conteggio per l'override è X.
libufdt
è sviluppato con alcune API e dati di libfdt
strutture. Quando utilizzi libufdt
, devi includere e collegare
libfdt
(tuttavia, nel tuo codice puoi utilizzare libfdt
API per il funzionamento di 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 che include i contenuti di
.dtbo
file. Il valore restituito è un nuovo buffer contenente
DT unito (o null
in caso di errore). Il DT unito è formattato
in FDT, che puoi passare al kernel all'avvio.
Il nuovo buffer del valore restituito viene creato da dto_malloc()
,
che dovresti implementare durante il trasferimento di libufdt
in 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à nel nodo principale del DT principale poiché le operazioni di overlay si basano sulle etichette. Poiché il DT principale deve definire e l'overlay DT assegna i nodi da sovrapporre alle etichette, non possono assegnare un'etichetta al nodo radice (e quindi non possono sovrapporsi al nodo radice ).
i fornitori di SoC devono definire la capacità di sovrapposizione del DT principale; Gli ODM/OEM possono solo
aggiungere o eseguire l'override dei nodi con etichette definite dal fornitore del SoC. Come
alternativa, puoi definire un nodo odm
nella
nodo radice nel DT di base, che consente a tutti i nodi ODM nel DT in overlay di aggiungere nuovi nodi.
In alternativa, potresti inserire tutti i nodi relativi a SoC nel DT di base in un
soc
nel nodo principale, 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 viene utilizzata la versione 1 dell'intestazione della tabella DT. Quando si utilizza l'intestazione DTBO v1, i quattro bit meno significativi del campo flags in dt_table_entry indica 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 */ };
Attualmente sono supportate le compressione zlib
e gzip
.
enum dt_compression_info { NO_COMPRESSION, ZLIB_COMPRESSION, GZIP_COMPRESSION };
Android 9 aggiunge il supporto per i test compressi
overlay al test VtsFirmwareDtboVerification
per aiutarti
verificare la correttezza dell'app di overlay.
Esempio di implementazione di DTO
Le seguenti istruzioni illustrano un'implementazione di esempio di DTO
con libufdt
(codice di esempio di seguito).
Istruzioni di esempio per DTO
- Includi librerie. Per utilizzare
libufdt
, includilibfdt
per strutture dati e API:#include <libfdt.h> #include <ufdt_overlay.h>
- Carica il DT principale e il DT overlay. Carica
.dtb
e.dtbo
dall'archiviazione alla memoria (i passaggi esatti dipendono dal progetto). A questo punto, Dovresti avere il buffer e la dimensione 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);
- Sovrapposizione dei DT:
- Utilizza
ufdt_install_blob()
per ottenere l'intestazione FDT per il DT principale:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- Chiama
ufdt_apply_overlay()
a DTO per ottenere un DT unito in FDT formato:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size);
- Usa
merged_fdt
per ottenere la dimensione 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
Esempio di codice 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); }