dtb.cc revision 358206
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: stable/11/usr.bin/dtc/dtb.cc 358206 2020-02-21 04:38:59Z kevans $ 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 43using std::string; 44 45namespace { 46 47void 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 68namespace dtc 69{ 70namespace dtb 71{ 72 73void output_writer::write_data(byte_buffer b) 74{ 75 for (auto i : b) 76 { 77 write_data(i); 78 } 79} 80 81void 82binary_writer::write_string(const string &name) 83{ 84 push_string(buffer, name); 85 // Trailing nul 86 buffer.push_back(0); 87} 88 89void 90binary_writer::write_data(uint8_t v) 91{ 92 buffer.push_back(v); 93} 94 95void 96binary_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 105void 106binary_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 115void 116binary_writer::write_to_file(int fd) 117{ 118 write(buffer, fd); 119} 120 121uint32_t 122binary_writer::size() 123{ 124 return buffer.size(); 125} 126 127void 128asm_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 138void 139asm_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 162void 163asm_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 178void 179asm_writer::write_comment(const string &name) 180{ 181 write_line("\t/* "); 182 push_string(buffer, name); 183 write_string(" */\n"); 184} 185 186void 187asm_writer::write_string(const char *c) 188{ 189 while (*c) 190 { 191 buffer.push_back((uint8_t)*(c++)); 192 } 193} 194 195 196void 197asm_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 205void 206asm_writer::write_data(uint8_t v) 207{ 208 write_byte(v); 209 bytes_written++; 210} 211 212void 213asm_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 227void 228asm_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 246void 247asm_writer::write_to_file(int fd) 248{ 249 write(buffer, fd); 250} 251 252uint32_t 253asm_writer::size() 254{ 255 return bytes_written; 256} 257 258void 259header::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 285bool 286header::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} 309uint32_t 310string_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 328void 329string_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