fdt.cc (d6d16831c555d9c626ed2b49977241abd0d5f97e) fdt.cc (21d5d37ba4c0131d6c141695366e266e32cc3bc1)
1/*-
2 * Copyright (c) 2013 David Chisnall
3 * All rights reserved.
4 *
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.
8 *

--- 155 unchanged lines hidden (view full) ---

164 type = STRING_LIST;
165 }
166 return;
167 }
168 }
169 type = BINARY;
170}
171
1/*-
2 * Copyright (c) 2013 David Chisnall
3 * All rights reserved.
4 *
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.
8 *

--- 155 unchanged lines hidden (view full) ---

164 type = STRING_LIST;
165 }
166 return;
167 }
168 }
169 type = BINARY;
170}
171
172size_t
173property_value::size()
174{
175 if (!byte_data.empty())
176 {
177 return byte_data.size();
178 }
179 return string_data.size() + 1;
180}
181
172void
173property_value::write_as_string(FILE *file)
174{
175 putc('"', file);
176 if (byte_data.empty())
177 {
178 fputs(string_data.c_str(), file);
179 }

--- 101 unchanged lines hidden (view full) ---

281 {
282 if (cell_size != 32)
283 {
284 input.parse_error("reference only permitted in 32-bit arrays");
285 valid = false;
286 return;
287 }
288 input.next_token();
182void
183property_value::write_as_string(FILE *file)
184{
185 putc('"', file);
186 if (byte_data.empty())
187 {
188 fputs(string_data.c_str(), file);
189 }

--- 101 unchanged lines hidden (view full) ---

291 {
292 if (cell_size != 32)
293 {
294 input.parse_error("reference only permitted in 32-bit arrays");
295 valid = false;
296 return;
297 }
298 input.next_token();
289 bool isPath = false;
290 string referenced;
291 if (!input.consume('{'))
292 {
293 referenced = input.parse_node_name();
294 }
295 else
296 {
297 referenced = input.parse_to('}');
298 input.consume('}');
299 string referenced;
300 if (!input.consume('{'))
301 {
302 referenced = input.parse_node_name();
303 }
304 else
305 {
306 referenced = input.parse_to('}');
307 input.consume('}');
299 isPath = true;
300 }
301 if (referenced.empty())
302 {
303 input.parse_error("Expected node name");
304 valid = false;
305 return;
306 }
307 input.next_token();

--- 342 unchanged lines hidden (view full) ---

650 putc(',', file);
651 putc(' ', file);
652 }
653 }
654 }
655 fputs(";\n", file);
656}
657
308 }
309 if (referenced.empty())
310 {
311 input.parse_error("Expected node name");
312 valid = false;
313 return;
314 }
315 input.next_token();

--- 342 unchanged lines hidden (view full) ---

658 putc(',', file);
659 putc(' ', file);
660 }
661 }
662 }
663 fputs(";\n", file);
664}
665
666size_t
667property::offset_of_value(property_value &val)
668{
669 size_t off = 0;
670 for (auto &v : values)
671 {
672 if (&v == &val)
673 {
674 return off;
675 }
676 off += v.size();
677 }
678 return -1;
679}
680
658string
659node::parse_name(text_input_buffer &input, bool &is_property, const char *error)
660{
661 if (!valid)
662 {
663 return string();
664 }
665 input.next_token();

--- 93 unchanged lines hidden (view full) ---

759 break;
760 }
761 }
762 fprintf(stderr, "Failed to read token from structs table while parsing node.\n");
763 valid = false;
764 return;
765}
766
681string
682node::parse_name(text_input_buffer &input, bool &is_property, const char *error)
683{
684 if (!valid)
685 {
686 return string();
687 }
688 input.next_token();

--- 93 unchanged lines hidden (view full) ---

782 break;
783 }
784 }
785 fprintf(stderr, "Failed to read token from structs table while parsing node.\n");
786 valid = false;
787 return;
788}
789
790
791node::node(const string &n,
792 const std::vector<property_ptr> &p)
793 : name(n)
794{
795 props.insert(props.begin(), p.begin(), p.end());
796}
797
798node_ptr node::create_special_node(const string &name,
799 const std::vector<property_ptr> &props)
800{
801 node_ptr n(new node(name, props));
802 return n;
803}
804
767node::node(text_input_buffer &input,
768 string &&n,
769 std::unordered_set<string> &&l,
770 string &&a,
771 define_map *defines)
772 : labels(l), name(n), unit_address(a), valid(true)
773{
774 if (!input.consume('{'))

--- 343 unchanged lines hidden (view full) ---

1118 fprintf(stderr, "Label not unique: %s. References to this label will not be resolved.\n", name.c_str());
1119 }
1120 }
1121 }
1122 for (auto &c : n->child_nodes())
1123 {
1124 collect_names_recursive(c, path);
1125 }
805node::node(text_input_buffer &input,
806 string &&n,
807 std::unordered_set<string> &&l,
808 string &&a,
809 define_map *defines)
810 : labels(l), name(n), unit_address(a), valid(true)
811{
812 if (!input.consume('{'))

--- 343 unchanged lines hidden (view full) ---

1156 fprintf(stderr, "Label not unique: %s. References to this label will not be resolved.\n", name.c_str());
1157 }
1158 }
1159 }
1160 for (auto &c : n->child_nodes())
1161 {
1162 collect_names_recursive(c, path);
1163 }
1126 path.pop_back();
1127 // Now we collect the phandles and properties that reference
1128 // other nodes.
1129 for (auto &p : n->properties())
1130 {
1131 for (auto &v : *p)
1132 {
1133 if (v.is_phandle())
1134 {
1164 // Now we collect the phandles and properties that reference
1165 // other nodes.
1166 for (auto &p : n->properties())
1167 {
1168 for (auto &v : *p)
1169 {
1170 if (v.is_phandle())
1171 {
1135 phandles.push_back(&v);
1172 fixups.push_back({path, p, v});
1136 }
1137 if (v.is_cross_reference())
1138 {
1139 cross_references.push_back(&v);
1140 }
1141 }
1142 if ((p->get_key() == "phandle") ||
1143 (p->get_key() == "linux,phandle"))

--- 5 unchanged lines hidden (view full) ---

1149 }
1150 else
1151 {
1152 uint32_t phandle = p->begin()->get_as_uint32();
1153 used_phandles.insert(std::make_pair(phandle, n.get()));
1154 }
1155 }
1156 }
1173 }
1174 if (v.is_cross_reference())
1175 {
1176 cross_references.push_back(&v);
1177 }
1178 }
1179 if ((p->get_key() == "phandle") ||
1180 (p->get_key() == "linux,phandle"))

--- 5 unchanged lines hidden (view full) ---

1186 }
1187 else
1188 {
1189 uint32_t phandle = p->begin()->get_as_uint32();
1190 used_phandles.insert(std::make_pair(phandle, n.get()));
1191 }
1192 }
1193 }
1194 path.pop_back();
1157}
1158
1159void
1160device_tree::collect_names()
1161{
1162 node_path p;
1163 node_names.clear();
1164 node_paths.clear();
1165 cross_references.clear();
1195}
1196
1197void
1198device_tree::collect_names()
1199{
1200 node_path p;
1201 node_names.clear();
1202 node_paths.clear();
1203 cross_references.clear();
1166 phandles.clear();
1204 fixups.clear();
1167 collect_names_recursive(root, p);
1168}
1169
1170void
1171device_tree::resolve_cross_references()
1172{
1173 for (auto *pv : cross_references)
1174 {

--- 11 unchanged lines hidden (view full) ---

1186 {
1187 pv->byte_data.push_back('@');
1188 push_string(pv->byte_data, p->second);
1189 pv->byte_data.push_back(0);
1190 }
1191 }
1192 }
1193 }
1205 collect_names_recursive(root, p);
1206}
1207
1208void
1209device_tree::resolve_cross_references()
1210{
1211 for (auto *pv : cross_references)
1212 {

--- 11 unchanged lines hidden (view full) ---

1224 {
1225 pv->byte_data.push_back('@');
1226 push_string(pv->byte_data, p->second);
1227 pv->byte_data.push_back(0);
1228 }
1229 }
1230 }
1231 }
1194 std::unordered_set<property_value*> phandle_set;
1195 for (auto &i : phandles)
1232 std::unordered_map<property_value*, fixup&> phandle_set;
1233 for (auto &i : fixups)
1196 {
1234 {
1197 phandle_set.insert(i);
1235 phandle_set.insert({&i.val, i});
1198 }
1236 }
1199 std::vector<property_value*> sorted_phandles;
1237 std::vector<std::reference_wrapper<fixup>> sorted_phandles;
1200 root->visit([&](node &n) {
1201 for (auto &p : n.properties())
1202 {
1203 for (auto &v : *p)
1204 {
1238 root->visit([&](node &n) {
1239 for (auto &p : n.properties())
1240 {
1241 for (auto &v : *p)
1242 {
1205 if (phandle_set.count(&v))
1243 auto i = phandle_set.find(&v);
1244 if (i != phandle_set.end())
1206 {
1245 {
1207 sorted_phandles.push_back(&v);
1246 sorted_phandles.push_back(i->second);
1208 }
1209 }
1210 }
1211 });
1247 }
1248 }
1249 }
1250 });
1212 assert(sorted_phandles.size() == phandles.size());
1251 assert(sorted_phandles.size() == fixups.size());
1213
1214 uint32_t phandle = 1;
1215 for (auto &i : sorted_phandles)
1216 {
1252
1253 uint32_t phandle = 1;
1254 for (auto &i : sorted_phandles)
1255 {
1217 string target_name = i->string_data;
1256 string target_name = i.get().val.string_data;
1218 node *target = nullptr;
1219 string possible;
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] == '/')
1223 {
1257 node *target = nullptr;
1258 string possible;
1259 // If the node name is a path, then look it up by following the path,
1260 // otherwise jump directly to the named node.
1261 if (target_name[0] == '/')
1262 {
1224 std::string path;
1263 string path;
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
1231 while (!ss.eof())
1232 {

--- 38 unchanged lines hidden (view full) ---

1271 }
1272 }
1273 else
1274 {
1275 target = node_names[target_name];
1276 }
1277 if (target == nullptr)
1278 {
1264 target = root.get();
1265 std::istringstream ss(target_name);
1266 string path_element;
1267 // Read the leading /
1268 std::getline(ss, path_element, '/');
1269 // Iterate over path elements
1270 while (!ss.eof())
1271 {

--- 38 unchanged lines hidden (view full) ---

1310 }
1311 }
1312 else
1313 {
1314 target = node_names[target_name];
1315 }
1316 if (target == nullptr)
1317 {
1279 fprintf(stderr, "Failed to find node with label: %s\n", target_name.c_str());
1280 if (possible != string())
1318 if (is_plugin)
1281 {
1319 {
1282 fprintf(stderr, "Possible intended match: %s\n", possible.c_str());
1320 unresolved_fixups.push_back(i);
1321 continue;
1283 }
1322 }
1284 valid = 0;
1285 return;
1323 else
1324 {
1325 fprintf(stderr, "Failed to find node with label: %s\n", target_name.c_str());
1326 if (possible != string())
1327 {
1328 fprintf(stderr, "Possible intended match: %s\n", possible.c_str());
1329 }
1330 valid = 0;
1331 return;
1332 }
1286 }
1287 // If there is an existing phandle, use it
1288 property_ptr p = target->get_property("phandle");
1289 if (p == 0)
1290 {
1291 p = target->get_property("linux,phandle");
1292 }
1293 if (p == 0)

--- 23 unchanged lines hidden (view full) ---

1317 }
1318 if (phandle_node_name == BOTH || phandle_node_name == EPAPR)
1319 {
1320 p.reset(new property("phandle"));
1321 p->add_value(v);
1322 target->add_property(p);
1323 }
1324 }
1333 }
1334 // If there is an existing phandle, use it
1335 property_ptr p = target->get_property("phandle");
1336 if (p == 0)
1337 {
1338 p = target->get_property("linux,phandle");
1339 }
1340 if (p == 0)

--- 23 unchanged lines hidden (view full) ---

1364 }
1365 if (phandle_node_name == BOTH || phandle_node_name == EPAPR)
1366 {
1367 p.reset(new property("phandle"));
1368 p->add_value(v);
1369 target->add_property(p);
1370 }
1371 }
1325 p->begin()->push_to_buffer(i->byte_data);
1326 assert(i->byte_data.size() == 4);
1372 p->begin()->push_to_buffer(i.get().val.byte_data);
1373 assert(i.get().val.byte_data.size() == 4);
1327 }
1328}
1329
1330
1331void
1332device_tree::parse_file(text_input_buffer &input,
1333 std::vector<node_ptr> &roots,
1334 bool &read_header)
1335{
1336 input.next_token();
1337 // Read the header
1338 if (input.consume("/dts-v1/;"))
1339 {
1340 read_header = true;
1341 }
1342 input.next_token();
1374 }
1375}
1376
1377
1378void
1379device_tree::parse_file(text_input_buffer &input,
1380 std::vector<node_ptr> &roots,
1381 bool &read_header)
1382{
1383 input.next_token();
1384 // Read the header
1385 if (input.consume("/dts-v1/;"))
1386 {
1387 read_header = true;
1388 }
1389 input.next_token();
1390 if (input.consume("/plugin/;"))
1391 {
1392 is_plugin = true;
1393 }
1343 input.next_token();
1344 if (!read_header)
1345 {
1346 input.parse_error("Expected /dts-v1/; version string");
1347 }
1348 // Read any memory reservations
1349 while (input.consume("/memreserve/"))
1350 {

--- 211 unchanged lines hidden (view full) ---

1562 {
1563 fprintf(stderr, "Expected FDT_END token after parsing root node.\n");
1564 valid = false;
1565 return;
1566 }
1567 valid = (root != 0);
1568}
1569
1394 input.next_token();
1395 if (!read_header)
1396 {
1397 input.parse_error("Expected /dts-v1/; version string");
1398 }
1399 // Read any memory reservations
1400 while (input.consume("/memreserve/"))
1401 {

--- 211 unchanged lines hidden (view full) ---

1613 {
1614 fprintf(stderr, "Expected FDT_END token after parsing root node.\n");
1615 valid = false;
1616 return;
1617 }
1618 valid = (root != 0);
1619}
1620
1621string
1622device_tree::node_path::to_string() const
1623{
1624 string path;
1625 auto p = begin();
1626 auto pe = end();
1627 if ((p == pe) || (p+1 == pe))
1628 {
1629 return string("/");
1630 }
1631 // Skip the first name in the path. It's always "", and implicitly /
1632 for (++p ; p!=pe ; ++p)
1633 {
1634 path += '/';
1635 path += p->first;
1636 if (!(p->second.empty()))
1637 {
1638 path += '@';
1639 path += p->second;
1640 }
1641 }
1642 return path;
1643}
1644
1570void
1571device_tree::parse_dts(const string &fn, FILE *depfile)
1572{
1573 auto in = input_buffer::buffer_for_file(fn);
1574 if (!in)
1575 {
1576 valid = false;
1577 return;

--- 48 unchanged lines hidden (view full) ---

1626 existing->second->merge_node(std::move(node));
1627 }
1628 }
1629 }
1630 }
1631 }
1632 collect_names();
1633 resolve_cross_references();
1645void
1646device_tree::parse_dts(const string &fn, FILE *depfile)
1647{
1648 auto in = input_buffer::buffer_for_file(fn);
1649 if (!in)
1650 {
1651 valid = false;
1652 return;

--- 48 unchanged lines hidden (view full) ---

1701 existing->second->merge_node(std::move(node));
1702 }
1703 }
1704 }
1705 }
1706 }
1707 collect_names();
1708 resolve_cross_references();
1709 if (write_symbols)
1710 {
1711 std::vector<property_ptr> symbols;
1712 // Create a symbol table. Each label in this device tree may be
1713 // referenced by other plugins, so we create a __symbols__ node inside
1714 // the root that contains mappings (properties) from label names to
1715 // paths.
1716 for (auto &s : node_paths)
1717 {
1718 property_value v;
1719 v.string_data = s.second.to_string();
1720 v.type = property_value::STRING;
1721 string name = s.first;
1722 auto prop = std::make_shared<property>(std::move(name));
1723 prop->add_value(v);
1724 symbols.push_back(prop);
1725 }
1726 root->add_child(node::create_special_node("__symbols__", symbols));
1727 // If this is a plugin, then we also need to create two extra nodes.
1728 // Internal phandles will need to be renumbered to avoid conflicts with
1729 // already-loaded nodes and external references will need to be
1730 // resolved.
1731 if (is_plugin)
1732 {
1733 // Create the fixups entry. This is of the form:
1734 // {target} = {path}:{property name}:{offset}
1735 auto create_fixup_entry = [&](fixup &i, string target)
1736 {
1737 string value = i.path.to_string();
1738 value += ':';
1739 value += i.prop->get_key();
1740 value += ':';
1741 value += std::to_string(i.prop->offset_of_value(i.val));
1742 property_value v;
1743 v.string_data = value;
1744 v.type = property_value::STRING;
1745 auto prop = std::make_shared<property>(std::move(target));
1746 prop->add_value(v);
1747 return prop;
1748 };
1749 // If we have any unresolved phandle references in this plugin,
1750 // then we must update them to 0xdeadbeef and leave a property in
1751 // the /__fixups__ node whose key is the label and whose value is
1752 // as described above.
1753 if (!unresolved_fixups.empty())
1754 {
1755 symbols.clear();
1756 for (auto &i : unresolved_fixups)
1757 {
1758 auto &val = i.get().val;
1759 symbols.push_back(create_fixup_entry(i, val.string_data));
1760 val.byte_data.push_back(0xde);
1761 val.byte_data.push_back(0xad);
1762 val.byte_data.push_back(0xbe);
1763 val.byte_data.push_back(0xef);
1764 val.type = property_value::BINARY;
1765 }
1766 root->add_child(node::create_special_node("__fixups__", symbols));
1767 }
1768 symbols.clear();
1769 // If we have any resolved phandle references in this plugin, then
1770 // we must leave a property in the /__local_fixups__ node whose key
1771 // is 'fixup' and whose value is as described above.
1772 for (auto &i : fixups)
1773 {
1774 if (!i.val.is_phandle())
1775 {
1776 continue;
1777 }
1778 symbols.push_back(create_fixup_entry(i, "fixup"));
1779 }
1780 // We've iterated over all fixups, but only emit the
1781 // __local_fixups__ if we found some that were resolved internally.
1782 if (!symbols.empty())
1783 {
1784 root->add_child(node::create_special_node("__local_fixups__", symbols));
1785 }
1786 }
1787 }
1634}
1635
1636bool device_tree::parse_define(const char *def)
1637{
1638 const char *val = strchr(def, '=');
1639 if (!val)
1640 {
1641 if (strlen(def) != 0)

--- 6 unchanged lines hidden (view full) ---

1648 }
1649 string name(def, val-def);
1650 string name_copy = name;
1651 val++;
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>(),
1788}
1789
1790bool device_tree::parse_define(const char *def)
1791{
1792 const char *val = strchr(def, '=');
1793 if (!val)
1794 {
1795 if (strlen(def) != 0)

--- 6 unchanged lines hidden (view full) ---

1802 }
1803 string name(def, val-def);
1804 string name_copy = name;
1805 val++;
1806 std::unique_ptr<input_buffer> raw(new input_buffer(val, strlen(val)));
1807 text_input_buffer in(std::move(raw),
1808 std::unordered_set<string>(),
1809 std::vector<string>(),
1656 std::string(),
1810 string(),
1657 nullptr);
1658 property_ptr p = property::parse(in, std::move(name_copy), string_set(), false);
1659 if (p)
1660 defines[name] = p;
1661 return (bool)p;
1662}
1663
1664} // namespace fdt
1665
1666} // namespace dtc
1667
1811 nullptr);
1812 property_ptr p = property::parse(in, std::move(name_copy), string_set(), false);
1813 if (p)
1814 defines[name] = p;
1815 return (bool)p;
1816}
1817
1818} // namespace fdt
1819
1820} // namespace dtc
1821