1245803Stheraven/*- 2245803Stheraven * Copyright (c) 2013 David Chisnall 3245803Stheraven * All rights reserved. 4245803Stheraven * 5245803Stheraven * This software was developed by SRI International and the University of 6245803Stheraven * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7245803Stheraven * ("CTSRD"), as part of the DARPA CRASH research programme. 8245803Stheraven * 9245803Stheraven * Redistribution and use in source and binary forms, with or without 10245803Stheraven * modification, are permitted provided that the following conditions 11245803Stheraven * are met: 12245803Stheraven * 1. Redistributions of source code must retain the above copyright 13245803Stheraven * notice, this list of conditions and the following disclaimer. 14245803Stheraven * 2. Redistributions in binary form must reproduce the above copyright 15245803Stheraven * notice, this list of conditions and the following disclaimer in the 16245803Stheraven * documentation and/or other materials provided with the distribution. 17245803Stheraven * 18245803Stheraven * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19245803Stheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20245803Stheraven * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21245803Stheraven * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22245803Stheraven * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23245803Stheraven * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24245803Stheraven * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25245803Stheraven * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26245803Stheraven * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27245803Stheraven * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28245803Stheraven * SUCH DAMAGE. 29245803Stheraven * 30245803Stheraven * $FreeBSD$ 31245803Stheraven */ 32245803Stheraven 33253149Stheraven#define __STDC_LIMIT_MACROS 1 34253149Stheraven 35245803Stheraven#include "fdt.hh" 36245803Stheraven 37245803Stheraven#include <algorithm> 38245839Stheraven#include <ctype.h> 39245839Stheraven#include <fcntl.h> 40245803Stheraven#include <inttypes.h> 41245803Stheraven#include <libgen.h> 42245839Stheraven#include <stdio.h> 43245839Stheraven#include <stdlib.h> 44245839Stheraven#include <unistd.h> 45245803Stheraven#include "dtb.hh" 46245803Stheraven 47245803Stheravennamespace dtc 48245803Stheraven{ 49245803Stheraven 50245803Stheravennamespace fdt 51245803Stheraven{ 52245803Stheraven 53245803Stheravenuint32_t 54245803Stheravenproperty_value::get_as_uint32() 55245803Stheraven{ 56245803Stheraven if (byte_data.size() != 4) 57245803Stheraven { 58245803Stheraven return 0; 59245803Stheraven } 60245803Stheraven uint32_t v = 0; 61245803Stheraven v &= byte_data[0] << 24; 62245803Stheraven v &= byte_data[1] << 16; 63245803Stheraven v &= byte_data[2] << 8; 64245803Stheraven v &= byte_data[3] << 0; 65245803Stheraven return v; 66245803Stheraven} 67245803Stheraven 68245803Stheravenvoid 69245803Stheravenproperty_value::push_to_buffer(byte_buffer &buffer) 70245803Stheraven{ 71245803Stheraven if (!byte_data.empty()) 72245803Stheraven { 73245803Stheraven buffer.insert(buffer.end(), byte_data.begin(), byte_data.end()); 74245803Stheraven } 75245803Stheraven else 76245803Stheraven { 77245803Stheraven string_data.push_to_buffer(buffer, true); 78245803Stheraven // Trailing nul 79245803Stheraven buffer.push_back(0); 80245803Stheraven } 81245803Stheraven} 82245803Stheraven 83245803Stheravenvoid 84245803Stheravenproperty_value::write_dts(FILE *file) 85245803Stheraven{ 86245803Stheraven resolve_type(); 87245803Stheraven switch (type) 88245803Stheraven { 89245803Stheraven default: 90245803Stheraven assert(0 && "Invalid type"); 91245803Stheraven case STRING: 92245803Stheraven case STRING_LIST: 93245803Stheraven case CROSS_REFERENCE: 94245803Stheraven write_as_string(file); 95245803Stheraven break; 96245803Stheraven case PHANDLE: 97245803Stheraven write_as_cells(file); 98245803Stheraven break; 99245803Stheraven case BINARY: 100245803Stheraven if (byte_data.size() % 4 == 0) 101245803Stheraven { 102245803Stheraven write_as_cells(file); 103245803Stheraven break; 104245803Stheraven } 105245803Stheraven write_as_bytes(file); 106245803Stheraven break; 107245803Stheraven } 108245803Stheraven} 109245803Stheraven 110245803Stheravenvoid 111245803Stheravenproperty_value::resolve_type() 112245803Stheraven{ 113245803Stheraven if (type != UNKNOWN) 114245803Stheraven { 115245803Stheraven return; 116245803Stheraven } 117245803Stheraven if (byte_data.empty()) 118245803Stheraven { 119245803Stheraven type = STRING; 120245803Stheraven return; 121245803Stheraven } 122245803Stheraven if (byte_data.back() == 0) 123245803Stheraven { 124245803Stheraven bool is_all_printable = true; 125245803Stheraven int nuls = 0; 126245803Stheraven int bytes = 0; 127245803Stheraven for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end()-1; i<e ; i++) 128245803Stheraven { 129245803Stheraven bytes++; 130245803Stheraven is_all_printable &= (*i == '\0') || isprint(*i); 131245803Stheraven if (*i == '\0') 132245803Stheraven { 133245803Stheraven nuls++; 134245803Stheraven } 135245803Stheraven if (!is_all_printable) 136245803Stheraven { 137245803Stheraven break; 138245803Stheraven } 139245803Stheraven } 140245803Stheraven if (is_all_printable && (bytes > nuls)) 141245803Stheraven { 142245803Stheraven type = STRING; 143245803Stheraven if (nuls > 0) 144245803Stheraven { 145245803Stheraven type = STRING_LIST; 146245803Stheraven } 147245803Stheraven return; 148245803Stheraven } 149245803Stheraven } 150245803Stheraven type = BINARY; 151245803Stheraven} 152245803Stheraven 153245803Stheravenvoid 154245803Stheravenproperty_value::write_as_string(FILE *file) 155245803Stheraven{ 156245803Stheraven putc('"', file); 157245803Stheraven if (byte_data.empty()) 158245803Stheraven { 159245803Stheraven string_data.print(file); 160245803Stheraven } 161245803Stheraven else 162245803Stheraven { 163245803Stheraven for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end()-1; i!=e ; ++i) 164245803Stheraven { 165245803Stheraven // FIXME Escape tabs, newlines, and so on. 166245803Stheraven if (*i == '\0') 167245803Stheraven { 168245803Stheraven fputs("\", \"", file); 169245803Stheraven continue; 170245803Stheraven } 171245803Stheraven putc(*i, file); 172245803Stheraven } 173245803Stheraven } 174245803Stheraven putc('"', file); 175245803Stheraven} 176245803Stheraven 177245803Stheravenvoid 178245803Stheravenproperty_value::write_as_cells(FILE *file) 179245803Stheraven{ 180245803Stheraven putc('<', file); 181245803Stheraven assert((byte_data.size() % 4) == 0); 182245803Stheraven for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end(); i!=e ; ++i) 183245803Stheraven { 184245803Stheraven uint32_t v = 0; 185245803Stheraven v = (v << 8) | *i; 186245803Stheraven ++i; 187245803Stheraven v = (v << 8) | *i; 188245803Stheraven ++i; 189245803Stheraven v = (v << 8) | *i; 190245803Stheraven ++i; 191245803Stheraven v = (v << 8) | *i; 192245803Stheraven fprintf(file, "0x%" PRIx32, v); 193245803Stheraven if (i+1 != e) 194245803Stheraven { 195245803Stheraven putc(' ', file); 196245803Stheraven } 197245803Stheraven } 198245803Stheraven putc('>', file); 199245803Stheraven} 200245803Stheraven 201245803Stheravenvoid 202245803Stheravenproperty_value::write_as_bytes(FILE *file) 203245803Stheraven{ 204245803Stheraven putc('[', file); 205245803Stheraven for (byte_buffer::iterator i=byte_data.begin(), e=byte_data.end(); i!=e ; i++) 206245803Stheraven { 207245803Stheraven fprintf(file, "%hhx", *i); 208245803Stheraven if (i+1 != e) 209245803Stheraven { 210245803Stheraven putc(' ', file); 211245803Stheraven } 212245803Stheraven } 213245803Stheraven putc(']', file); 214245803Stheraven} 215245803Stheraven 216245803Stheravenvoid 217245803Stheravenproperty::parse_string(input_buffer &input) 218245803Stheraven{ 219245803Stheraven property_value v; 220245803Stheraven assert(input[0] == '"'); 221245803Stheraven ++input; 222245803Stheraven const char *start = (const char*)input; 223245803Stheraven int length = 0; 224245803Stheraven while (char c = input[0]) 225245803Stheraven { 226245803Stheraven if (c == '"' && input[-1] != '\\') 227245803Stheraven { 228245803Stheraven input.consume('"'); 229245803Stheraven break; 230245803Stheraven } 231245803Stheraven ++input; 232245803Stheraven ++length; 233245803Stheraven } 234245803Stheraven v.string_data = string(start, length); 235245803Stheraven values.push_back(v); 236245803Stheraven} 237245803Stheraven 238245803Stheravenvoid 239245803Stheravenproperty::parse_cells(input_buffer &input) 240245803Stheraven{ 241245803Stheraven assert(input[0] == '<'); 242245803Stheraven ++input; 243245803Stheraven property_value v; 244245803Stheraven input.next_token(); 245245803Stheraven while (!input.consume('>')) 246245803Stheraven { 247245803Stheraven input.next_token(); 248245803Stheraven // If this is a phandle then we need to get the name of the 249245803Stheraven // referenced node 250245803Stheraven if (input.consume('&')) 251245803Stheraven { 252245803Stheraven input.next_token(); 253245803Stheraven // FIXME: We should support full paths here, but we 254245803Stheraven // don't. 255245803Stheraven string referenced = string::parse_node_name(input); 256245803Stheraven if (referenced.empty()) 257245803Stheraven { 258245803Stheraven input.parse_error("Expected node name"); 259245803Stheraven valid = false; 260245803Stheraven return; 261245803Stheraven } 262245803Stheraven input.next_token(); 263245803Stheraven // If we already have some bytes, make the phandle a 264245803Stheraven // separate component. 265245803Stheraven if (!v.byte_data.empty()) 266245803Stheraven { 267245803Stheraven values.push_back(v); 268245803Stheraven v = property_value(); 269245803Stheraven } 270245803Stheraven v.string_data = referenced; 271245803Stheraven v.type = property_value::PHANDLE; 272245803Stheraven values.push_back(v); 273245803Stheraven v = property_value(); 274245803Stheraven } 275245803Stheraven else 276245803Stheraven { 277245803Stheraven //FIXME: We should support labels in the middle 278245803Stheraven //of these, but we don't. 279245803Stheraven long long val; 280245803Stheraven if (!input.consume_integer(val)) 281245803Stheraven { 282245803Stheraven input.parse_error("Expected numbers in array of cells"); 283245803Stheraven valid = false; 284245803Stheraven return; 285245803Stheraven } 286253149Stheraven if ((val < 0) || (val > UINT32_MAX)) 287253149Stheraven { 288253149Stheraven input.parse_error("Value out of range"); 289253149Stheraven valid = false; 290253149Stheraven return; 291253149Stheraven } 292245803Stheraven push_big_endian(v.byte_data, (uint32_t)val); 293245803Stheraven input.next_token(); 294245803Stheraven } 295245803Stheraven } 296245803Stheraven // Don't store an empty string value here. 297245803Stheraven if (v.byte_data.size() > 0) 298245803Stheraven { 299245803Stheraven values.push_back(v); 300245803Stheraven } 301245803Stheraven} 302245803Stheraven 303245803Stheravenvoid 304245803Stheravenproperty::parse_bytes(input_buffer &input) 305245803Stheraven{ 306245803Stheraven assert(input[0] == '['); 307245803Stheraven ++input; 308245803Stheraven property_value v; 309245803Stheraven input.next_token(); 310245803Stheraven while (!input.consume(']')) 311245803Stheraven { 312245803Stheraven { 313245803Stheraven //FIXME: We should support 314245803Stheraven //labels in the middle of 315245803Stheraven //these, but we don't. 316245803Stheraven uint8_t val; 317245803Stheraven if (!input.consume_hex_byte(val)) 318245803Stheraven { 319245803Stheraven input.parse_error("Expected hex bytes in array of bytes"); 320245803Stheraven valid = false; 321245803Stheraven return; 322245803Stheraven } 323245803Stheraven v.byte_data.push_back(val); 324245803Stheraven input.next_token(); 325245803Stheraven } 326245803Stheraven } 327245803Stheraven values.push_back(v); 328245803Stheraven} 329245803Stheraven 330245803Stheravenvoid 331245803Stheravenproperty::parse_reference(input_buffer &input) 332245803Stheraven{ 333245803Stheraven assert(input[0] == '&'); 334245803Stheraven ++input; 335245803Stheraven input.next_token(); 336245803Stheraven property_value v; 337245803Stheraven v.string_data = string::parse_node_name(input); 338245803Stheraven if (v.string_data.empty()) 339245803Stheraven { 340245803Stheraven input.parse_error("Expected node name"); 341245803Stheraven valid = false; 342245803Stheraven return; 343245803Stheraven } 344245803Stheraven v.type = property_value::CROSS_REFERENCE; 345245803Stheraven values.push_back(v); 346245803Stheraven} 347245803Stheraven 348245803Stheravenproperty::property(input_buffer &structs, input_buffer &strings) 349245803Stheraven{ 350245803Stheraven uint32_t name_offset; 351245803Stheraven uint32_t length; 352245803Stheraven valid = structs.consume_binary(length) && 353245803Stheraven structs.consume_binary(name_offset); 354245803Stheraven if (!valid) 355245803Stheraven { 356245803Stheraven fprintf(stderr, "Failed to read property\n"); 357245803Stheraven return; 358245803Stheraven } 359245803Stheraven // Find the name 360245803Stheraven input_buffer name_buffer = strings.buffer_from_offset(name_offset); 361245803Stheraven if (name_buffer.empty()) 362245803Stheraven { 363245803Stheraven fprintf(stderr, "Property name offset %" PRIu32 364245803Stheraven " is past the end of the strings table\n", 365245803Stheraven name_offset); 366245803Stheraven valid = false; 367245803Stheraven return; 368245803Stheraven } 369245803Stheraven key = string(name_buffer); 370245803Stheraven // Read the value 371245803Stheraven uint8_t byte; 372245803Stheraven property_value v; 373245803Stheraven for (uint32_t i=0 ; i<length ; i++) 374245803Stheraven { 375245803Stheraven if (!(valid = structs.consume_binary(byte))) 376245803Stheraven { 377245803Stheraven fprintf(stderr, "Failed to read property value\n"); 378245803Stheraven return; 379245803Stheraven } 380245803Stheraven v.byte_data.push_back(byte); 381245803Stheraven } 382245803Stheraven values.push_back(v); 383245803Stheraven} 384245803Stheraven 385254522Stheravenvoid property::parse_define(input_buffer &input, define_map *defines) 386245803Stheraven{ 387254522Stheraven input.consume('$'); 388254522Stheraven if (!defines) 389254522Stheraven { 390254522Stheraven input.parse_error("No predefined properties to match name\n"); 391254522Stheraven valid = false; 392254522Stheraven return; 393254522Stheraven } 394254522Stheraven string name = string::parse_property_name(input); 395254522Stheraven define_map::iterator found; 396254522Stheraven if ((name == string()) || 397254522Stheraven ((found = defines->find(name)) == defines->end())) 398254522Stheraven { 399254522Stheraven input.parse_error("Undefined property name\n"); 400254522Stheraven valid = false; 401254522Stheraven return; 402254522Stheraven } 403254522Stheraven values.push_back((*found).second->values[0]); 404254522Stheraven} 405254522Stheraven 406254522Stheravenproperty::property(input_buffer &input, 407254522Stheraven string k, 408254522Stheraven string l, 409254522Stheraven bool semicolonTerminated, 410254522Stheraven define_map *defines) : key(k), label(l), valid(true) 411254522Stheraven{ 412245803Stheraven do { 413245803Stheraven input.next_token(); 414245803Stheraven switch (input[0]) 415245803Stheraven { 416254522Stheraven case '$': 417254522Stheraven { 418254522Stheraven parse_define(input, defines); 419254522Stheraven if (valid) 420254522Stheraven { 421254522Stheraven break; 422254522Stheraven } 423254522Stheraven } 424245803Stheraven default: 425245803Stheraven input.parse_error("Invalid property value."); 426245803Stheraven valid = false; 427245803Stheraven return; 428245803Stheraven case '"': 429245803Stheraven parse_string(input); 430245803Stheraven break; 431245803Stheraven case '<': 432245803Stheraven parse_cells(input); 433245803Stheraven break; 434245803Stheraven case '[': 435245803Stheraven parse_bytes(input); 436245803Stheraven break; 437245803Stheraven case '&': 438245803Stheraven parse_reference(input); 439245803Stheraven break; 440245803Stheraven case ';': 441245803Stheraven { 442245803Stheraven break; 443245803Stheraven } 444245803Stheraven } 445245803Stheraven input.next_token(); 446245803Stheraven } while (input.consume(',')); 447254522Stheraven if (semicolonTerminated && !input.consume(';')) 448245803Stheraven { 449245803Stheraven input.parse_error("Expected ; at end of property"); 450245803Stheraven valid = false; 451245803Stheraven } 452245803Stheraven} 453245803Stheraven 454245803Stheravenproperty* 455245803Stheravenproperty::parse_dtb(input_buffer &structs, input_buffer &strings) 456245803Stheraven{ 457245803Stheraven property *p = new property(structs, strings); 458245803Stheraven if (!p->valid) 459245803Stheraven { 460245803Stheraven delete p; 461245803Stheraven p = 0; 462245803Stheraven } 463245803Stheraven return p; 464245803Stheraven} 465245803Stheraven 466245803Stheravenproperty* 467254522Stheravenproperty::parse(input_buffer &input, string key, string label, 468254522Stheraven bool semicolonTerminated, define_map *defines) 469245803Stheraven{ 470254522Stheraven property *p = new property(input, key, label, semicolonTerminated, defines); 471245803Stheraven if (!p->valid) 472245803Stheraven { 473245803Stheraven delete p; 474245803Stheraven p = 0; 475245803Stheraven } 476245803Stheraven return p; 477245803Stheraven} 478245803Stheraven 479245803Stheravenvoid 480245803Stheravenproperty::write(dtb::output_writer &writer, dtb::string_table &strings) 481245803Stheraven{ 482245803Stheraven writer.write_token(dtb::FDT_PROP); 483245803Stheraven byte_buffer value_buffer; 484245803Stheraven for (value_iterator i=begin(), e=end() ; i!=e ; ++i) 485245803Stheraven { 486245803Stheraven i->push_to_buffer(value_buffer); 487245803Stheraven } 488245803Stheraven writer.write_data((uint32_t)value_buffer.size()); 489245803Stheraven writer.write_comment(key); 490245803Stheraven writer.write_data(strings.add_string(key)); 491245803Stheraven writer.write_data(value_buffer); 492245803Stheraven} 493245803Stheraven 494245803Stheravenvoid 495245803Stheravenproperty::write_dts(FILE *file, int indent) 496245803Stheraven{ 497245803Stheraven for (int i=0 ; i<indent ; i++) 498245803Stheraven { 499245803Stheraven putc('\t', file); 500245803Stheraven } 501245803Stheraven if (label != string()) 502245803Stheraven { 503245803Stheraven label.print(file); 504245803Stheraven fputs(": ", file); 505245803Stheraven } 506245803Stheraven if (key != string()) 507245803Stheraven { 508245803Stheraven key.print(file); 509245803Stheraven } 510245803Stheraven if (!values.empty()) 511245803Stheraven { 512245803Stheraven fputs(" = ", file); 513245803Stheraven for (value_iterator i=begin(), e=end() ; i!=e ; ++i) 514245803Stheraven { 515245803Stheraven i->write_dts(file); 516245803Stheraven if (i+1 != e) 517245803Stheraven { 518245803Stheraven putc(',', file); 519245803Stheraven putc(' ', file); 520245803Stheraven } 521245803Stheraven } 522245803Stheraven } 523245803Stheraven fputs(";\n", file); 524245803Stheraven} 525245803Stheraven 526245803Stheravenstring 527245803Stheravennode::parse_name(input_buffer &input, bool &is_property, const char *error) 528245803Stheraven{ 529245803Stheraven if (!valid) 530245803Stheraven { 531245803Stheraven return string(); 532245803Stheraven } 533245803Stheraven input.next_token(); 534245803Stheraven if (is_property) 535245803Stheraven { 536245803Stheraven return string::parse_property_name(input); 537245803Stheraven } 538245803Stheraven string n = string::parse_node_or_property_name(input, is_property); 539245803Stheraven if (n.empty()) 540245803Stheraven { 541245803Stheraven if (n.empty()) 542245803Stheraven { 543245803Stheraven input.parse_error(error); 544245803Stheraven valid = false; 545245803Stheraven } 546245803Stheraven } 547245803Stheraven return n; 548245803Stheraven} 549245803Stheraven 550245803Stheravennode::node(input_buffer &structs, input_buffer &strings) : valid(true) 551245803Stheraven{ 552245803Stheraven const char *name_start = (const char*)structs; 553245803Stheraven int name_length = 0; 554245803Stheraven while (structs[0] != '\0' && structs[0] != '@') 555245803Stheraven { 556245803Stheraven name_length++; 557245803Stheraven ++structs; 558245803Stheraven } 559245803Stheraven name = string(name_start, name_length); 560245803Stheraven if (structs[0] == '@') 561245803Stheraven { 562245803Stheraven ++structs; 563245803Stheraven name_start = (const char*)structs; 564245803Stheraven name_length = 0; 565245803Stheraven while (structs[0] != '\0') 566245803Stheraven { 567245803Stheraven name_length++; 568245803Stheraven ++structs; 569245803Stheraven } 570245803Stheraven unit_address = string(name_start, name_length); 571245803Stheraven } 572245803Stheraven ++structs; 573245803Stheraven uint32_t token; 574245803Stheraven while (structs.consume_binary(token)) 575245803Stheraven { 576245803Stheraven switch (token) 577245803Stheraven { 578245803Stheraven default: 579245803Stheraven fprintf(stderr, "Unexpected token 0x%" PRIx32 580245803Stheraven " while parsing node.\n", token); 581245803Stheraven valid = false; 582245803Stheraven return; 583245803Stheraven // Child node, parse it. 584245803Stheraven case dtb::FDT_BEGIN_NODE: 585245803Stheraven { 586245803Stheraven node *child = node::parse_dtb(structs, strings); 587245803Stheraven if (child == 0) 588245803Stheraven { 589245803Stheraven valid = false; 590245803Stheraven return; 591245803Stheraven } 592245803Stheraven children.push_back(child); 593245803Stheraven break; 594245803Stheraven } 595245803Stheraven // End of this node, no errors. 596245803Stheraven case dtb::FDT_END_NODE: 597245803Stheraven return; 598245803Stheraven // Property, parse it. 599245803Stheraven case dtb::FDT_PROP: 600245803Stheraven { 601245803Stheraven property *prop = property::parse_dtb(structs, strings); 602245803Stheraven if (prop == 0) 603245803Stheraven { 604245803Stheraven valid = false; 605245803Stheraven return; 606245803Stheraven } 607245803Stheraven properties.push_back(prop); 608245803Stheraven break; 609245803Stheraven } 610245803Stheraven break; 611245803Stheraven // End of structs table. Should appear after 612245803Stheraven // the end of the last node. 613245803Stheraven case dtb::FDT_END: 614245803Stheraven fprintf(stderr, "Unexpected FDT_END token while parsing node.\n"); 615245803Stheraven valid = false; 616245803Stheraven return; 617245803Stheraven // NOPs are padding. Ignore them. 618245803Stheraven case dtb::FDT_NOP: 619245803Stheraven break; 620245803Stheraven } 621245803Stheraven } 622245803Stheraven fprintf(stderr, "Failed to read token from structs table while parsing node.\n"); 623245803Stheraven valid = false; 624245803Stheraven return; 625245803Stheraven} 626245803Stheraven 627254522Stheravennode::node(input_buffer &input, string n, string l, string a, define_map *defines) : 628245803Stheraven label(l), name(n), unit_address(a), valid(true) 629245803Stheraven{ 630245803Stheraven if (!input.consume('{')) 631245803Stheraven { 632245803Stheraven input.parse_error("Expected { to start new device tree node.\n"); 633245803Stheraven } 634245803Stheraven input.next_token(); 635245803Stheraven while (valid && !input.consume('}')) 636245803Stheraven { 637245803Stheraven // flag set if we find any characters that are only in 638245803Stheraven // the property name character set, not the node 639245803Stheraven bool is_property = false; 640245803Stheraven string child_name, child_label, child_address; 641245803Stheraven child_name = parse_name(input, is_property, 642245803Stheraven "Expected property or node name"); 643245803Stheraven if (input.consume(':')) 644245803Stheraven { 645245803Stheraven // Node labels can contain any characters? The 646245803Stheraven // spec doesn't say, so we guess so... 647245803Stheraven is_property = false; 648245803Stheraven child_label = child_name; 649245803Stheraven child_name = parse_name(input, is_property, "Expected property or node name"); 650245803Stheraven } 651245803Stheraven if (input.consume('@')) 652245803Stheraven { 653245803Stheraven child_address = parse_name(input, is_property, "Expected unit address"); 654245803Stheraven } 655245803Stheraven if (!valid) 656245803Stheraven { 657245803Stheraven return; 658245803Stheraven } 659245803Stheraven input.next_token(); 660245803Stheraven // If we're parsing a property, then we must actually do that. 661245803Stheraven if (input.consume('=')) 662245803Stheraven { 663245803Stheraven property *p= property::parse(input, child_name, 664254522Stheraven child_label, true, defines); 665245803Stheraven if (p == 0) 666245803Stheraven { 667245803Stheraven valid = false; 668245803Stheraven } 669245803Stheraven else 670245803Stheraven { 671245803Stheraven properties.push_back(p); 672245803Stheraven } 673245803Stheraven } 674245803Stheraven else if (!is_property && input[0] == ('{')) 675245803Stheraven { 676245803Stheraven node *child = node::parse(input, child_name, 677254522Stheraven child_label, child_address, defines); 678245803Stheraven if (child) 679245803Stheraven { 680245803Stheraven children.push_back(child); 681245803Stheraven } 682245803Stheraven else 683245803Stheraven { 684245803Stheraven valid = false; 685245803Stheraven } 686245803Stheraven } 687245803Stheraven else if (input.consume(';')) 688245803Stheraven { 689245803Stheraven properties.push_back(new property(child_name, child_label)); 690245803Stheraven } 691245803Stheraven else 692245803Stheraven { 693245803Stheraven input.parse_error("Error parsing property."); 694245803Stheraven valid = false; 695245803Stheraven } 696245803Stheraven input.next_token(); 697245803Stheraven } 698245803Stheraven input.consume(';'); 699245803Stheraven} 700245803Stheraven 701245803Stheravenbool 702245803Stheravennode::cmp_properties(property *p1, property *p2) 703245803Stheraven{ 704245803Stheraven return p1->get_key() < p2->get_key(); 705245803Stheraven} 706245803Stheraven 707245803Stheravenbool 708245803Stheravennode::cmp_children(node *c1, node *c2) 709245803Stheraven{ 710245803Stheraven if (c1->name == c2->name) 711245803Stheraven { 712245803Stheraven return c1->unit_address < c2->unit_address; 713245803Stheraven } 714245803Stheraven return c1->name < c2->name; 715245803Stheraven} 716245803Stheraven 717245803Stheravenvoid 718245803Stheravennode::sort() 719245803Stheraven{ 720245803Stheraven std::sort(property_begin(), property_end(), cmp_properties); 721245803Stheraven std::sort(child_begin(), child_end(), cmp_children); 722245803Stheraven for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i) 723245803Stheraven { 724245803Stheraven (*i)->sort(); 725245803Stheraven } 726245803Stheraven} 727245803Stheraven 728245803Stheravennode* 729254522Stheravennode::parse(input_buffer &input, 730254522Stheraven string name, 731254522Stheraven string label, 732254522Stheraven string address, 733254522Stheraven define_map *defines) 734245803Stheraven{ 735254522Stheraven node *n = new node(input, name, label, address, defines); 736245803Stheraven if (!n->valid) 737245803Stheraven { 738245803Stheraven delete n; 739245803Stheraven n = 0; 740245803Stheraven } 741245803Stheraven return n; 742245803Stheraven} 743245803Stheraven 744245803Stheravennode* 745245803Stheravennode::parse_dtb(input_buffer &structs, input_buffer &strings) 746245803Stheraven{ 747245803Stheraven node *n = new node(structs, strings); 748245803Stheraven if (!n->valid) 749245803Stheraven { 750245803Stheraven delete n; 751245803Stheraven n = 0; 752245803Stheraven } 753245803Stheraven return n; 754245803Stheraven} 755245803Stheraven 756245803Stheravennode::~node() 757245803Stheraven{ 758245803Stheraven while (!children.empty()) 759245803Stheraven { 760245803Stheraven delete children.back(); 761245803Stheraven children.pop_back(); 762245803Stheraven } 763245803Stheraven while (!properties.empty()) 764245803Stheraven { 765245803Stheraven delete properties.back(); 766245803Stheraven properties.pop_back(); 767245803Stheraven } 768245803Stheraven} 769245803Stheraven 770245803Stheravenproperty* 771245803Stheravennode::get_property(string key) 772245803Stheraven{ 773245803Stheraven for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i) 774245803Stheraven { 775245803Stheraven if ((*i)->get_key() == key) 776245803Stheraven { 777245803Stheraven return *i; 778245803Stheraven } 779245803Stheraven } 780245803Stheraven return 0; 781245803Stheraven} 782245803Stheraven 783245803Stheravenvoid 784245803Stheravennode::merge_node(node *other) 785245803Stheraven{ 786245803Stheraven if (!other->label.empty()) 787245803Stheraven { 788245803Stheraven label = other->label; 789245803Stheraven } 790245803Stheraven // Note: this is an O(n*m) operation. It might be sensible to 791245803Stheraven // optimise this if we find that there are nodes with very 792245803Stheraven // large numbers of properties, but for typical usage the 793245803Stheraven // entire vector will fit (easily) into cache, so iterating 794245803Stheraven // over it repeatedly isn't that expensive. 795245803Stheraven while (!other->properties.empty()) 796245803Stheraven { 797245803Stheraven property *p = other->properties.front(); 798245803Stheraven for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i) 799245803Stheraven { 800245803Stheraven if ((*i)->get_key() == p->get_key()) 801245803Stheraven { 802245803Stheraven delete *i; 803245803Stheraven properties.erase(i); 804245803Stheraven break; 805245803Stheraven } 806245803Stheraven } 807245803Stheraven add_property(p); 808245803Stheraven other->properties.erase(other->properties.begin()); 809245803Stheraven } 810245803Stheraven while (!other->children.empty()) 811245803Stheraven { 812245803Stheraven node *c = other->children.front(); 813245803Stheraven bool found = false; 814245803Stheraven for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i) 815245803Stheraven { 816245803Stheraven if ((*i)->name == c->name && (*i)->unit_address == c->unit_address) 817245803Stheraven { 818245803Stheraven (*i)->merge_node(c); 819245803Stheraven delete c; 820245803Stheraven found = true; 821245803Stheraven break; 822245803Stheraven } 823245803Stheraven } 824245803Stheraven if (!found) 825245803Stheraven { 826245803Stheraven children.push_back(c); 827245803Stheraven } 828245803Stheraven other->children.erase(other->children.begin()); 829245803Stheraven } 830245803Stheraven} 831245803Stheraven 832245803Stheravenvoid 833245803Stheravennode::write(dtb::output_writer &writer, dtb::string_table &strings) 834245803Stheraven{ 835245803Stheraven writer.write_token(dtb::FDT_BEGIN_NODE); 836245803Stheraven byte_buffer name_buffer; 837245803Stheraven name.push_to_buffer(name_buffer); 838245803Stheraven if (unit_address != string()) 839245803Stheraven { 840245803Stheraven name_buffer.push_back('@'); 841245803Stheraven unit_address.push_to_buffer(name_buffer); 842245803Stheraven } 843245803Stheraven writer.write_comment(name); 844245803Stheraven writer.write_data(name_buffer); 845245803Stheraven writer.write_data((uint8_t)0); 846245803Stheraven for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i) 847245803Stheraven { 848245803Stheraven (*i)->write(writer, strings); 849245803Stheraven } 850245803Stheraven for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i) 851245803Stheraven { 852245803Stheraven (*i)->write(writer, strings); 853245803Stheraven } 854245803Stheraven writer.write_token(dtb::FDT_END_NODE); 855245803Stheraven} 856245803Stheraven 857245803Stheravenvoid 858245803Stheravennode::write_dts(FILE *file, int indent) 859245803Stheraven{ 860245803Stheraven for (int i=0 ; i<indent ; i++) 861245803Stheraven { 862245803Stheraven putc('\t', file); 863245803Stheraven } 864245803Stheraven if (label != string()) 865245803Stheraven { 866245803Stheraven label.print(file); 867245803Stheraven fputs(": ", file); 868245803Stheraven } 869245803Stheraven if (name != string()) 870245803Stheraven { 871245803Stheraven name.print(file); 872245803Stheraven } 873245803Stheraven if (unit_address != string()) 874245803Stheraven { 875245803Stheraven putc('@', file); 876245803Stheraven unit_address.print(file); 877245803Stheraven } 878245803Stheraven fputs(" {\n\n", file); 879245803Stheraven for (property_iterator i=property_begin(), e=property_end() ; i!=e ; ++i) 880245803Stheraven { 881245803Stheraven (*i)->write_dts(file, indent+1); 882245803Stheraven } 883245803Stheraven for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i) 884245803Stheraven { 885245803Stheraven (*i)->write_dts(file, indent+1); 886245803Stheraven } 887245803Stheraven for (int i=0 ; i<indent ; i++) 888245803Stheraven { 889245803Stheraven putc('\t', file); 890245803Stheraven } 891245803Stheraven fputs("};\n", file); 892245803Stheraven} 893245803Stheraven 894245803Stheravenvoid 895245803Stheravendevice_tree::collect_names_recursive(node* n, node_path &path) 896245803Stheraven{ 897245803Stheraven string name = n->label; 898245803Stheraven path.push_back(std::make_pair(n->name, n->unit_address)); 899245803Stheraven if (name != string()) 900245803Stheraven { 901245803Stheraven if (node_names.find(name) == node_names.end()) 902245803Stheraven { 903245803Stheraven node_names.insert(std::make_pair(name, n)); 904245803Stheraven node_paths.insert(std::make_pair(name, path)); 905245803Stheraven } 906245803Stheraven else 907245803Stheraven { 908245803Stheraven node_names[name] = (node*)-1; 909245803Stheraven std::map<string, node_path>::iterator i = node_paths.find(name); 910245803Stheraven if (i != node_paths.end()) 911245803Stheraven { 912245803Stheraven node_paths.erase(name); 913245803Stheraven } 914245803Stheraven fprintf(stderr, "Label not unique: "); 915245803Stheraven name.dump(); 916245803Stheraven fprintf(stderr, ". References to this label will not be resolved."); 917245803Stheraven } 918245803Stheraven } 919245803Stheraven for (node::child_iterator i=n->child_begin(), e=n->child_end() ; i!=e ; ++i) 920245803Stheraven { 921245803Stheraven collect_names_recursive(*i, path); 922245803Stheraven } 923245803Stheraven path.pop_back(); 924245803Stheraven // Now we collect the phandles and properties that reference 925245803Stheraven // other nodes. 926245803Stheraven for (node::property_iterator i=n->property_begin(), e=n->property_end() ; i!=e ; ++i) 927245803Stheraven { 928245803Stheraven for (property::value_iterator p=(*i)->begin(),pe=(*i)->end() ; p!=pe ; ++p) 929245803Stheraven { 930245803Stheraven if (p->is_phandle()) 931245803Stheraven { 932245803Stheraven phandles.push_back(&*p); 933245803Stheraven } 934245803Stheraven if (p->is_cross_reference()) 935245803Stheraven { 936245803Stheraven cross_references.push_back(&*p); 937245803Stheraven } 938245803Stheraven } 939245803Stheraven if ((*i)->get_key() == string("phandle") || 940245803Stheraven (*i)->get_key() == string("linux,phandle")) 941245803Stheraven { 942245803Stheraven if ((*i)->begin()->byte_data.size() != 4) 943245803Stheraven { 944245803Stheraven fprintf(stderr, "Invalid phandle value for node "); 945245803Stheraven n->name.dump(); 946245803Stheraven fprintf(stderr, ". Should be a 4-byte value.\n"); 947245803Stheraven valid = false; 948245803Stheraven } 949245803Stheraven else 950245803Stheraven { 951245803Stheraven uint32_t phandle = (*i)->begin()->get_as_uint32(); 952245803Stheraven used_phandles.insert(std::make_pair(phandle, n)); 953245803Stheraven } 954245803Stheraven } 955245803Stheraven } 956245803Stheraven} 957245803Stheraven 958245803Stheravenvoid 959245803Stheravendevice_tree::collect_names() 960245803Stheraven{ 961245803Stheraven node_path p; 962245803Stheraven collect_names_recursive(root, p); 963245803Stheraven} 964245803Stheraven 965245803Stheravenvoid 966245803Stheravendevice_tree::resolve_cross_references() 967245803Stheraven{ 968245803Stheraven for (std::vector<property_value*>::iterator i=cross_references.begin(), e=cross_references.end() ; i!=e ; ++i) 969245803Stheraven { 970245803Stheraven property_value* pv = *i; 971245803Stheraven node_path path = node_paths[pv->string_data]; 972245803Stheraven // Skip the first name in the path. It's always "", and implicitly / 973245803Stheraven for (node_path::iterator p=path.begin()+1, pe=path.end() ; p!=pe ; ++p) 974245803Stheraven { 975245803Stheraven pv->byte_data.push_back('/'); 976245803Stheraven p->first.push_to_buffer(pv->byte_data); 977245803Stheraven if (!(p->second.empty())) 978245803Stheraven { 979245803Stheraven pv->byte_data.push_back('@'); 980245803Stheraven p->second.push_to_buffer(pv->byte_data); 981245803Stheraven } 982245803Stheraven } 983245803Stheraven pv->byte_data.push_back(0); 984245803Stheraven } 985245803Stheraven uint32_t phandle = 1; 986245803Stheraven for (std::vector<property_value*>::iterator i=phandles.begin(), e=phandles.end() ; i!=e ; ++i) 987245803Stheraven { 988245803Stheraven string target_name = (*i)->string_data; 989245803Stheraven node *target = node_names[target_name]; 990245803Stheraven if (target == 0) 991245803Stheraven { 992245803Stheraven fprintf(stderr, "Failed to find node with label:"); 993245803Stheraven target_name.dump(); 994245803Stheraven fprintf(stderr, "\n"); 995245803Stheraven valid = 0; 996245803Stheraven return; 997245803Stheraven } 998245803Stheraven // If there is an existing phandle, use it 999245803Stheraven property *p = target->get_property("phandle"); 1000245803Stheraven if (p == 0) 1001245803Stheraven { 1002245803Stheraven p = target->get_property("linux,phandle"); 1003245803Stheraven } 1004245803Stheraven if (p == 0) 1005245803Stheraven { 1006245803Stheraven // Otherwise insert a new phandle node 1007245803Stheraven property_value v; 1008245803Stheraven while (used_phandles.find(phandle) != used_phandles.end()) 1009245803Stheraven { 1010245803Stheraven // Note that we only don't need to 1011245803Stheraven // store this phandle in the set, 1012245803Stheraven // because we are monotonically 1013245803Stheraven // increasing the value of phandle and 1014245803Stheraven // so will only ever revisit this value 1015245803Stheraven // if we have used 2^32 phandles, at 1016245803Stheraven // which point our blob won't fit in 1017245803Stheraven // any 32-bit system and we've done 1018245803Stheraven // something badly wrong elsewhere 1019245803Stheraven // already. 1020245803Stheraven phandle++; 1021245803Stheraven } 1022245803Stheraven push_big_endian(v.byte_data, phandle++); 1023245803Stheraven if (phandle_node_name == BOTH || phandle_node_name == LINUX) 1024245803Stheraven { 1025245803Stheraven p = new property(string("linux,phandle")); 1026245803Stheraven p->add_value(v); 1027245803Stheraven target->add_property(p); 1028245803Stheraven } 1029245803Stheraven if (phandle_node_name == BOTH || phandle_node_name == EPAPR) 1030245803Stheraven { 1031245803Stheraven p = new property(string("phandle")); 1032245803Stheraven p->add_value(v); 1033245803Stheraven target->add_property(p); 1034245803Stheraven } 1035245803Stheraven } 1036245803Stheraven p->begin()->push_to_buffer((*i)->byte_data); 1037245803Stheraven assert((*i)->byte_data.size() == 4); 1038245803Stheraven } 1039245803Stheraven} 1040245803Stheraven 1041245803Stheravenvoid 1042245803Stheravendevice_tree::parse_roots(input_buffer &input, std::vector<node*> &roots) 1043245803Stheraven{ 1044245803Stheraven input.next_token(); 1045245803Stheraven while (valid && input.consume('/')) 1046245803Stheraven { 1047245803Stheraven input.next_token(); 1048254522Stheraven node *n = node::parse(input, string("", 1), string(), string(), &defines); 1049245803Stheraven if (n) 1050245803Stheraven { 1051245803Stheraven roots.push_back(n); 1052245803Stheraven } 1053245803Stheraven else 1054245803Stheraven { 1055245803Stheraven valid = false; 1056245803Stheraven } 1057266202Sian input.next_token(); 1058245803Stheraven } 1059245803Stheraven} 1060245803Stheraven 1061245803Stheraveninput_buffer* 1062245803Stheravendevice_tree::buffer_for_file(const char *path) 1063245803Stheraven{ 1064245803Stheraven if (string(path) == string("-")) 1065245803Stheraven { 1066245803Stheraven input_buffer *b = new stream_input_buffer(); 1067245803Stheraven buffers.push_back(b); 1068245803Stheraven return b; 1069245803Stheraven } 1070245803Stheraven int source = open(path, O_RDONLY); 1071245803Stheraven if (source == -1) 1072245803Stheraven { 1073245803Stheraven fprintf(stderr, "Unable to open file %s\n", path); 1074245803Stheraven return 0; 1075245803Stheraven } 1076245803Stheraven input_buffer *b = new mmap_input_buffer(source); 1077245803Stheraven // Keep the buffer that owns the memory around for the lifetime 1078245803Stheraven // of this FDT. Ones simply referring to it may have shorter 1079245803Stheraven // lifetimes. 1080245803Stheraven buffers.push_back(b); 1081245803Stheraven close(source); 1082245803Stheraven return b; 1083245803Stheraven} 1084245803Stheraven 1085245803Stheraventemplate<class writer> void 1086245803Stheravendevice_tree::write(int fd) 1087245803Stheraven{ 1088245803Stheraven dtb::string_table st; 1089245803Stheraven dtb::header head; 1090245803Stheraven writer head_writer; 1091245803Stheraven writer reservation_writer; 1092245803Stheraven writer struct_writer; 1093245803Stheraven writer strings_writer; 1094245803Stheraven 1095245803Stheraven // Build the reservation table 1096245803Stheraven reservation_writer.write_comment(string("Memory reservations")); 1097245803Stheraven reservation_writer.write_label(string("dt_reserve_map")); 1098245803Stheraven for (std::vector<reservation>::iterator i=reservations.begin(), 1099245803Stheraven e=reservations.end() ; i!=e ; ++i) 1100245803Stheraven { 1101245803Stheraven reservation_writer.write_comment(string("Reservation start")); 1102245803Stheraven reservation_writer.write_data(i->first); 1103245803Stheraven reservation_writer.write_comment(string("Reservation length")); 1104245803Stheraven reservation_writer.write_data(i->first); 1105245803Stheraven } 1106245803Stheraven // Write n spare reserve map entries, plus the trailing 0. 1107245803Stheraven for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++) 1108245803Stheraven { 1109245803Stheraven reservation_writer.write_data((uint64_t)0); 1110245803Stheraven reservation_writer.write_data((uint64_t)0); 1111245803Stheraven } 1112245803Stheraven 1113245803Stheraven 1114245803Stheraven struct_writer.write_comment(string("Device tree")); 1115245803Stheraven struct_writer.write_label(string("dt_struct_start")); 1116245803Stheraven root->write(struct_writer, st); 1117245803Stheraven struct_writer.write_token(dtb::FDT_END); 1118245803Stheraven struct_writer.write_label(string("dt_struct_end")); 1119245803Stheraven 1120245803Stheraven st.write(strings_writer); 1121245803Stheraven // Find the strings size before we stick padding on the end. 1122245803Stheraven // Note: We should possibly use a new writer for the padding. 1123245803Stheraven head.size_dt_strings = strings_writer.size(); 1124245803Stheraven 1125245803Stheraven // Stick the padding in the strings writer, but after the 1126245803Stheraven // marker indicating that it's the end. 1127245803Stheraven // Note: We probably should add a padding call to the writer so 1128245803Stheraven // that the asm back end can write padding directives instead 1129245803Stheraven // of a load of 0 bytes. 1130245803Stheraven for (uint32_t i=0 ; i<blob_padding ; i++) 1131245803Stheraven { 1132245803Stheraven strings_writer.write_data((uint8_t)0); 1133245803Stheraven } 1134245803Stheraven head.totalsize = sizeof(head) + strings_writer.size() + 1135245803Stheraven struct_writer.size() + reservation_writer.size(); 1136245803Stheraven while (head.totalsize < minimum_blob_size) 1137245803Stheraven { 1138245803Stheraven head.totalsize++; 1139245803Stheraven strings_writer.write_data((uint8_t)0); 1140245803Stheraven } 1141245803Stheraven head.off_dt_struct = sizeof(head) + reservation_writer.size();; 1142245803Stheraven head.off_dt_strings = head.off_dt_struct + struct_writer.size(); 1143245803Stheraven head.off_mem_rsvmap = sizeof(head); 1144245803Stheraven head.boot_cpuid_phys = boot_cpu; 1145245803Stheraven head.size_dt_struct = struct_writer.size(); 1146245803Stheraven head.write(head_writer); 1147245803Stheraven 1148245803Stheraven head_writer.write_to_file(fd); 1149245803Stheraven reservation_writer.write_to_file(fd); 1150245803Stheraven struct_writer.write_to_file(fd); 1151245803Stheraven strings_writer.write_label(string("dt_blob_end")); 1152245803Stheraven strings_writer.write_to_file(fd); 1153245803Stheraven} 1154245803Stheraven 1155245803Stheravennode* 1156245803Stheravendevice_tree::referenced_node(property_value &v) 1157245803Stheraven{ 1158245803Stheraven if (v.is_phandle()) 1159245803Stheraven { 1160245803Stheraven return node_names[v.string_data]; 1161245803Stheraven } 1162245803Stheraven if (v.is_binary()) 1163245803Stheraven { 1164245803Stheraven return used_phandles[v.get_as_uint32()]; 1165245803Stheraven } 1166245803Stheraven return 0; 1167245803Stheraven} 1168245803Stheraven 1169245803Stheravenvoid 1170245803Stheravendevice_tree::write_binary(int fd) 1171245803Stheraven{ 1172245803Stheraven write<dtb::binary_writer>(fd); 1173245803Stheraven} 1174245803Stheraven 1175245803Stheravenvoid 1176245803Stheravendevice_tree::write_asm(int fd) 1177245803Stheraven{ 1178245803Stheraven write<dtb::asm_writer>(fd); 1179245803Stheraven} 1180245803Stheraven 1181245803Stheravenvoid 1182245803Stheravendevice_tree::write_dts(int fd) 1183245803Stheraven{ 1184245803Stheraven FILE *file = fdopen(fd, "w"); 1185245803Stheraven fputs("/dtc-v1/;\n\n", file); 1186245803Stheraven 1187245803Stheraven if (!reservations.empty()) 1188245803Stheraven { 1189245803Stheraven const char msg[] = "/memreserve/"; 1190245803Stheraven fwrite(msg, sizeof(msg), 1, file); 1191245803Stheraven for (std::vector<reservation>::iterator i=reservations.begin(), 1192245803Stheraven e=reservations.end() ; i!=e ; ++i) 1193245803Stheraven { 1194245803Stheraven fprintf(stderr, " %" PRIx64 " %" PRIx64, i->first, i->second); 1195245803Stheraven } 1196245803Stheraven fputs(";\n\n", file); 1197245803Stheraven } 1198245803Stheraven putc('/', file); 1199245803Stheraven putc(' ', file); 1200245803Stheraven root->write_dts(file, 0); 1201245803Stheraven fclose(file); 1202245803Stheraven} 1203245803Stheraven 1204245803Stheravenvoid 1205245803Stheravendevice_tree::parse_dtb(const char *fn, FILE *depfile) 1206245803Stheraven{ 1207245803Stheraven input_buffer *in = buffer_for_file(fn); 1208245803Stheraven if (in == 0) 1209245803Stheraven { 1210245803Stheraven valid = false; 1211245803Stheraven return; 1212245803Stheraven } 1213245803Stheraven input_buffer &input = *in; 1214245803Stheraven dtb::header h; 1215245803Stheraven valid = h.read_dtb(input); 1216245803Stheraven boot_cpu = h.boot_cpuid_phys; 1217245803Stheraven if (h.last_comp_version > 17) 1218245803Stheraven { 1219245803Stheraven fprintf(stderr, "Don't know how to read this version of the device tree blob"); 1220245803Stheraven valid = false; 1221245803Stheraven } 1222245803Stheraven if (!valid) 1223245803Stheraven { 1224245803Stheraven return; 1225245803Stheraven } 1226245803Stheraven input_buffer reservation_map = 1227245803Stheraven input.buffer_from_offset(h.off_mem_rsvmap, 0); 1228245803Stheraven uint64_t start, length; 1229245803Stheraven do 1230245803Stheraven { 1231245803Stheraven if (!(reservation_map.consume_binary(start) && 1232245803Stheraven reservation_map.consume_binary(length))) 1233245803Stheraven { 1234245803Stheraven fprintf(stderr, "Failed to read memory reservation table\n"); 1235245803Stheraven valid = false; 1236245803Stheraven return; 1237245803Stheraven } 1238245803Stheraven } while (!((start == 0) && (length == 0))); 1239245803Stheraven input_buffer struct_table = 1240245803Stheraven input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct); 1241245803Stheraven input_buffer strings_table = 1242245803Stheraven input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings); 1243245803Stheraven uint32_t token; 1244245803Stheraven if (!(struct_table.consume_binary(token) && 1245245803Stheraven (token == dtb::FDT_BEGIN_NODE))) 1246245803Stheraven { 1247245803Stheraven fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n"); 1248245803Stheraven valid = false; 1249245803Stheraven return; 1250245803Stheraven } 1251245803Stheraven root = node::parse_dtb(struct_table, strings_table); 1252245803Stheraven if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END))) 1253245803Stheraven { 1254245803Stheraven fprintf(stderr, "Expected FDT_END token after parsing root node.\n"); 1255245803Stheraven valid = false; 1256245803Stheraven return; 1257245803Stheraven } 1258245803Stheraven valid = (root != 0); 1259245803Stheraven} 1260245803Stheraven 1261245803Stheravenvoid 1262245803Stheravendevice_tree::parse_dts(const char *fn, FILE *depfile) 1263245803Stheraven{ 1264245803Stheraven input_buffer *in = buffer_for_file(fn); 1265245803Stheraven if (in == 0) 1266245803Stheraven { 1267245803Stheraven valid = false; 1268245803Stheraven return; 1269245803Stheraven } 1270245803Stheraven std::vector<node*> roots; 1271245803Stheraven input_buffer &input = *in; 1272245803Stheraven input.next_token(); 1273245803Stheraven bool read_header = false; 1274245803Stheraven // Read the header 1275245803Stheraven if (input.consume("/dts-v1/;")) 1276245803Stheraven { 1277245803Stheraven read_header = true; 1278245803Stheraven } 1279245803Stheraven input.next_token(); 1280245803Stheraven while(input.consume("/include/")) 1281245803Stheraven { 1282254522Stheraven bool reallyInclude = true; 1283254522Stheraven if (input.consume("if ")) 1284254522Stheraven { 1285254522Stheraven input.next_token(); 1286254522Stheraven string name = string::parse_property_name(input); 1287254522Stheraven // XXX: Error handling 1288254522Stheraven if (defines.find(name) == defines.end()) 1289254522Stheraven { 1290254522Stheraven reallyInclude = false; 1291254522Stheraven } 1292254522Stheraven input.consume('/'); 1293254522Stheraven } 1294245803Stheraven input.next_token(); 1295245803Stheraven if (!input.consume('"')) 1296245803Stheraven { 1297245803Stheraven input.parse_error("Expected quoted filename"); 1298245803Stheraven valid = false; 1299245803Stheraven return; 1300245803Stheraven } 1301245803Stheraven int length = 0; 1302245803Stheraven while (input[length] != '"') length++; 1303245803Stheraven 1304245803Stheraven const char *file = (const char*)input; 1305245803Stheraven const char *dir = dirname(fn); 1306245803Stheraven int dir_length = strlen(dir); 1307245803Stheraven char *include_file = (char*)malloc(strlen(dir) + length + 2); 1308245803Stheraven memcpy(include_file, dir, dir_length); 1309245803Stheraven include_file[dir_length] = '/'; 1310245803Stheraven memcpy(include_file+dir_length+1, file, length); 1311245803Stheraven include_file[dir_length+length+1] = 0; 1312254522Stheraven 1313254522Stheraven input.consume(include_file+dir_length+1); 1314254522Stheraven input.consume('"'); 1315254522Stheraven if (!reallyInclude) 1316254522Stheraven { 1317254522Stheraven continue; 1318254522Stheraven } 1319254522Stheraven 1320245803Stheraven input_buffer *include_buffer = buffer_for_file(include_file); 1321245803Stheraven 1322245803Stheraven if (include_buffer == 0) 1323245803Stheraven { 1324245803Stheraven for (std::vector<const char*>::iterator i=include_paths.begin(), e=include_paths.end() ; e!=i ; ++i) 1325245803Stheraven { 1326245803Stheraven free(include_file); 1327245803Stheraven dir = *i; 1328245803Stheraven dir_length = strlen(dir); 1329245803Stheraven include_file = (char*)malloc(strlen(dir) + 1330245803Stheraven length + 2); 1331245803Stheraven memcpy(include_file, dir, dir_length); 1332245803Stheraven include_file[dir_length] = '/'; 1333245803Stheraven memcpy(include_file+dir_length+1, file, length); 1334245803Stheraven include_file[dir_length+length+1] = 0; 1335245803Stheraven include_buffer = buffer_for_file(include_file); 1336245803Stheraven if (include_buffer != 0) 1337245803Stheraven { 1338245803Stheraven break; 1339245803Stheraven } 1340245803Stheraven } 1341245803Stheraven } 1342245803Stheraven if (depfile != 0) 1343245803Stheraven { 1344245803Stheraven putc(' ', depfile); 1345245803Stheraven fputs(include_file, depfile); 1346245803Stheraven } 1347245803Stheraven if (include_buffer == 0) 1348245803Stheraven { 1349245803Stheraven valid = false; 1350245803Stheraven return; 1351245803Stheraven } 1352245803Stheraven input_buffer &include = *include_buffer; 1353245803Stheraven free((void*)include_file); 1354245803Stheraven 1355245803Stheraven if (!read_header) 1356245803Stheraven { 1357245803Stheraven include.next_token(); 1358245803Stheraven read_header = include.consume("/dts-v1/;"); 1359245803Stheraven } 1360245803Stheraven parse_roots(include, roots); 1361245803Stheraven } 1362245803Stheraven input.next_token(); 1363245803Stheraven if (!read_header) 1364245803Stheraven { 1365245803Stheraven input.parse_error("Expected /dts-v1/; version string"); 1366245803Stheraven } 1367245803Stheraven // Read any memory reservations 1368245803Stheraven while(input.consume("/memreserve/")) 1369245803Stheraven { 1370245803Stheraven long long start, len; 1371245803Stheraven input.next_token(); 1372245803Stheraven // Read the start and length. 1373245803Stheraven if (!(input.consume_integer(start) && 1374245803Stheraven (input.next_token(), 1375245803Stheraven input.consume_integer(len)))) 1376245803Stheraven { 1377266313Sian input.parse_error("Expected size on /memreserve/ node."); 1378245803Stheraven } 1379245803Stheraven input.next_token(); 1380245803Stheraven input.consume(';'); 1381245803Stheraven reservations.push_back(reservation(start, len)); 1382245803Stheraven } 1383245803Stheraven parse_roots(input, roots); 1384245803Stheraven switch (roots.size()) 1385245803Stheraven { 1386245803Stheraven case 0: 1387245803Stheraven valid = false; 1388245803Stheraven input.parse_error("Failed to find root node /."); 1389245803Stheraven return; 1390245803Stheraven case 1: 1391245803Stheraven root = roots[0]; 1392245803Stheraven break; 1393245803Stheraven default: 1394245803Stheraven { 1395245803Stheraven root = roots[0]; 1396245803Stheraven for (std::vector<node*>::iterator i=roots.begin()+1, 1397245803Stheraven e=roots.end() ; i!=e ; ++i) 1398245803Stheraven { 1399245803Stheraven root->merge_node(*i); 1400245803Stheraven delete *i; 1401245803Stheraven } 1402245803Stheraven roots.resize(1); 1403245803Stheraven } 1404245803Stheraven } 1405245803Stheraven collect_names(); 1406245803Stheraven resolve_cross_references(); 1407245803Stheraven} 1408245803Stheraven 1409245803Stheravendevice_tree::~device_tree() 1410245803Stheraven{ 1411245803Stheraven if (root != 0) 1412245803Stheraven { 1413245803Stheraven delete root; 1414245803Stheraven } 1415245803Stheraven while (!buffers.empty()) 1416245803Stheraven { 1417245803Stheraven delete buffers.back(); 1418245803Stheraven buffers.pop_back(); 1419245803Stheraven } 1420254522Stheraven for (define_map::iterator i=defines.begin(), e=defines.end() ; 1421254522Stheraven i!=e ; ++i) 1422254522Stheraven { 1423254522Stheraven delete i->second; 1424254522Stheraven } 1425245803Stheraven} 1426245803Stheraven 1427254522Stheravenbool device_tree::parse_define(const char *def) 1428254522Stheraven{ 1429254522Stheraven char *val = strchr(def, '='); 1430254522Stheraven if (!val) 1431254522Stheraven { 1432254522Stheraven if (strlen(def) != 0) 1433254522Stheraven { 1434254522Stheraven string name(def); 1435254522Stheraven defines[name]; 1436254522Stheraven return true; 1437254522Stheraven } 1438254522Stheraven return false; 1439254522Stheraven } 1440254522Stheraven string name(def, val-def); 1441254522Stheraven val++; 1442254522Stheraven input_buffer in = input_buffer(val, strlen(val)); 1443254522Stheraven property *p = property::parse(in, name, string(), false); 1444254522Stheraven if (p) 1445254522Stheraven defines[name] = p; 1446254522Stheraven return p; 1447254522Stheraven} 1448254522Stheraven 1449245803Stheraven} // namespace fdt 1450245803Stheraven 1451245803Stheraven} // namespace dtc 1452245803Stheraven 1453