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