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 */ 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 */ 166 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 */ 194 void write_label(const std::string &) override {} 195 /** 196 * Comments are ignored by the binary writer. 197 */ 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: 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 */ 323 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 */ 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