5. Flattened Devicetree(DTB)フォーマット

Devicetree Blob(DTB)形式は、デバイスツリーデータのフラットバイナリエンコーディングです。 これは、ソフトウェアプログラム間でデバイスツリーデータを交換するために使用されていました。 たとえば、オペレーティングシステムを起動すると、ファームウェアはDTBをOSカーネルに渡します。

DTB形式は、単一の線形のポインターレスデータ構造内でデバイスツリーデータをエンコードします。 これは、小さなヘッダー(sect-fdt-header を参照)と、それに続く3つの可変サイズのセクションで構成されます。 メモリ予約ブロック(5.3 章 を参照)、構造ブロック(5.4 章 を参照)、および文字列ブロック(5.5 章 を参照)。 これらは、フラット化されたデバイスツリーにこの順序で存在する必要があります。 したがって、デバイスツリー構造全体は、アドレスでメモリにロードされると、 図 5.1 の図のようになります(下のアドレスは図の上部にあります)。

digraph tree { rankdir = LR ranksep = "1.5" size = "6,8" edge [ dir="none" ] node [ shape="Mrecord" width="2.5" ] "node" [ label = "struct fdt_header | (free space) | memory reservation block | (free space) | structure block | (free space) | strings block | (free space)" ] }

図 5.1 Devicetree .dtb Structure

(free space)セクションは存在しない場合がありますが、場合によっては、個々のブロックの配置制約を満たす必要がある場合があります(:numref:`sect-fdt-alignment`を参照)。 .. _sect-fdt-versioning:

5.1. バージョニング

フォーマットの元の定義以降、フラット化されたデバイスツリー構造のいくつかのバージョンが定義されています。 ヘッダーのフィールドはバージョンを示し、クライアントプログラムがデバイスツリーが互換性のある形式でエンコードされているかどうかを判断できるようにします。

本文書では、このフォーマットのバージョン17についてのみ説明します。 DTSpec 準拠したブートプログラムは、バージョン17以降のデバイスツリーを提供する必要があり、バージョン16と下位互換性のあるバージョンのデバイスツリーを提供する必要があります。 DTSpec 準拠するクライアントプログラムは、バージョン17と下位互換性のある任意のバージョンのデバイスツリーを受け入れるものとし、他のバージョンも受け入れることができます。

注釈

The version is with respect to the binary structure of the device tree, not its content.

5.2. ヘッダー

デバイスツリーのヘッダーのレイアウトは、次のC構造によって定義されます。 すべてのヘッダーフィールドは32ビット整数であり、ビッグエンディアン形式で格納されます。

Flattened Devicetree Header Fields

struct fdt_header {
    uint32_t magic;
    uint32_t totalsize;
    uint32_t off_dt_struct;
    uint32_t off_dt_strings;
    uint32_t off_mem_rsvmap;
    uint32_t version;
    uint32_t last_comp_version;
    uint32_t boot_cpuid_phys;
    uint32_t size_dt_strings;
    uint32_t size_dt_struct;
};
magic

This field shall contain the value 0xd00dfeed (big-endian).

totalsize

This field shall contain the total size in bytes of the devicetree data structure. This size shall encompass all sections of the structure: the header, the memory reservation block, structure block and strings block, as well as any free space gaps between the blocks or after the final block.

off_dt_struct

This field shall contain the offset in bytes of the structure block (see 5.4 章) from the beginning of the header.

off_dt_strings

This field shall contain the offset in bytes of the strings block (see 5.5 章) from the beginning of the header.

off_mem_rsvmap

This field shall contain the offset in bytes of the memory reservation block (see 5.3 章) from the beginning of the header.

version

This field shall contain the version of the devicetree data structure. The version is 17 if using the structure as defined in this document. An DTSpec boot program may provide the devicetree of a later version, in which case this field shall contain the version number defined in whichever later document gives the details of that version.

last_comp_version

This field shall contain the lowest version of the devicetree data structure with which the version used is backwards compatible. So, for the structure as defined in this document (version 17), this field shall contain 16 because version 17 is backwards compatible with version 16, but not earlier versions. As per sect-fdt-versioning, a DTSpec boot program should provide a devicetree in a format which is backwards compatible with version 16, and thus this field shall always contain 16.

boot_cpuid_phys

This field shall contain the physical ID of the system’s boot CPU. It shall be identical to the physical ID given in the reg property of that CPU node within the devicetree.

size_dt_strings

