Esta página analiza las optimizaciones que puede realizar en su implementación de DTO, describe las restricciones contra la superposición del nodo raíz y detalla cómo configurar superposiciones comprimidas en la imagen de DTBO. También proporciona código e instrucciones de implementación de ejemplo.
Línea de comando del núcleo
La línea de comandos del kernel original en el árbol de dispositivos se encuentra en el nodo chosen/bootargs
. El gestor de arranque debe concatenar esta ubicación con otras fuentes de la línea de comandos del kernel:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
DTO no puede concatenar valores del DT principal y el DT superpuesto, por lo que debe colocar la línea de comando del kernel del DT principal en chosen/bootargs
y la línea de comando del kernel del DT superpuesto en chosen/bootargs_ext
. Bootloader luego puede concatenar estas ubicaciones y pasar el resultado al kernel.
principal.dts | superposición.dts |
---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; | /dts-v1/; /plugin/; &chosen { bootargs_ext = "..."; }; |
libufdt
Si bien la última versión de libfdt
es compatible con DTO, se recomienda usar libufdt
para implementar DTO (fuente de AOSP en platform/system/libufdt
). libufdt
crea una estructura de árbol real (árbol de dispositivos sin aplanar, o ufdt ) a partir del árbol de dispositivos aplanados (FDT), por lo que puede mejorar la fusión de dos archivos .dtb
de O(N 2 ) a O(N), donde N es el número de nodos en el árbol.
Pruebas de rendimiento
En las pruebas internas de Google, el uso de libufdt
en 2405 .dtb
y 283 .dtbo
DT nodos da como resultado tamaños de archivo de 70 618 y 8 566 bytes después de la compilación. En comparación con una implementación de DTO portada desde FreeBSD (tiempo de ejecución de 124 ms), el tiempo de ejecución de DTO de libufdt
es de 10 ms.
Las pruebas de rendimiento para dispositivos Pixel compararon libufdt
y libfdt
. El efecto del número de nodos base es similar, pero incluye las siguientes diferencias:
- 500 operaciones de superposición (añadir o anular) tienen una diferencia horaria de 6x a 8x
- 1000 operaciones superpuestas (añadir o anular) tienen una diferencia horaria de 8x a 10x
Ejemplo con el conteo agregado establecido en X:
Ejemplo con recuento anulado establecido en X:
libufdt
se desarrolla con algunas API y estructuras de datos de libfdt
. Al usar libufdt
, debe incluir y vincular libfdt
(sin embargo, en su código puede usar la API de libfdt
para operar DTB o DTBO).
API de DTO de libufdt
La API principal para DTO en libufdt
es la siguiente:
struct fdt_header *ufdt_apply_overlay( struct fdt_header *main_fdt_header, size_t main_fdt_size, void *overlay_fdt, size_t overlay_size);
El parámetro main_fdt_header
es el DT principal y overlay_fdt
es el búfer que contiene el contenido de un archivo .dtbo
. El valor devuelto es un nuevo búfer que contiene el DT fusionado (o null
en caso de error). El DT fusionado está formateado en FDT, que puede pasar al kernel cuando inicia el kernel.
El nuevo búfer a partir del valor devuelto lo crea dto_malloc()
, que debe implementar al transferir libufdt
al gestor de arranque. Para ver implementaciones de referencia, consulte sysdeps/libufdt_sysdeps_*.c
.
Restricciones del nodo raíz
No puede superponer un nuevo nodo o propiedad en el nodo raíz del IME principal porque las operaciones de superposición se basan en etiquetas. Debido a que el IME principal debe definir una etiqueta y el IME de superposición asigna los nodos para que se superpongan con etiquetas, no puede proporcionar una etiqueta para el nodo raíz (y, por lo tanto, no puede superponerse al nodo raíz).
Los proveedores de SoC deben definir la capacidad de superposición del DT principal; Los ODM/OEM solo pueden agregar o anular nodos con etiquetas definidas por el proveedor de SoC. Como solución alternativa, puede definir un nodo odm
debajo del nodo raíz en el DT base, lo que permite que todos los nodos ODM en el DT superpuesto agreguen nuevos nodos. Como alternativa, puede colocar todos los nodos relacionados con SoC en el DT base en un nodo soc
debajo del nodo raíz como se describe a continuación:
principal.dts | superposición.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 { ... }; ... }; |
Uso de superposiciones comprimidas
Android 9 agrega compatibilidad para usar superposiciones comprimidas en la imagen DTBO cuando se usa la versión 1 del encabezado de la tabla del árbol del dispositivo. Cuando se usa el encabezado DTBO v1, los cuatro bits menos significativos del campo de banderas en dt_table_entry indican el formato de compresión de la 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 */ };
Actualmente, se admiten las compresiones zlib
y gzip
.
enum dt_compression_info { NO_COMPRESSION, ZLIB_COMPRESSION, GZIP_COMPRESSION };
Android 9 agrega soporte para probar superposiciones comprimidas a la prueba VtsFirmwareDtboVerification
para ayudarlo a verificar la corrección de la aplicación de superposición.
Ejemplo de implementación de DTO
Las siguientes instrucciones lo guían a través de una implementación de muestra de DTO con libufdt
(código de muestra a continuación).
Ejemplo de instrucciones DTO
- Incluir bibliotecas. Para usar
libufdt
, incluyalibfdt
para estructuras de datos y API:#include <libfdt.h> #include <ufdt_overlay.h>
- Cargue el IME principal y el IME superpuesto. Cargue
.dtb
y.dtbo
desde el almacenamiento a la memoria (los pasos exactos dependen de su diseño). En este punto, debe tener el búfer y el tamaño 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);
- Superponga los DT:
- Use
ufdt_install_blob()
para obtener el encabezado FDT para el DT principal:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- Llame a
ufdt_apply_overlay()
a DTO para obtener un DT fusionado en formato FDT:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size);
- Use
merged_fdt
para obtener el tamaño dedtc_totalsize()
:merged_fdt_size = dtc_totalsize(merged_fdt);
- Pase el DT fusionado para iniciar el kernel:
my_kernel_entry(0, machine_type, merged_fdt);
- Use
Ejemplo 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); }