優化 DTO

此頁面討論您可以對 DTO 實現進行的優化,描述對覆蓋根節點的限制,並詳細說明如何在 DTBO 映像中配置壓縮覆蓋。它還提供示例實現說明和代碼。

內核命令行

在設備樹原始內核命令行位於chosen/bootargs節點。引導加載程序必須將此位置與其他內核命令行源連接起來:

/dts-v1/;

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

DTO無法從主DT和覆蓋DT,所以你必須把在主DT的內核命令行串聯值chosen/bootargs和覆蓋DT的內核命令行chosen/bootargs_ext 。然後引導加載程序可以連接這些位置並將結果傳遞給內核。

主文件覆蓋.dts
/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};
/dts-v1/;
/plugin/;

&chosen {
  bootargs_ext = "...";
};

而最新的libfdt支持DTO,是它建議使用libufdt實現DTO(在AOSP源platform/system/libufdt )。 libufdt構建從扁平設備樹(FDT)一個真正的樹結構(未平坦化設備樹,或ufdt),因此它可以提高兩個合併.dtb文件從O(N 2)至O(N),其中N是樹中的節點數。

性能測試

在谷歌的內部測試中,使用libufdt在2405 .dtb和283 .dtbo DT節點的編譯後70618和8566個字節的文件大小的結果。與比較DTO實現從FreeBSD的移植(124毫秒運行時), libufdt DTO運行時為10毫秒。

像素設備性能測試比較libufdtlibfdt 。基節點數效果類似,但包括以下差異:

  • 500 次疊加(追加或覆蓋)操作有 6 到 8 倍的時間差
  • 1000 次疊加(追加或覆蓋)操作有 8 到 10 倍的時間差

附加計數設置為 X 的示例:

圖1附加計數X

覆蓋計數設置為 X 的示例:

圖2.重寫計數被X

libufdt與一些發達libfdt API和數據結構。當使用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進入bootloader。參考實施方式中,參照sysdeps/libufdt_sysdeps_*.c

根節點限制

您不能將新節點或屬性疊加到主 DT 的根節點中,因為疊加操作依賴於標籤。因為主 DT 必須定義一個標籤,而覆蓋 DT 為要覆蓋的節點分配標籤,所以您不能為根節點提供標籤(因此不能覆蓋根節點)。

SoC廠商必須定義主DT的疊加能力; ODM/OEM 只能使用 SoC 供應商定義的標籤附加或覆蓋節點。作為一種變通方法,您可以定義一個odm在基地DT根節點下的節點,使在覆蓋所有DT ODM節點添加新節點。或者,你可以把在基礎DT所有的SoC相關節點到soc下根節點節點如下所述:

主文件覆蓋.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 {
        ...
    };
    ...
};

使用壓縮覆蓋

當使用設備樹表頭的版本 1 時,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' 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 */
};

目前, zlibgzip壓縮的支持。

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

Android的9增加了對測試壓縮覆蓋到支持VtsFirmwareDtboVerification測試,以幫助您驗證疊加應用的正確性。

示例 DTO 實現

下面的說明引導您完成一個樣本實現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. 疊加 DT:
    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來獲得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);
}