2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2013 David Chisnall
7 * This software was developed by SRI International and the University of
8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9 * ("CTSRD"), as part of the DARPA CRASH research programme.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #define __STDC_LIMIT_MACROS 1
50 #include <sys/types.h>
63 property_value::get_as_uint32()
65 if (byte_data.size() != 4)
70 v &= byte_data[0] << 24;
71 v &= byte_data[1] << 16;
72 v &= byte_data[2] << 8;
73 v &= byte_data[3] << 0;
78 property_value::push_to_buffer(byte_buffer &buffer)
80 if (!byte_data.empty())
82 buffer.insert(buffer.end(), byte_data.begin(), byte_data.end());
86 push_string(buffer, string_data, true);
93 property_value::write_dts(FILE *file)
99 assert(0 && "Invalid type");
102 case CROSS_REFERENCE:
103 write_as_string(file);
106 write_as_cells(file);
109 if (byte_data.size() % 4 == 0)
111 write_as_cells(file);
114 write_as_bytes(file);
120 property_value::resolve_type()
126 if (byte_data.empty())
131 if (byte_data.back() == 0)
133 bool is_all_printable = true;
136 bool lastWasNull = false;
137 for (auto i : byte_data)
140 is_all_printable &= (i == '\0') || isprint(i);
143 // If there are two nulls in a row, then we're probably binary.
156 if (!is_all_printable)
161 if ((is_all_printable && (bytes > nuls)) || bytes == 0)
175 property_value::size()
177 if (!byte_data.empty())
179 return byte_data.size();
181 return string_data.size() + 1;
185 property_value::write_as_string(FILE *file)
188 if (byte_data.empty())
190 fputs(string_data.c_str(), file);
194 bool hasNull = (byte_data.back() == '\0');
195 // Remove trailing null bytes from the string before printing as dts.
198 byte_data.pop_back();
200 for (auto i : byte_data)
202 // FIXME Escape tabs, newlines, and so on.
205 fputs("\", \"", file);
212 byte_data.push_back('\0');
219 property_value::write_as_cells(FILE *file)
222 assert((byte_data.size() % 4) == 0);
223 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; ++i)
233 fprintf(file, "0x%" PRIx32, v);
243 property_value::write_as_bytes(FILE *file)
246 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; i++)
248 fprintf(file, "%02hhx", *i);
258 property::parse_string(text_input_buffer &input)
261 assert(*input == '"');
263 std::vector<char> bytes;
264 bool isEscaped = false;
265 while (char c = *input)
267 if (c == '"' && !isEscaped)
272 isEscaped = (c == '\\');
276 v.string_data = string(bytes.begin(), bytes.end());
281 property::parse_cells(text_input_buffer &input, int cell_size)
283 assert(*input == '<');
287 while (!input.consume('>'))
290 // If this is a phandle then we need to get the name of the
292 if (input.consume('&'))
296 input.parse_error("reference only permitted in 32-bit arrays");
302 if (!input.consume('{'))
304 referenced = input.parse_node_name();
308 referenced = input.parse_to('}');
311 if (referenced.empty())
313 input.parse_error("Expected node name");
318 // If we already have some bytes, make the phandle a
319 // separate component.
320 if (!v.byte_data.empty())
323 v = property_value();
325 v.string_data = referenced;
326 v.type = property_value::PHANDLE;
328 v = property_value();
332 //FIXME: We should support labels in the middle
333 //of these, but we don't.
334 unsigned long long val;
335 if (!input.consume_integer_expression(val))
337 input.parse_error("Expected numbers in array of cells");
344 v.byte_data.push_back(val);
347 push_big_endian(v.byte_data, (uint16_t)val);
350 push_big_endian(v.byte_data, (uint32_t)val);
353 push_big_endian(v.byte_data, (uint64_t)val);
356 assert(0 && "Invalid cell size!");
361 // Don't store an empty string value here.
362 if (v.byte_data.size() > 0)
369 property::parse_bytes(text_input_buffer &input)
371 assert(*input == '[');
375 while (!input.consume(']'))
378 //FIXME: We should support
379 //labels in the middle of
380 //these, but we don't.
382 if (!input.consume_hex_byte(val))
384 input.parse_error("Expected hex bytes in array of bytes");
388 v.byte_data.push_back(val);
396 property::parse_reference(text_input_buffer &input)
398 assert(*input == '&');
402 v.string_data = input.parse_node_name();
403 if (v.string_data.empty())
405 input.parse_error("Expected node name");
409 v.type = property_value::CROSS_REFERENCE;
413 property::property(input_buffer &structs, input_buffer &strings)
415 uint32_t name_offset;
417 valid = structs.consume_binary(length) &&
418 structs.consume_binary(name_offset);
421 fprintf(stderr, "Failed to read property\n");
425 input_buffer name_buffer = strings.buffer_from_offset(name_offset);
426 if (name_buffer.finished())
428 fprintf(stderr, "Property name offset %" PRIu32
429 " is past the end of the strings table\n",
434 key = name_buffer.parse_to(0);
436 // If we're empty, do not push anything as value.
443 for (uint32_t i=0 ; i<length ; i++)
445 if (!(valid = structs.consume_binary(byte)))
447 fprintf(stderr, "Failed to read property value\n");
450 v.byte_data.push_back(byte);
455 void property::parse_define(text_input_buffer &input, define_map *defines)
460 input.parse_error("No predefined properties to match name\n");
464 string name = input.parse_property_name();
465 define_map::iterator found;
466 if ((name == string()) ||
467 ((found = defines->find(name)) == defines->end()))
469 input.parse_error("Undefined property name\n");
473 values.push_back((*found).second->values[0]);
476 property::property(text_input_buffer &input,
479 bool semicolonTerminated,
480 define_map *defines) : key(k), labels(l), valid(true)
488 parse_define(input, defines);
495 input.parse_error("Invalid property value.");
500 unsigned long long bits = 0;
501 valid = input.consume("/bits/");
503 valid &= input.consume_integer(bits);
508 input.parse_error("Invalid size for elements");
515 input.parse_error("/bits/ directive is only valid on arrays");
519 parse_cells(input, bits);
526 parse_cells(input, 32);
532 parse_reference(input);
540 } while (input.consume(','));
541 if (semicolonTerminated && !input.consume(';'))
543 input.parse_error("Expected ; at end of property");
549 property::parse_dtb(input_buffer &structs, input_buffer &strings)
551 property_ptr p(new property(structs, strings));
560 property::parse(text_input_buffer &input, string &&key, string_set &&label,
561 bool semicolonTerminated, define_map *defines)
563 property_ptr p(new property(input,
576 property::write(dtb::output_writer &writer, dtb::string_table &strings)
578 writer.write_token(dtb::FDT_PROP);
579 byte_buffer value_buffer;
580 for (value_iterator i=begin(), e=end() ; i!=e ; ++i)
582 i->push_to_buffer(value_buffer);
584 writer.write_data((uint32_t)value_buffer.size());
585 writer.write_comment(key);
586 writer.write_data(strings.add_string(key));
587 writer.write_data(value_buffer);
591 property_value::try_to_merge(property_value &other)
597 __builtin_unreachable();
604 case CROSS_REFERENCE:
608 if (other.type == PHANDLE || other.type == BINARY)
611 byte_data.insert(byte_data.end(), other.byte_data.begin(),
612 other.byte_data.end());
620 property::write_dts(FILE *file, int indent)
622 for (int i=0 ; i<indent ; i++)
627 for (auto &l : labels)
629 fputs(l.c_str(), file);
635 fputs(key.c_str(), file);
639 std::vector<property_value> *vals = &values;
640 std::vector<property_value> v;
641 // If we've got multiple values then try to merge them all together.
642 if (values.size() > 1)
645 v.push_back(values.front());
646 for (auto i=(++begin()), e=end() ; i!=e ; ++i)
648 if (!v.back().try_to_merge(*i))
655 for (auto i=vals->begin(), e=vals->end() ; i!=e ; ++i)
669 property::offset_of_value(property_value &val)
672 for (auto &v : values)
684 node::parse_name(text_input_buffer &input, bool &is_property, const char *error)
693 return input.parse_property_name();
695 string n = input.parse_node_or_property_name(is_property);
700 input.parse_error(error);
708 node::visit(std::function<void(node&)> fn)
711 for (auto &&c : children)
717 node::node(input_buffer &structs, input_buffer &strings) : valid(true)
719 std::vector<char> bytes;
720 while (structs[0] != '\0' && structs[0] != '@')
722 bytes.push_back(structs[0]);
725 name = string(bytes.begin(), bytes.end());
727 if (structs[0] == '@')
730 while (structs[0] != '\0')
732 bytes.push_back(structs[0]);
735 unit_address = string(bytes.begin(), bytes.end());
739 while (structs.consume_binary(token))
744 fprintf(stderr, "Unexpected token 0x%" PRIx32
745 " while parsing node.\n", token);
748 // Child node, parse it.
749 case dtb::FDT_BEGIN_NODE:
751 node_ptr child = node::parse_dtb(structs, strings);
757 children.push_back(std::move(child));
760 // End of this node, no errors.
761 case dtb::FDT_END_NODE:
763 // Property, parse it.
766 property_ptr prop = property::parse_dtb(structs, strings);
772 props.push_back(prop);
776 // End of structs table. Should appear after
777 // the end of the last node.
779 fprintf(stderr, "Unexpected FDT_END token while parsing node.\n");
782 // NOPs are padding. Ignore them.
787 fprintf(stderr, "Failed to read token from structs table while parsing node.\n");
793 node::node(const string &n,
794 const std::vector<property_ptr> &p)
797 props.insert(props.begin(), p.begin(), p.end());
800 node_ptr node::create_special_node(const string &name,
801 const std::vector<property_ptr> &props)
803 node_ptr n(new node(name, props));
807 node::node(text_input_buffer &input,
809 std::unordered_set<string> &&l,
812 : labels(l), name(n), unit_address(a), valid(true)
814 if (!input.consume('{'))
816 input.parse_error("Expected { to start new device tree node.\n");
819 while (valid && !input.consume('}'))
821 // flag set if we find any characters that are only in
822 // the property name character set, not the node
823 bool is_property = false;
824 string child_name, child_address;
825 std::unordered_set<string> child_labels;
826 auto parse_delete = [&](const char *expected, bool at)
828 if (child_name == string())
830 input.parse_error(expected);
835 if (at && input.consume('@'))
838 child_name += parse_name(input, is_property, "Expected unit address");
840 if (!input.consume(';'))
842 input.parse_error("Expected semicolon");
848 if (input.consume("/delete-node/"))
851 child_name = input.parse_node_name();
852 parse_delete("Expected node name", true);
855 deleted_children.insert(child_name);
859 if (input.consume("/delete-property/"))
862 child_name = input.parse_property_name();
863 parse_delete("Expected property name", false);
866 deleted_props.insert(child_name);
870 child_name = parse_name(input, is_property,
871 "Expected property or node name");
872 while (input.consume(':'))
874 // Node labels can contain any characters? The
875 // spec doesn't say, so we guess so...
877 child_labels.insert(std::move(child_name));
878 child_name = parse_name(input, is_property, "Expected property or node name");
880 if (input.consume('@'))
882 child_address = parse_name(input, is_property, "Expected unit address");
889 // If we're parsing a property, then we must actually do that.
890 if (input.consume('='))
892 property_ptr p = property::parse(input, std::move(child_name),
893 std::move(child_labels), true, defines);
903 else if (!is_property && *input == ('{'))
905 node_ptr child = node::parse(input, std::move(child_name),
906 std::move(child_labels), std::move(child_address), defines);
909 children.push_back(std::move(child));
916 else if (input.consume(';'))
918 props.push_back(property_ptr(new property(std::move(child_name), std::move(child_labels))));
922 input.parse_error("Error parsing property. Expected property value");
932 node::cmp_properties(property_ptr &p1, property_ptr &p2)
934 return p1->get_key() < p2->get_key();
938 node::cmp_children(node_ptr &c1, node_ptr &c2)
940 if (c1->name == c2->name)
942 return c1->unit_address < c2->unit_address;
944 return c1->name < c2->name;
950 std::sort(property_begin(), property_end(), cmp_properties);
951 std::sort(child_begin(), child_end(), cmp_children);
952 for (auto &c : child_nodes())
959 node::parse(text_input_buffer &input,
965 node_ptr n(new node(input,
978 node::parse_dtb(input_buffer &structs, input_buffer &strings)
980 node_ptr n(new node(structs, strings));
989 node::get_property(const string &key)
991 for (auto &i : props)
993 if (i->get_key() == key)
1002 node::merge_node(node_ptr other)
1004 for (auto &l : other->labels)
1008 // Note: this is an O(n*m) operation. It might be sensible to
1009 // optimise this if we find that there are nodes with very
1010 // large numbers of properties, but for typical usage the
1011 // entire vector will fit (easily) into cache, so iterating
1012 // over it repeatedly isn't that expensive.
1013 for (auto &p : other->properties())
1016 for (auto &mp : properties())
1018 if (mp->get_key() == p->get_key())
1030 for (auto &c : other->children)
1033 for (auto &i : children)
1035 if (i->name == c->name && i->unit_address == c->unit_address)
1037 i->merge_node(std::move(c));
1044 children.push_back(std::move(c));
1047 children.erase(std::remove_if(children.begin(), children.end(),
1048 [&](const node_ptr &p) {
1049 string full_name = p->name;
1050 if (p->unit_address != string())
1053 full_name += p->unit_address;
1055 if (other->deleted_children.count(full_name) > 0)
1057 other->deleted_children.erase(full_name);
1061 }), children.end());
1062 props.erase(std::remove_if(props.begin(), props.end(),
1063 [&](const property_ptr &p) {
1064 if (other->deleted_props.count(p->get_key()) > 0)
1066 other->deleted_props.erase(p->get_key());
1074 node::write(dtb::output_writer &writer, dtb::string_table &strings)
1076 writer.write_token(dtb::FDT_BEGIN_NODE);
1077 byte_buffer name_buffer;
1078 push_string(name_buffer, name);
1079 if (unit_address != string())
1081 name_buffer.push_back('@');
1082 push_string(name_buffer, unit_address);
1084 writer.write_comment(name);
1085 writer.write_data(name_buffer);
1086 writer.write_data((uint8_t)0);
1087 for (auto p : properties())
1089 p->write(writer, strings);
1091 for (auto &c : child_nodes())
1093 c->write(writer, strings);
1095 writer.write_token(dtb::FDT_END_NODE);
1099 node::write_dts(FILE *file, int indent)
1101 for (int i=0 ; i<indent ; i++)
1106 for (auto &label : labels)
1108 fprintf(file, "%s: ", label.c_str());
1111 if (name != string())
1113 fputs(name.c_str(), file);
1115 if (unit_address != string())
1118 fputs(unit_address.c_str(), file);
1120 fputs(" {\n\n", file);
1121 for (auto p : properties())
1123 p->write_dts(file, indent+1);
1125 for (auto &c : child_nodes())
1127 c->write_dts(file, indent+1);
1129 for (int i=0 ; i<indent ; i++)
1133 fputs("};\n", file);
1137 device_tree::collect_names_recursive(node_ptr &n, node_path &path)
1139 path.push_back(std::make_pair(n->name, n->unit_address));
1140 for (const string &name : n->labels)
1142 if (name != string())
1144 auto iter = node_names.find(name);
1145 if (iter == node_names.end())
1147 node_names.insert(std::make_pair(name, n.get()));
1148 node_paths.insert(std::make_pair(name, path));
1152 node_names.erase(iter);
1153 auto i = node_paths.find(name);
1154 if (i != node_paths.end())
1156 node_paths.erase(name);
1158 fprintf(stderr, "Label not unique: %s. References to this label will not be resolved.\n", name.c_str());
1162 for (auto &c : n->child_nodes())
1164 collect_names_recursive(c, path);
1166 // Now we collect the phandles and properties that reference
1168 for (auto &p : n->properties())
1174 fixups.push_back({path, p, v});
1176 if (v.is_cross_reference())
1178 cross_references.push_back(&v);
1181 if ((p->get_key() == "phandle") ||
1182 (p->get_key() == "linux,phandle"))
1184 if (p->begin()->byte_data.size() != 4)
1186 fprintf(stderr, "Invalid phandle value for node %s. Should be a 4-byte value.\n", n->name.c_str());
1191 uint32_t phandle = p->begin()->get_as_uint32();
1192 used_phandles.insert(std::make_pair(phandle, n.get()));
1200 device_tree::collect_names()
1205 cross_references.clear();
1207 collect_names_recursive(root, p);
1211 device_tree::resolve_cross_references()
1213 for (auto *pv : cross_references)
1215 node_path path = node_paths[pv->string_data];
1216 auto p = path.begin();
1217 auto pe = path.end();
1220 // Skip the first name in the path. It's always "", and implicitly /
1221 for (++p ; p!=pe ; ++p)
1223 pv->byte_data.push_back('/');
1224 push_string(pv->byte_data, p->first);
1225 if (!(p->second.empty()))
1227 pv->byte_data.push_back('@');
1228 push_string(pv->byte_data, p->second);
1231 pv->byte_data.push_back(0);
1234 std::unordered_map<property_value*, fixup&> phandle_set;
1235 for (auto &i : fixups)
1237 phandle_set.insert({&i.val, i});
1239 std::vector<std::reference_wrapper<fixup>> sorted_phandles;
1240 root->visit([&](node &n) {
1241 for (auto &p : n.properties())
1245 auto i = phandle_set.find(&v);
1246 if (i != phandle_set.end())
1248 sorted_phandles.push_back(i->second);
1253 assert(sorted_phandles.size() == fixups.size());
1255 uint32_t phandle = 1;
1256 for (auto &i : sorted_phandles)
1258 string target_name = i.get().val.string_data;
1259 node *target = nullptr;
1261 // If the node name is a path, then look it up by following the path,
1262 // otherwise jump directly to the named node.
1263 if (target_name[0] == '/')
1266 target = root.get();
1267 std::istringstream ss(target_name);
1268 string path_element;
1269 // Read the leading /
1270 std::getline(ss, path_element, '/');
1271 // Iterate over path elements
1275 std::getline(ss, path_element, '/');
1276 std::istringstream nss(path_element);
1277 string node_name, node_address;
1278 std::getline(nss, node_name, '@');
1279 std::getline(nss, node_address, '@');
1280 node *next = nullptr;
1281 for (auto &c : target->child_nodes())
1283 if (c->name == node_name)
1285 if (c->unit_address == node_address)
1292 possible = path + c->name;
1293 if (c->unit_address != string())
1296 possible += c->unit_address;
1302 if (node_address != string())
1305 path += node_address;
1308 if (target == nullptr)
1316 target = node_names[target_name];
1318 if (target == nullptr)
1322 unresolved_fixups.push_back(i);
1327 fprintf(stderr, "Failed to find node with label: %s\n", target_name.c_str());
1328 if (possible != string())
1330 fprintf(stderr, "Possible intended match: %s\n", possible.c_str());
1336 // If there is an existing phandle, use it
1337 property_ptr p = target->get_property("phandle");
1340 p = target->get_property("linux,phandle");
1344 // Otherwise insert a new phandle node
1346 while (used_phandles.find(phandle) != used_phandles.end())
1348 // Note that we only don't need to
1349 // store this phandle in the set,
1350 // because we are monotonically
1351 // increasing the value of phandle and
1352 // so will only ever revisit this value
1353 // if we have used 2^32 phandles, at
1354 // which point our blob won't fit in
1355 // any 32-bit system and we've done
1356 // something badly wrong elsewhere
1360 push_big_endian(v.byte_data, phandle++);
1361 if (phandle_node_name == BOTH || phandle_node_name == LINUX)
1363 p.reset(new property("linux,phandle"));
1365 target->add_property(p);
1367 if (phandle_node_name == BOTH || phandle_node_name == EPAPR)
1369 p.reset(new property("phandle"));
1371 target->add_property(p);
1374 p->begin()->push_to_buffer(i.get().val.byte_data);
1375 assert(i.get().val.byte_data.size() == 4);
1381 device_tree::parse_file(text_input_buffer &input,
1382 std::vector<node_ptr> &roots,
1387 if (input.consume("/dts-v1/;"))
1392 if (input.consume("/plugin/;"))
1399 input.parse_error("Expected /dts-v1/; version string");
1401 // Read any memory reservations
1402 while (input.consume("/memreserve/"))
1404 unsigned long long start, len;
1406 // Read the start and length.
1407 if (!(input.consume_integer_expression(start) &&
1408 (input.next_token(),
1409 input.consume_integer_expression(len))))
1411 input.parse_error("Expected size on /memreserve/ node.");
1415 reservations.push_back(reservation(start, len));
1418 while (valid && !input.finished())
1421 if (input.consume('/'))
1424 n = node::parse(input, string(), string_set(), string(), &defines);
1426 else if (input.consume('&'))
1429 string name = input.parse_node_name();
1431 n = node::parse(input, std::move(name), string_set(), string(), &defines);
1435 input.parse_error("Failed to find root node /.");
1439 roots.push_back(std::move(n));
1449 template<class writer> void
1450 device_tree::write(int fd)
1452 dtb::string_table st;
1455 writer reservation_writer;
1456 writer struct_writer;
1457 writer strings_writer;
1459 // Build the reservation table
1460 reservation_writer.write_comment(string("Memory reservations"));
1461 reservation_writer.write_label(string("dt_reserve_map"));
1462 for (auto &i : reservations)
1464 reservation_writer.write_comment(string("Reservation start"));
1465 reservation_writer.write_data(i.first);
1466 reservation_writer.write_comment(string("Reservation length"));
1467 reservation_writer.write_data(i.first);
1469 // Write n spare reserve map entries, plus the trailing 0.
1470 for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++)
1472 reservation_writer.write_data((uint64_t)0);
1473 reservation_writer.write_data((uint64_t)0);
1477 struct_writer.write_comment(string("Device tree"));
1478 struct_writer.write_label(string("dt_struct_start"));
1479 root->write(struct_writer, st);
1480 struct_writer.write_token(dtb::FDT_END);
1481 struct_writer.write_label(string("dt_struct_end"));
1483 st.write(strings_writer);
1484 // Find the strings size before we stick padding on the end.
1485 // Note: We should possibly use a new writer for the padding.
1486 head.size_dt_strings = strings_writer.size();
1488 // Stick the padding in the strings writer, but after the
1489 // marker indicating that it's the end.
1490 // Note: We probably should add a padding call to the writer so
1491 // that the asm back end can write padding directives instead
1492 // of a load of 0 bytes.
1493 for (uint32_t i=0 ; i<blob_padding ; i++)
1495 strings_writer.write_data((uint8_t)0);
1497 head.totalsize = sizeof(head) + strings_writer.size() +
1498 struct_writer.size() + reservation_writer.size();
1499 while (head.totalsize < minimum_blob_size)
1502 strings_writer.write_data((uint8_t)0);
1504 head.off_dt_struct = sizeof(head) + reservation_writer.size();;
1505 head.off_dt_strings = head.off_dt_struct + struct_writer.size();
1506 head.off_mem_rsvmap = sizeof(head);
1507 head.boot_cpuid_phys = boot_cpu;
1508 head.size_dt_struct = struct_writer.size();
1509 head.write(head_writer);
1511 head_writer.write_to_file(fd);
1512 reservation_writer.write_to_file(fd);
1513 struct_writer.write_to_file(fd);
1514 strings_writer.write_label(string("dt_blob_end"));
1515 strings_writer.write_to_file(fd);
1519 device_tree::referenced_node(property_value &v)
1523 return node_names[v.string_data];
1527 return used_phandles[v.get_as_uint32()];
1533 device_tree::write_binary(int fd)
1535 write<dtb::binary_writer>(fd);
1539 device_tree::write_asm(int fd)
1541 write<dtb::asm_writer>(fd);
1545 device_tree::write_dts(int fd)
1547 FILE *file = fdopen(fd, "w");
1548 fputs("/dts-v1/;\n\n", file);
1550 if (!reservations.empty())
1552 const char msg[] = "/memreserve/";
1553 fwrite(msg, sizeof(msg), 1, file);
1554 for (auto &i : reservations)
1556 fprintf(file, " %" PRIx64 " %" PRIx64, i.first, i.second);
1558 fputs(";\n\n", file);
1562 root->write_dts(file, 0);
1567 device_tree::parse_dtb(const string &fn, FILE *)
1569 auto in = input_buffer::buffer_for_file(fn);
1575 input_buffer &input = *in;
1577 valid = h.read_dtb(input);
1578 boot_cpu = h.boot_cpuid_phys;
1579 if (h.last_comp_version > 17)
1581 fprintf(stderr, "Don't know how to read this version of the device tree blob");
1588 input_buffer reservation_map =
1589 input.buffer_from_offset(h.off_mem_rsvmap, 0);
1590 uint64_t start, length;
1593 if (!(reservation_map.consume_binary(start) &&
1594 reservation_map.consume_binary(length)))
1596 fprintf(stderr, "Failed to read memory reservation table\n");
1600 } while (!((start == 0) && (length == 0)));
1601 input_buffer struct_table =
1602 input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct);
1603 input_buffer strings_table =
1604 input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings);
1606 if (!(struct_table.consume_binary(token) &&
1607 (token == dtb::FDT_BEGIN_NODE)))
1609 fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n");
1613 root = node::parse_dtb(struct_table, strings_table);
1614 if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END)))
1616 fprintf(stderr, "Expected FDT_END token after parsing root node.\n");
1620 valid = (root != 0);
1624 device_tree::node_path::to_string() const
1629 if ((p == pe) || (p+1 == pe))
1633 // Skip the first name in the path. It's always "", and implicitly /
1634 for (++p ; p!=pe ; ++p)
1638 if (!(p->second.empty()))
1648 device_tree::parse_dts(const string &fn, FILE *depfile)
1650 auto in = input_buffer::buffer_for_file(fn);
1656 std::vector<node_ptr> roots;
1657 std::unordered_set<string> defnames;
1658 for (auto &i : defines)
1660 defnames.insert(i.first);
1662 text_input_buffer input(std::move(in),
1663 std::move(defnames),
1664 std::vector<string>(include_paths),
1667 bool read_header = false;
1668 parse_file(input, roots, read_header);
1669 switch (roots.size())
1673 input.parse_error("Failed to find root node /.");
1676 root = std::move(roots[0]);
1680 root = std::move(roots[0]);
1681 for (auto i=++(roots.begin()), e=roots.end() ; i!=e ; ++i)
1684 string name = node->name;
1685 if (name == string())
1687 root->merge_node(std::move(node));
1691 auto existing = node_names.find(name);
1692 if (existing == node_names.end())
1695 existing = node_names.find(name);
1697 if (existing == node_names.end())
1699 fprintf(stderr, "Unable to merge node: %s\n", name.c_str());
1703 existing->second->merge_node(std::move(node));
1710 resolve_cross_references();
1713 std::vector<property_ptr> symbols;
1714 // Create a symbol table. Each label in this device tree may be
1715 // referenced by other plugins, so we create a __symbols__ node inside
1716 // the root that contains mappings (properties) from label names to
1718 for (auto &s : node_paths)
1721 v.string_data = s.second.to_string();
1722 v.type = property_value::STRING;
1723 string name = s.first;
1724 auto prop = std::make_shared<property>(std::move(name));
1726 symbols.push_back(prop);
1728 root->add_child(node::create_special_node("__symbols__", symbols));
1729 // If this is a plugin, then we also need to create two extra nodes.
1730 // Internal phandles will need to be renumbered to avoid conflicts with
1731 // already-loaded nodes and external references will need to be
1735 // Create the fixups entry. This is of the form:
1736 // {target} = {path}:{property name}:{offset}
1737 auto create_fixup_entry = [&](fixup &i, string target)
1739 string value = i.path.to_string();
1741 value += i.prop->get_key();
1743 value += std::to_string(i.prop->offset_of_value(i.val));
1745 v.string_data = value;
1746 v.type = property_value::STRING;
1747 auto prop = std::make_shared<property>(std::move(target));
1751 // If we have any unresolved phandle references in this plugin,
1752 // then we must update them to 0xdeadbeef and leave a property in
1753 // the /__fixups__ node whose key is the label and whose value is
1754 // as described above.
1755 if (!unresolved_fixups.empty())
1758 for (auto &i : unresolved_fixups)
1760 auto &val = i.get().val;
1761 symbols.push_back(create_fixup_entry(i, val.string_data));
1762 val.byte_data.push_back(0xde);
1763 val.byte_data.push_back(0xad);
1764 val.byte_data.push_back(0xbe);
1765 val.byte_data.push_back(0xef);
1766 val.type = property_value::BINARY;
1768 root->add_child(node::create_special_node("__fixups__", symbols));
1771 // If we have any resolved phandle references in this plugin, then
1772 // we must leave a property in the /__local_fixups__ node whose key
1773 // is 'fixup' and whose value is as described above.
1774 for (auto &i : fixups)
1776 if (!i.val.is_phandle())
1780 symbols.push_back(create_fixup_entry(i, "fixup"));
1782 // We've iterated over all fixups, but only emit the
1783 // __local_fixups__ if we found some that were resolved internally.
1784 if (!symbols.empty())
1786 root->add_child(node::create_special_node("__local_fixups__", symbols));
1792 bool device_tree::parse_define(const char *def)
1794 const char *val = strchr(def, '=');
1797 if (strlen(def) != 0)
1805 string name(def, val-def);
1806 string name_copy = name;
1808 std::unique_ptr<input_buffer> raw(new input_buffer(val, strlen(val)));
1809 text_input_buffer in(std::move(raw),
1810 std::unordered_set<string>(),
1811 std::vector<string>(),
1814 property_ptr p = property::parse(in, std::move(name_copy), string_set(), false);