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