DTB/DTBO 파티션

DTB/DTBO가 고유 파티션에 있는 경우(예: dtbdtbo 파티션) 다음 표 구조 및 헤더 형식을 사용합니다.

그림 1. 예: dtb/dtbo 파티션 레이아웃(AVB 서명의 경우 보안 참고).

데이터 구조

dt_table_headerdtb/dtbo 파티션 전용이므로 이 형식을 image.gz 끝부분 이후에 추가할 수 없습니다. 단일 DTB/DTBO를 보유한 경우에도 계속 이 형식을 사용해야 합니다(또한 dt_table_headerdt_entry_count는 1입니다).

#define DT_TABLE_MAGIC 0xd7b7ab1e

struct dt_table_header {
  uint32_t magic;             // DT_TABLE_MAGIC
  uint32_t total_size;        // includes dt_table_header + all dt_table_entry
                              // and all dtb/dtbo
  uint32_t header_size;       // sizeof(dt_table_header)

  uint32_t dt_entry_size;     // sizeof(dt_table_entry)
  uint32_t dt_entry_count;    // number of dt_table_entry
  uint32_t dt_entries_offset; // offset to the first dt_table_entry
                              // from head of dt_table_header

  uint32_t page_size;         // flash page size we assume
  uint32_t version;       // DTBO image version, the current version is 0.
                          // The version will be incremented when the
                          // dt_table_header struct is updated.
};

struct dt_table_entry {
  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 custom[4];         // optional, must be zero if unused
};

모든 dt_table_entry를 읽으려면, dt_entry_size, dt_entry_count, dt_entries_offset을 사용합니다. 예를 들면 다음과 같습니다.

my_read(entries_buf,
        header_addr + header->dt_entries_offset,
        header->dt_entry_size * header->dt_entry_count);

dt_table_entryid, rev, custom는 부트로더가 로드할 DTB/DTBO를 효율적으로 식별하는 데 사용할 수 있는 기기 트리의 선택적 하드웨어 ID입니다. 부트로더에 추가 정보가 필요한 경우 부트로더가 DTB/DTBO를 파싱하여 이를 읽을 수 있는 DTB/DTBO에 삽입합니다(아래의 샘플 코드 참조).

샘플 코드

다음 샘플 코드는 부트로더의 하드웨어 ID를 확인합니다.

  • check_dtbo() 함수는 하드웨어 ID를 확인합니다. 먼저 dt_table_entry 구조체의 데이터(id, rev 등)를 확인합니다. 이 데이터가 충분하지 않으면 dtb 데이터를 메모리에 로드하고 dtb의 값을 확인합니다.
  • my_hw_informationsoc_id 속성의 값은 루트 노드에 파싱됩니다(my_dtbo_1.dts의 예).
    [my_dtbo_1.dts]
    /dts-v1/;
    /plugin/;
    
    / {
      /* As DTS design, these properties only for loader, won't overlay */
      compatible = "board_manufacturer,board_model";
    
      /* These properties are examples */
      board_id = <0x00010000>;
      board_rev = <0x00010001>;
      another_hw_information = "some_data";
      soc_id = <0x68000000>;
      ...
    };
    
    &device@0 {
      value = <0x1>;
      status = "okay";
    };
    
    [my_bootloader.c]
    int check_dtbo(const dt_table_entry *entry, uint32_t header_addr) {
      ...
      if (entry->id != ... || entry->rev != ...) {
        ...
      }
      ...
      void * fdt_buf = my_load_dtb(header_addr + entry->dt_offset, entry->dt_size);
      int root_node_off = fdt_path_offset(fdt_buf, "/");
      ...
      const char *my_hw_information =
        (const char *)fdt_getprop(fdt_buf, root_node_off, "my_hw_information", NULL);
      if (my_hw_information != NULL && strcmp(my_hw_information, ...) != 0) {
        ...
      }
      const fdt32_t *soc_id = fdt_getprop(fdt_buf, root_node_off, "soc_id", NULL);
      if (soc_id != NULL && *soc_id != ...) {
        ...
      }
      ...
    }
    

mkdtimg

mkdtimgdtb/dtbo 이미지 생성 도구입니다(AOSP의 system/libufdt에 있는 소스 코드). mkdtimgcreate, cfg_create, dump를 비롯한 여러 명령어를 지원합니다.

create

create 명령어를 사용하여 dtb/dtbo 이미지를 생성합니다.

mkdtimg create <image_filename> (<global-option>...) \
    <ftb1_filename> (<entry1_option>...) \
    <ftb2_filename> (<entry2_option>...) \
    ...

