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