DTB- und DTBO-Partitionen

Befindet sich Ihr Gerätebaum-BLOB (Device Tree Blob, Device Tree Blob) oder „Device Tree Blob for Overlay“ (DTBO) in einer eindeutigen Partition, Die Partition dtb und dtbo hat beispielsweise die folgende Tabellenstruktur: und Headerformat:

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

<ph type="x-smartling-placeholder">

Datenstrukturen

dt_table_header gilt nur für den Partition dtb/dtbo; Sie KÖNNEN dieses Format NICHT anhängen nach dem Ende von image.gz. Bei einem einzelnen DTB oder DTBO weiterhin dieses Format verwenden (und die dt_entry_count in dt_table_header ist 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 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
};

Um alle dt_table_entry zu lesen, verwenden Sie 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-Identifikationen des Geräts Baum, anhand dessen der Bootloader den zu ladenden DTB oder DTBO effizient identifizieren kann. Wenn die Bootloader benötigt zusätzliche Informationen, speichere die DTB oder DTBO Bootloader kann sie durch Parsen von DTB oder DTBO lesen (siehe Beispielcode unten).

Beispielcode

Der folgende Beispielcode prüft die Hardware-Identifizierung im Bootloader.

  • Die Funktion check_dtbo() prüft die Hardwareidentifikation. Zuerst werden die Daten in der Struktur dt_table_entry (id, rev usw.). Wenn diese Daten nicht ausreichen, werden dtb geladen. Daten in den Arbeitsspeicher und prüft den Wert in dtb.
  • Die Werte von my_hw_information und soc_id Properties 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 dtb/dtbo Bildern (Quelle Code unter system/libufdt in AOSP). mkdtimg unterstützt verschiedene Befehle, darunter create, cfg_create und dump.

create

Verwenden Sie den Befehl create, um eine dtb/dtbo Bild:

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

ftbX_filename generiert ein dt_table_entry im Bild. entryX_option-Werte sind die Werte, die dt_table_entry. 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-Ziffer (z. B. 68.000) oder eine Hexadezimalzahl (z. B. 0x6800). 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) einem relativen in dt_table_entry. Alternativ können Sie auch eine global_option als Standardoption für alle Einträge. Standardeinstellung Wert von page_size in dt_table_header ist 2048; nutzen global_option --page_size=<number>, um eine andere Wert.

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.
  • Der dritte id ist 0x00006801 und custom[0] ist 0x00000123.
  • Alle anderen verwenden den Standardwert (0).

cfg_create

Der Befehl cfg_create erstellt ein Image mit einer Konfigurationsdatei in im folgenden Format:

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

Optionen global_option und entryX_option müssen beginnen mit einem oder mehreren Leerzeichen (diese Optionen entsprechen der 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 übernimmt die Ausrichtung nicht für .dtb/.dtbo-Dateien an, sondern hängt sie an das Bild an. Wenn Sie dtc verwenden, um .dts zu kompilieren, .dtb/.dtbo, du musst die Option -a hinzufügen. Für Durch Hinzufügen der Option -a 4 wird ein Abstand hinzugefügt, sodass die Größe der .dtb/.dtbo entspricht 4 Byte.

Mehrere DT-Tabelleneinträge können .dtb/.dtbo gemeinsam nutzen. Wenn Sie denselben Dateinamen für verschiedene Einträge verwenden, wird nur ein Inhalt in das Bild mit denselben dt_offset und dt_size. Dies ist nützlich bei Verwendung unterschiedlicher Hardware mit identischen DTs.

auslagern

Für dtb/dtbo Bilder dump verwenden um die Informationen im Bild auszugeben. 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
...