ftbX_filename은 이미지에 dt_table_entry를 생성합니다. entryX_optiondt_table_entry에 할당할 값입니다. 이러한 값은 다음 중 하나일 수 있습니다.

--id=<number|path>
--rev=<number|path>
--custom0=<number|path>
--custom1=<number|path>
--custom2=<number|path>
--custom3=<number|path>

숫자 값은 32비트 숫자(예: 68000) 또는 16진수(예: 0x6800)일 수 있습니다. 아니면 다음 형식을 사용하여 경로를 지정할 수 있습니다.

<full_node_path>:<property_name>

예를 들어 /board/:id가 이에 해당합니다. mkdtimg는 DTB/DTBO 파일의 경로에서 값을 읽고 이 32비트 값을 dt_table_entry의 관련 속성에 할당합니다. 아니면 모든 항목에 기본값 옵션으로 global_option을 부여할 수 있습니다. dt_table_header에 있는 page_size의 기본값은 2048입니다. 다른 값을 할당하려면 global_option --page_size=<number>를 사용합니다.

예를 들면 다음과 같습니다.

[board1.dts]
/dts-v1/;
/plugin/;

/ {
  compatible = "board_manufacturer,board_model";
  board_id = <0x00010000>;
  board_rev = <0x00010001>;
  another_hw_information = "some_data";
  ...
};

&device@0 {
  value = <0x1>;
  status = "okay";
};

mkdtimg create dtbo.img --id=/:board_id --custom0=0xabc \
  board1.dtbo \
  board2.dtbo --id=0x6800 \
  board3.dtbo --id=0x6801 --custom0=0x123
  • 첫번째 dt_table_entry (board1.dtbo) id0x00010000, custom[0]0x00000abc입니다.
  • 두번째 id0x00006800, custom[0]0x00000abc입니다.
  • 세번째 id0x00006801, custom[0]0x00000123입니다.
  • 나머지는 모두 기본값(0)을 사용합니다.

cfg_create

cfg_create 명령어는 다음 형식의 구성 파일로 이미지를 만듭니다.

# global options
  <global_option>
  ...
# entries
<ftb1_filename>     # comment
  <entry1_option>   # comment
  ...
<ftb2_filename>
  <entry2_option>
  ...
...

옵션 global_optionentryX_option은 하나 이상의 문자로 시작해야 합니다(이 옵션은 create 옵션과 동일하지만 -- 프리픽스가 없습니다). 빈 행이나 #으로 시작되는 행은 무시됩니다.

예를 들면 다음과 같습니다.

[dtboimg.cfg]
# global options
  id=/:board_id
  rev=/:board_rev
  custom0=0xabc

board1.dtbo

board2.dtbo
  id=0x6800       # override the value of id in global options

board2.dtbo
  id=0x6801       # override the value of id in global options
  custom0=0x123   # override the value of custom0 in global options

mkdtimg cfg_create dtbo.img dtboimg.cfg

mkdtimg.dtb/.dtbo 파일의 정렬을 처리하지 않는 대신 이 파일을 이미지에 추가합니다. dtc를 사용하여 .dts.dtb/.dtbo로 컴파일하려면 -a 옵션을 추가해야 합니다. 예를 들어 -a 4 옵션을 추가하면 패딩이 덧붙어서 .dtb/.dtbo의 크기가 4바이트로 정렬됩니다.

여러 DT 표 항목은 .dtb/.dtbo를 공유할 수 있습니다. 다른 항목에서 동일한 파일 이름을 사용하는 경우 동일한 dt_offsetdt_size를 갖는 이미지에 한 개의 콘텐츠만 저장합니다. 이는 동일한 DT를 포함하는 상이한 하드웨어를 사용하는 경우에 유용합니다.

dump

dtb/dtbo 이미지에서 dump 명령어를 사용하여 이미지의 정보를 출력합니다. 예를 들면 다음과 같습니다.

mkdtimg dump dtbo.img
dt_table_header:
               magic = d7b7ab1e
          total_size = 1300
         header_size = 32
       dt_entry_size = 32
      dt_entry_count = 3
   dt_entries_offset = 32
           page_size = 2048
             version = 0
dt_table_entry[0]:
             dt_size = 380
           dt_offset = 128
                  id = 00010000
                 rev = 00010001
           custom[0] = 00000abc
           custom[1] = 00000000
           custom[2] = 00000000
           custom[3] = 00000000
           (FDT)size = 380
     (FDT)compatible = board_manufacturer,board_model
...