This field shall contain the length in bytes of the strings block section of the devicetree blob.

size_dt_struct

This field shall contain the length in bytes of the structure block section of the devicetree blob.

5.3. Memory Reservation Block

5.3.1. Purpose

The memory reservation block provides the client program with a list of areas in physical memory which are reserved; that is, which shall not be used for general memory allocations. It is used to protect vital data structures from being overwritten by the client program. For example, on some systems with an IOMMU, the TCE (translation control entry) tables initialized by a DTSpec boot program would need to be protected in this manner. Likewise, any boot program code or data used during the client program’s runtime would need to be reserved (e.g., RTAS on Open Firmware platforms). DTSpec does not require the boot program to provide any such runtime components, but it does not prohibit implementations from doing so as an extension.

More specifically, a client program shall not access memory in a reserved region unless other information provided by the boot program explicitly indicates that it shall do so. The client program may then access the indicated section of the reserved memory in the indicated manner. Methods by which the boot program can indicate to the client program specific uses for reserved memory may appear in this document, in optional extensions to it, or in platform-specific documentation.

The reserved regions supplied by a boot program may, but are not required to, encompass the devicetree blob itself. The client program shall ensure that it does not overwrite this data structure before it is used, whether or not it is in the reserved areas.

Any memory that is declared in a memory node and is accessed by the boot program or caused to be accessed by the boot program after client entry must be reserved. Examples of this type of access include (e.g., speculative memory reads through a non-guarded virtual page).

This requirement is necessary because any memory that is not reserved may be accessed by the client program with arbitrary storage attributes.

Any accesses to reserved memory by or caused by the boot program must be done as not Caching Inhibited and Memory Coherence Required (i.e., WIMG = 0bx01x), and additionally for Book III-S implementations as not Write Through Required (i.e., WIMG = 0b001x). Further, if the VLE storage attribute is supported, all accesses to reserved memory must be done as VLE=0.

This requirement is necessary because the client program is permitted to map memory with storage attributes specified as not Write Through Required, not Caching Inhibited, and Memory Coherence Required (i.e., WIMG = 0b001x), and VLE=0 where supported. The client program may use large virtual pages that contain reserved memory. However, the client program may not modify reserved memory, so the boot program may perform accesses to reserved memory as Write Through Required where conflicting values for this storage attribute are architecturally permissible.

5.3.2. Format

The memory reservation block consists of a list of pairs of 64-bit big-endian integers, each pair being represented by the following C structure.

struct fdt_reserve_entry {
    uint64_t address;
    uint64_t size;
};

Each pair gives the physical address and size in bytes of a reserved memory region. These given regions shall not overlap each other. The list of reserved blocks shall be terminated with an entry where both address and size are equal to 0. Note that the address and size values are always 64-bit. On 32-bit CPUs the upper 32-bits of the value are ignored.

Each uint64_t in the memory reservation block, and thus the memory reservation block as a whole, shall be located at an 8-byte aligned offset from the beginning of the devicetree blob (see sect-fdt-alignment).

5.3.3. Memory Reservation Block and UEFI

As with the /reserved-memory node (3.5.4 章), when booting via [UEFI] entries in the Memory Reservation Block must also be listed in the system memory map obtained via the GetMemoryMap() to protect against allocations by UEFI applications. The memory reservation block entries should be listed with type EfiReservedMemoryType.

5.4. Structure Block

The structure block describes the structure and contents of the devicetree itself. It is composed of a sequence of tokens with data, as described below. These are organized into a linear tree structure, as described below.

Each token in the structure block, and thus the structure block itself, shall be located at a 4-byte aligned offset from the beginning of the devicetree blob (see sect-fdt-alignment).

5.4.1. Lexical structure

The structure block is composed of a sequence of pieces, each beginning with a token, that is, a big-endian 32-bit integer. Some tokens are followed by extra data, the format of which is determined by the token value. All tokens shall be aligned on a 32-bit boundary, which may require padding bytes (with a value of 0x0) to be inserted after the previous token’s data.

The five token types are as follows:

FDT_BEGIN_NODE (0x00000001)

The FDT_BEGIN_NODE token marks the beginning of a node’s representation. It shall be followed by the node’s unit name as extra data. The name is stored as a null-terminated string, and shall include the unit address (see sect-node-names), if any. The node name is followed by zeroed padding bytes, if necessary for alignment, and then the next token, which may be any token except FDT_END.

FDT_END_NODE (0x00000002)

