DTB- und DTBO-Partitionen

Wenn sich Ihr Gerätebaum-Blob (Device Tree Blob, DTB) oder Ihr Gerätebaum-Blob für Overlay (Device Tree Blob Overlay, DTBO) in einer eindeutigen Partition befindet, z. B. in der Partition dtb und dtbo, verwenden Sie die folgende Tabellenstruktur und das folgende Headerformat:

Abbildung 1: Beispiel für ein DTB- und DTBO-Partitionslayout

Datenstrukturen

Das dt_table_header ist nur für die dtb/dtbo-Partition vorgesehen. Dieses Format darf NICHT nach dem Ende von image.gz angehängt werden. Wenn Sie nur eine DTB- oder DTBO-Datei haben, müssen Sie dieses Format trotzdem verwenden. Die dt_entry_count in dt_table_header muss dann 1 sein.

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

Wenn Sie alle dt_table_entry lesen möchten, verwenden Sie die dt_entry_size, dt_entry_count und dt_entries_offset. Beispiel:

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

id, rev und custom in dt_table_entry sind optionale Hardware-IDs des Gerätebaums, mit denen der Bootloader die zu ladende DTB- oder DTBO-Datei effizient identifizieren kann. Wenn der Bootloader zusätzliche Informationen benötigt, fügen Sie sie in das DTB oder DTBO ein, damit der Bootloader sie durch Parsen des DTB oder DTBO lesen kann (siehe Beispielcode unten).

Beispielcode

Im folgenden Beispielcode wird die Hardwareidentifikation im Bootloader geprüft.

  • Die Funktion check_dtbo() prüft die Hardware-Identifikation. Zuerst werden die Daten in Struktur dt_table_entry (id, rev usw.) geprüft. Wenn diese Daten nicht ausreichen, werden dtb-Daten in den Arbeitsspeicher geladen und der Wert in dtb wird geprüft.
  • Die Werte der Properties my_hw_information und soc_id werden im Stammknoten geparst (Beispiel in 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

mkdtimg ist ein Tool zum Erstellen von dtb/dtbo-Images (Quellcode unter system/libufdt in AOSP). mkdtimg unterstützt mehrere Befehle, darunter create, cfg_create und dump.

create

Mit dem Befehl create können Sie ein dtb/dtbo-Image erstellen:

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

ftbX_filename generiert ein dt_table_entry im Bild. entryX_options sind die Werte, die dt_table_entry zugewiesen werden sollen. Folgende Werte sind möglich:

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

Zahlenwerte können eine 32-Bit-Zahl (z. B. 68000) oder eine Hexadezimalzahl (z. B. 0x6800) sein. Alternativ können Sie einen Pfad im folgenden Format angeben:

<full_node_path>:<property_name>

Beispiel: /board/:id. mkdtimg liest den Wert aus dem Pfad in der DTB- oder DTBO-Datei und weist den Wert (32 Bit) einer relativen Eigenschaft in dt_table_entry zu. Alternativ können Sie für alle Einträge eine global_option als Standardoption angeben. Der Standardwert von page_size in dt_table_header ist 2048. Verwenden Sie global_option --page_size=<number>, um einen anderen Wert zuzuweisen.

Beispiel:

[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
  • Erste dt_table_entry (board1.dtbo) id ist 0x00010000 und custom[0] ist 0x00000abc.
  • Der zweite id ist 0x00006800 und custom[0] ist 0x00000abc.
  • id ist 0x00006801 und custom[0] ist 0x00000123.
  • Für alle anderen wird der Standardwert (0) verwendet.

cfg_create

Mit dem Befehl cfg_create wird ein Image mit einer Konfigurationsdatei im folgenden Format erstellt:

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

Die Optionen global_option und entryX_option müssen mit einem oder mehreren Leerzeichen beginnen. Diese Optionen entsprechen den create-Optionen ohne das Präfix --. Leere Zeilen oder Zeilen, die mit # beginnen, werden ignoriert.

Beispiel:

[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 unterstützt keine Ausrichtung für .dtb-/.dtbo-Dateien, sondern hängt sie an das Bild an. Wenn Sie dtc verwenden, um .dts in .dtb/.dtbo zu kompilieren, müssen Sie die Option -a hinzufügen. Wenn Sie beispielsweise die Option -a 4 hinzufügen, wird ein Padding hinzugefügt, damit die Größe von .dtb/.dtbo auf 4 Byte ausgerichtet ist.

Mehrere DT-Tabelleneinträge können dieselbe .dtb/.dtbo haben. Wenn Sie für verschiedene Einträge denselben Dateinamen verwenden, wird im Bild nur ein Inhalt mit denselben dt_offset und dt_size gespeichert. Das ist nützlich, wenn Sie unterschiedliche Hardware mit identischen DTs verwenden.

Dump

Verwenden Sie für dtb-/dtbo-Images den Befehl dump, um die Informationen im Bild zu drucken. Beispiel:

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