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
52 #include <sys/types.h>
65 property_value::get_as_uint32()
67 if (byte_data.size() != 4)
72 v &= byte_data[0] << 24;
73 v &= byte_data[1] << 16;
74 v &= byte_data[2] << 8;
75 v &= byte_data[3] << 0;
80 property_value::push_to_buffer(byte_buffer &buffer)
82 if (!byte_data.empty())
84 buffer.insert(buffer.end(), byte_data.begin(), byte_data.end());
88 push_string(buffer, string_data, true);
95 property_value::write_dts(FILE *file)
101 assert(0 && "Invalid type");
104 case CROSS_REFERENCE:
105 write_as_string(file);
108 write_as_cells(file);
111 if (byte_data.size() % 4 == 0)
113 write_as_cells(file);
116 write_as_bytes(file);
122 property_value::resolve_type()
128 if (byte_data.empty())
133 if (byte_data.back() == 0)
135 bool is_all_printable = true;
138 bool lastWasNull = false;
139 for (auto i : byte_data)
142 is_all_printable &= (i == '\0') || isprint(i);
145 // If there are two nulls in a row, then we're probably binary.
158 if (!is_all_printable)
163 if ((is_all_printable && (bytes > nuls)) || bytes == 0)
177 property_value::size()
179 if (!byte_data.empty())
181 return byte_data.size();
183 return string_data.size() + 1;
187 property_value::write_as_string(FILE *file)
190 if (byte_data.empty())
192 fputs(string_data.c_str(), file);
196 bool hasNull = (byte_data.back() == '\0');
197 // Remove trailing null bytes from the string before printing as dts.
200 byte_data.pop_back();
202 for (auto i : byte_data)
204 // FIXME Escape tabs, newlines, and so on.
207 fputs("\", \"", file);
214 byte_data.push_back('\0');
221 property_value::write_as_cells(FILE *file)
224 assert((byte_data.size() % 4) == 0);
225 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; ++i)
235 fprintf(file, "0x%" PRIx32, v);
245 property_value::write_as_bytes(FILE *file)
248 for (auto i=byte_data.begin(), e=byte_data.end(); i!=e ; i++)
250 fprintf(file, "%02hhx", *i);
260 property::parse_string(text_input_buffer &input)
263 assert(*input == '"');
265 std::vector<char> bytes;
266 bool isEscaped = false;
267 while (char c = *input)
269 if (c == '"' && !isEscaped)
274 isEscaped = (c == '\\');
278 v.string_data = string(bytes.begin(), bytes.end());
283 property::parse_cells(text_input_buffer &input, int cell_size)
285 assert(*input == '<');
289 while (!input.consume('>'))
292 // If this is a phandle then we need to get the name of the
294 if (input.consume('&'))
298 input.parse_error("reference only permitted in 32-bit arrays");
304 if (!input.consume('{'))
306 referenced = input.parse_node_name();
310 referenced = input.parse_to('}');
313 if (referenced.empty())
315 input.parse_error("Expected node name");
320 // If we already have some bytes, make the phandle a
321 // separate component.
322 if (!v.byte_data.empty())
325 v = property_value();
327 v.string_data = referenced;
328 v.type = property_value::PHANDLE;
330 v = property_value();
334 //FIXME: We should support labels in the middle
335 //of these, but we don't.
336 unsigned long long val;
337 if (!input.consume_integer_expression(val))
339 // FIXME: Distinguish invalid syntax from a
340 // number that cannot be represented in an
341 // unsigned long long.
342 input.parse_error("Expected numbers in array of cells");
346 // FIXME: No sign information available, so cannot
347 // distinguish small negative values from large
348 // positive ones, and thus we have to conservatively
349 // permit anything that looks like a sign-extended
351 if (cell_size < 64 && val >= (1ull << cell_size) &&
352 (val | ((1ull << (cell_size - 1)) - 1)) !=
353 std::numeric_limits<unsigned long long>::max())
355 std::string msg = "Value does not fit in a " +
356 std::to_string(cell_size) + "-bit cell";
357 input.parse_error(msg.c_str());
364 v.byte_data.push_back(val);
367 push_big_endian(v.byte_data, (uint16_t)val);
370 push_big_endian(v.byte_data, (uint32_t)val);
373 push_big_endian(v.byte_data, (uint64_t)val);
376 assert(0 && "Invalid cell size!");
381 // Don't store an empty string value here.
382 if (v.byte_data.size() > 0)
389 property::parse_bytes(text_input_buffer &input)
391 assert(*input == '[');
395 while (!input.consume(']'))
398 //FIXME: We should support
399 //labels in the middle of
400 //these, but we don't.
402 if (!input.consume_hex_byte(val))
404 input.parse_error("Expected hex bytes in array of bytes");
408 v.byte_data.push_back(val);
416 property::parse_reference(text_input_buffer &input)
418 assert(*input == '&');
422 v.string_data = input.parse_node_name();
423 if (v.string_data.empty())
425 input.parse_error("Expected node name");
429 v.type = property_value::CROSS_REFERENCE;
433 property::property(input_buffer &structs, input_buffer &strings)
435 uint32_t name_offset;
437 valid = structs.consume_binary(length) &&
438 structs.consume_binary(name_offset);
441 fprintf(stderr, "Failed to read property\n");
445 input_buffer name_buffer = strings.buffer_from_offset(name_offset);
446 if (name_buffer.finished())
448 fprintf(stderr, "Property name offset %" PRIu32
449 " is past the end of the strings table\n",
454 key = name_buffer.parse_to(0);
456 // If we're empty, do not push anything as value.
463 for (uint32_t i=0 ; i<length ; i++)
465 if (!(valid = structs.consume_binary(byte)))
467 fprintf(stderr, "Failed to read property value\n");
470 v.byte_data.push_back(byte);
475 void property::parse_define(text_input_buffer &input, define_map *defines)
480 input.parse_error("No predefined properties to match name\n");
484 string name = input.parse_property_name();
485 define_map::iterator found;
486 if ((name == string()) ||
487 ((found = defines->find(name)) == defines->end()))
489 input.parse_error("Undefined property name\n");
493 values.push_back((*found).second->values[0]);
496 property::property(text_input_buffer &input,
499 bool semicolonTerminated,
500 define_map *defines) : key(k), labels(l), valid(true)
508 parse_define(input, defines);
516 input.parse_error("Invalid property value.");
521 if (input.consume("/incbin/(\""))
523 auto loc = input.location();
524 std::string filename = input.parse_to('"');
525 if (!(valid = input.consume('"')))
527 loc.report_error("Syntax error, expected '\"' to terminate /incbin/(");
531 if (!(valid = input.read_binary_file(filename, v.byte_data)))
533 input.parse_error("Cannot open binary include file");
536 if (!(valid &= input.consume(')')))
538 input.parse_error("Syntax error, expected ')' to terminate /incbin/(");
544 unsigned long long bits = 0;
545 valid = input.consume("/bits/");
547 valid &= input.consume_integer(bits);
552 input.parse_error("Invalid size for elements");
559 input.parse_error("/bits/ directive is only valid on arrays");
563 parse_cells(input, bits);
570 parse_cells(input, 32);
576 parse_reference(input);
584 } while (input.consume(','));
585 if (semicolonTerminated && !input.consume(';'))
587 input.parse_error("Expected ; at end of property");
593 property::parse_dtb(input_buffer &structs, input_buffer &strings)
595 property_ptr p(new property(structs, strings));
604 property::parse(text_input_buffer &input, string &&key, string_set &&label,
605 bool semicolonTerminated, define_map *defines)
607 property_ptr p(new property(input,
620 property::write(dtb::output_writer &writer, dtb::string_table &strings)
622 writer.write_token(dtb::FDT_PROP);
623 byte_buffer value_buffer;
624 for (value_iterator i=begin(), e=end() ; i!=e ; ++i)
626 i->push_to_buffer(value_buffer);
628 writer.write_data((uint32_t)value_buffer.size());
629 writer.write_comment(key);
630 writer.write_data(strings.add_string(key));
631 writer.write_data(value_buffer);
635 property_value::try_to_merge(property_value &other)
641 __builtin_unreachable();
649 case CROSS_REFERENCE:
653 if (other.type == PHANDLE || other.type == BINARY)
656 byte_data.insert(byte_data.end(), other.byte_data.begin(),
657 other.byte_data.end());
665 property::write_dts(FILE *file, int indent)
667 for (int i=0 ; i<indent ; i++)
672 for (auto &l : labels)
674 fputs(l.c_str(), file);
680 fputs(key.c_str(), file);
684 std::vector<property_value> *vals = &values;
685 std::vector<property_value> v;
686 // If we've got multiple values then try to merge them all together.
687 if (values.size() > 1)
690 v.push_back(values.front());
691 for (auto i=(++begin()), e=end() ; i!=e ; ++i)
693 if (!v.back().try_to_merge(*i))
700 for (auto i=vals->begin(), e=vals->end() ; i!=e ; ++i)
714 property::offset_of_value(property_value &val)
717 for (auto &v : values)
729 node::parse_name(text_input_buffer &input, bool &is_property, const char *error)
738 return input.parse_property_name();
740 string n = input.parse_node_or_property_name(is_property);
745 input.parse_error(error);
753 node::visit(std::function<visit_behavior(node&, node*)> fn, node *parent)
755 visit_behavior behavior;
756 behavior = fn(*this, parent);
757 if (behavior == VISIT_BREAK)
761 else if (behavior != VISIT_CONTINUE)
763 for (auto &&c : children)
765 behavior = c->visit(fn, this);
766 // Any status other than VISIT_RECURSE stops our execution and
767 // bubbles up to our caller. The caller may then either continue
768 // visiting nodes that are siblings to this one or completely halt
770 if (behavior != VISIT_RECURSE)
776 // Continue recursion by default
777 return VISIT_RECURSE;
780 node::node(input_buffer &structs, input_buffer &strings) : valid(true)
782 std::vector<char> bytes;
783 while (structs[0] != '\0' && structs[0] != '@')
785 bytes.push_back(structs[0]);
788 name = string(bytes.begin(), bytes.end());
790 if (structs[0] == '@')
793 while (structs[0] != '\0')
795 bytes.push_back(structs[0]);
798 unit_address = string(bytes.begin(), bytes.end());
802 while (structs.consume_binary(token))
807 fprintf(stderr, "Unexpected token 0x%" PRIx32
808 " while parsing node.\n", token);
811 // Child node, parse it.
812 case dtb::FDT_BEGIN_NODE:
814 node_ptr child = node::parse_dtb(structs, strings);
820 children.push_back(std::move(child));
823 // End of this node, no errors.
824 case dtb::FDT_END_NODE:
826 // Property, parse it.
829 property_ptr prop = property::parse_dtb(structs, strings);
835 props.push_back(prop);
839 // End of structs table. Should appear after
840 // the end of the last node.
842 fprintf(stderr, "Unexpected FDT_END token while parsing node.\n");
845 // NOPs are padding. Ignore them.
850 fprintf(stderr, "Failed to read token from structs table while parsing node.\n");
856 node::node(const string &n,
857 const std::vector<property_ptr> &p)
860 props.insert(props.begin(), p.begin(), p.end());
863 node_ptr node::create_special_node(const string &name,
864 const std::vector<property_ptr> &props)
866 node_ptr n(new node(name, props));
870 node::node(text_input_buffer &input,
873 std::unordered_set<string> &&l,
876 : labels(l), name(n), unit_address(a), valid(true)
878 if (!input.consume('{'))
880 input.parse_error("Expected { to start new device tree node.\n");
883 while (valid && !input.consume('}'))
885 // flag set if we find any characters that are only in
886 // the property name character set, not the node
887 bool is_property = false;
888 // flag set if our node is marked as /omit-if-no-ref/ to be
889 // garbage collected later if nothing references it
890 bool marked_omit_if_no_ref = false;
891 string child_name, child_address;
892 std::unordered_set<string> child_labels;
893 auto parse_delete = [&](const char *expected, bool at)
895 if (child_name == string())
897 input.parse_error(expected);
902 if (at && input.consume('@'))
905 child_name += parse_name(input, is_property, "Expected unit address");
907 if (!input.consume(';'))
909 input.parse_error("Expected semicolon");
915 if (input.consume("/delete-node/"))
918 child_name = input.parse_node_name();
919 parse_delete("Expected node name", true);
922 deleted_children.insert(child_name);
926 if (input.consume("/delete-property/"))
929 child_name = input.parse_property_name();
930 parse_delete("Expected property name", false);
933 deleted_props.insert(child_name);
937 if (input.consume("/omit-if-no-ref/"))
940 marked_omit_if_no_ref = true;
941 tree.set_needs_garbage_collection();
943 child_name = parse_name(input, is_property,
944 "Expected property or node name");
945 while (input.consume(':'))
947 // Node labels can contain any characters? The
948 // spec doesn't say, so we guess so...
950 child_labels.insert(std::move(child_name));
951 child_name = parse_name(input, is_property, "Expected property or node name");
953 if (input.consume('@'))
955 child_address = parse_name(input, is_property, "Expected unit address");
962 // If we're parsing a property, then we must actually do that.
963 if (input.consume('='))
965 property_ptr p = property::parse(input, std::move(child_name),
966 std::move(child_labels), true, defines);
976 else if (!is_property && *input == ('{'))
978 node_ptr child = node::parse(input, tree, std::move(child_name),
979 std::move(child_labels), std::move(child_address), defines);
982 child->omit_if_no_ref = marked_omit_if_no_ref;
983 children.push_back(std::move(child));
990 else if (input.consume(';'))
992 props.push_back(property_ptr(new property(std::move(child_name), std::move(child_labels))));
996 input.parse_error("Error parsing property. Expected property value");
1006 node::cmp_properties(property_ptr &p1, property_ptr &p2)
1008 return p1->get_key() < p2->get_key();
1012 node::cmp_children(node_ptr &c1, node_ptr &c2)
1014 if (c1->name == c2->name)
1016 return c1->unit_address < c2->unit_address;
1018 return c1->name < c2->name;
1024 std::sort(property_begin(), property_end(), cmp_properties);
1025 std::sort(child_begin(), child_end(), cmp_children);
1026 for (auto &c : child_nodes())
1033 node::parse(text_input_buffer &input,
1038 define_map *defines)
1040 node_ptr n(new node(input,
1054 node::parse_dtb(input_buffer &structs, input_buffer &strings)
1056 node_ptr n(new node(structs, strings));
1065 node::get_property(const string &key)
1067 for (auto &i : props)
1069 if (i->get_key() == key)
1078 node::merge_node(node_ptr &other)
1080 for (auto &l : other->labels)
1084 children.erase(std::remove_if(children.begin(), children.end(),
1085 [&](const node_ptr &p) {
1086 string full_name = p->name;
1087 if (p->unit_address != string())
1090 full_name += p->unit_address;
1092 if (other->deleted_children.count(full_name) > 0)
1094 other->deleted_children.erase(full_name);
1098 }), children.end());
1099 props.erase(std::remove_if(props.begin(), props.end(),
1100 [&](const property_ptr &p) {
1101 if (other->deleted_props.count(p->get_key()) > 0)
1103 other->deleted_props.erase(p->get_key());
1108 // Note: this is an O(n*m) operation. It might be sensible to
1109 // optimise this if we find that there are nodes with very
1110 // large numbers of properties, but for typical usage the
1111 // entire vector will fit (easily) into cache, so iterating
1112 // over it repeatedly isn't that expensive.
1113 for (auto &p : other->properties())
1116 for (auto &mp : properties())
1118 if (mp->get_key() == p->get_key())
1130 for (auto &c : other->children)
1133 for (auto &i : children)
1135 if (i->name == c->name && i->unit_address == c->unit_address)
1144 children.push_back(std::move(c));
1150 node::write(dtb::output_writer &writer, dtb::string_table &strings)
1152 writer.write_token(dtb::FDT_BEGIN_NODE);
1153 byte_buffer name_buffer;
1154 push_string(name_buffer, name);
1155 if (unit_address != string())
1157 name_buffer.push_back('@');
1158 push_string(name_buffer, unit_address);
1160 writer.write_comment(name);
1161 writer.write_data(name_buffer);
1162 writer.write_data((uint8_t)0);
1163 for (auto p : properties())
1165 p->write(writer, strings);
1167 for (auto &c : child_nodes())
1169 c->write(writer, strings);
1171 writer.write_token(dtb::FDT_END_NODE);
1175 node::write_dts(FILE *file, int indent)
1177 for (int i=0 ; i<indent ; i++)
1182 for (auto &label : labels)
1184 fprintf(file, "%s: ", label.c_str());
1187 if (name != string())
1189 fputs(name.c_str(), file);
1191 if (unit_address != string())
1194 fputs(unit_address.c_str(), file);
1196 fputs(" {\n\n", file);
1197 for (auto p : properties())
1199 p->write_dts(file, indent+1);
1201 for (auto &c : child_nodes())
1203 c->write_dts(file, indent+1);
1205 for (int i=0 ; i<indent ; i++)
1209 fputs("};\n", file);
1213 device_tree::collect_names_recursive(node_ptr &n, node_path &path)
1215 path.push_back(std::make_pair(n->name, n->unit_address));
1216 for (const string &name : n->labels)
1218 if (name != string())
1220 auto iter = node_names.find(name);
1221 if (iter == node_names.end())
1223 node_names.insert(std::make_pair(name, n.get()));
1224 node_paths.insert(std::make_pair(name, path));
1225 ordered_node_paths.push_back({name, path});
1229 node_names.erase(iter);
1230 auto i = node_paths.find(name);
1231 if (i != node_paths.end())
1233 node_paths.erase(name);
1235 fprintf(stderr, "Label not unique: %s. References to this label will not be resolved.\n", name.c_str());
1239 for (auto &c : n->child_nodes())
1241 collect_names_recursive(c, path);
1243 // Now we collect the phandles and properties that reference
1245 for (auto &p : n->properties())
1251 fixups.push_back({path, p, v});
1253 if (v.is_cross_reference())
1255 cross_references.push_back(&v);
1258 if ((p->get_key() == "phandle") ||
1259 (p->get_key() == "linux,phandle"))
1261 if (p->begin()->byte_data.size() != 4)
1263 fprintf(stderr, "Invalid phandle value for node %s. Should be a 4-byte value.\n", n->name.c_str());
1268 uint32_t phandle = p->begin()->get_as_uint32();
1269 used_phandles.insert(std::make_pair(phandle, n.get()));
1277 device_tree::collect_names()
1282 ordered_node_paths.clear();
1283 cross_references.clear();
1285 collect_names_recursive(root, p);
1289 device_tree::assign_phandle(node *n, uint32_t &phandle)
1291 // If there is an existing phandle, use it
1292 property_ptr p = n->get_property("phandle");
1295 p = n->get_property("linux,phandle");
1299 // Otherwise insert a new phandle node
1301 while (used_phandles.find(phandle) != used_phandles.end())
1303 // Note that we only don't need to
1304 // store this phandle in the set,
1305 // because we are monotonically
1306 // increasing the value of phandle and
1307 // so will only ever revisit this value
1308 // if we have used 2^32 phandles, at
1309 // which point our blob won't fit in
1310 // any 32-bit system and we've done
1311 // something badly wrong elsewhere
1315 push_big_endian(v.byte_data, phandle++);
1316 if (phandle_node_name == BOTH || phandle_node_name == LINUX)
1318 p.reset(new property("linux,phandle"));
1322 if (phandle_node_name == BOTH || phandle_node_name == EPAPR)
1324 p.reset(new property("phandle"));
1334 device_tree::assign_phandles(node_ptr &n, uint32_t &next)
1336 if (!n->labels.empty())
1338 assign_phandle(n.get(), next);
1341 for (auto &c : n->child_nodes())
1343 assign_phandles(c, next);
1348 device_tree::resolve_cross_references(uint32_t &phandle)
1350 for (auto *pv : cross_references)
1352 node_path path = node_paths[pv->string_data];
1353 auto p = path.begin();
1354 auto pe = path.end();
1357 // Skip the first name in the path. It's always "", and implicitly /
1358 for (++p ; p!=pe ; ++p)
1360 pv->byte_data.push_back('/');
1361 push_string(pv->byte_data, p->first);
1362 if (!(p->second.empty()))
1364 pv->byte_data.push_back('@');
1365 push_string(pv->byte_data, p->second);
1368 pv->byte_data.push_back(0);
1371 std::unordered_map<property_value*, fixup&> phandle_set;
1372 for (auto &i : fixups)
1374 phandle_set.insert({&i.val, i});
1376 std::vector<std::reference_wrapper<fixup>> sorted_phandles;
1377 root->visit([&](node &n, node *) {
1378 for (auto &p : n.properties())
1382 auto i = phandle_set.find(&v);
1383 if (i != phandle_set.end())
1385 sorted_phandles.push_back(i->second);
1390 return node::VISIT_RECURSE;
1392 assert(sorted_phandles.size() == fixups.size());
1393 for (auto &i : sorted_phandles)
1395 string target_name = i.get().val.string_data;
1396 node *target = nullptr;
1398 // If the node name is a path, then look it up by following the path,
1399 // otherwise jump directly to the named node.
1400 if (target_name[0] == '/')
1403 target = root.get();
1404 std::istringstream ss(target_name);
1405 string path_element;
1406 // Read the leading /
1407 std::getline(ss, path_element, '/');
1408 // Iterate over path elements
1412 std::getline(ss, path_element, '/');
1413 std::istringstream nss(path_element);
1414 string node_name, node_address;
1415 std::getline(nss, node_name, '@');
1416 std::getline(nss, node_address, '@');
1417 node *next = nullptr;
1418 for (auto &c : target->child_nodes())
1420 if (c->name == node_name)
1422 if (c->unit_address == node_address)
1429 possible = path + c->name;
1430 if (c->unit_address != string())
1433 possible += c->unit_address;
1439 if (node_address != string())
1442 path += node_address;
1445 if (target == nullptr)
1453 target = node_names[target_name];
1455 if (target == nullptr)
1459 unresolved_fixups.push_back(i);
1464 fprintf(stderr, "Failed to find node with label: %s\n", target_name.c_str());
1465 if (possible != string())
1467 fprintf(stderr, "Possible intended match: %s\n", possible.c_str());
1473 // If there is an existing phandle, use it
1474 property_ptr p = assign_phandle(target, phandle);
1475 p->begin()->push_to_buffer(i.get().val.byte_data);
1476 assert(i.get().val.byte_data.size() == 4);
1481 device_tree::garbage_collect_marked_nodes()
1483 std::unordered_set<node*> previously_referenced_nodes;
1484 std::unordered_set<node*> newly_referenced_nodes;
1486 auto mark_referenced_nodes_used = [&](node &n)
1488 for (auto &p : n.properties())
1494 node *nx = node_names[v.string_data];
1497 // Try it again, but as a path
1498 for (auto &s : node_paths)
1500 if (v.string_data == s.second.to_string())
1502 nx = node_names[s.first];
1509 // Couldn't resolve this one?
1512 // Only mark those currently unmarked
1516 newly_referenced_nodes.insert(nx);
1523 // Seed our referenced nodes with those that have been seen by a node that
1524 // either will not be omitted if it's unreferenced or has a symbol.
1525 // Nodes with symbols are explicitly not garbage collected because they may
1526 // be expected for referencing by an overlay, and we do not want surprises
1528 root->visit([&](node &n, node *) {
1529 if (!n.omit_if_no_ref || (write_symbols && !n.labels.empty()))
1531 mark_referenced_nodes_used(n);
1533 // Recurse as normal
1534 return node::VISIT_RECURSE;
1537 while (!newly_referenced_nodes.empty())
1539 previously_referenced_nodes = std::move(newly_referenced_nodes);
1540 for (auto *n : previously_referenced_nodes)
1542 mark_referenced_nodes_used(*n);
1546 previously_referenced_nodes.clear();
1547 bool children_deleted = false;
1550 root->visit([&](node &n, node *) {
1551 bool gc_children = false;
1553 for (auto &cn : n.child_nodes())
1555 if (cn->omit_if_no_ref && !cn->used)
1564 children_deleted = true;
1565 n.delete_children_if([](node_ptr &nx) {
1566 return (nx->omit_if_no_ref && !nx->used);
1569 return node::VISIT_CONTINUE;
1572 return node::VISIT_RECURSE;
1575 return children_deleted;
1579 device_tree::parse_file(text_input_buffer &input,
1580 std::vector<node_ptr> &roots,
1585 while (input.consume("/dts-v1/;"))
1590 if (input.consume("/plugin/;"))
1597 input.parse_error("Expected /dts-v1/; version string");
1599 // Read any memory reservations
1600 while (input.consume("/memreserve/"))
1602 unsigned long long start, len;
1604 // Read the start and length.
1605 if (!(input.consume_integer_expression(start) &&
1606 (input.next_token(),
1607 input.consume_integer_expression(len))))
1609 input.parse_error("Expected size on /memreserve/ node.");
1613 reservations.push_back(reservation(start, len));
1619 while (valid && !input.finished())
1622 if (input.consume('/'))
1625 n = node::parse(input, *this, string(), string_set(), string(), &defines);
1627 else if (input.consume('&'))
1631 bool name_is_path_reference = false;
1632 // This is to deal with names intended as path references, e.g. &{/path}.
1633 // While it may make sense in a non-plugin context, we don't support such
1634 // usage at this time.
1635 if (input.consume('{') && is_plugin)
1637 name = input.parse_to('}');
1639 name_is_path_reference = true;
1643 name = input.parse_node_name();
1646 n = node::parse(input, *this, std::move(name), string_set(), string(), &defines);
1649 n->name_is_path_reference = name_is_path_reference;
1654 input.parse_error("Failed to find root node /.");
1658 roots.push_back(std::move(n));
1668 template<class writer> void
1669 device_tree::write(int fd)
1671 dtb::string_table st;
1674 writer reservation_writer;
1675 writer struct_writer;
1676 writer strings_writer;
1678 // Build the reservation table
1679 reservation_writer.write_comment(string("Memory reservations"));
1680 reservation_writer.write_label(string("dt_reserve_map"));
1681 for (auto &i : reservations)
1683 reservation_writer.write_comment(string("Reservation start"));
1684 reservation_writer.write_data(i.first);
1685 reservation_writer.write_comment(string("Reservation length"));
1686 reservation_writer.write_data(i.second);
1688 // Write n spare reserve map entries, plus the trailing 0.
1689 for (uint32_t i=0 ; i<=spare_reserve_map_entries ; i++)
1691 reservation_writer.write_data((uint64_t)0);
1692 reservation_writer.write_data((uint64_t)0);
1696 struct_writer.write_comment(string("Device tree"));
1697 struct_writer.write_label(string("dt_struct_start"));
1698 root->write(struct_writer, st);
1699 struct_writer.write_token(dtb::FDT_END);
1700 struct_writer.write_label(string("dt_struct_end"));
1702 st.write(strings_writer);
1703 // Find the strings size before we stick padding on the end.
1704 // Note: We should possibly use a new writer for the padding.
1705 head.size_dt_strings = strings_writer.size();
1707 // Stick the padding in the strings writer, but after the
1708 // marker indicating that it's the end.
1709 // Note: We probably should add a padding call to the writer so
1710 // that the asm back end can write padding directives instead
1711 // of a load of 0 bytes.
1712 for (uint32_t i=0 ; i<blob_padding ; i++)
1714 strings_writer.write_data((uint8_t)0);
1716 head.totalsize = sizeof(head) + strings_writer.size() +
1717 struct_writer.size() + reservation_writer.size();
1718 while (head.totalsize < minimum_blob_size)
1721 strings_writer.write_data((uint8_t)0);
1723 head.off_dt_struct = sizeof(head) + reservation_writer.size();;
1724 head.off_dt_strings = head.off_dt_struct + struct_writer.size();
1725 head.off_mem_rsvmap = sizeof(head);
1726 head.boot_cpuid_phys = boot_cpu;
1727 head.size_dt_struct = struct_writer.size();
1728 head.write(head_writer);
1730 head_writer.write_to_file(fd);
1731 reservation_writer.write_to_file(fd);
1732 struct_writer.write_to_file(fd);
1733 strings_writer.write_label(string("dt_blob_end"));
1734 strings_writer.write_to_file(fd);
1738 device_tree::referenced_node(property_value &v)
1742 return node_names[v.string_data];
1746 return used_phandles[v.get_as_uint32()];
1752 device_tree::write_binary(int fd)
1754 write<dtb::binary_writer>(fd);
1758 device_tree::write_asm(int fd)
1760 write<dtb::asm_writer>(fd);
1764 device_tree::write_dts(int fd)
1766 FILE *file = fdopen(fd, "w");
1767 fputs("/dts-v1/;\n\n", file);
1769 if (!reservations.empty())
1771 const char msg[] = "/memreserve/";
1772 // Exclude the null byte when we're writing it out to the file.
1773 fwrite(msg, sizeof(msg) - 1, 1, file);
1774 for (auto &i : reservations)
1776 fprintf(file, " 0x%" PRIx64 " 0x%" PRIx64, i.first, i.second);
1778 fputs(";\n\n", file);
1782 root->write_dts(file, 0);
1787 device_tree::parse_dtb(const string &fn, FILE *)
1789 auto in = input_buffer::buffer_for_file(fn);
1795 input_buffer &input = *in;
1797 valid = h.read_dtb(input);
1798 boot_cpu = h.boot_cpuid_phys;
1799 if (h.last_comp_version > 17)
1801 fprintf(stderr, "Don't know how to read this version of the device tree blob");
1808 input_buffer reservation_map =
1809 input.buffer_from_offset(h.off_mem_rsvmap, 0);
1810 uint64_t start, length;
1813 if (!(reservation_map.consume_binary(start) &&
1814 reservation_map.consume_binary(length)))
1816 fprintf(stderr, "Failed to read memory reservation table\n");
1820 if (start != 0 || length != 0)
1822 reservations.push_back(reservation(start, length));
1824 } while (!((start == 0) && (length == 0)));
1825 input_buffer struct_table =
1826 input.buffer_from_offset(h.off_dt_struct, h.size_dt_struct);
1827 input_buffer strings_table =
1828 input.buffer_from_offset(h.off_dt_strings, h.size_dt_strings);
1830 if (!(struct_table.consume_binary(token) &&
1831 (token == dtb::FDT_BEGIN_NODE)))
1833 fprintf(stderr, "Expected FDT_BEGIN_NODE token.\n");
1837 root = node::parse_dtb(struct_table, strings_table);
1838 if (!(struct_table.consume_binary(token) && (token == dtb::FDT_END)))
1840 fprintf(stderr, "Expected FDT_END token after parsing root node.\n");
1844 valid = (root != 0);
1848 device_tree::node_path::to_string() const
1853 if ((p == pe) || (p+1 == pe))
1857 // Skip the first name in the path. It's always "", and implicitly /
1858 for (++p ; p!=pe ; ++p)
1862 if (!(p->second.empty()))
1872 device_tree::create_fragment_wrapper(node_ptr &node, int &fragnum)
1874 // In a plugin, we can massage these non-/ root nodes into into a fragment
1875 std::string fragment_address = "fragment@" + std::to_string(fragnum);
1878 std::vector<property_ptr> symbols;
1880 // Intentionally left empty
1881 node_ptr newroot = node::create_special_node("", symbols);
1882 node_ptr wrapper = node::create_special_node("__overlay__", symbols);
1884 // Generate the fragment with $propname = <&name>
1886 std::string propname;
1887 v.string_data = node->name;
1888 if (!node->name_is_path_reference)
1890 propname = "target";
1891 v.type = property_value::PHANDLE;
1895 propname = "target-path";
1896 v.type = property_value::STRING;
1898 auto prop = std::make_shared<property>(std::string(propname));
1900 symbols.push_back(prop);
1902 node_ptr fragment = node::create_special_node(fragment_address, symbols);
1904 wrapper->merge_node(node);
1905 fragment->add_child(std::move(wrapper));
1906 newroot->add_child(std::move(fragment));
1911 device_tree::generate_root(node_ptr &node, int &fragnum)
1914 string name = node->name;
1915 if (name == string())
1917 return std::move(node);
1919 else if (!is_plugin)
1924 return create_fragment_wrapper(node, fragnum);
1928 device_tree::reassign_fragment_numbers(node_ptr &node, int &delta)
1931 for (auto &c : node->child_nodes())
1933 if (c->name == std::string("fragment"))
1935 int current_address = std::stoi(c->unit_address, nullptr, 16);
1936 std::ostringstream new_address;
1937 current_address += delta;
1938 // It's possible that we hopped more than one somewhere, so just reset
1939 // delta to the next in sequence.
1940 delta = current_address + 1;
1941 new_address << std::hex << current_address;
1942 c->unit_address = new_address.str();
1948 device_tree::parse_dts(const string &fn, FILE *depfile)
1950 auto in = input_buffer::buffer_for_file(fn);
1956 std::vector<node_ptr> roots;
1957 std::unordered_set<string> defnames;
1958 for (auto &i : defines)
1960 defnames.insert(i.first);
1962 text_input_buffer input(std::move(in),
1963 std::move(defnames),
1964 std::vector<string>(include_paths),
1967 bool read_header = false;
1969 parse_file(input, roots, read_header);
1970 switch (roots.size())
1974 input.parse_error("Failed to find root node /.");
1977 root = generate_root(roots[0], fragnum);
1981 input.parse_error("Failed to find root node /.");
1987 root = generate_root(roots[0], fragnum);
1991 input.parse_error("Failed to find root node /.");
1994 for (auto i=++(roots.begin()), e=roots.end() ; i!=e ; ++i)
1997 string name = node->name;
1998 if (name == string())
2002 // Re-assign any fragment numbers based on a delta of
2003 // fragnum before we merge it
2004 reassign_fragment_numbers(node, fragnum);
2006 root->merge_node(node);
2010 auto existing = node_names.find(name);
2011 if (existing == node_names.end())
2014 existing = node_names.find(name);
2016 if (existing == node_names.end())
2020 auto fragment = create_fragment_wrapper(node, fragnum);
2021 root->merge_node(fragment);
2025 fprintf(stderr, "Unable to merge node: %s\n", name.c_str());
2030 existing->second->merge_node(node);
2037 // Return value indicates whether we've dirtied the tree or not and need to
2039 if (garbage_collect && garbage_collect_marked_nodes())
2043 uint32_t phandle = 1;
2044 // If we're writing symbols, go ahead and assign phandles to the entire
2045 // tree. We'll do this before we resolve cross references, just to keep
2046 // order semi-predictable and stable.
2049 assign_phandles(root, phandle);
2051 resolve_cross_references(phandle);
2054 std::vector<property_ptr> symbols;
2055 // Create a symbol table. Each label in this device tree may be
2056 // referenced by other plugins, so we create a __symbols__ node inside
2057 // the root that contains mappings (properties) from label names to
2059 for (auto i=ordered_node_paths.rbegin(), e=ordered_node_paths.rend() ; i!=e ; ++i)
2062 if (node_paths.find(s.first) == node_paths.end())
2064 // Erased node, skip it.
2068 v.string_data = s.second.to_string();
2069 v.type = property_value::STRING;
2070 string name = s.first;
2071 auto prop = std::make_shared<property>(std::move(name));
2073 symbols.push_back(prop);
2075 root->add_child(node::create_special_node("__symbols__", symbols));
2077 // If this is a plugin, then we also need to create two extra nodes.
2078 // Internal phandles will need to be renumbered to avoid conflicts with
2079 // already-loaded nodes and external references will need to be
2083 std::vector<property_ptr> symbols;
2084 // Create the fixups entry. This is of the form:
2085 // {target} = {path}:{property name}:{offset}
2086 auto create_fixup_entry = [&](fixup &i, string target)
2088 string value = i.path.to_string();
2090 value += i.prop->get_key();
2092 value += std::to_string(i.prop->offset_of_value(i.val));
2094 v.string_data = value;
2095 v.type = property_value::STRING;
2096 auto prop = std::make_shared<property>(std::move(target));
2100 // If we have any unresolved phandle references in this plugin,
2101 // then we must update them to 0xdeadbeef and leave a property in
2102 // the /__fixups__ node whose key is the label and whose value is
2103 // as described above.
2104 if (!unresolved_fixups.empty())
2106 for (auto &i : unresolved_fixups)
2108 auto &val = i.get().val;
2109 symbols.push_back(create_fixup_entry(i, val.string_data));
2110 val.byte_data.push_back(0xde);
2111 val.byte_data.push_back(0xad);
2112 val.byte_data.push_back(0xbe);
2113 val.byte_data.push_back(0xef);
2114 val.type = property_value::BINARY;
2116 root->add_child(node::create_special_node("__fixups__", symbols));
2119 // If we have any resolved phandle references in this plugin, then
2120 // we must create a child in the __local_fixups__ node whose path
2121 // matches the node path from the root and whose value contains the
2122 // location of the reference within a property.
2124 // Create a local_fixups node that is initially empty.
2125 node_ptr local_fixups = node::create_special_node("__local_fixups__", symbols);
2126 for (auto &i : fixups)
2128 if (!i.val.is_phandle())
2132 node *n = local_fixups.get();
2133 for (auto &p : i.path)
2135 // Skip the implicit root
2136 if (p.first.empty())
2141 for (auto &c : n->child_nodes())
2143 if (c->name == p.first)
2145 if (c->unit_address == p.second)
2155 string path = p.first;
2156 if (!(p.second.empty()))
2161 n->add_child(node::create_special_node(path, symbols));
2162 n = (--n->child_end())->get();
2167 push_big_endian(pv.byte_data, static_cast<uint32_t>(i.prop->offset_of_value(i.val)));
2168 pv.type = property_value::BINARY;
2169 auto key = i.prop->get_key();
2170 property_ptr prop = n->get_property(key);
2171 // If we don't have an existing property then create one and
2172 // use this property value
2175 prop = std::make_shared<property>(std::move(key));
2176 n->add_property(prop);
2177 prop->add_value(pv);
2181 // If we do have an existing property value, try to append
2183 property_value &old_val = *(--prop->end());
2184 if (!old_val.try_to_merge(pv))
2186 prop->add_value(pv);
2190 // We've iterated over all fixups, but only emit the
2191 // __local_fixups__ if we found some that were resolved internally.
2192 if (local_fixups->child_begin() != local_fixups->child_end())
2194 root->add_child(std::move(local_fixups));
2199 bool device_tree::parse_define(const char *def)
2201 const char *val = strchr(def, '=');
2204 if (strlen(def) != 0)
2212 string name(def, val-def);
2213 string name_copy = name;
2215 std::unique_ptr<input_buffer> raw(new input_buffer(val, strlen(val)));
2216 text_input_buffer in(std::move(raw),
2217 std::unordered_set<string>(),
2218 std::vector<string>(),
2221 property_ptr p = property::parse(in, std::move(name_copy), string_set(), false);