The FDT_END_NODE token marks the end of a node’s representation. This token has no extra data; so it is followed immediately by the next token, which may be any token except FDT_PROP.

FDT_PROP (0x00000003)

The FDT_PROP token marks the beginning of the representation of one property in the devicetree. It shall be followed by extra data describing the property. This data consists first of the property’s length and name represented as the following C structure:

struct {
    uint32_t len;
    uint32_t nameoff;
}

Both the fields in this structure are 32-bit big-endian integers.

  • len gives the length of the property’s value in bytes (which may be zero, indicating an empty property, see sect-property-values).

  • nameoff gives an offset into the strings block (see 5.5 章) at which the property’s name is stored as a null-terminated string.

After this structure, the property’s value is given as a byte string of length len. This value is followed by zeroed padding bytes (if necessary) to align to the next 32-bit boundary and then the next token, which may be any token except FDT_END.

FDT_NOP (0x00000004)

The FDT_NOP token will be ignored by any program parsing the device tree. This token has no extra data; so it is followed immediately by the next token, which can be any valid token. A property or node definition in the tree can be overwritten with FDT_NOP tokens to remove it from the tree without needing to move other sections of the tree’s representation in the devicetree blob.

FDT_END (0x00000009)

The FDT_END token marks the end of the structure block. There shall be only one FDT_END token, and it shall be the last token in the structure block. It has no extra data; so the byte immediately after the FDT_END token has offset from the beginning of the structure block equal to the value of the size_dt_struct field in the device tree blob header.

5.4.2. Tree structure

The devicetree structure is represented as a linear tree: the representation of each node begins with an FDT_BEGIN_NODE token and ends with an FDT_END_NODE token. The node’s properties and subnodes (if any) are represented before the FDT_END_NODE, so that the FDT_BEGIN_NODE and FDT_END_NODE tokens for those subnodes are nested within those of the parent.

The structure block as a whole consists of the root node’s representation (which contains the representations for all other nodes), followed by an FDT_END token to mark the end of the structure block as a whole.

More precisely, each node’s representation consists of the following components:

  • (optionally) any number of FDT_NOP tokens

  • FDT_BEGIN_NODE token

    • The node’s name as a null-terminated string

    • [zeroed padding bytes to align to a 4-byte boundary]

  • For each property of the node:

    • (optionally) any number of FDT_NOP tokens

    • FDT_PROP token

      • property information as given in 5.4.1 章

      • [zeroed padding bytes to align to a 4-byte boundary]

  • Representations of all child nodes in this format

  • (optionally) any number of FDT_NOP tokens

  • FDT_END_NODE token

Note that this process requires that all property definitions for a particular node precede any subnode definitions for that node. Although the structure would not be ambiguous if properties and subnodes were intermingled, the code needed to process a flat tree is simplified by this requirement.

5.5. Strings Block

The strings block contains strings representing all the property names used in the tree. These null terminated strings are simply concatenated together in this section, and referred to from the structure block by an offset into the strings block.

The strings block has no alignment constraints and may appear at any offset from the beginning of the devicetree blob.

5.6. アラインメント

デバイスツリーBLOBは、8バイトにアラインされたアドレスに配置する必要があります。 32ビットマシンの下位互換性を維持するために、一部のソフトウェアでは4バイトアライメントがサポートされていますが、これは DTSpec に準拠していません。

メモリ予約および構造ブロック内のデータを、整列されていないメモリアクセスなしで使用するには、それらは適切に整列されたメモリアドレスにある必要があります。 具体的には、メモリ予約ブロックを8バイト境界に、構造ブロックを4バイト境界に揃える必要があります。

さらに、サブブロックの配置を破壊することなく、デバイスツリーBLOB全体を再配置できます。

前のセクションで説明したように、構造体ブロックと文字列ブロックは、デバイスツリーブロブの先頭からオフセットを揃える必要があります。 ブロックのメモリ内アラインメントを確実にするには、デバイスツリー全体が、サブブロックのいずれかの最大アラインメント、つまり8バイト境界にアラインメントされたアドレスにロードされるようにするだけで十分です。 DTSpec 準拠したブートプログラムは、デバイスツリーブロブをクライアントプログラムに渡す前に、そのような位置合わせされたアドレスにロードする必要があります。 DTSpec の場合クライアントプログラムは、デバイスツリーブロブをメモリに再配置します。 これは、別の8バイトに整列されたアドレスにのみ再配置する必要があります。