Flattened Devicetree Format: PHP parsing library

Also referred to as Devicetree Blob (DTB). It is a flat binary encoding of data (primarily devicetree data, although other data is possible as well). The data is internally stored as a tree of named nodes and properties. Nodes contain properties and child nodes, while properties are name-value pairs.

The Devicetree Blobs (.dtb files) are compiled from the Devicetree Source files (.dts) through the Devicetree compiler (DTC).

On Linux systems that support this, the blobs can be accessed in /sys/firmware/fdt:

The encoding of strings used in the strings_block and structure_block is actually a subset of ASCII:

https://devicetree-specification.readthedocs.io/en/v0.3/devicetree-basics.html#node-names

Example files:

Application

["Linux", "Das U-Boot"]

File extension

dtb

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.9

References

This page hosts a formal specification of Flattened Devicetree Format using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

PHP source code to parse Flattened Devicetree Format

Dtb.php

<?php
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

/**
 * Also referred to as Devicetree Blob (DTB). It is a flat binary encoding
 * of data (primarily devicetree data, although other data is possible as well).
 * The data is internally stored as a tree of named nodes and properties. Nodes
 * contain properties and child nodes, while properties are name-value pairs.
 * 
 * The Devicetree Blobs (`.dtb` files) are compiled from the Devicetree Source
 * files (`.dts`) through the Devicetree compiler (DTC).
 * 
 * On Linux systems that support this, the blobs can be accessed in
 * `/sys/firmware/fdt`:
 * 
 * * <https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-firmware-ofw>
 * 
 * The encoding of strings used in the `strings_block` and `structure_block` is
 * actually a subset of ASCII:
 * 
 * <https://devicetree-specification.readthedocs.io/en/v0.3/devicetree-basics.html#node-names>
 * 
 * Example files:
 * 
 * * <https://github.com/qemu/qemu/tree/master/pc-bios>
 */

namespace {
    class Dtb extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Kaitai\Struct\Struct $_parent = null, \Dtb $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_magic = $this->_io->readBytes(4);
            if (!($this->magic() == "\xD0\x0D\xFE\xED")) {
                throw new \Kaitai\Struct\Error\ValidationNotEqualError("\xD0\x0D\xFE\xED", $this->magic(), $this->_io(), "/seq/0");
            }
            $this->_m_totalSize = $this->_io->readU4be();
            $this->_m_ofsStructureBlock = $this->_io->readU4be();
            $this->_m_ofsStringsBlock = $this->_io->readU4be();
            $this->_m_ofsMemoryReservationBlock = $this->_io->readU4be();
            $this->_m_version = $this->_io->readU4be();
            $this->_m_minCompatibleVersion = $this->_io->readU4be();
            if (!($this->minCompatibleVersion() <= $this->version())) {
                throw new \Kaitai\Struct\Error\ValidationGreaterThanError($this->version(), $this->minCompatibleVersion(), $this->_io(), "/seq/6");
            }
            $this->_m_bootCpuidPhys = $this->_io->readU4be();
            $this->_m_lenStringsBlock = $this->_io->readU4be();
            $this->_m_lenStructureBlock = $this->_io->readU4be();
        }
        protected $_m_memoryReservationBlock;
        public function memoryReservationBlock() {
            if ($this->_m_memoryReservationBlock !== null)
                return $this->_m_memoryReservationBlock;
            $_pos = $this->_io->pos();
            $this->_io->seek($this->ofsMemoryReservationBlock());
            $this->_m__raw_memoryReservationBlock = $this->_io->readBytes(($this->ofsStructureBlock() - $this->ofsMemoryReservationBlock()));
            $_io__raw_memoryReservationBlock = new \Kaitai\Struct\Stream($this->_m__raw_memoryReservationBlock);
            $this->_m_memoryReservationBlock = new \Dtb\MemoryBlock($_io__raw_memoryReservationBlock, $this, $this->_root);
            $this->_io->seek($_pos);
            return $this->_m_memoryReservationBlock;
        }
        protected $_m_structureBlock;
        public function structureBlock() {
            if ($this->_m_structureBlock !== null)
                return $this->_m_structureBlock;
            $_pos = $this->_io->pos();
            $this->_io->seek($this->ofsStructureBlock());
            $this->_m__raw_structureBlock = $this->_io->readBytes($this->lenStructureBlock());
            $_io__raw_structureBlock = new \Kaitai\Struct\Stream($this->_m__raw_structureBlock);
            $this->_m_structureBlock = new \Dtb\FdtBlock($_io__raw_structureBlock, $this, $this->_root);
            $this->_io->seek($_pos);
            return $this->_m_structureBlock;
        }
        protected $_m_stringsBlock;
        public function stringsBlock() {
            if ($this->_m_stringsBlock !== null)
                return $this->_m_stringsBlock;
            $_pos = $this->_io->pos();
            $this->_io->seek($this->ofsStringsBlock());
            $this->_m__raw_stringsBlock = $this->_io->readBytes($this->lenStringsBlock());
            $_io__raw_stringsBlock = new \Kaitai\Struct\Stream($this->_m__raw_stringsBlock);
            $this->_m_stringsBlock = new \Dtb\Strings($_io__raw_stringsBlock, $this, $this->_root);
            $this->_io->seek($_pos);
            return $this->_m_stringsBlock;
        }
        protected $_m_magic;
        protected $_m_totalSize;
        protected $_m_ofsStructureBlock;
        protected $_m_ofsStringsBlock;
        protected $_m_ofsMemoryReservationBlock;
        protected $_m_version;
        protected $_m_minCompatibleVersion;
        protected $_m_bootCpuidPhys;
        protected $_m_lenStringsBlock;
        protected $_m_lenStructureBlock;
        protected $_m__raw_memoryReservationBlock;
        protected $_m__raw_structureBlock;
        protected $_m__raw_stringsBlock;
        public function magic() { return $this->_m_magic; }
        public function totalSize() { return $this->_m_totalSize; }
        public function ofsStructureBlock() { return $this->_m_ofsStructureBlock; }
        public function ofsStringsBlock() { return $this->_m_ofsStringsBlock; }
        public function ofsMemoryReservationBlock() { return $this->_m_ofsMemoryReservationBlock; }
        public function version() { return $this->_m_version; }
        public function minCompatibleVersion() { return $this->_m_minCompatibleVersion; }
        public function bootCpuidPhys() { return $this->_m_bootCpuidPhys; }
        public function lenStringsBlock() { return $this->_m_lenStringsBlock; }
        public function lenStructureBlock() { return $this->_m_lenStructureBlock; }
        public function _raw_memoryReservationBlock() { return $this->_m__raw_memoryReservationBlock; }
        public function _raw_structureBlock() { return $this->_m__raw_structureBlock; }
        public function _raw_stringsBlock() { return $this->_m__raw_stringsBlock; }
    }
}

