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