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