1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 */
token_type_name(token_type t)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 */
write_tokendtc::dtb::output_writer168 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 */
write_label(const std::string &)196 void write_label(const std::string &) override {}
197 /**
198 * Comments are ignored by the binary writer.
199 */
write_comment(const std::string &)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:
asm_writer()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 */
headerdtc::dtb::header325 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 */
string_table()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