xref: /freebsd/usr.bin/dtc/dtb.hh (revision d91f8db5f1822c43cd256f19aae1d059e4b25a26)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2013 David Chisnall
5  * All rights reserved.
6  *
7  * This software was developed by SRI International and the University of
8  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9  * ("CTSRD"), as part of the DARPA CRASH research programme.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34 
35 #ifndef _DTB_HH_
36 #define _DTB_HH_
37 #include <map>
38 #include <string>
39 
40 #include <assert.h>
41 
42 #include "input_buffer.hh"
43 #include "util.hh"
44 
45 namespace dtc
46 {
47 /**
48  * The dtb namespace contains code related to the generation of device tree
49  * blobs, the binary representation of flattened device trees.  The abstract
50  * tree representation calls into this code to generate the output.
51  */
52 namespace dtb
53 {
54 /** The token types in the DTB, as defined by §7.4.1 of the ePAPR
55  * specification.  All of these values are written in big-endian format in the
56  * output.
57  */
58 enum token_type
59 {
60 	/**
61 	 * Marker indicating the start of a node in the tree.  This is followed
62 	 * by the nul-terminated name.  If a unit address is specified, then
63 	 * the name also contains the address, with an @ symbol between the end
64 	 * of the name and the start of the address.
65 	 *
66 	 * The name is then padded such that the next token begins on a 4-byte
67 	 * boundary.  The node may contain properties, other nodes, both, or be
68 	 * empty.
69 	 */
70 	FDT_BEGIN_NODE = 0x00000001,
71 	/**
72 	 * Marker indicating the end of a node.
73 	 */
74 	FDT_END_NODE   = 0x00000002,
75 	/**
76 	 * The start of a property.  This is followed by two 32-bit big-endian
77 	 * values.  The first indicates the length of the property value, the
78 	 * second its index in the strings table.  It is then followed by the
79 	 * property value, if the value is of non-zero length.
80 	 */
81 	FDT_PROP       = 0x00000003,
82 	/**
83 	 * Ignored token.  May be used for padding inside DTB nodes.
84 	 */
85 	FDT_NOP        = 0x00000004,
86 	/**
87 	 * Marker indicating the end of the tree.
88 	 */
89 	FDT_END        = 0x00000009
90 };
91 
92 /**
93  * Returns the token as a string.  This is used for debugging and for printing
94  * human-friendly error messages about malformed DTB input.
95  */
96 inline const char *token_type_name(token_type t)
97 {
98 	switch(t)
99 	{
100 		case FDT_BEGIN_NODE:
101 			return "FDT_BEGIN_NODE";
102 		case FDT_END_NODE:
103 			return "FDT_END_NODE";
104 		case FDT_PROP:
105 			return "FDT_PROP";
106 		case FDT_NOP:
107 			return "FDT_NOP";
108 		case FDT_END:
109 			return "FDT_END";
110 	}
111 	assert(0);
112 	// Not reached.
113 	return nullptr;
114 }
115 
116 /**
117  * Abstract class for writing a section of the output.  We create one
118  * of these for each section that needs to be written.  It is intended to build
119  * a temporary buffer of the output in memory and then write it to a file
120  * stream.  The size can be returned after all of the data has been written
121  * into the internal buffer, so the sizes of the three tables can be calculated
122  * before storing them in the buffer.
123  */
124 struct output_writer
125 {
126 	/**
127 	 * Writes a label into the output stream.  This is only applicable for
128 	 * assembly output, where the labels become symbols that can be
129 	 * resolved at link time.
130 	 */
131 	virtual void write_label(const std::string &name)   = 0;
132 	/**
133 	 * Writes a comment into the output stream.  Useful only when debugging
134 	 * the output.
135 	 */
136 	virtual void write_comment(const std::string &name) = 0;
137 	/**
138 	 * Writes a string.  A nul terminator is implicitly added.
139 	 */
140 	virtual void write_string(const std::string &name)  = 0;
141 	/**
142 	 * Writes a single 8-bit value.
143 	 */
144 	virtual void write_data(uint8_t)        = 0;
145 	/**
146 	 * Writes a single 32-bit value.  The value is written in big-endian
147 	 * format, but should be passed in the host's native endian.
148 	 */
149 	virtual void write_data(uint32_t)       = 0;
150 	/**
151 	 * Writes a single 64-bit value.  The value is written in big-endian
152 	 * format, but should be passed in the host's native endian.
153 	 */
154 	virtual void write_data(uint64_t)       = 0;
155 	/**
156 	 * Writes the collected output to the specified file descriptor.
157 	 */
158 	virtual void write_to_file(int fd)      = 0;
159 	/**
160 	 * Returns the number of bytes.
161 	 */
162 	virtual uint32_t size()                 = 0;
163 	/**
164 	 * Helper for writing tokens to the output stream.  This writes a
165 	 * comment above the token describing its value, for easier debugging
166 	 * of the output.
167 	 */
168 	inline void write_token(token_type t)
169 	{
170 		write_comment(token_type_name(t));
171 		write_data((uint32_t)t);
172 	}
173 	/**
174 	 * Helper function that writes a byte buffer to the output, one byte at
175 	 * a time.
176 	 */
177 	void write_data(byte_buffer b);
178 };
179 
180 /**
181  * Binary file writer.  This class is responsible for writing the DTB output
182  * directly in blob format.
183  */
184 class binary_writer : public output_writer
185 {
186 	/**
187 	 * The internal buffer used to store the blob while it is being
188 	 * constructed.
189 	 */
190 	byte_buffer buffer;
191 	public:
192 	/**
193 	 *  The binary format does not support labels, so this method
194 	 * does nothing.
195 	 */
196 	void write_label(const std::string &) override {}
197 	/**
198 	 * Comments are ignored by the binary writer.
199 	 */
200 	void write_comment(const std::string&)  override {}
201 	void write_string(const std::string &name) override;
202 	void write_data(uint8_t v) override;
203 	void write_data(uint32_t v) override;
204 	void write_data(uint64_t v) override;
205 	void write_to_file(int fd) override;
206 	uint32_t size() override;
207 };
208 /**
209  * Assembly writer.  This class is responsible for writing the output in an
210  * assembly format that is suitable for linking into a kernel, loader, and so
211  * on.
212  */
213 class asm_writer : public output_writer
214 {
215 	/**
216 	 * The internal buffer for temporary values.  Note that this actually
217 	 * contains ASCII text, but it is a byte buffer so that we can just
218 	 * copy strings across as-is.
219 	 */
220 	byte_buffer buffer;
221 	/**
222 	 * The number of bytes written to the current line.  This is used to
223 	 * allow line wrapping, where we aim to write four .byte directives to
224 	 * make the alignment clearer.
225 	 */
226 	int byte_count;
227 	/**
228 	 * The current number of bytes written.  This is the number in binary
229 	 * format, not the number of bytes in the buffer.
230 	 */
231 	uint32_t bytes_written;
232 
233 	/**
234 	 * Writes a string directly to the output as-is.  This is the function that
235 	 * performs the real output.
236 	 */
237 	void write_string(const char *c);
238 	/**
239 	 * Write a string to the output.
240 	 */
241 	void write_string(const std::string &c) override;
242 	/**
243 	 * Writes the string, starting on a new line.
244 	 */
245 	void write_line(const char *c);
246 	/**
247 	 * Writes a byte in binary format.  This will emit a single .byte
248 	 * directive, with up to four per line.
249 	 */
250 	void write_byte(uint8_t b);
251 	public:
252 	asm_writer() : byte_count(0), bytes_written(0) {}
253 	void write_label(const std::string &name) override;
254 	void write_comment(const std::string &name) override;
255 	void write_data(uint8_t v) override;
256 	void write_data(uint32_t v) override;
257 	void write_data(uint64_t v) override;
258 	void write_to_file(int fd) override;
259 	uint32_t size() override;
260 };
261 
262 /**
263  * Class encapsulating the device tree blob header.  This class stores all of
264  * the values found in the header and is responsible for writing them to the
265  * output.
266  */
267 struct header
268 {
269 	/**
270 	 * Magic value, used to validate that this really is a device tree
271 	 * blob.  Should always be set to 0xd00dfeed.
272 	 */
273 	uint32_t magic;
274 	/**
275 	 * The total size of the blob, including header, reservations, strings
276 	 * table, and padding.
277 	 */
278 	uint32_t totalsize;
279 	/**
280 	 * The offset from the start of the blob of the struct table (i.e. the
281 	 * part of the blob containing the entire device tree).
282 	 */
283 	uint32_t off_dt_struct;
284 	/**
285 	 * The offset from the start of the blob of the strings table.
286 	 */
287 	uint32_t off_dt_strings;
288 	/**
289 	 * The offset of the reservation map from the start of the blob.
290 	 */
291 	uint32_t off_mem_rsvmap;
292 	/**
293 	 * The version of the blob.  This should always be 17.
294 	 */
295 	uint32_t version;
296 	/**
297 	 * The earliest version of the DTB specification with which this blob
298 	 * is backwards compatible.  This should always be 16.
299 	 */
300 	uint32_t last_comp_version;
301 	/**
302 	 * The ID of the CPU where this boots.
303 	 */
304 	uint32_t boot_cpuid_phys;
305 	/**
306 	 * The size of the strings table.
307 	 */
308 	uint32_t size_dt_strings;
309 	/**
310 	 * The size of the struct table.
311 	 */
312 	uint32_t size_dt_struct;
313 	/**
314 	 * Writes the entire header to the specified output buffer.
315 	 */
316 	void write(output_writer &out);
317 	/**
318 	 * Reads the header from bits binary representation in a blob.
319 	 */
320 	bool read_dtb(input_buffer &input);
321 	/**
322 	 * Default constructor.  Initialises the values that have sensible
323 	 * defaults, leaves the others blank.
324 	 */
325 	header() : magic(0xd00dfeed), version(17), last_comp_version(16),
326 		boot_cpuid_phys(0) {}
327 };
328 
329 /**
330  * Class encapsulating the string table.  FDT strings are stored in a string
331  * section.  This maintains a map from strings to their offsets in the strings
332  * section.
333  *
334  * Note: We don't currently do suffix matching, which may save a small amount
335  * of space.
336  */
337 class string_table {
338 	/**
339 	 * Map from strings to their offset.
340 	 */
341 	std::map<std::string, uint32_t> string_offsets;
342 	/**
343 	 * The strings, in the order in which they should be written to the
344 	 * output.  The order must be stable - adding another string must not
345 	 * change the offset of any that we have already referenced - and so we
346 	 * simply write the strings in the order that they are passed.
347 	 */
348 	std::vector<std::string> strings;
349 	/**
350 	 * The current size of the strings section.
351 	 */
352 	uint32_t size;
353 	public:
354 	/**
355 	 * Default constructor, creates an empty strings table.
356 	 */
357 	string_table() : size(0) {}
358 	/**
359 	 * Adds a string to the table, returning the offset from the start
360 	 * where it will be written.  If the string is already present, this
361 	 * will return its existing offset, otherwise it will return a new
362 	 * offset.
363 	 */
364 	uint32_t add_string(const std::string &str);
365 	/**
366 	 * Writes the strings table to the specified output.
367 	 */
368 	void write(dtb::output_writer &writer);
369 };
370 
371 } // namespace dtb
372 
373 } // namespace dtc
374 
375 #endif // !_DTB_HH_
376