На этой странице обсуждаются оптимизации, которые вы можете внести в реализацию наложения дерева устройств (DTO), описываются ограничения на наложение корневого узла и подробно описано, как настроить сжатые наложения в образе DTBO. Он также предоставляет примеры инструкций по реализации и код.
Командная строка ядра
Исходная командная строка ядра в дереве устройств (DT) расположена в узле chosen/bootargs
. Загрузчик должен объединить это местоположение с другими источниками командной строки ядра:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
DTO не может объединить значения из основного DT и Overlay DT, поэтому вы должны поместить командную строку ядра основного DT в chosen/bootargs
и командную строку ядра наложного DT в chosen/bootargs_ext
. Затем загрузчик может объединить эти местоположения и передать результат ядру.
main.dts | оверлей.dts |
---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; | /dts-v1/; /plugin/; &chosen { bootargs_ext = "..."; }; |
libufdt
Хотя последняя версия libfdt
поддерживает DTO, рекомендуется ли использовать libufdt
для реализации DTO (исходный код AOSP по адресу platform/system/libufdt
). libufdt
создает реальную структуру дерева (дерево устройств без флаттену, или UFDT ) из сплющенного дерева устройств (FDT), поэтому оно может улучшить слияние двух файлов .dtb
от O (n 2 ) до O (n), где n n — количество узлов в дереве.
Тестирование производительности
По данным внутреннего тестирования Google, использование libufdt
на узлах DT 2405 .dtb
и 283 .dtbo
приводит к получению размеров файлов 70 618 и 8 566 байт после компиляции. По сравнению с реализацией DTO, перенесенной из FreeBSD (время выполнения 124 мс), время выполнения DTO libufdt
составляет 10 мс.
Тестирование производительности устройств Pixel сравнивало libufdt
и libfdt
. Эффект количества базовых узлов аналогичен, но включает в себя следующие различия:
- 500 операций наложения (добавления или переопределения) имеют разницу во времени от 6 до 8 раз.
- 1000 операций наложения (добавления или переопределения) имеют разницу во времени от 8 до 10 раз.
Пример с добавлением счетчика, установленного в X:
Рисунок 1. Добавляемый счетчик равен X.
Пример с переопределяющим счетчиком, установленным на X:
Рисунок 2. Переопределяющее значение равно X.
libufdt
разработан с использованием некоторых API-интерфейсов libfdt
и структур данных. При использовании libufdt
вы должны включить и связать libfdt
(однако в вашем коде вы можете использовать API libfdt
для работы с DTB или DTBO).
API-интерфейс libufdt DTO
Основной API для DTO в 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);
Параметр main_fdt_header
— это основное ОУ, а overlay_fdt
— это буфер, содержащий содержимое файла .dtbo
. Возвращаемое значение — это новый буфер, содержащий объединенное ОУ (или null
в случае ошибки). Объединенное DT форматируется в FDT, которое вы можете передать ядру при запуске ядра.
Новый буфер из возвращаемого значения создается с помощью dto_malloc()
, который вы должны реализовать при портировании libufdt
в загрузчик. Справочные реализации см. в sysdeps/libufdt_sysdeps_*.c
.
Ограничения корневого узла
Вы не можете наложить новый узел или свойство на корневой узел основного ОУ, поскольку операции наложения зависят от меток. Поскольку основное ОУ должно определять метку, а ОУ наложения назначает узлы, на которые будут наложены метки, вы не можете задать метку для корневого узла (и, следовательно, не можете наложить корневой узел).
Поставщики SoC должны определить возможность наложения основного ОУ; ODM/OEM могут только добавлять или переопределять узлы с метками, определенными поставщиком SoC. В качестве обходного пути вы можете определить узел odm
под корневым узлом в базовом DT, позволяя всем узлам ODM в наложенном DT добавлять новые узлы. В качестве альтернативы вы можете поместить все узлы, связанные с SoC, в базовом DT в узел soc
под корневым узлом, как описано ниже:
main.dts | оверлей.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 { ... }; ... }; |
Используйте сжатые наложения
В Android 9 добавлена поддержка использования сжатых наложений в изображении DTBO при использовании версии 1 заголовка таблицы DT. При использовании заголовка DTBO v1 четыре младших бита поля флагов в dt_table_entry указывают формат сжатия записи 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 */ };
В настоящее время поддерживаются сжатия zlib
и gzip
.
enum dt_compression_info { NO_COMPRESSION, ZLIB_COMPRESSION, GZIP_COMPRESSION };
В Android 9 добавлена поддержка тестирования сжатых наложений в тест VtsFirmwareDtboVerification
, чтобы помочь вам проверить правильность приложения наложения.
Пример реализации DTO
Следующие инструкции проведут вас через пример реализации DTO с libufdt
(пример кода ниже).
Примеры инструкций DTO
- Включите библиотеки. Чтобы использовать
libufdt
, включитеlibfdt
для структур данных и API:#include <libfdt.h> #include <ufdt_overlay.h>
- Загрузите основное ОУ и наложенное ОУ. Загрузите
.dtb
и.dtbo
из хранилища в память (точные шаги зависят от вашего дизайна). На этом этапе у вас должен быть буфер и размер.dtb
/.dtbo
:main_size = my_load_main_dtb(main_buf, main_buf_size)
overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
- Наложение DT:
- Используйте
ufdt_install_blob()
, чтобы получить заголовок FDT для основного DT:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- Вызовите
ufdt_apply_overlay()
в DTO, чтобы получить объединенное DT в формате FDT:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size);
- Используйте
merged_fdt
, чтобы получить размерdtc_totalsize()
:merged_fdt_size = dtc_totalsize(merged_fdt);
- Передайте объединенное DT для запуска ядра:
my_kernel_entry(0, machine_type, merged_fdt);
- Используйте
Пример кода 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); }
На этой странице обсуждается оптимизация, которую вы можете сделать в реализации наложения дерева устройств (DTO), описывает ограничения против наложения корневого узла и подробно, как настроить сжатые наложения в изображении DTBO. Он также предоставляет примеры инструкций и кода реализации.
Командная строка ядра
The original kernel command line in device tree (DT) is located in the chosen/bootargs
node. The bootloader must concatenate this location with other sources of kernel command line:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
DTO не может объединить значения из основного DT и Overlay DT, поэтому вы должны поместить командную строку ядра основного DT в chosen/bootargs
и командную строку ядра наложного DT в chosen/bootargs_ext
. Затем загрузчик может объединить эти местоположения и передать результат ядру.
main.dts | оверлей.dts |
---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; | /dts-v1/; /plugin/; &chosen { bootargs_ext = "..."; }; |
либуфдт
Хотя последняя версия libfdt
поддерживает DTO, рекомендуется ли использовать libufdt
для реализации DTO (исходный код AOSP по адресу platform/system/libufdt
). libufdt
создает реальную древовидную структуру (несведенное дерево устройств или ufdt ) из плоского дерева устройств (FDT), поэтому он может улучшить объединение двух файлов .dtb
из O(N 2 ) в O(N), где N — количество узлов в дереве.
Тестирование производительности
По данным внутреннего тестирования Google, использование libufdt
на узлах DT 2405 .dtb
и 283 .dtbo
приводит к получению размеров файлов 70 618 и 8 566 байт после компиляции. По сравнению с реализацией DTO, перенесенной из FreeBSD (время выполнения 124 мс), время выполнения DTO libufdt
составляет 10 мс.
При тестировании производительности устройств Pixel сравнивались libufdt
и libfdt
. Эффект количества базовых узлов аналогичен, но включает в себя следующие различия:
- Операции 500 наложений (добавление или переопределение) имеют разницу во времени от 6x до 8x
- 1000 Overlay (добавление или переопределение)
Пример с добавлением счетчика, установленного в X:
Рисунок 1. Добавляемый счетчик равен X.
Пример с переопределяющим счетчиком, установленным на X:
Рисунок 2. Число переопределения — X.
libufdt
разработан с помощью некоторых API libfdt
и структур данных. При использовании libufdt
вы должны включить и связать libfdt
(однако, в ваш код вы можете использовать API libfdt
для работы DTB или DTBO).
Libufdt DTO API
Основной API для DTO в 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);
Параметр main_fdt_header
— это основное ОУ, а overlay_fdt
— это буфер, содержащий содержимое файла .dtbo
. Возвращаемое значение — это новый буфер, содержащий объединенное ОУ (или null
в случае ошибки). Объединенное DT форматируется в FDT, которое вы можете передать ядру при запуске ядра.
Новый буфер из возвращаемого значения создается с помощью dto_malloc()
, который вы должны реализовать при портировании libufdt
в загрузчик. Справочные реализации см. в sysdeps/libufdt_sysdeps_*.c
.
Ограничения корневого узла
Вы не можете наложить новый узел или свойство на корневой узел основного ОУ, поскольку операции наложения зависят от меток. Поскольку основной DT должен определить метку, а наложенный DT назначает узлы, которые должны быть наложены на метки, вы не можете дать метку для корневого узла (и, следовательно, не может наложить корневой узел).
Поставщики SoC должны определить возможность наложения основного ОУ; ODM/OEM могут только добавлять или переопределять узлы с метками, определенными поставщиком SoC. В качестве обходного пути вы можете определить узел odm
под корневым узлом в базовом DT, позволяя всем узлам ODM в наложенном DT добавлять новые узлы. В качестве альтернативы вы можете поместить все узлы, связанные с SoC, в базовом DT в узел soc
под корневым узлом, как описано ниже:
main.dts | alplay.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 { ... }; ... }; |
Используйте сжатые наложения
В Android 9 добавлена поддержка использования сжатых наложений в изображении DTBO при использовании версии 1 заголовка таблицы DT. При использовании заголовка DTBO v1 четыре младших бита поля флагов в dt_table_entry указывают формат сжатия записи 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 */ };
В настоящее время поддерживаются сжатия zlib
и gzip
.
enum dt_compression_info { NO_COMPRESSION, ZLIB_COMPRESSION, GZIP_COMPRESSION };
В Android 9 добавлена поддержка тестирования сжатых наложений в тест VtsFirmwareDtboVerification
, чтобы помочь вам проверить правильность приложения наложения.
Пример реализации DTO
Следующие инструкции проведут вас через пример реализации DTO с libufdt
(пример кода ниже).
Примеры инструкций DTO
- Включите библиотеки. Чтобы использовать
libufdt
, включитеlibfdt
для структур данных и API:#include <libfdt.h> #include <ufdt_overlay.h>
- Загрузите основное ОУ и наложенное ОУ. Загрузите
.dtb
и.dtbo
из хранилища в память (точные шаги зависят от вашего дизайна). На этом этапе у вас должен быть буфер и размер.dtb
/.dtbo
:main_size = my_load_main_dtb(main_buf, main_buf_size)
overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
- Наложение DT:
- Используйте
ufdt_install_blob()
, чтобы получить заголовок FDT для основного DT:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- Вызовите
ufdt_apply_overlay()
в DTO, чтобы получить объединенное DT в формате FDT:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size);
- Используйте
merged_fdt
, чтобы получить размерdtc_totalsize()
:merged_fdt_size = dtc_totalsize(merged_fdt);
- Передайте объединенное DT для запуска ядра:
my_kernel_entry(0, machine_type, merged_fdt);
- Используйте
Пример кода 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); }
На этой странице обсуждаются оптимизации, которые вы можете внести в реализацию наложения дерева устройств (DTO), описываются ограничения на наложение корневого узла и подробно описано, как настроить сжатые наложения в образе DTBO. Он также предоставляет примеры инструкций и кода реализации.
Командная строка ядра
Исходная командная строка ядра в дереве устройств (DT) расположена в узле chosen/bootargs
. Загрузчик должен объединить это местоположение с другими источниками командной строки ядра:
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; };
DTO не может объединить значения из основного DT и Overlay DT, поэтому вы должны поместить командную строку ядра основного DT в chosen/bootargs
и командную строку ядра наложного DT в chosen/bootargs_ext
. Затем загрузчик может объединить эти местоположения и передать результат ядру.
main.dts | оверлей.dts |
---|---|
/dts-v1/; / { chosen: chosen { bootargs = "..."; }; }; | /dts-v1/; /plugin/; &chosen { bootargs_ext = "..."; }; |
либуфдт
Хотя последняя версия libfdt
поддерживает DTO, рекомендуется ли использовать libufdt
для реализации DTO (исходный код AOSP по адресу platform/system/libufdt
). libufdt
создает реальную древовидную структуру (несведенное дерево устройств или ufdt ) из плоского дерева устройств (FDT), поэтому он может улучшить объединение двух файлов .dtb
из O(N 2 ) в O(N), где N — количество узлов в дереве.
Тестирование производительности
По данным внутреннего тестирования Google, использование libufdt
на узлах DT 2405 .dtb
и 283 .dtbo
приводит к получению размеров файлов 70 618 и 8 566 байт после компиляции. По сравнению с реализацией DTO, перенесенной из FreeBSD (время выполнения 124 мс), время выполнения DTO libufdt
составляет 10 мс.
Тестирование производительности для пиксельных устройств по сравнению с libufdt
и libfdt
. Эффект количества базовых узлов аналогичен, но включает в себя следующие различия:
- 500 операций наложения (добавления или переопределения) имеют разницу во времени от 6 до 8 раз.
- 1000 операций наложения (добавления или переопределения) имеют разницу во времени от 8 до 10 раз.
Пример с добавлением счетчика, установленного в X:
Рисунок 1. Добавляемый счетчик равен X.
Пример с переопределяющим счетчиком, установленным на X:
Рисунок 2. Число переопределения — X.
libufdt
разработан с использованием некоторых API-интерфейсов libfdt
и структур данных. При использовании libufdt
вы должны включить и связать libfdt
(однако, в ваш код вы можете использовать API libfdt
для работы DTB или DTBO).
API-интерфейс libufdt DTO
Основной API для DTO в 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);
Параметр main_fdt_header
является основным dt, а overlay_fdt
- буфер, содержащий содержимое файла .dtbo
. Возвращаемое значение — это новый буфер, содержащий объединенное ОУ (или null
в случае ошибки). Объединенное DT форматируется в FDT, которое вы можете передать ядру при запуске ядра.
Новый буфер из возвращаемого значения создается с помощью dto_malloc()
, который вы должны реализовать при портировании libufdt
в загрузчик. Справочные реализации см. в sysdeps/libufdt_sysdeps_*.c
.
Ограничения корневого узла
Вы не можете наложить новый узел или свойство на корневой узел основного ОУ, поскольку операции наложения зависят от меток. Поскольку основное ОУ должно определять метку, а ОУ наложения назначает узлы, на которые будут наложены метки, вы не можете задать метку для корневого узла (и, следовательно, не можете наложить корневой узел).
Поставщики SoC должны определить возможность наложения основного ОУ; ODM/OEM могут добавлять или переопределять узлы только с метками, определенными поставщиком SoC. В качестве обходного пути вы можете определить узел odm
под корневым узлом в базовом DT, позволяя всем узлам ODM в наложенном DT добавлять новые узлы. В качестве альтернативы вы можете поместить все узлы, связанные с SoC, в базовом DT в узел soc
под корневым узлом, как описано ниже:
main.dts | оверлей.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 { ... }; ... }; |
Используйте сжатые наложения
В Android 9 добавлена поддержка использования сжатых наложений в изображении DTBO при использовании версии 1 заголовка таблицы DT. При использовании заголовка DTBO v1 четыре младших бита поля флагов в dt_table_entry указывают формат сжатия записи 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 */ };
В настоящее время поддерживаются компрессии zlib
и gzip
.
enum dt_compression_info { NO_COMPRESSION, ZLIB_COMPRESSION, GZIP_COMPRESSION };
В Android 9 добавлена поддержка тестирования сжатых наложений в тест VtsFirmwareDtboVerification
, чтобы помочь вам проверить правильность приложения наложения.
Пример реализации DTO
Следующие инструкции проводят вас через образец реализации DTO с libufdt
(пример кода ниже).
Примеры инструкций DTO
- Включите библиотеки. Чтобы использовать
libufdt
, включитеlibfdt
для структур данных и API:#include <libfdt.h> #include <ufdt_overlay.h>
- Загрузите основное ОУ и наложенное ОУ. Загрузить
.dtb
и.dtbo
из хранилища в память (точные шаги зависят от вашей конструкции). На этом этапе у вас должен быть буфер и размер.dtb
/.dtbo
:main_size = my_load_main_dtb(main_buf, main_buf_size)
overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
- Наложение DT:
- Используйте
ufdt_install_blob()
, чтобы получить заголовок FDT для основного DT:main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size;
- Позвоните
ufdt_apply_overlay()
DTO, чтобы получить объединенный DT в формате FDT:merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size, overlay_buf, overlay_size);
- Используйте
merged_fdt
, чтобы получить размерdtc_totalsize()
:merged_fdt_size = dtc_totalsize(merged_fdt);
- Передайте объединенное DT для запуска ядра:
my_kernel_entry(0, machine_type, merged_fdt);
- Используйте
Пример кода 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); }