DTB ve DTBO bölümleri

Cihaz ağacı blob'unuz (DTB) veya yer paylaşımı için cihaz ağacı blob'unuz (DTBO) benzersiz bir bölümdeyse (ör. dtb ve dtbo bölümü) aşağıdaki tablo yapısını ve başlık biçimini kullanın:

Şekil 1. Örnek DTB ve DTBO bölüm düzeni.

Veri yapıları

dt_table_header, yalnızca dtb/dtbo bölümü içindir; bu biçimi image.gz'in sonuna ekleyemezsiniz. Tek bir DTB veya DTBO'nuz varsa yine bu biçimi kullanmanız gerekir (ve dt_table_header içindeki dt_entry_count 1'dir).

#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 is 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
};

Tüm dt_table_entry'leri okumak için dt_entry_size, dt_entry_count ve dt_entries_offset'ı kullanın. Örnek:

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

dt_table_entry içindeki id, rev, custom, önyükleyicinin yüklenecek DTB veya DTBO'yu verimli bir şekilde tanımlamak için kullanabileceği cihaz ağacının isteğe bağlı donanım kimlikleridir. Önyükleyicinin ek bilgilere ihtiyacı varsa bu bilgileri, önyükleyicinin DTB veya DTBO'yu ayrıştırarak okuyabileceği DTB ya da DTBO'ya yerleştirin (Aşağıdaki örnek koda bakın).

Örnek kod

Aşağıdaki örnek kod, önyükleyicideki donanım kimliğini kontrol eder.

  • check_dtbo() işlevi, donanım tanımlamasını kontrol eder. Öncelikle dt_table_entry yapılandırmasında (id, rev vb.) verileri kontrol eder. Bu veriler yeterli değilse dtb verilerini belleğe yükler ve dtb içindeki değeri kontrol eder.
  • my_hw_information ve soc_id özelliklerinin değerleri kök düğümde ayrıştırılır (my_dtbo_1.dts örneği).
    [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

mkdtimg, dtb/dtbo resimleri oluşturmaya yönelik bir araçtır (AOSP'deki system/libufdt adresinde kaynak kod). mkdtimg, create, cfg_create ve dump gibi çeşitli komutları destekler.

oluştur

dtb/dtbo resmi oluşturmak için create komutunu kullanın:

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

ftbX_filename, resimde bir dt_table_entry oluşturur. entryX_option, dt_table_entry öğesine atanacak değerlerdir. Bu değerler aşağıdakilerden herhangi biri olabilir:

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

Sayı değerleri 32 bitlik bir basamak (ör. 68000) veya on altılık sayı (ör. 0x6800) olabilir. Alternatif olarak, aşağıdaki biçimi kullanarak bir yol da belirtebilirsiniz:

<full_node_path>:<property_name>

Örneğin, /board/:id. mkdtimg, değeri DTB veya DTBO dosyasındaki yoldan okur ve değeri (32 bit) dt_table_entry içindeki göreli bir mülke atar. Alternatif olarak, tüm girişler için varsayılan seçenek olarak global_option verebilirsiniz. dt_table_header içindeki page_size değerinin varsayılan değeri 2048'dir. Farklı bir değer atamak için global_option --page_size=<number> değerini kullanın.

Örnek:

[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
  • İlk dt_table_entry (board1.dtbo) id 0x00010000, custom[0] ise 0x00000abc değerini alır.
  • İkinci id, 0x00006800 ve custom[0], 0x00000abc'tır.
  • Üçüncü id, 0x00006801 ve custom[0], 0x00000123'tır.
  • Diğer tüm alanlar için varsayılan değer (0) kullanılır.

cfg_create

cfg_create komutu, aşağıdaki biçimde bir yapılandırma dosyası içeren bir resim oluşturur:

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

global_option ve entryX_option seçenekleri bir veya daha fazla boşluk karakteriyle başlamalıdır (bu seçenekler, -- ön eki olmadan create seçenekleriyle aynıdır). Boş satırlar veya # ile başlayan satırlar yoksayılır.

Örnek:

[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 dosyaları için hizalamayı işlemez, dosyaları resme ekler. .dts'u .dtb/.dtbo olarak derlemek için dtc'ü kullandığınızda -a seçeneğini eklemeniz gerekir. Örneğin, -a 4 seçeneği eklendiğinde .dtb/.dtbo boyutunun 4 bayta hizalanması için dolgu eklenir.

Birkaç DT tablo girişi bir .dtb/.dtbo paylaşabilir. Farklı girişler için aynı dosya adını kullanırsanız resimde aynı dt_offset ve dt_size ile yalnızca bir içerik depolanır. Bu, aynı DT'lere sahip farklı donanımlar kullanırken yararlıdır.

dökümü

dtb/dtbo resimleri için resimdeki bilgileri yazdırmak üzere dump komutunu kullanın. Örnek:

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
...