Google is committed to advancing racial equity for Black communities. See how.
Эта страница была переведа с помощью Cloud Translation API.
Switch to English

Оптимизация DTO

На этой странице обсуждаются оптимизации, которые вы можете внести в свою реализацию DTO, описываются ограничения на наложение корневого узла и подробно описывается, как настроить сжатые наложения в образе DTBO. Он также предоставляет примеры инструкций по реализации и кода.

Командная строка ядра

Исходная командная строка ядра в дереве устройств находится в chosen/bootargs узле chosen/bootargs . Загрузчик должен объединить это местоположение с другими исходными кодами командной строки ядра:

/dts-v1/;

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

DTO не может объединять значения из основного DT и оверлейного DT, поэтому вы должны поместить командную строку ядра основного DT в chosen/bootargs а командную строку ядра для оверлейного DT в chosen/bootargs_ext . Затем загрузчик может объединить эти местоположения и передать результат ядру.

main.dts overlay.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 количество узлов в дереве.

Тестирование производительности

Во внутреннем тестировании Google использование libufdt на 2405 .dtb и 283 .dtbo узлах DT приводит к размерам файлов 70 618 и 8566 байт после компиляции. По сравнению с реализацией DTO, перенесенной из FreeBSD (время выполнения 124 мс), время выполнения libufdt DTO составляет 10 мс.

При тестировании производительности устройств Pixel сравнивались libufdt и libfdt . Эффект количества базовых узлов аналогичен, но включает следующие отличия:

  • 500 операций наложения (добавления или отмены) имеют разницу во времени от 6x до 8x
  • 1000 операций наложения (добавления или отмены) имеют разницу во времени от 8x до 10x

Пример с добавляемым счетчиком, установленным на X:

Рисунок 1. Добавляемый счетчик - X

Пример с заданным значением счетчика X:

Рис. 2. Счетчик переопределения - X

libufdt разработан с использованием некоторых API-интерфейсов libfdt и структур данных. При использовании libufdt вы должны включить и связать libfdt (однако в вашем коде вы можете использовать libfdt API для работы с 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 - это главное DT, а overlay_fdt - это буфер, содержащий содержимое файла .dtbo . Возвращаемое значение - новый буфер, содержащий объединенное DT (или null в случае ошибки). Объединенный DT формируется в FDT, который вы можете передать ядру при запуске ядра.

Новый буфер из возвращаемого значения создается dto_malloc() , который вы должны реализовать при переносе libufdt в загрузчик. Справочные реализации см. В sysdeps/libufdt_sysdeps_*.c

Ограничения корневого узла

Вы не можете наложить новый узел или свойство на корневой узел основного ОУ, потому что операции наложения зависят от меток. Поскольку основное ОУ должно определять метку, а оверлейное ОУ назначает узлы, которые должны быть перекрыты метками, вы не можете дать метку для корневого узла (и, следовательно, не можете перекрыть корневой узел).

Производители SoC должны определить возможность наложения основного DT; ODM / OEM-производители могут добавлять или замещать узлы только с метками, определенными поставщиком SoC. В качестве обходного пути можно определить узел odm под корневым узлом в базовом DT, что позволит всем узлам ODM в оверлейном DT добавлять новые узлы. В качестве альтернативы вы можете поместить все связанные с SoC узлы в базовом DT в узел soc под корневым узлом, как описано ниже:

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

Использование сжатых оверлеев

В Android 9 добавлена ​​поддержка использования сжатых наложений в образе DTBO при использовании версии 1 заголовка таблицы дерева устройств. При использовании заголовка 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' 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 */
};

В настоящее время поддерживается сжатие zlib и gzip .

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

Android 9 добавляет поддержку тестирования сжатых оверлеев в тест VtsFirmwareDtboVerification чтобы помочь вам проверить правильность приложения наложения.

Пример реализации DTO

Следующие инструкции libufdt вас через образец реализации DTO с libufdt (пример кода ниже).

Примеры инструкций DTO

  1. Включите библиотеки. Чтобы использовать libufdt , libfdt для структур данных и API:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
    
  2. Загрузите основное ОУ и оверлейное ОУ. Загрузите .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);
    
  3. Наложить ОУ:
    1. Используйте ufdt_install_blob() чтобы получить заголовок FDT для основного DT:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
      
    2. Вызовите ufdt_apply_overlay() в DTO, чтобы получить объединенное DT в формате FDT:
      merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                      overlay_buf, overlay_size);
      
    3. Используйте merged_fdt чтобы получить размер dtc_totalsize() :
      merged_fdt_size = dtc_totalsize(merged_fdt);
      
    4. Передайте объединенный 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);
}