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