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
48 #include <sys/types.h>
61 property_value::get_as_uint32()
63 if (byte_data.size() != 4)
68 v &= byte_data[0] << 24;
69 v &= byte_data[1] << 16;
70 v &= byte_data[2] << 8;
71 v &= byte_data[3] << 0;
76 property_value::push_to_buffer(byte_buffer &buffer)
78 if (!byte_data.empty())
80 buffer.insert(buffer.end(), byte_data.begin(), byte_data.end());
84 push_string(buffer, string_data, true);
91 property_value::write_dts(FILE *file)
97 assert(0 && "Invalid type");
100 case CROSS_REFERENCE:
101 write_as_string(file);
104 write_as_cells(file);
107 if (byte_data.size() % 4 == 0)
109 write_as_cells(file);
112 write_as_bytes(file);
118 property_value::resolve_type()
124 if (byte_data.empty())
129 if (byte_data.back() == 0)
131 bool is_all_printable = true;
134 bool lastWasNull = false;
135 for (auto i : byte_data)
138 is_all_printable &= (i == '\0') || isprint(i);
141 // If there are two nulls in a row, then we're probably binary.
154 if (!is_all_printable)
159 if ((is_all_printable && (bytes > nuls)) || bytes == 0)
173 property_value::write_as_string(FILE *file)
176 if (byte_data.empty())
178 fputs(string_data.c_str(), file);
182 bool hasNull = (byte_data.back() == '\0');
183 // Remove trailing null bytes from the string before printing as dts.
186 byte_data.pop_back();
188 for (auto i : byte_data)
190 // FIXME Escape tabs, newlines, and so on.
193 fputs("\", \"", file);
200 byte_data.push_back('\0');
207 property_value::write_as_cells(FILE *file)
210 assert((byte_data.size() % 4) == 0);
211 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; ++i)
221 fprintf(file, "0x%" PRIx32, v);
231 property_value::write_as_bytes(FILE *file)
234 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; i++)
236 fprintf(file, "%02hhx", *i);
246 property::parse_string(text_input_buffer &input)
249 assert(*input == '"');
251 std::vector<char> bytes;
252 bool isEscaped = false;
253 while (char c = *input)
255 if (c == '"' && !isEscaped)
260 isEscaped = (c == '\\');
264 v.string_data = string(bytes.begin(), bytes.end());
269 property::parse_cells(text_input_buffer &input, int cell_size)
271 assert(*input == '<');
275 while (!input.consume('>'))
278 // If this is a phandle then we need to get the name of the
280 if (input.consume('&'))
284 input.parse_error("reference only permitted in 32-bit arrays");
291 if (!input.consume('{'))
293 referenced = input.parse_node_name();
297 referenced = input.parse_to('}');
301 if (referenced.empty())
303 input.parse_error("Expected node name");
308 // If we already have some bytes, make the phandle a
309 // separate component.
310 if (!v.byte_data.empty())
313 v = property_value();
315 v.string_data = referenced;
316 v.type = property_value::PHANDLE;
318 v = property_value();
322 //FIXME: We should support labels in the middle
323 //of these, but we don't.
324 unsigned long long val;
325 if (!input.consume_integer_expression(val))
327 input.parse_error("Expected numbers in array of cells");
334 v.byte_data.push_back(val);
337 push_big_endian(v.byte_data, (uint16_t)val);
340 push_big_endian(v.byte_data, (uint32_t)val);
343 push_big_endian(v.byte_data, (uint64_t)val);
346 assert(0 && "Invalid cell size!");
351 // Don't store an empty string value here.
352 if (v.byte_data.size() > 0)
359 property::parse_bytes(text_input_buffer &input)
361 assert(*input == '[');
365 while (!input.consume(']'))
368 //FIXME: We should support
369 //labels in the middle of
370 //these, but we don't.
372 if (!input.consume_hex_byte(val))
374 input.parse_error("Expected hex bytes in array of bytes");
378 v.byte_data.push_back(val);
386 property::parse_reference(text_input_buffer &input)
388 assert(*input == '&');
392 v.string_data = input.parse_node_name();
393 if (v.string_data.empty())
395 input.parse_error("Expected node name");
399 v.type = property_value::CROSS_REFERENCE;
403 property::property(input_buffer &structs, input_buffer &strings)
405 uint32_t name_offset;
407 valid = structs.consume_binary(length) &&
408 structs.consume_binary(name_offset);
411 fprintf(stderr, "Failed to read property\n");
415 input_buffer name_buffer = strings.buffer_from_offset(name_offset);
416 if (name_buffer.finished())
418 fprintf(stderr, "Property name offset %" PRIu32
419 " is past the end of the strings table\n",
424 key = name_buffer.parse_to(0);
426 // If we're empty, do not push anything as value.
433 for (uint32_t i=0 ; i<length ; i++)
435 if (!(valid = structs.consume_binary(byte)))
437 fprintf(stderr, "Failed to read property value\n");
440 v.byte_data.push_back(byte);
445 void property::parse_define(text_input_buffer &input, define_map *defines)
450 input.parse_error("No predefined properties to match name\n");
454 string name = input.parse_property_name();
455 define_map::iterator found;
456 if ((name == string()) ||
457 ((found = defines->find(name)) == defines->end()))
459 input.parse_error("Undefined property name\n");
463 values.push_back((*found).second->values[0]);
466 property::property(text_input_buffer &input,
469 bool semicolonTerminated,
470 define_map *defines) : key(k), labels(l), valid(true)
478 parse_define(input, defines);
485 input.parse_error("Invalid property value.");
490 unsigned long long bits = 0;
491 valid = input.consume("/bits/");
493 valid &= input.consume_integer(bits);
498 input.parse_error("Invalid size for elements");
505 input.parse_error("/bits/ directive is only valid on arrays");
509 parse_cells(input, bits);
516 parse_cells(input, 32);
522 parse_reference(input);
530 } while (input.consume(','));
531 if (semicolonTerminated && !input.consume(';'))
533 input.parse_error("Expected ; at end of property");
539 property::parse_dtb(input_buffer &structs, input_buffer &strings)
541 property_ptr p(new property(structs, strings));
550 property::parse(text_input_buffer &input, string &&key, string_set &&label,
551 bool semicolonTerminated, define_map *defines)
553 property_ptr p(new property(input,
566 property::write(dtb::output_writer &writer, dtb::string_table &strings)
568 writer.write_token(dtb::FDT_PROP);
569 byte_buffer value_buffer;
570 for (value_iterator i=begin(), e=end() ; i!=e ; ++i)
572 i->push_to_buffer(value_buffer);
574 writer.write_data((uint32_t)value_buffer.size());
575 writer.write_comment(key);
576 writer.write_data(strings.add_string(key));
577 writer.write_data(value_buffer);
581 property_value::try_to_merge(property_value &other)
587 __builtin_unreachable();
594 case CROSS_REFERENCE:
598 if (other.type == PHANDLE || other.type == BINARY)
601 byte_data.insert(byte_data.end(), other.byte_data.begin(),
602 other.byte_data.end());
610 property::write_dts(FILE *file, int indent)
612 for (int i=0 ; i<indent ; i++)
617 for (auto &l : labels)
619 fputs(l.c_str(), file);
625 fputs(key.c_str(), file);
629 std::vector<property_value> *vals = &values;
630 std::vector<property_value> v;
631 // If we've got multiple values then try to merge them all together.
632 if (values.size() > 1)
635 v.push_back(values.front());
636 for (auto i=(++begin()), e=end() ; i!=e ; ++i)
638 if (!v.back().try_to_merge(*i))
645 for (auto i=vals->begin(), e=vals->end() ; i!=e ; ++i)
659 node::parse_name(text_input_buffer &input, bool &is_property, const char *error)
668 return input.parse_property_name();
670 string n = input.parse_node_or_property_name(is_property);
675 input.parse_error(error);
683 node::visit(std::function<void(node&)> fn)
686 for (auto &&c : children)
692 node::node(input_buffer &structs, input_buffer &strings) : valid(true)
694 std::vector<char> bytes;
695 while (structs[0] != '\0' && structs[0] != '@')
697 bytes.push_back(structs[0]);
700 name = string(bytes.begin(), bytes.end());
702 if (structs[0] == '@')
705 while (structs[0] != '\0')
707 bytes.push_back(structs[0]);
710 unit_address = string(bytes.begin(), bytes.end());
714 while (structs.consume_binary(token))
719 fprintf(stderr, "Unexpected token 0x%" PRIx32
720 " while parsing node.\n", token);
723 // Child node, parse it.
724 case dtb::FDT_BEGIN_NODE:
726 node_ptr child = node::parse_dtb(structs, strings);
732 children.push_back(std::move(child));
735 // End of this node, no errors.
736 case dtb::FDT_END_NODE:
738 // Property, parse it.
741 property_ptr prop = property::parse_dtb(structs, strings);
747 props.push_back(prop);
751 // End of structs table. Should appear after
752 // the end of the last node.
754 fprintf(stderr, "Unexpected FDT_END token while parsing node.\n");
757 // NOPs are padding. Ignore them.
762 fprintf(stderr, "Failed to read token from structs table while parsing node.\n");
767 node::node(text_input_buffer &input,
769 std::unordered_set<string> &&l,
772 : labels(l), name(n), unit_address(a), valid(true)
774 if (!input.consume('{'))
776 input.parse_error("Expected { to start new device tree node.\n");
779 while (valid && !input.consume('}'))
781 // flag set if we find any characters that are only in
782 // the property name character set, not the node
783 bool is_property = false;
784 string child_name, child_address;
785 std::unordered_set<string> child_labels;
786 auto parse_delete = [&](const char *expected, bool at)
788 if (child_name == string())
790 input.parse_error(expected);
795 if (at && input.consume('@'))
798 child_name += parse_name(input, is_property, "Expected unit address");
800 if (!input.consume(';'))
802 input.parse_error("Expected semicolon");
808 if (input.consume("/delete-node/"))
811 child_name = input.parse_node_name();
812 parse_delete("Expected node name", true);
815 deleted_children.insert(child_name);
819 if (input.consume("/delete-property/"))
822 child_name = input.parse_property_name();
823 parse_delete("Expected property name", false);
826 deleted_props.insert(child_name);
830 child_name = parse_name(input, is_property,
831 "Expected property or node name");
832 while (input.consume(':'))
834 // Node labels can contain any characters? The
835 // spec doesn't say, so we guess so...
837 child_labels.insert(std::move(child_name));
838 child_name = parse_name(input, is_property, "Expected property or node name");
840 if (input.consume('@'))
842 child_address = parse_name(input, is_property, "Expected unit address");
849 // If we're parsing a property, then we must actually do that.
850 if (input.consume('='))
852 property_ptr p = property::parse(input, std::move(child_name),
853 std::move(child_labels), true, defines);
863 else if (!is_property && *input == ('{'))
865 node_ptr child = node::parse(input, std::move(child_name),
866 std::move(child_labels), std::move(child_address), defines);
869 children.push_back(std::move(child));
876 else if (input.consume(';'))
878 props.push_back(property_ptr(new property(std::move(child_name), std::move(child_labels))));
882 input.parse_error("Error parsing property. Expected property value");
892 node::cmp_properties(property_ptr &p1, property_ptr &p2)
894 return p1->get_key() < p2->get_key();
898 node::cmp_children(node_ptr &c1, node_ptr &c2)
900 if (c1->name == c2->name)
902 return c1->unit_address < c2->unit_address;
904 return c1->name < c2->name;
910 std::sort(property_begin(), property_end(), cmp_properties);
911 std::sort(child_begin(), child_end(), cmp_children);
912 for (auto &c : child_nodes())
919 node::parse(text_input_buffer &input,
925 node_ptr n(new node(input,
938 node::parse_dtb(input_buffer &structs, input_buffer &strings)
940 node_ptr n(new node(structs, strings));
949 node::get_property(const string &key)
951 for (auto &i : props)
953 if (i->get_key() == key)
962 node::merge_node(node_ptr other)
964 for (auto &l : other->labels)
968 // Note: this is an O(n*m) operation. It might be sensible to
969 // optimise this if we find that there are nodes with very
970 // large numbers of properties, but for typical usage the
971 // entire vector will fit (easily) into cache, so iterating
972 // over it repeatedly isn't that expensive.
973 for (auto &p : other->properties())
976 for (auto &mp : properties())
978 if (mp->get_key() == p->get_key())
990 for (auto &c : other->children)
993 for (auto &i : children)
995 if (i->name == c->name && i->unit_address == c->unit_address)
997 i->merge_node(std::move(c));
1004 children.push_back(std::move(c));
1007 children.erase(std::remove_if(children.begin(), children.end(),
1008 [&](const node_ptr &p) {
1009 string full_name = p->name;
1010 if (p->unit_address != string())
1013 full_name += p->unit_address;
1015 if (other->deleted_children.count(full_name) > 0)
1017 other->deleted_children.erase(full_name);
1021 }), children.end());
1022 props.erase(std::remove_if(props.begin(), props.end(),
1023 [&](const property_ptr &p) {
1024 if (other->deleted_props.count(p->get_key()) > 0)
1026 other->deleted_props.erase(p->get_key());
1034 node::write(dtb::output_writer &writer, dtb::string_table &strings)
1036 writer.write_token(dtb::FDT_BEGIN_NODE);
1037 byte_buffer name_buffer;
1038 push_string(name_buffer, name);
1039 if (unit_address != string())
1041 name_buffer.push_back('@');
1042 push_string(name_buffer, unit_address);
1044 writer.write_comment(name);
1045 writer.write_data(name_buffer);
1046 writer.write_data((uint8_t)0);
1047 for (auto p : properties())
1049 p->write(writer, strings);
1051 for (auto &c : child_nodes())
1053 c->write(writer, strings);
1055 writer.write_token(dtb::FDT_END_NODE);
1059 node::write_dts(FILE *file, int indent)
1061 for (int i=0 ; i<indent ; i++)
1066 for (auto &label : labels)
1068 fprintf(file, "%s: ", label.c_str());
1071 if (name != string())
1073 fputs(name.c_str(), file);
1075 if (unit_address != string())
1078 fputs(unit_address.c_str(), file);
1080 fputs(" {\n\n", file);
1081 for (auto p : properties())
1083 p->write_dts(file, indent+1);
1085 for (auto &c : child_nodes())
1087 c->write_dts(file, indent+1);
1089 for (int i=0 ; i<indent ; i++)
1093 fputs("};\n", file);
1097 device_tree::collect_names_recursive(node_ptr &n, node_path &path)
1099 path.push_back(std::make_pair(n->name, n->unit_address));
1100 for (const string &name : n->labels)
1102 if (name != string())
1104 auto iter = node_names.find(name);
1105 if (iter == node_names.end())
1107 node_names.insert(std::make_pair(name, n.get()));
1108 node_paths.insert(std::make_pair(name, path));
1112 node_names.erase(iter);
1113 auto i = node_paths.find(name);
1114 if (i != node_paths.end())
1116 node_paths.erase(name);
1118 fprintf(stderr, "Label not unique: %s. References to this label will not be resolved.\n", name.c_str());
1122 for (auto &c : n->child_nodes())
1124 collect_names_recursive(c, path);
1127 // Now we collect the phandles and properties that reference
1129 for (auto &p : n->properties())
1135 phandles.push_back(&v);
1137 if (v.is_cross_reference())
1139 cross_references.push_back(&v);
1142 if ((p->get_key() == "phandle") ||
1143 (p->get_key() == "linux,phandle"))
1145 if (p->begin()->byte_data.size() != 4)
1147 fprintf(stderr, "Invalid phandle value for node %s. Should be a 4-byte value.\n", n->name.c_str());
1152 uint32_t phandle = p->begin()->get_as_uint32();
1153 used_phandles.insert(std::make_pair(phandle, n.get()));
1160 device_tree::collect_names()
1165 cross_references.clear();
1167 collect_names_recursive(root, p);
1171 device_tree::resolve_cross_references()
1173 for (auto *pv : cross_references)
1175 node_path path = node_paths[pv->string_data];
1176 auto p = path.begin();
1177 auto pe = path.end();
1180 // Skip the first name in the path. It's always "", and implicitly /
1181 for (++p ; p!=pe ; ++p)
1183 pv->byte_data.push_back('/');
1184 push_string(pv->byte_data, p->first);
1185 if (!(p->second.empty()))
1187 pv->byte_data.push_back('@');
1188 push_string(pv->byte_data, p->second);
1189 pv->byte_data.push_back(0);
1194 std::unordered_set<property_value*> phandle_set;
1195 for (auto &i : phandles)
1197 phandle_set.insert(i);
1199 std::vector<property_value*> sorted_phandles;
1200 root->visit([&](node &n) {
1201 for (auto &p : n.properties())
1205 if (phandle_set.count(&v))
1207 sorted_phandles.push_back(&v);
1212 assert(sorted_phandles.size() == phandles.size());
1214 uint32_t phandle = 1;
1215 for (auto &i : sorted_phandles)
1217 string target_name = i->string_data;
1218 node *target = nullptr;
1220 // If the node name is a path, then look it up by following the path,
1221 // otherwise jump directly to the named node.
1222 if (target_name[0] == '/')
1225 target = root.get();
1226 std::istringstream ss(target_name);
1227 string path_element;
1228 // Read the leading /
1229 std::getline(ss, path_element, '/');
1230 // Iterate over path elements
1234 std::getline(ss, path_element, '/');
1235 std::istringstream nss(path_element);
1236 string node_name, node_address;
1237 std::getline(nss, node_name, '@');
1238 std::getline(nss, node_address, '@');
1239 node *next = nullptr;
1240 for (auto &c : target->child_nodes())
1242 if (c->name == node_name)
1244 if (c->unit_address == node_address)
1251 possible = path + c->name;
1252 if (c->unit_address != string())
1255 possible += c->unit_address;
1261 if (node_address != string())
1264 path += node_address;
1267 if (target == nullptr)
1275 target = node_names[target_name];
1277 if (target == nullptr)
1279 fprintf(stderr, "Failed to find node with label: %s\n", target_name.c_str());
1280 if (possible != string())
1282 fprintf(stderr, "Possible intended match: %s\n", possible.c_str());
1287 // If there is an existing phandle, use it
1288 property_ptr p = target->get_property("phandle");
1291 p = target->get_property("linux,phandle");
1295 // Otherwise insert a new phandle node
1297 while (used_phandles.find(phandle) != used_phandles.end())
1299 // Note that we only don't need to
1300 // store this phandle in the set,
1301 // because we are monotonically
1302 // increasing the value of phandle and
1303 // so will only ever revisit this value
1304 // if we have used 2^32 phandles, at
1305 // which point our blob won't fit in
1306 // any 32-bit system and we've done
1307 // something badly wrong elsewhere
1311 push_big_endian(v.byte_data, phandle++);
1312 if (phandle_node_name == BOTH || phandle_node_name == LINUX)
1314 p.reset(new property("linux,phandle"));
1316 target->add_property(p);
1318 if (phandle_node_name == BOTH || phandle_node_name == EPAPR)
1320 p.reset(new property("phandle"));
1322 target->add_property(p);
1325 p->begin()->push_to_buffer(i->byte_data);
1326 assert(i->byte_data.size() == 4);
1332 device_tree::parse_file(text_input_buffer &input,
1333 std::vector<node_ptr> &roots,
1338 if (input.consume("/dts-v1/;"))
1346 input.parse_error("Expected /dts-v1/; version string");
1348 // Read any memory reservations
1349 while (input.consume("/memreserve/"))
1351 unsigned long long start, len;
1353 // Read the start and length.
1354 if (!(input.consume_integer_expression(start) &&
1355 (input.next_token(),
1356 input.consume_integer_expression(len))))
1358 input.parse_error("Expected size on /memreserve/ node.");
1362 reservations.push_back(reservation(start, len));
1365 while (valid && !input.finished())
1368 if (input.consume('/'))
1371 n = node::parse(input, string(), string_set(), string(), &defines);
1373 else if (input.consume('&'))
1376 string name = input.parse_node_name();
1378 n = node::parse(input, std::move(name), string_set(), string(), &defines);
1382 input.parse_error("Failed to find root node /.");
1386 roots.push_back(std::move(n));
1396 template<class writer> void
1397 device_tree::write(int fd)
1399 dtb::string_table st;
1402 writer reservation_writer;
1403 writer struct_writer;
1404 writer strings_writer;
1406 // Build the reservation table
1407 reservation_writer.write_comment(string("Memory reservations"));
1408 reservation_writer.write_label(string("dt_reserve_map"));
1409 for (auto &i : reservations)
1411 reservation_writer.write_comment(string("Reservation start"));
1412 reservation_writer.write_data(i.first);
1413 reservation_writer.write_comment(string("Reservation length"));
1414 reservation_writer.write_data(i.first);
1416 // Write n spare reserve map entries, plus the trailing 0.
1417 for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++)
1419 reservation_writer.write_data((uint64_t)0);
1420 reservation_writer.write_data((uint64_t)0);
1424 struct_writer.write_comment(string("Device tree"));
1425 struct_writer.write_label(string("dt_struct_start"));
1426 root->write(struct_writer, st);
1427 struct_writer.write_token(dtb::FDT_END);
1428 struct_writer.write_label(string("dt_struct_end"));
1430 st.write(strings_writer);
1431 // Find the strings size before we stick padding on the end.
1432 // Note: We should possibly use a new writer for the padding.
1433 head.size_dt_strings = strings_writer.size();
1435 // Stick the padding in the strings writer, but after the
1436 // marker indicating that it's the end.
1437 // Note: We probably should add a padding call to the writer so
1438 // that the asm back end can write padding directives instead
1439 // of a load of 0 bytes.
1440 for (uint32_t i=0 ; i<blob_padding ; i++)
1442 strings_writer.write_data((uint8_t)0);
1444 head.totalsize = sizeof(head) + strings_writer.size() +
1445 struct_writer.size() + reservation_writer.size();
1446 while (head.totalsize < minimum_blob_size)
1449 strings_writer.write_data((uint8_t)0);
1451 head.off_dt_struct = sizeof(head) + reservation_writer.size();;
1452 head.off_dt_strings = head.off_dt_struct + struct_writer.size();
1453 head.off_mem_rsvmap = sizeof(head);
1454 head.boot_cpuid_phys = boot_cpu;
1455 head.size_dt_struct = struct_writer.size();
1456 head.write(head_writer);
1458 head_writer.write_to_file(fd);
1459 reservation_writer.write_to_file(fd);
1460 struct_writer.write_to_file(fd);
1461 strings_writer.write_label(string("dt_blob_end"));
1462 strings_writer.write_to_file(fd);
1466 device_tree::referenced_node(property_value &v)
1470 return node_names[v.string_data];
1474 return used_phandles[v.get_as_uint32()];
1480 device_tree::write_binary(int fd)
1482 write<dtb::binary_writer>(fd);
1486 device_tree::write_asm(int fd)
1488 write<dtb::asm_writer>(fd);
1492 device_tree::write_dts(int fd)
1494 FILE *file = fdopen(fd, "w");
1495 fputs("/dts-v1/;\n\n", file);
1497 if (!reservations.empty())
1499 const char msg[] = "/memreserve/";
1500 fwrite(msg, sizeof(msg), 1, file);
1501 for (auto &i : reservations)
1503 fprintf(file, " %" PRIx64 " %" PRIx64, i.first, i.second);
1505 fputs(";\n\n", file);
1509 root->write_dts(file, 0);
1514 device_tree::parse_dtb(const string &fn, FILE *)
1516 auto in = input_buffer::buffer_for_file(fn);
1522 input_buffer &input = *in;
1524 valid = h.read_dtb(input);
1525 boot_cpu = h.boot_cpuid_phys;
1526 if (h.last_comp_version > 17)
1528 fprintf(stderr, "Don't know how to read this version of the device tree blob");
1535 input_buffer reservation_map =
1536 input.buffer_from_offset(h.off_mem_rsvmap, 0);
1537 uint64_t start, length;
1540 if (!(reservation_map.consume_binary(start) &&
1541 reservation_map.consume_binary(length)))
1543 fprintf(stderr, "Failed to read memory reservation table\n");
1547 } while (!((start == 0) && (length == 0)));
1548 input_buffer struct_table =
1549 input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct);
1550 input_buffer strings_table =
1551 input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings);
1553 if (!(struct_table.consume_binary(token) &&
1554 (token == dtb::FDT_BEGIN_NODE)))
1556 fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n");
1560 root = node::parse_dtb(struct_table, strings_table);
1561 if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END)))
1563 fprintf(stderr, "Expected FDT_END token after parsing root node.\n");
1567 valid = (root != 0);
1571 device_tree::parse_dts(const string &fn, FILE *depfile)
1573 auto in = input_buffer::buffer_for_file(fn);
1579 std::vector<node_ptr> roots;
1580 std::unordered_set<string> defnames;
1581 for (auto &i : defines)
1583 defnames.insert(i.first);
1585 text_input_buffer input(std::move(in),
1586 std::move(defnames),
1587 std::vector<string>(include_paths),
1590 bool read_header = false;
1591 parse_file(input, roots, read_header);
1592 switch (roots.size())
1596 input.parse_error("Failed to find root node /.");
1599 root = std::move(roots[0]);
1603 root = std::move(roots[0]);
1604 for (auto i=++(roots.begin()), e=roots.end() ; i!=e ; ++i)
1607 string name = node->name;
1608 if (name == string())
1610 root->merge_node(std::move(node));
1614 auto existing = node_names.find(name);
1615 if (existing == node_names.end())
1618 existing = node_names.find(name);
1620 if (existing == node_names.end())
1622 fprintf(stderr, "Unable to merge node: %s\n", name.c_str());
1626 existing->second->merge_node(std::move(node));
1633 resolve_cross_references();
1636 bool device_tree::parse_define(const char *def)
1638 const char *val = strchr(def, '=');
1641 if (strlen(def) != 0)
1649 string name(def, val-def);
1650 string name_copy = name;
1652 std::unique_ptr<input_buffer> raw(new input_buffer(val, strlen(val)));
1653 text_input_buffer in(std::move(raw),
1654 std::unordered_set<string>(),
1655 std::vector<string>(),
1658 property_ptr p = property::parse(in, std::move(name_copy), string_set(), false);