DTO 最佳化

本頁說明如何最佳化裝置樹狀結構重疊 (DTO) 實作。 說明瞭疊加根節點的限制,並詳細說明 在 DTBO 圖像中設定壓縮的疊加層。並提供範例 導入操作說明和程式碼

核心指令列

裝置樹狀結構的原始核心指令列 (DT) 位於 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 (Android 開放原始碼計畫原始碼,網址為 platform/system/libufdt). libufdt 會建構真實的樹狀結構 (整併裝置樹狀結構、 或 ufdt)。這樣一來,您就能改善 將兩個 .dtb 檔案從 O(N2) 合併到 O(N),其中 N 是 樹狀結構中的節點數量

效能測試

在 Google 的內部測試中,於 2405 使用 libufdt .dtb 和 283 .dtbo DT 節點會導致檔案大小: 編譯後 70,618 和 8,566 個位元組。與 DTO 從 FreeBSD (124 毫秒的執行階段) 移植的實作libufdt DTO 執行階段為 10 毫秒。

Pixel 裝置效能測試比較:libufdtlibfdt。基本節點數量大致相同,但包含 其差異如下:

  • 500 次重疊 (附加或覆寫) 作業的時間為 6 至 8 倍 差異
  • 1000 次重疊 (附加或覆寫) 作業的時間可達 8 至 10 倍 差異

附加計數設為 X 的範例:

圖 1. 附加次數為 X。

將覆寫計數設為 X 的範例:

圖 2. 覆寫計數為 X。

libufdt 是使用某些 libfdt API 和資料開發而成 成本中心的架構使用 libufdt 時,您必須加入 libfdt (不過,在程式碼中,您可以使用 libfdt 執行 DTB 或 DTBO 的 API)。

Libufdt DTO API

libufdt 中的主要 API 至 DTO 如下:

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 格式化 ,可在啟動核心時傳遞至核心。

來自傳回值的新緩衝區是由 dto_malloc() 建立, 將 libufdt 移植至系統啟動載入程式時,應實作這種方式。 如需參考實作,請參閱 sysdeps/libufdt_sysdeps_*.c

根節點限制

你無法將新的節點或屬性重疊至主要 DT 的根節點 因為疊加層作業必須仰賴標籤由於主要 DT 必須定義 標籤,而覆蓋 DT 會指派要與標籤重疊的節點 無法為根節點加上標籤 (因此也無法疊加根節點) 節點)。

SoC 供應商必須定義主要 DT 的重疊功能。ODM/原始設備製造商 (OEM) 只能 以 SoC 供應商定義的標籤附加或覆寫節點。身為 您可以在odm 根節點,啟用重疊 DT 中的所有 ODM 節點以新增節點。 您也可以在基本 DT 中將所有 SoC 相關節點放入 根節點下的 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 圖片中的樣子。 使用 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 */
};

目前支援 zlibgzip 壓縮。

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

Android 9 新增對壓縮測試的支援 是疊加在 VtsFirmwareDtboVerification 測試中 並驗證疊加應用程式的正確性。

DTO 實作範例

以下操作說明會引導您完成 DTO 實作範例 來呼叫 libufdt (請見下方的程式碼範例)。

DTO 範例操作說明

  1. 包含程式庫。如要使用「libufdt」,請加入 適用於資料結構和 API 的 libfdt
    #include <libfdt.h>
    #include <ufdt_overlay.h>
    
  2. 載入主要 DT 和重疊 DT。載入 .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. 疊加 DT:
    1. 使用 ufdt_install_blob() 取得主要 DT 的 FDT 標頭:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
      
    2. 呼叫 ufdt_apply_overlay() 給 DTO,即可取得 FDT 中的合併 DT 格式:
      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);
}