namespace Dtb {
    class MemoryBlock extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dtb $_parent = null, \Dtb $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_entries = [];
            $i = 0;
            while (!$this->_io->isEof()) {
                $this->_m_entries[] = new \Dtb\MemoryBlockEntry($this->_io, $this, $this->_root);
                $i++;
            }
        }
        protected $_m_entries;
        public function entries() { return $this->_m_entries; }
    }
}

namespace Dtb {
    class FdtBlock extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dtb $_parent = null, \Dtb $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_nodes = [];
            $i = 0;
            do {
                $_ = new \Dtb\FdtNode($this->_io, $this, $this->_root);
                $this->_m_nodes[] = $_;
                $i++;
            } while (!($_->type() == \Dtb\Fdt::END));
        }
        protected $_m_nodes;
        public function nodes() { return $this->_m_nodes; }
    }
}

namespace Dtb {
    class MemoryBlockEntry extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dtb\MemoryBlock $_parent = null, \Dtb $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_address = $this->_io->readU8be();
            $this->_m_size = $this->_io->readU8be();
        }
        protected $_m_address;
        protected $_m_size;

        /**
         * physical address of a reserved memory region
         */
        public function address() { return $this->_m_address; }

        /**
         * size of a reserved memory region
         */
        public function size() { return $this->_m_size; }
    }
}

namespace Dtb {
    class Strings extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dtb $_parent = null, \Dtb $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_strings = [];
            $i = 0;
            while (!$this->_io->isEof()) {
                $this->_m_strings[] = \Kaitai\Struct\Stream::bytesToStr($this->_io->readBytesTerm(0, false, true, true), "ASCII");
                $i++;
            }
        }
        protected $_m_strings;
        public function strings() { return $this->_m_strings; }
    }
}

namespace Dtb {
    class FdtProp extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dtb\FdtNode $_parent = null, \Dtb $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_lenProperty = $this->_io->readU4be();
            $this->_m_ofsName = $this->_io->readU4be();
            $this->_m_property = $this->_io->readBytes($this->lenProperty());
            $this->_m_padding = $this->_io->readBytes(\Kaitai\Struct\Stream::mod(-($this->_io()->pos()), 4));
        }
        protected $_m_name;
        public function name() {
            if ($this->_m_name !== null)
                return $this->_m_name;
            $io = $this->_root()->stringsBlock()->_io();
            $_pos = $io->pos();
            $io->seek($this->ofsName());
            $this->_m_name = \Kaitai\Struct\Stream::bytesToStr($io->readBytesTerm(0, false, true, true), "ASCII");
            $io->seek($_pos);
            return $this->_m_name;
        }
        protected $_m_lenProperty;
        protected $_m_ofsName;
        protected $_m_property;
        protected $_m_padding;
        public function lenProperty() { return $this->_m_lenProperty; }
        public function ofsName() { return $this->_m_ofsName; }
        public function property() { return $this->_m_property; }
        public function padding() { return $this->_m_padding; }
    }
}

namespace Dtb {
    class FdtNode extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dtb\FdtBlock $_parent = null, \Dtb $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_type = $this->_io->readU4be();
            switch ($this->type()) {
                case \Dtb\Fdt::BEGIN_NODE:
                    $this->_m_body = new \Dtb\FdtBeginNode($this->_io, $this, $this->_root);
                    break;
                case \Dtb\Fdt::PROP:
                    $this->_m_body = new \Dtb\FdtProp($this->_io, $this, $this->_root);
                    break;
            }
        }
        protected $_m_type;
        protected $_m_body;
        public function type() { return $this->_m_type; }
        public function body() { return $this->_m_body; }
    }
}

namespace Dtb {
    class FdtBeginNode extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Dtb\FdtNode $_parent = null, \Dtb $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_name = \Kaitai\Struct\Stream::bytesToStr($this->_io->readBytesTerm(0, false, true, true), "ASCII");
            $this->_m_padding = $this->_io->readBytes(\Kaitai\Struct\Stream::mod(-($this->_io()->pos()), 4));
        }
        protected $_m_name;
        protected $_m_padding;
        public function name() { return $this->_m_name; }
        public function padding() { return $this->_m_padding; }
    }
}

namespace Dtb {
    class Fdt {
        const BEGIN_NODE = 1;
        const END_NODE = 2;
        const PROP = 3;
        const NOP = 4;
        const END = 9;
    }
}