Flattened Device Tree (FDT) Essential for Virtualization Developers

Michael Zhao
5 min readApr 2, 2022

--

This article is not a formal introduction or spec of Flattened Device Tree (FDT), but is a collection of practical skills and experience. They are mainly from the view of a virtualization developer on arm64 architecture.

What is FDT?

FDT is a data structure, describing the hardware configuration of a machine.

This is not the formal definition of FDT, but it is practical enough for developers to understand why it exists.

Before FDT came around, the hardware information (like the starting address and size of the RAM, or where a UART device is, etc) was written in source code. You can imagine, a lot of source code was written only to define the resources of a particular machine, and these code cannot be shared between different machines. This problem was then serious on arm-based platform due to architecture reason.

FDT was invented to separate source code and resource definition. Source code is only for functionality; while resources are described in a tree-like data structure.

Now you can download the latest specification for FDT from devicetree.org .

The advantage of introducing FDT includes at least:

  • Source code for different devices drivers and platforms can be shared easily
  • The presentation of resources is uniformed
  • The new designed tree-view makes it easy to understand what hardware a machine owns

The content of a typical FDT is like:

/{
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;

memory {
device_type = "memory";
reg = <0x00000000 0x40000000>;
};
......

The basic elements of a device tree are:

  • Node: A node stands for a device or a collection of devices. memory in the previous example is a node. The whole itself is also node (root node).
  • Attribute: Key-value pair used to describe the node.

Several sorts of artifacts are related to FDT:

  • .dts : Device tree source file. This is the human readable source file. The content piece shown above is picked from a .dts file. People create .dts files for there own machines, write the device node and specify the resources.
  • .dtsi : You may find many .dtsi files under Linux kernel source folder arch/arm64/boot/dts/ . They are the common “header files” of device tree source. They are included in other .dts files.
  • .dtb : Device tree blob file. This is the FDT binary built from .dts . Kernel reads and parses .dtb file to understand hardware structure.
  • dtc : dtc is not part of a device tree itself, but the most commonly used tool to encode and decode device trees on Linux.

How to observe FDT?

Decoding a `.dtb` file

If you can get the .dtb file you are interested in. Decoding is as easy as running the command:

# dtc -I dtb -O dts -o device-tree.dts device-tree.dtb

The command means: Input (-I) is a device tree blob file (dtb): “device-tree.dtb”, output (-O)is a device tree source file (dts): “device-tree.dts”. Then you can check the content of .dts with any text editor.

On a running system

If you want to check the device tree of a running operating system, you can get the input from the kernel file system:

# dtc -I fs /sys/firmware/devicetree/base

From a VMM

If you are using a virtual machine. Besides the 2 ways just mentioned, the virtual machine monitor (VMM) may provide additional support to observe FDT.

Cloud Hypervisor prints the decoded FDT content to its log file. The FDT content is output in DEBUG level, it’s only dumped with the most verbose logging level. If you enable -vvv option, you can see the FDT text in log file, like:

How to build FDT?

Encoding a `.dts` file

This is the most typical way. After preparing a device tree source file, you can generate the blob file with:

# dtc -I dts -O dtb -o device-tree.dtb device-tree.dts

This is the invert process of the decoding.

In a VMM

Using libfdt

dtc tool provides a library libfdt which contains a rich set of APIs for building FDT. In this header file you can have a glance of all the functions to be used in creating a FDT.

For a VMM written in C language, using libfdt looks the most natural and convenient way. That is the case of kvmtool .

To a Rust based VMM developer, there are 2 ways to build FDT.

libfdt wrapper

Cloud Hypervisor used a libfdt wrapper to create FDT in early stage. You can see how is the FDT generated in this source file. That’s almost the same thing as using libfdt itself, just written in Rust language.

A piece of code for example:

The drawback of this method is obvious: the build environment is not independent, it requires a native library.

At that time, all 3 major Rust based VMMs (Cloud Hypervisor, Firecracker and CrosVM) works with FDT in the same way.

Rust crate for FDT

Later, a Google engineer contributed a FDT crate in Rust language to rust-vmm project: vmm-fdt.

With the FDT crate, now the code creating the same node looks like:

The overall process is quite similar. But now we are saved from using external library. It helps avoid a lot of trouble in setting up development environment, especially in CI (continuous integration).

--

--

Michael Zhao
Michael Zhao

Written by Michael Zhao

Major in virtualization, security and ARM.

No responses yet