Google is committed to advancing racial equity for Black communities. See how.
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

優化DTO

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

內核命令行

設備樹中的原始內核命令行位於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(位於platform/system/libufdt AOSP源代碼)。 libufdt從展平的設備樹(FDT)構建一個真實的樹結構(未展平的設備樹,即ufdt ),因此它可以改善將兩個.dtb文件從O(N 2 )合併到O(N),其中N是樹中節點的數量。

性能測試

在Google的內部測試中, libufdt在2405 .dtb和283 .dtbo DT節點上使用libufdt導致文件大小為70,618和8,566字節。與從FreeBSD移植的DTO實現 (運行時間為124毫秒)相比, libufdt DTO運行時為10毫秒。

Pixel設備的性能測試將libufdtlibfdt進行了比較。基本節點的數量效果相似,但包括以下差異:

  • 500個疊加(附加或覆蓋)操作的時差為6到8倍
  • 1000次疊加(附加或覆蓋)操作的時差為8x至10x

將計數設置為X的示例:

圖1.追加計數為X

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

圖2.覆蓋計數為X

libufdt是使用一些libfdt API和數據結構開發的。使用libufdt ,必須包括並鏈接libfdt (但是,在代碼中可以使用libfdt API來操作DTB或DTBO)。

libufdt DTO API

libufdt DTO的主要API如下:

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

根節點限制

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

SoC供應商必須定義主要DT的覆蓋能力; ODM / OEM只能使用SoC供應商定義的標籤附加或覆蓋節點。解決方法是,您可以在基本DT中的根節點下定義一個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 {
        ...
    };
    ...
};

使用壓縮的疊加層

當使用設備樹表標頭的版本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實施範例

以下說明將引導您完成使用libufdt的DTO示例實現(下面的示例代碼)。

DTO指令樣本

  1. 包括庫。要使用libufdtlibfdt libufdt包含在數據結構和API中:
    #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);
}