이 페이지에서는 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)를 빌드하므로 2개의 .dtb 파일을 O(N2)에서 O(N)으로 병합하는 과정을 개선할 수 있습니다. 여기서 N은 트리의 노드 수입니다.
성능 테스트
  Google의 내부 테스트에서 2405 .dtb 및 283 .dtbo DT 노드에 libufdt를 사용하면 컴파일 후 파일 크기가 70,618 및 8,566바이트가 됩니다. FreeBSD(124ms 런타임)에서 포팅된 DTO 구현과 비교하면 libufdt DTO 런타임은 10ms입니다.
  Pixel 기기의 성능 테스트에서는 libufdt와 libfdt를 비교했습니다. 기본 노드 효과의 수는 비슷하지만 다음과 같은 차이가 있습니다.
- 500 오버레이(추가 또는 재정의) 작업에 6배~8배의 시간차가 있음
- 1000 오버레이(추가 또는 재정의) 작업에 8배~10배의 시간차가 있음
X로 설정된 횟수 추가 예시:
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로 형식이 지정되며 커널을 시작할 때 커널에 전달할 수 있습니다.
  반환 값의 새 버퍼는 libufdt를 부트로더에 포팅할 때 구현해야 하는 dto_malloc()에서 만듭니다.
  참조 구현은 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 {
        ...
    };
    ...
};
 | 
압축된 오버레이 사용
Android 9에는 기기 트리 테이블 헤더의 1 버전을 사용할 때 DTBO 이미지에 압축된 오버레이를 사용할 수 있도록 지원하는 기능이 추가되었습니다. DTBO 헤더 v1을 사용할 때에는 dt_table_entry에 있는 가장 작은 4개의 플래그 필드 비트가 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의 샘플 구현을 보여줍니다.
샘플 DTO 안내
- 라이브러리를 포함합니다. libufdt를 사용하려면 데이터 구조 및 API에libfdt를 포함합니다.#include <libfdt.h> #include <ufdt_overlay.h> 
- 기본 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); 
- DT 오버레이:- ufdt_install_blob()를 사용하여 기본 DT에서 FDT 헤더를 가져옵니다.- main_fdt_header = ufdt_install_blob(main_buf, main_size); main_fdt_size = main_size; 
- DTO에 ufdt_apply_overlay()를 호출하여 FDT 형식의 병합된 DT를 가져옵니다.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);
}