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 #include "dtb.hh" 34 #include <sys/types.h> 35 #include <inttypes.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <unistd.h> 39 #include <errno.h> 40 41 using std::string; 42 43 namespace { 44 45 void write(dtc::byte_buffer &buffer, int fd) 46 { 47 size_t size = buffer.size(); 48 uint8_t *data = buffer.data(); 49 while (size > 0) 50 { 51 ssize_t r = ::write(fd, data, size); 52 if (r >= 0) 53 { 54 data += r; 55 size -= r; 56 } 57 else if (errno != EAGAIN) 58 { 59 fprintf(stderr, "Writing to file failed\n"); 60 exit(-1); 61 } 62 } 63 } 64 } 65 66 namespace dtc 67 { 68 namespace dtb 69 { 70 71 void output_writer::write_data(byte_buffer b) 72 { 73 for (auto i : b) 74 { 75 write_data(i); 76 } 77 } 78 79 void 80 binary_writer::write_string(const string &name) 81 { 82 push_string(buffer, name); 83 // Trailing nul 84 buffer.push_back(0); 85 } 86 87 void 88 binary_writer::write_data(uint8_t v) 89 { 90 buffer.push_back(v); 91 } 92 93 void 94 binary_writer::write_data(uint32_t v) 95 { 96 while (buffer.size() % 4 != 0) 97 { 98 buffer.push_back(0); 99 } 100 push_big_endian(buffer, v); 101 } 102 103 void 104 binary_writer::write_data(uint64_t v) 105 { 106 while (buffer.size() % 8 != 0) 107 { 108 buffer.push_back(0); 109 } 110 push_big_endian(buffer, v); 111 } 112 113 void 114 binary_writer::write_to_file(int fd) 115 { 116 write(buffer, fd); 117 } 118 119 uint32_t 120 binary_writer::size() 121 { 122 return buffer.size(); 123 } 124 125 void 126 asm_writer::write_line(const char *c) 127 { 128 if (byte_count != 0) 129 { 130 byte_count = 0; 131 buffer.push_back('\n'); 132 } 133 write_string(c); 134 } 135 136 void 137 asm_writer::write_byte(uint8_t b) 138 { 139 char out[3] = {0}; 140 if (byte_count++ == 0) 141 { 142 buffer.push_back('\t'); 143 } 144 write_string(".byte 0x"); 145 snprintf(out, 3, "%.2hhx", b); 146 buffer.push_back(out[0]); 147 buffer.push_back(out[1]); 148 if (byte_count == 4) 149 { 150 buffer.push_back('\n'); 151 byte_count = 0; 152 } 153 else 154 { 155 buffer.push_back(';'); 156 buffer.push_back(' '); 157 } 158 } 159 160 void 161 asm_writer::write_label(const string &name) 162 { 163 write_line("\t.globl "); 164 push_string(buffer, name); 165 buffer.push_back('\n'); 166 push_string(buffer, name); 167 buffer.push_back(':'); 168 buffer.push_back('\n'); 169 buffer.push_back('_'); 170 push_string(buffer, name); 171 buffer.push_back(':'); 172 buffer.push_back('\n'); 173 174 } 175 176 void 177 asm_writer::write_comment(const string &name) 178 { 179 write_line("\t/* "); 180 push_string(buffer, name); 181 write_string(" */\n"); 182 } 183 184 void 185 asm_writer::write_string(const char *c) 186 { 187 while (*c) 188 { 189 buffer.push_back((uint8_t)*(c++)); 190 } 191 } 192 193 194 void 195 asm_writer::write_string(const string &name) 196 { 197 write_line("\t.string \""); 198 push_string(buffer, name); 199 write_line("\"\n"); 200 bytes_written += name.size() + 1; 201 } 202 203 void 204 asm_writer::write_data(uint8_t v) 205 { 206 write_byte(v); 207 bytes_written++; 208 } 209 210 void 211 asm_writer::write_data(uint32_t v) 212 { 213 if (bytes_written % 4 != 0) 214 { 215 write_line("\t.balign 4\n"); 216 bytes_written += (4 - (bytes_written % 4)); 217 } 218 write_byte((v >> 24) & 0xff); 219 write_byte((v >> 16) & 0xff); 220 write_byte((v >> 8) & 0xff); 221 write_byte((v >> 0) & 0xff); 222 bytes_written += 4; 223 } 224 225 void 226 asm_writer::write_data(uint64_t v) 227 { 228 if (bytes_written % 8 != 0) 229 { 230 write_line("\t.balign 8\n"); 231 bytes_written += (8 - (bytes_written % 8)); 232 } 233 write_byte((v >> 56) & 0xff); 234 write_byte((v >> 48) & 0xff); 235 write_byte((v >> 40) & 0xff); 236 write_byte((v >> 32) & 0xff); 237 write_byte((v >> 24) & 0xff); 238 write_byte((v >> 16) & 0xff); 239 write_byte((v >> 8) & 0xff); 240 write_byte((v >> 0) & 0xff); 241 bytes_written += 8; 242 } 243 244 void 245 asm_writer::write_to_file(int fd) 246 { 247 write(buffer, fd); 248 } 249 250 uint32_t 251 asm_writer::size() 252 { 253 return bytes_written; 254 } 255 256 void 257 header::write(output_writer &out) 258 { 259 out.write_label("dt_blob_start"); 260 out.write_label("dt_header"); 261 out.write_comment("magic"); 262 out.write_data(magic); 263 out.write_comment("totalsize"); 264 out.write_data(totalsize); 265 out.write_comment("off_dt_struct"); 266 out.write_data(off_dt_struct); 267 out.write_comment("off_dt_strings"); 268 out.write_data(off_dt_strings); 269 out.write_comment("off_mem_rsvmap"); 270 out.write_data(off_mem_rsvmap); 271 out.write_comment("version"); 272 out.write_data(version); 273 out.write_comment("last_comp_version"); 274 out.write_data(last_comp_version); 275 out.write_comment("boot_cpuid_phys"); 276 out.write_data(boot_cpuid_phys); 277 out.write_comment("size_dt_strings"); 278 out.write_data(size_dt_strings); 279 out.write_comment("size_dt_struct"); 280 out.write_data(size_dt_struct); 281 } 282 283 bool 284 header::read_dtb(input_buffer &input) 285 { 286 if (!input.consume_binary(magic)) 287 { 288 fprintf(stderr, "Missing magic token in header."); 289 return false; 290 } 291 if (magic != 0xd00dfeed) 292 { 293 fprintf(stderr, "Bad magic token in header. Got %" PRIx32 294 " expected 0xd00dfeed\n", magic); 295 return false; 296 } 297 return input.consume_binary(totalsize) && 298 input.consume_binary(off_dt_struct) && 299 input.consume_binary(off_dt_strings) && 300 input.consume_binary(off_mem_rsvmap) && 301 input.consume_binary(version) && 302 input.consume_binary(last_comp_version) && 303 input.consume_binary(boot_cpuid_phys) && 304 input.consume_binary(size_dt_strings) && 305 input.consume_binary(size_dt_struct); 306 } 307 uint32_t 308 string_table::add_string(const string &str) 309 { 310 auto old = string_offsets.find(str); 311 if (old == string_offsets.end()) 312 { 313 uint32_t start = size; 314 // Don't forget the trailing nul 315 size += str.size() + 1; 316 string_offsets.insert(std::make_pair(str, start)); 317 strings.push_back(str); 318 return start; 319 } 320 else 321 { 322 return old->second; 323 } 324 } 325 326 void 327 string_table::write(dtb::output_writer &writer) 328 { 329 writer.write_comment("Strings table."); 330 writer.write_label("dt_strings_start"); 331 for (auto &i : strings) 332 { 333 writer.write_string(i); 334 } 335 writer.write_label("dt_strings_end"); 336 } 337 338 } // namespace dtb 339 340 } // namespace dtc 341 342