aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/dtc/dtb.hh
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/dtc/dtb.hh')
-rw-r--r--usr.bin/dtc/dtb.hh373
1 files changed, 373 insertions, 0 deletions
diff --git a/usr.bin/dtc/dtb.hh b/usr.bin/dtc/dtb.hh
new file mode 100644
index 000000000000..410ec98569be
--- /dev/null
+++ b/usr.bin/dtc/dtb.hh
@@ -0,0 +1,373 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2013 David Chisnall
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DTB_HH_
+#define _DTB_HH_
+#include <map>
+#include <string>
+
+#include <assert.h>
+
+#include "input_buffer.hh"
+#include "util.hh"
+
+namespace dtc
+{
+/**
+ * The dtb namespace contains code related to the generation of device tree
+ * blobs, the binary representation of flattened device trees. The abstract
+ * tree representation calls into this code to generate the output.
+ */
+namespace dtb
+{
+/** The token types in the DTB, as defined by ยง7.4.1 of the ePAPR
+ * specification. All of these values are written in big-endian format in the
+ * output.
+ */
+enum token_type
+{
+ /**
+ * Marker indicating the start of a node in the tree. This is followed
+ * by the nul-terminated name. If a unit address is specified, then
+ * the name also contains the address, with an @ symbol between the end
+ * of the name and the start of the address.
+ *
+ * The name is then padded such that the next token begins on a 4-byte
+ * boundary. The node may contain properties, other nodes, both, or be
+ * empty.
+ */
+ FDT_BEGIN_NODE = 0x00000001,
+ /**
+ * Marker indicating the end of a node.
+ */
+ FDT_END_NODE = 0x00000002,
+ /**
+ * The start of a property. This is followed by two 32-bit big-endian
+ * values. The first indicates the length of the property value, the
+ * second its index in the strings table. It is then followed by the
+ * property value, if the value is of non-zero length.
+ */
+ FDT_PROP = 0x00000003,
+ /**
+ * Ignored token. May be used for padding inside DTB nodes.
+ */
+ FDT_NOP = 0x00000004,
+ /**
+ * Marker indicating the end of the tree.
+ */
+ FDT_END = 0x00000009
+};
+
+/**
+ * Returns the token as a string. This is used for debugging and for printing
+ * human-friendly error messages about malformed DTB input.
+ */
+inline const char *token_type_name(token_type t)
+{
+ switch(t)
+ {
+ case FDT_BEGIN_NODE:
+ return "FDT_BEGIN_NODE";
+ case FDT_END_NODE:
+ return "FDT_END_NODE";
+ case FDT_PROP:
+ return "FDT_PROP";
+ case FDT_NOP:
+ return "FDT_NOP";
+ case FDT_END:
+ return "FDT_END";
+ }
+ assert(0);
+ // Not reached.
+ return nullptr;
+}
+
+/**
+ * Abstract class for writing a section of the output. We create one
+ * of these for each section that needs to be written. It is intended to build
+ * a temporary buffer of the output in memory and then write it to a file
+ * stream. The size can be returned after all of the data has been written
+ * into the internal buffer, so the sizes of the three tables can be calculated
+ * before storing them in the buffer.
+ */
+struct output_writer
+{
+ /**
+ * Writes a label into the output stream. This is only applicable for
+ * assembly output, where the labels become symbols that can be
+ * resolved at link time.
+ */
+ virtual void write_label(const std::string &name) = 0;
+ /**
+ * Writes a comment into the output stream. Useful only when debugging
+ * the output.
+ */
+ virtual void write_comment(const std::string &name) = 0;
+ /**
+ * Writes a string. A nul terminator is implicitly added.
+ */
+ virtual void write_string(const std::string &name) = 0;
+ /**
+ * Writes a single 8-bit value.
+ */
+ virtual void write_data(uint8_t) = 0;
+ /**
+ * Writes a single 32-bit value. The value is written in big-endian
+ * format, but should be passed in the host's native endian.
+ */
+ virtual void write_data(uint32_t) = 0;
+ /**
+ * Writes a single 64-bit value. The value is written in big-endian
+ * format, but should be passed in the host's native endian.
+ */
+ virtual void write_data(uint64_t) = 0;
+ /**
+ * Writes the collected output to the specified file descriptor.
+ */
+ virtual void write_to_file(int fd) = 0;
+ /**
+ * Returns the number of bytes.
+ */
+ virtual uint32_t size() = 0;
+ /**
+ * Helper for writing tokens to the output stream. This writes a
+ * comment above the token describing its value, for easier debugging
+ * of the output.
+ */
+ inline void write_token(token_type t)
+ {
+ write_comment(token_type_name(t));
+ write_data((uint32_t)t);
+ }
+ /**
+ * Helper function that writes a byte buffer to the output, one byte at
+ * a time.
+ */
+ void write_data(byte_buffer b);
+};
+
+/**
+ * Binary file writer. This class is responsible for writing the DTB output
+ * directly in blob format.
+ */
+class binary_writer : public output_writer
+{
+ /**
+ * The internal buffer used to store the blob while it is being
+ * constructed.
+ */
+ byte_buffer buffer;
+ public:
+ /**
+ * The binary format does not support labels, so this method
+ * does nothing.
+ */
+ void write_label(const std::string &) override {}
+ /**
+ * Comments are ignored by the binary writer.
+ */
+ void write_comment(const std::string&) override {}
+ void write_string(const std::string &name) override;
+ void write_data(uint8_t v) override;
+ void write_data(uint32_t v) override;
+ void write_data(uint64_t v) override;
+ void write_to_file(int fd) override;
+ uint32_t size() override;
+};
+/**
+ * Assembly writer. This class is responsible for writing the output in an
+ * assembly format that is suitable for linking into a kernel, loader, and so
+ * on.
+ */
+class asm_writer : public output_writer
+{
+ /**
+ * The internal buffer for temporary values. Note that this actually
+ * contains ASCII text, but it is a byte buffer so that we can just
+ * copy strings across as-is.
+ */
+ byte_buffer buffer;
+ /**
+ * The number of bytes written to the current line. This is used to
+ * allow line wrapping, where we aim to write four .byte directives to
+ * make the alignment clearer.
+ */
+ int byte_count;
+ /**
+ * The current number of bytes written. This is the number in binary
+ * format, not the number of bytes in the buffer.
+ */
+ uint32_t bytes_written;
+
+ /**
+ * Writes a string directly to the output as-is. This is the function that
+ * performs the real output.
+ */
+ void write_string(const char *c);
+ /**
+ * Write a string to the output.
+ */
+ void write_string(const std::string &c) override;
+ /**
+ * Writes the string, starting on a new line.
+ */
+ void write_line(const char *c);
+ /**
+ * Writes a byte in binary format. This will emit a single .byte
+ * directive, with up to four per line.
+ */
+ void write_byte(uint8_t b);
+ public:
+ asm_writer() : byte_count(0), bytes_written(0) {}
+ void write_label(const std::string &name) override;
+ void write_comment(const std::string &name) override;
+ void write_data(uint8_t v) override;
+ void write_data(uint32_t v) override;
+ void write_data(uint64_t v) override;
+ void write_to_file(int fd) override;
+ uint32_t size() override;
+};
+
+/**
+ * Class encapsulating the device tree blob header. This class stores all of
+ * the values found in the header and is responsible for writing them to the
+ * output.
+ */
+struct header
+{
+ /**
+ * Magic value, used to validate that this really is a device tree
+ * blob. Should always be set to 0xd00dfeed.
+ */
+ uint32_t magic;
+ /**
+ * The total size of the blob, including header, reservations, strings
+ * table, and padding.
+ */
+ uint32_t totalsize;
+ /**
+ * The offset from the start of the blob of the struct table (i.e. the
+ * part of the blob containing the entire device tree).
+ */
+ uint32_t off_dt_struct;
+ /**
+ * The offset from the start of the blob of the strings table.
+ */
+ uint32_t off_dt_strings;
+ /**
+ * The offset of the reservation map from the start of the blob.
+ */
+ uint32_t off_mem_rsvmap;
+ /**
+ * The version of the blob. This should always be 17.
+ */
+ uint32_t version;
+ /**
+ * The earliest version of the DTB specification with which this blob
+ * is backwards compatible. This should always be 16.
+ */
+ uint32_t last_comp_version;
+ /**
+ * The ID of the CPU where this boots.
+ */
+ uint32_t boot_cpuid_phys;
+ /**
+ * The size of the strings table.
+ */
+ uint32_t size_dt_strings;
+ /**
+ * The size of the struct table.
+ */
+ uint32_t size_dt_struct;
+ /**
+ * Writes the entire header to the specified output buffer.
+ */
+ void write(output_writer &out);
+ /**
+ * Reads the header from bits binary representation in a blob.
+ */
+ bool read_dtb(input_buffer &input);
+ /**
+ * Default constructor. Initialises the values that have sensible
+ * defaults, leaves the others blank.
+ */
+ header() : magic(0xd00dfeed), version(17), last_comp_version(16),
+ boot_cpuid_phys(0) {}
+};
+
+/**
+ * Class encapsulating the string table. FDT strings are stored in a string
+ * section. This maintains a map from strings to their offsets in the strings
+ * section.
+ *
+ * Note: We don't currently do suffix matching, which may save a small amount
+ * of space.
+ */
+class string_table {
+ /**
+ * Map from strings to their offset.
+ */
+ std::map<std::string, uint32_t> string_offsets;
+ /**
+ * The strings, in the order in which they should be written to the
+ * output. The order must be stable - adding another string must not
+ * change the offset of any that we have already referenced - and so we
+ * simply write the strings in the order that they are passed.
+ */
+ std::vector<std::string> strings;
+ /**
+ * The current size of the strings section.
+ */
+ uint32_t size;
+ public:
+ /**
+ * Default constructor, creates an empty strings table.
+ */
+ string_table() : size(0) {}
+ /**
+ * Adds a string to the table, returning the offset from the start
+ * where it will be written. If the string is already present, this
+ * will return its existing offset, otherwise it will return a new
+ * offset.
+ */
+ uint32_t add_string(const std::string &str);
+ /**
+ * Writes the strings table to the specified output.
+ */
+ void write(dtb::output_writer &writer);
+};
+
+} // namespace dtb
+
+} // namespace dtc
+
+#endif // !_DTB_HH_