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