2 * Copyright (c) 2013 David Chisnall
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #define __STDC_LIMIT_MACROS 1
47 #include <sys/types.h>
58 property_value::get_as_uint32()
60 if (byte_data.size() != 4)
65 v &= byte_data[0] << 24;
66 v &= byte_data[1] << 16;
67 v &= byte_data[2] << 8;
68 v &= byte_data[3] << 0;
73 property_value::push_to_buffer(byte_buffer &buffer)
75 if (!byte_data.empty())
77 buffer.insert(buffer.end(), byte_data.begin(), byte_data.end());
81 string_data.push_to_buffer(buffer, true);
88 property_value::write_dts(FILE *file)
94 assert(0 && "Invalid type");
98 write_as_string(file);
101 write_as_cells(file);
104 if (byte_data.size() % 4 == 0)
106 write_as_cells(file);
109 write_as_bytes(file);
115 property_value::resolve_type()
121 if (byte_data.empty())
126 if (byte_data.back() == 0)
128 bool is_all_printable = true;
131 bool lastWasNull = false;
132 for (auto i : byte_data)
135 is_all_printable &= (i == '\0') || isprint(i);
138 // If there are two nulls in a row, then we're probably binary.
151 if (!is_all_printable)
156 if ((is_all_printable && (bytes > nuls)) || bytes == 0)
170 property_value::write_as_string(FILE *file)
173 if (byte_data.empty())
175 string_data.print(file);
179 bool hasNull = (byte_data.back() == '\0');
180 // Remove trailing null bytes from the string before printing as dts.
183 byte_data.pop_back();
185 for (auto i : byte_data)
187 // FIXME Escape tabs, newlines, and so on.
190 fputs("\", \"", file);
197 byte_data.push_back('\0');
204 property_value::write_as_cells(FILE *file)
207 assert((byte_data.size() % 4) == 0);
208 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; ++i)
218 fprintf(file, "0x%" PRIx32, v);
228 property_value::write_as_bytes(FILE *file)
231 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; i++)
233 fprintf(file, "%02hhx", *i);
243 property::parse_string(input_buffer &input)
246 assert(input[0] == '"');
248 const char *start = (const char*)input;
250 while (char c = input[0])
252 if (c == '"' && input[-1] != '\\')
260 v.string_data = string(start, length);
265 property::parse_cells(input_buffer &input, int cell_size)
267 assert(input[0] == '<');
271 while (!input.consume('>'))
274 // If this is a phandle then we need to get the name of the
276 if (input.consume('&'))
280 input.parse_error("reference only permitted in 32-bit arrays");
285 // FIXME: We should support full paths here, but we
287 string referenced = string::parse_node_name(input);
288 if (referenced.empty())
290 input.parse_error("Expected node name");
295 // If we already have some bytes, make the phandle a
296 // separate component.
297 if (!v.byte_data.empty())
300 v = property_value();
302 v.string_data = referenced;
303 v.type = property_value::PHANDLE;
305 v = property_value();
309 //FIXME: We should support labels in the middle
310 //of these, but we don't.
311 unsigned long long val;
312 if (!input.consume_integer_expression(val))
314 input.parse_error("Expected numbers in array of cells");
321 v.byte_data.push_back(val);
324 push_big_endian(v.byte_data, (uint16_t)val);
327 push_big_endian(v.byte_data, (uint32_t)val);
330 push_big_endian(v.byte_data, (uint64_t)val);
333 assert(0 && "Invalid cell size!");
338 // Don't store an empty string value here.
339 if (v.byte_data.size() > 0)
346 property::parse_bytes(input_buffer &input)
348 assert(input[0] == '[');
352 while (!input.consume(']'))
355 //FIXME: We should support
356 //labels in the middle of
357 //these, but we don't.
359 if (!input.consume_hex_byte(val))
361 input.parse_error("Expected hex bytes in array of bytes");
365 v.byte_data.push_back(val);
373 property::parse_reference(input_buffer &input)
375 assert(input[0] == '&');
379 v.string_data = string::parse_node_name(input);
380 if (v.string_data.empty())
382 input.parse_error("Expected node name");
386 v.type = property_value::CROSS_REFERENCE;
390 property::property(input_buffer &structs, input_buffer &strings)
392 uint32_t name_offset;
394 valid = structs.consume_binary(length) &&
395 structs.consume_binary(name_offset);
398 fprintf(stderr, "Failed to read property\n");
402 input_buffer name_buffer = strings.buffer_from_offset(name_offset);
403 if (name_buffer.empty())
405 fprintf(stderr, "Property name offset %" PRIu32
406 " is past the end of the strings table\n",
411 key = string(name_buffer);
413 // If we're empty, do not push anything as value.
420 for (uint32_t i=0 ; i<length ; i++)
422 if (!(valid = structs.consume_binary(byte)))
424 fprintf(stderr, "Failed to read property value\n");
427 v.byte_data.push_back(byte);
432 void property::parse_define(input_buffer &input, define_map *defines)
437 input.parse_error("No predefined properties to match name\n");
441 string name = string::parse_property_name(input);
442 define_map::iterator found;
443 if ((name == string()) ||
444 ((found = defines->find(name)) == defines->end()))
446 input.parse_error("Undefined property name\n");
450 values.push_back((*found).second->values[0]);
453 property::property(input_buffer &input,
456 bool semicolonTerminated,
457 define_map *defines) : key(k), label(l), valid(true)
465 parse_define(input, defines);
472 input.parse_error("Invalid property value.");
477 unsigned long long bits = 0;
478 valid = input.consume("/bits/");
480 valid &= input.consume_integer(bits);
485 input.parse_error("Invalid size for elements");
492 input.parse_error("/bits/ directive is only valid on arrays");
496 parse_cells(input, bits);
503 parse_cells(input, 32);
509 parse_reference(input);
517 } while (input.consume(','));
518 if (semicolonTerminated && !input.consume(';'))
520 input.parse_error("Expected ; at end of property");
526 property::parse_dtb(input_buffer &structs, input_buffer &strings)
528 property_ptr p(new property(structs, strings));
537 property::parse(input_buffer &input, string key, string label,
538 bool semicolonTerminated, define_map *defines)
540 property_ptr p(new property(input, key, label, semicolonTerminated, defines));
549 property::write(dtb::output_writer &writer, dtb::string_table &strings)
551 writer.write_token(dtb::FDT_PROP);
552 byte_buffer value_buffer;
553 for (value_iterator i=begin(), e=end() ; i!=e ; ++i)
555 i->push_to_buffer(value_buffer);
557 writer.write_data((uint32_t)value_buffer.size());
558 writer.write_comment(key);
559 writer.write_data(strings.add_string(key));
560 writer.write_data(value_buffer);
564 property_value::try_to_merge(property_value &other)
570 __builtin_unreachable();
577 case CROSS_REFERENCE:
581 if (other.type == PHANDLE || other.type == BINARY)
584 byte_data.insert(byte_data.end(), other.byte_data.begin(),
585 other.byte_data.end());
593 property::write_dts(FILE *file, int indent)
595 for (int i=0 ; i<indent ; i++)
599 if (label != string())
610 std::vector<property_value> *vals = &values;
611 std::vector<property_value> v;
612 // If we've got multiple values then try to merge them all together.
613 if (values.size() > 1)
616 v.push_back(values.front());
617 for (auto i=(++begin()), e=end() ; i!=e ; ++i)
619 if (!v.back().try_to_merge(*i))
626 for (auto i=vals->begin(), e=vals->end() ; i!=e ; ++i)
640 node::parse_name(input_buffer &input, bool &is_property, const char *error)
649 return string::parse_property_name(input);
651 string n = string::parse_node_or_property_name(input, is_property);
656 input.parse_error(error);
664 node::visit(std::function<void(node&)> fn)
667 for (auto &&c : children)
673 node::node(input_buffer &structs, input_buffer &strings) : valid(true)
675 const char *name_start = (const char*)structs;
677 while (structs[0] != '\0' && structs[0] != '@')
682 name = string(name_start, name_length);
683 if (structs[0] == '@')
686 name_start = (const char*)structs;
688 while (structs[0] != '\0')
693 unit_address = string(name_start, name_length);
697 while (structs.consume_binary(token))
702 fprintf(stderr, "Unexpected token 0x%" PRIx32
703 " while parsing node.\n", token);
706 // Child node, parse it.
707 case dtb::FDT_BEGIN_NODE:
709 node_ptr child = node::parse_dtb(structs, strings);
715 children.push_back(std::move(child));
718 // End of this node, no errors.
719 case dtb::FDT_END_NODE:
721 // Property, parse it.
724 property_ptr prop = property::parse_dtb(structs, strings);
730 props.push_back(prop);
734 // End of structs table. Should appear after
735 // the end of the last node.
737 fprintf(stderr, "Unexpected FDT_END token while parsing node.\n");
740 // NOPs are padding. Ignore them.
745 fprintf(stderr, "Failed to read token from structs table while parsing node.\n");
750 node::node(input_buffer &input, string n, string l, string a, define_map *defines) :
751 label(l), name(n), unit_address(a), valid(true)
753 if (!input.consume('{'))
755 input.parse_error("Expected { to start new device tree node.\n");
758 while (valid && !input.consume('}'))
760 // flag set if we find any characters that are only in
761 // the property name character set, not the node
762 bool is_property = false;
763 string child_name, child_label, child_address;
764 child_name = parse_name(input, is_property,
765 "Expected property or node name");
766 if (input.consume(':'))
768 // Node labels can contain any characters? The
769 // spec doesn't say, so we guess so...
771 child_label = child_name;
772 child_name = parse_name(input, is_property, "Expected property or node name");
774 if (input.consume('@'))
776 child_address = parse_name(input, is_property, "Expected unit address");
783 // If we're parsing a property, then we must actually do that.
784 if (input.consume('='))
786 property_ptr p = property::parse(input, child_name,
787 child_label, true, defines);
797 else if (!is_property && input[0] == ('{'))
799 node_ptr child = node::parse(input, child_name,
800 child_label, child_address, defines);
803 children.push_back(std::move(child));
810 else if (input.consume(';'))
812 props.push_back(property_ptr(new property(child_name, child_label)));
816 input.parse_error("Error parsing property.");
825 node::cmp_properties(property_ptr &p1, property_ptr &p2)
827 return p1->get_key() < p2->get_key();
831 node::cmp_children(node_ptr &c1, node_ptr &c2)
833 if (c1->name == c2->name)
835 return c1->unit_address < c2->unit_address;
837 return c1->name < c2->name;
843 std::sort(property_begin(), property_end(), cmp_properties);
844 std::sort(child_begin(), child_end(), cmp_children);
845 for (auto &c : child_nodes())
852 node::parse(input_buffer &input,
858 node_ptr n(new node(input, name, label, address, defines));
867 node::parse_dtb(input_buffer &structs, input_buffer &strings)
869 node_ptr n(new node(structs, strings));
878 node::get_property(string key)
880 for (auto &i : props)
882 if (i->get_key() == key)
891 node::merge_node(node_ptr other)
893 if (!other->label.empty())
895 label = other->label;
897 // Note: this is an O(n*m) operation. It might be sensible to
898 // optimise this if we find that there are nodes with very
899 // large numbers of properties, but for typical usage the
900 // entire vector will fit (easily) into cache, so iterating
901 // over it repeatedly isn't that expensive.
902 for (auto &p : other->properties())
905 for (auto &mp : properties())
907 if (mp->get_key() == p->get_key())
919 for (auto &c : other->children)
922 for (auto &i : children)
924 if (i->name == c->name && i->unit_address == c->unit_address)
926 i->merge_node(std::move(c));
933 children.push_back(std::move(c));
939 node::write(dtb::output_writer &writer, dtb::string_table &strings)
941 writer.write_token(dtb::FDT_BEGIN_NODE);
942 byte_buffer name_buffer;
943 name.push_to_buffer(name_buffer);
944 if (unit_address != string())
946 name_buffer.push_back('@');
947 unit_address.push_to_buffer(name_buffer);
949 writer.write_comment(name);
950 writer.write_data(name_buffer);
951 writer.write_data((uint8_t)0);
952 for (auto p : properties())
954 p->write(writer, strings);
956 for (auto &c : child_nodes())
958 c->write(writer, strings);
960 writer.write_token(dtb::FDT_END_NODE);
964 node::write_dts(FILE *file, int indent)
966 for (int i=0 ; i<indent ; i++)
971 if (label != string())
977 if (name != string())
981 if (unit_address != string())
984 unit_address.print(file);
986 fputs(" {\n\n", file);
987 for (auto p : properties())
989 p->write_dts(file, indent+1);
991 for (auto &c : child_nodes())
993 c->write_dts(file, indent+1);
995 for (int i=0 ; i<indent ; i++)
1003 device_tree::collect_names_recursive(node_ptr &n, node_path &path)
1005 string name = n->label;
1006 path.push_back(std::make_pair(n->name, n->unit_address));
1007 if (name != string())
1009 if (node_names.find(name) == node_names.end())
1011 node_names.insert(std::make_pair(name, n.get()));
1012 node_paths.insert(std::make_pair(name, path));
1016 node_names[name] = (node*)-1;
1017 auto i = node_paths.find(name);
1018 if (i != node_paths.end())
1020 node_paths.erase(name);
1022 fprintf(stderr, "Label not unique: ");
1024 fprintf(stderr, ". References to this label will not be resolved.");
1027 for (auto &c : n->child_nodes())
1029 collect_names_recursive(c, path);
1032 // Now we collect the phandles and properties that reference
1034 for (auto &p : n->properties())
1040 phandles.push_back(&v);
1042 if (v.is_cross_reference())
1044 cross_references.push_back(&v);
1047 if (p->get_key() == string("phandle") ||
1048 p->get_key() == string("linux,phandle"))
1050 if (p->begin()->byte_data.size() != 4)
1052 fprintf(stderr, "Invalid phandle value for node ");
1054 fprintf(stderr, ". Should be a 4-byte value.\n");
1059 uint32_t phandle = p->begin()->get_as_uint32();
1060 used_phandles.insert(std::make_pair(phandle, n.get()));
1067 device_tree::collect_names()
1072 cross_references.clear();
1074 collect_names_recursive(root, p);
1078 device_tree::resolve_cross_references()
1080 for (auto *pv : cross_references)
1082 node_path path = node_paths[pv->string_data];
1083 // Skip the first name in the path. It's always "", and implicitly /
1084 for (auto p=path.begin()+1, pe=path.end() ; p!=pe ; ++p)
1086 pv->byte_data.push_back('/');
1087 p->first.push_to_buffer(pv->byte_data);
1088 if (!(p->second.empty()))
1090 pv->byte_data.push_back('@');
1091 p->second.push_to_buffer(pv->byte_data);
1092 pv->byte_data.push_back(0);
1096 std::unordered_set<property_value*> phandle_set;
1097 for (auto &i : phandles)
1099 phandle_set.insert(i);
1101 std::vector<property_value*> sorted_phandles;
1102 root->visit([&](node &n) {
1103 for (auto &p : n.properties())
1107 if (phandle_set.count(&v))
1109 sorted_phandles.push_back(&v);
1114 assert(sorted_phandles.size() == phandles.size());
1116 uint32_t phandle = 1;
1117 for (auto &i : sorted_phandles)
1119 string target_name = i->string_data;
1120 node *target = node_names[target_name];
1123 fprintf(stderr, "Failed to find node with label: ");
1125 fprintf(stderr, "\n");
1129 // If there is an existing phandle, use it
1130 property_ptr p = target->get_property("phandle");
1133 p = target->get_property("linux,phandle");
1137 // Otherwise insert a new phandle node
1139 while (used_phandles.find(phandle) != used_phandles.end())
1141 // Note that we only don't need to
1142 // store this phandle in the set,
1143 // because we are monotonically
1144 // increasing the value of phandle and
1145 // so will only ever revisit this value
1146 // if we have used 2^32 phandles, at
1147 // which point our blob won't fit in
1148 // any 32-bit system and we've done
1149 // something badly wrong elsewhere
1153 push_big_endian(v.byte_data, phandle++);
1154 if (phandle_node_name == BOTH || phandle_node_name == LINUX)
1156 p.reset(new property(string("linux,phandle")));
1158 target->add_property(p);
1160 if (phandle_node_name == BOTH || phandle_node_name == EPAPR)
1162 p.reset(new property(string("phandle")));
1164 target->add_property(p);
1167 p->begin()->push_to_buffer(i->byte_data);
1168 assert(i->byte_data.size() == 4);
1173 device_tree::parse_include(input_buffer &input,
1174 const std::string &dir,
1175 std::vector<node_ptr> &roots,
1179 if (!input.consume("/include/"))
1183 bool reallyInclude = true;
1184 if (input.consume("if "))
1187 string name = string::parse_property_name(input);
1188 // XXX: Error handling
1189 if (defines.find(name) == defines.end())
1191 reallyInclude = false;
1196 if (!input.consume('"'))
1198 input.parse_error("Expected quoted filename");
1203 while (input[length] != '"') length++;
1205 std::string file((const char*)input, length);
1206 std::string include_file = dir + '/' + file;
1207 input.consume(file.c_str());
1215 input_buffer *include_buffer = buffer_for_file(include_file.c_str(), false);
1217 if (include_buffer == 0)
1219 for (auto i : include_paths)
1221 include_file = i + '/' + file;
1222 include_buffer = buffer_for_file(include_file.c_str());
1223 if (include_buffer != 0)
1232 fputs(include_file.c_str(), depfile);
1234 if (include_buffer == 0)
1236 input.parse_error("Unable to locate input file");
1244 parse_file(*include_buffer, dir, roots, depfile, read_header);
1249 device_tree::parse_file(input_buffer &input,
1250 const std::string &dir,
1251 std::vector<node_ptr> &roots,
1257 if (input.consume("/dts-v1/;"))
1265 input.parse_error("Expected /dts-v1/; version string");
1267 while(parse_include(input, dir, roots, depfile, read_header)) {}
1268 // Read any memory reservations
1269 while(input.consume("/memreserve/"))
1271 unsigned long long start, len;
1273 // Read the start and length.
1274 if (!(input.consume_integer_expression(start) &&
1275 (input.next_token(),
1276 input.consume_integer_expression(len))))
1278 input.parse_error("Expected size on /memreserve/ node.");
1282 reservations.push_back(reservation(start, len));
1285 while(parse_include(input, dir, roots, depfile, read_header)) {}
1286 while (valid && !input.finished())
1289 if (input.consume('/'))
1292 n = node::parse(input, string(), string(), string(), &defines);
1294 else if (input.consume('&'))
1297 string name = string::parse_node_name(input);
1299 n = node::parse(input, name, string(), string(), &defines);
1303 input.parse_error("Failed to find root node /.");
1307 roots.push_back(std::move(n));
1314 while(parse_include(input, dir, roots, depfile, read_header)) {}
1319 device_tree::buffer_for_file(const char *path, bool warn)
1321 if (string(path) == string("-"))
1323 input_buffer *b = new stream_input_buffer();
1326 std::unique_ptr<input_buffer> ptr(b);
1327 buffers.push_back(std::move(ptr));
1331 int source = open(path, O_RDONLY);
1336 fprintf(stderr, "Unable to open file '%s'. %s\n", path, strerror(errno));
1341 if (fstat(source, &st) == 0 && S_ISDIR(st.st_mode))
1343 fprintf(stderr, "File %s is a directory\n", path);
1347 input_buffer *b = new mmap_input_buffer(source);
1348 // Keep the buffer that owns the memory around for the lifetime
1349 // of this FDT. Ones simply referring to it may have shorter
1353 std::unique_ptr<input_buffer> ptr(b);
1354 buffers.push_back(std::move(ptr));
1360 template<class writer> void
1361 device_tree::write(int fd)
1363 dtb::string_table st;
1366 writer reservation_writer;
1367 writer struct_writer;
1368 writer strings_writer;
1370 // Build the reservation table
1371 reservation_writer.write_comment(string("Memory reservations"));
1372 reservation_writer.write_label(string("dt_reserve_map"));
1373 for (auto &i : reservations)
1375 reservation_writer.write_comment(string("Reservation start"));
1376 reservation_writer.write_data(i.first);
1377 reservation_writer.write_comment(string("Reservation length"));
1378 reservation_writer.write_data(i.first);
1380 // Write n spare reserve map entries, plus the trailing 0.
1381 for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++)
1383 reservation_writer.write_data((uint64_t)0);
1384 reservation_writer.write_data((uint64_t)0);
1388 struct_writer.write_comment(string("Device tree"));
1389 struct_writer.write_label(string("dt_struct_start"));
1390 root->write(struct_writer, st);
1391 struct_writer.write_token(dtb::FDT_END);
1392 struct_writer.write_label(string("dt_struct_end"));
1394 st.write(strings_writer);
1395 // Find the strings size before we stick padding on the end.
1396 // Note: We should possibly use a new writer for the padding.
1397 head.size_dt_strings = strings_writer.size();
1399 // Stick the padding in the strings writer, but after the
1400 // marker indicating that it's the end.
1401 // Note: We probably should add a padding call to the writer so
1402 // that the asm back end can write padding directives instead
1403 // of a load of 0 bytes.
1404 for (uint32_t i=0 ; i<blob_padding ; i++)
1406 strings_writer.write_data((uint8_t)0);
1408 head.totalsize = sizeof(head) + strings_writer.size() +
1409 struct_writer.size() + reservation_writer.size();
1410 while (head.totalsize < minimum_blob_size)
1413 strings_writer.write_data((uint8_t)0);
1415 head.off_dt_struct = sizeof(head) + reservation_writer.size();;
1416 head.off_dt_strings = head.off_dt_struct + struct_writer.size();
1417 head.off_mem_rsvmap = sizeof(head);
1418 head.boot_cpuid_phys = boot_cpu;
1419 head.size_dt_struct = struct_writer.size();
1420 head.write(head_writer);
1422 head_writer.write_to_file(fd);
1423 reservation_writer.write_to_file(fd);
1424 struct_writer.write_to_file(fd);
1425 strings_writer.write_label(string("dt_blob_end"));
1426 strings_writer.write_to_file(fd);
1430 device_tree::referenced_node(property_value &v)
1434 return node_names[v.string_data];
1438 return used_phandles[v.get_as_uint32()];
1444 device_tree::write_binary(int fd)
1446 write<dtb::binary_writer>(fd);
1450 device_tree::write_asm(int fd)
1452 write<dtb::asm_writer>(fd);
1456 device_tree::write_dts(int fd)
1458 FILE *file = fdopen(fd, "w");
1459 fputs("/dts-v1/;\n\n", file);
1461 if (!reservations.empty())
1463 const char msg[] = "/memreserve/";
1464 fwrite(msg, sizeof(msg), 1, file);
1465 for (auto &i : reservations)
1467 fprintf(file, " %" PRIx64 " %" PRIx64, i.first, i.second);
1469 fputs(";\n\n", file);
1473 root->write_dts(file, 0);
1478 device_tree::parse_dtb(const char *fn, FILE *)
1480 input_buffer *in = buffer_for_file(fn);
1486 input_buffer &input = *in;
1488 valid = h.read_dtb(input);
1489 boot_cpu = h.boot_cpuid_phys;
1490 if (h.last_comp_version > 17)
1492 fprintf(stderr, "Don't know how to read this version of the device tree blob");
1499 input_buffer reservation_map =
1500 input.buffer_from_offset(h.off_mem_rsvmap, 0);
1501 uint64_t start, length;
1504 if (!(reservation_map.consume_binary(start) &&
1505 reservation_map.consume_binary(length)))
1507 fprintf(stderr, "Failed to read memory reservation table\n");
1511 } while (!((start == 0) && (length == 0)));
1512 input_buffer struct_table =
1513 input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct);
1514 input_buffer strings_table =
1515 input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings);
1517 if (!(struct_table.consume_binary(token) &&
1518 (token == dtb::FDT_BEGIN_NODE)))
1520 fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n");
1524 root = node::parse_dtb(struct_table, strings_table);
1525 if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END)))
1527 fprintf(stderr, "Expected FDT_END token after parsing root node.\n");
1531 valid = (root != 0);
1535 device_tree::parse_dts(const char *fn, FILE *depfile)
1537 input_buffer *in = buffer_for_file(fn);
1538 std::string dir(dirname((char*)fn));
1544 std::vector<node_ptr> roots;
1545 input_buffer &input = *in;
1546 bool read_header = false;
1547 parse_file(input, dir, roots, depfile, read_header);
1548 switch (roots.size())
1552 input.parse_error("Failed to find root node /.");
1555 root = std::move(roots[0]);
1559 root = std::move(roots[0]);
1560 for (auto i=++(roots.begin()), e=roots.end() ; i!=e ; ++i)
1563 string name = node->name;
1564 if (name == string())
1566 root->merge_node(std::move(node));
1570 auto existing = node_names.find(name);
1571 if (existing == node_names.end())
1574 existing = node_names.find(name);
1576 if (existing == node_names.end())
1578 fprintf(stderr, "Unable to merge node: ");
1580 fprintf(stderr, "\n");
1582 existing->second->merge_node(std::move(node));
1588 resolve_cross_references();
1591 bool device_tree::parse_define(const char *def)
1593 char *val = strchr(def, '=');
1596 if (strlen(def) != 0)
1604 string name(def, val-def);
1606 input_buffer in = input_buffer(val, strlen(val));
1607 property_ptr p = property::parse(in, name, string(), false);