1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-23 11:18:54 +00:00
freebsd/usr.bin/dtc/dtb.hh
David Chisnall af0dd31fc4 Import new (BSDL) device tree compiler. Now built by default, so that it can't
be used on the host system (and not installed on the device, if required).  The
GPL'd one is still available if there are any devices that need it (make
universe passes with it, including kernels that use fdt, but there may be some
out-of-tree ones).  WITH_GPL_DTC can be used to select the old one, for now.

Probably won't be MFC'd, but we'll remove the GPL'd version in head after the
new one has had a lot more testing and ship it in 10.0.
2013-01-22 17:49:51 +00:00

366 lines
11 KiB
C++

/*-
* 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.
*
* $FreeBSD$
*/
#ifndef _DTB_HH_
#define _DTB_HH_
#include <map>
#include "string.hh"
#include <assert.h>
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);
}
/**
* 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(string name) = 0;
/**
* Writes a comment into the output stream. Useful only when debugging
* the output.
*/
virtual void write_comment(string name) = 0;
/**
* Writes a string. A nul terminator is implicitly added.
*/
virtual void write_string(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.
*/
virtual void write_label(string name) {}
/**
* Comments are ignored by the binary writer.
*/
virtual void write_comment(string name) {}
virtual void write_string(string name);
virtual void write_data(uint8_t v);
virtual void write_data(uint32_t v);
virtual void write_data(uint64_t v);
virtual void write_to_file(int fd);
virtual uint32_t size();
};
/**
* 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 C string directly to the ouput as-is. This is mainly used
* for writing directives.
*/
void write_string(const char *c);
/**
* 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) {}
virtual void write_label(string name);
virtual void write_comment(string name);
virtual void write_string(string name);
virtual void write_data(uint8_t v);
virtual void write_data(uint32_t v);
virtual void write_data(uint64_t v);
virtual void write_to_file(int fd);
virtual uint32_t size();
};
/**
* 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<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<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(string str);
/**
* Writes the strings table to the specified output.
*/
void write(dtb::output_writer &writer);
};
} // namespace dtb
} // namespace dtc
#endif // !_DTB_HH_