summaryrefslogtreecommitdiffstats
path: root/usr.bin/dtc/fdt.cc
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/dtc/fdt.cc')
-rw-r--r--usr.bin/dtc/fdt.cc258
1 files changed, 143 insertions, 115 deletions
diff --git a/usr.bin/dtc/fdt.cc b/usr.bin/dtc/fdt.cc
index 3908e0e..23476ae 100644
--- a/usr.bin/dtc/fdt.cc
+++ b/usr.bin/dtc/fdt.cc
@@ -264,24 +264,6 @@ property::parse_string(input_buffer &input)
void
property::parse_cells(input_buffer &input, int cell_size)
{
- unsigned long long cell_max;
- switch (cell_size)
- {
- case 8:
- cell_max = UINT8_MAX;
- break;
- case 16:
- cell_max = UINT16_MAX;
- break;
- case 32:
- cell_max = UINT32_MAX;
- break;
- case 64:
- cell_max = UINT64_MAX;
- break;
- default:
- assert(0 && "Invalid cell size!");
- }
assert(input[0] == '<');
++input;
property_value v;
@@ -327,19 +309,12 @@ property::parse_cells(input_buffer &input, int cell_size)
//FIXME: We should support labels in the middle
//of these, but we don't.
unsigned long long val;
- if (!input.consume_integer(val))
+ if (!input.consume_integer_expression(val))
{
input.parse_error("Expected numbers in array of cells");
valid = false;
return;
}
- if (val > cell_max)
- {
- fprintf(stderr, "%lld > %lld\n", val, cell_max);
- input.parse_error("Value out of range");
- valid = false;
- return;
- }
switch (cell_size)
{
case 8:
@@ -685,6 +660,16 @@ node::parse_name(input_buffer &input, bool &is_property, const char *error)
return n;
}
+void
+node::visit(std::function<void(node&)> fn)
+{
+ fn(*this);
+ for (auto &&c : children)
+ {
+ c->visit(fn);
+ }
+}
+
node::node(input_buffer &structs, input_buffer &strings) : valid(true)
{
const char *name_start = (const char*)structs;
@@ -742,7 +727,7 @@ node::node(input_buffer &structs, input_buffer &strings) : valid(true)
valid = false;
return;
}
- properties.push_back(prop);
+ props.push_back(prop);
break;
}
break;
@@ -806,7 +791,7 @@ node::node(input_buffer &input, string n, string l, string a, define_map *define
}
else
{
- properties.push_back(p);
+ props.push_back(p);
}
}
else if (!is_property && input[0] == ('{'))
@@ -824,7 +809,7 @@ node::node(input_buffer &input, string n, string l, string a, define_map *define
}
else if (input.consume(';'))
{
- properties.push_back(property_ptr(new property(child_name, child_label)));
+ props.push_back(property_ptr(new property(child_name, child_label)));
}
else
{
@@ -857,9 +842,9 @@ node::sort()
{
std::sort(property_begin(), property_end(), cmp_properties);
std::sort(child_begin(), child_end(), cmp_children);
- for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i)
+ for (auto &c : child_nodes())
{
- (*i)->sort();
+ c->sort();
}
}
@@ -892,7 +877,7 @@ node::parse_dtb(input_buffer &structs, input_buffer &strings)
property_ptr
node::get_property(string key)
{
- for (auto &i : properties)
+ for (auto &i : props)
{
if (i->get_key() == key)
{
@@ -914,14 +899,14 @@ node::merge_node(node_ptr other)
// large numbers of properties, but for typical usage the
// entire vector will fit (easily) into cache, so iterating
// over it repeatedly isn't that expensive.
- for (auto &p : other->properties)
+ for (auto &p : other->properties())
{
bool found = false;
- for (auto i=property_begin(), e=property_end() ; i!=e ; ++i)
+ for (auto &mp : properties())
{
- if ((*i)->get_key() == p->get_key())
+ if (mp->get_key() == p->get_key())
{
- *i = p;
+ mp = p;
found = true;
break;
}
@@ -964,13 +949,13 @@ node::write(dtb::output_writer &writer, dtb::string_table &strings)
writer.write_comment(name);
writer.write_data(name_buffer);
writer.write_data((uint8_t)0);
- for (auto i=property_begin(), e=property_end() ; i!=e ; ++i)
+ for (auto p : properties())
{
- (*i)->write(writer, strings);
+ p->write(writer, strings);
}
- for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i)
+ for (auto &c : child_nodes())
{
- (*i)->write(writer, strings);
+ c->write(writer, strings);
}
writer.write_token(dtb::FDT_END_NODE);
}
@@ -999,13 +984,13 @@ node::write_dts(FILE *file, int indent)
unit_address.print(file);
}
fputs(" {\n\n", file);
- for (auto i=property_begin(), e=property_end() ; i!=e ; ++i)
+ for (auto p : properties())
{
- (*i)->write_dts(file, indent+1);
+ p->write_dts(file, indent+1);
}
- for (child_iterator i=child_begin(), e=child_end() ; i!=e ; ++i)
+ for (auto &c : child_nodes())
{
- (*i)->write_dts(file, indent+1);
+ c->write_dts(file, indent+1);
}
for (int i=0 ; i<indent ; i++)
{
@@ -1039,30 +1024,30 @@ device_tree::collect_names_recursive(node_ptr &n, node_path &path)
fprintf(stderr, ". References to this label will not be resolved.");
}
}
- for (node::child_iterator i=n->child_begin(), e=n->child_end() ; i!=e ; ++i)
+ for (auto &c : n->child_nodes())
{
- collect_names_recursive(*i, path);
+ collect_names_recursive(c, path);
}
path.pop_back();
// Now we collect the phandles and properties that reference
// other nodes.
- for (auto i=n->property_begin(), e=n->property_end() ; i!=e ; ++i)
+ for (auto &p : n->properties())
{
- for (property::value_iterator p=(*i)->begin(),pe=(*i)->end() ; p!=pe ; ++p)
+ for (auto &v : *p)
{
- if (p->is_phandle())
+ if (v.is_phandle())
{
- phandles.push_back(&*p);
+ phandles.push_back(&v);
}
- if (p->is_cross_reference())
+ if (v.is_cross_reference())
{
- cross_references.push_back(&*p);
+ cross_references.push_back(&v);
}
}
- if ((*i)->get_key() == string("phandle") ||
- (*i)->get_key() == string("linux,phandle"))
+ if (p->get_key() == string("phandle") ||
+ p->get_key() == string("linux,phandle"))
{
- if ((*i)->begin()->byte_data.size() != 4)
+ if (p->begin()->byte_data.size() != 4)
{
fprintf(stderr, "Invalid phandle value for node ");
n->name.dump();
@@ -1071,7 +1056,7 @@ device_tree::collect_names_recursive(node_ptr &n, node_path &path)
}
else
{
- uint32_t phandle = (*i)->begin()->get_as_uint32();
+ uint32_t phandle = p->begin()->get_as_uint32();
used_phandles.insert(std::make_pair(phandle, n.get()));
}
}
@@ -1104,12 +1089,33 @@ device_tree::resolve_cross_references()
{
pv->byte_data.push_back('@');
p->second.push_to_buffer(pv->byte_data);
+ pv->byte_data.push_back(0);
}
}
}
- uint32_t phandle = 1;
+ std::unordered_set<property_value*> phandle_set;
for (auto &i : phandles)
{
+ phandle_set.insert(i);
+ }
+ std::vector<property_value*> sorted_phandles;
+ root->visit([&](node &n) {
+ for (auto &p : n.properties())
+ {
+ for (auto &v : *p)
+ {
+ if (phandle_set.count(&v))
+ {
+ sorted_phandles.push_back(&v);
+ }
+ }
+ }
+ });
+ assert(sorted_phandles.size() == phandles.size());
+
+ uint32_t phandle = 1;
+ for (auto &i : sorted_phandles)
+ {
string target_name = i->string_data;
node *target = node_names[target_name];
if (target == 0)
@@ -1163,94 +1169,111 @@ device_tree::resolve_cross_references()
}
}
-void
-device_tree::parse_file(input_buffer &input,
+bool
+device_tree::parse_include(input_buffer &input,
const std::string &dir,
std::vector<node_ptr> &roots,
FILE *depfile,
bool &read_header)
{
- input.next_token();
- // Read the header
- if (input.consume("/dts-v1/;"))
+ if (!input.consume("/include/"))
{
- read_header = true;
+ return false;
}
- input.next_token();
- while(input.consume("/include/"))
+ bool reallyInclude = true;
+ if (input.consume("if "))
{
- bool reallyInclude = true;
- if (input.consume("if "))
- {
- input.next_token();
- string name = string::parse_property_name(input);
- // XXX: Error handling
- if (defines.find(name) == defines.end())
- {
- reallyInclude = false;
- }
- input.consume('/');
- }
input.next_token();
- if (!input.consume('"'))
+ string name = string::parse_property_name(input);
+ // XXX: Error handling
+ if (defines.find(name) == defines.end())
{
- input.parse_error("Expected quoted filename");
- valid = false;
- return;
+ reallyInclude = false;
}
- int length = 0;
- while (input[length] != '"') length++;
+ input.consume('/');
+ }
+ input.next_token();
+ if (!input.consume('"'))
+ {
+ input.parse_error("Expected quoted filename");
+ valid = false;
+ return false;
+ }
+ int length = 0;
+ while (input[length] != '"') length++;
- std::string file((const char*)input, length);
- std::string include_file = dir + '/' + file;
- assert(input.consume(file.c_str()));
+ std::string file((const char*)input, length);
+ std::string include_file = dir + '/' + file;
+ input.consume(file.c_str());
+ if (!reallyInclude)
+ {
input.consume('"');
input.next_token();
- if (!reallyInclude)
- {
- continue;
- }
+ return true;
+ }
- input_buffer *include_buffer = buffer_for_file(include_file.c_str());
+ input_buffer *include_buffer = buffer_for_file(include_file.c_str(), false);
- if (include_buffer == 0)
+ if (include_buffer == 0)
+ {
+ for (auto i : include_paths)
{
- for (auto i : include_paths)
+ include_file = i + '/' + file;
+ include_buffer = buffer_for_file(include_file.c_str());
+ if (include_buffer != 0)
{
- include_file = i + '/' + file;
- include_buffer = buffer_for_file(include_file.c_str());
- if (include_buffer != 0)
- {
- break;
- }
+ break;
}
}
- if (depfile != 0)
- {
- putc(' ', depfile);
- fputs(include_file.c_str(), depfile);
- }
- if (include_buffer == 0)
- {
- valid = false;
- return;
- }
- parse_file(*include_buffer, dir, roots, depfile, read_header);
}
+ if (depfile != 0)
+ {
+ putc(' ', depfile);
+ fputs(include_file.c_str(), depfile);
+ }
+ if (include_buffer == 0)
+ {
+ input.parse_error("Unable to locate input file");
+ input.consume('"');
+ input.next_token();
+ valid = false;
+ return true;
+ }
+ input.consume('"');
+ input.next_token();
+ parse_file(*include_buffer, dir, roots, depfile, read_header);
+ return true;
+}
+
+void
+device_tree::parse_file(input_buffer &input,
+ const std::string &dir,
+ std::vector<node_ptr> &roots,
+ FILE *depfile,
+ bool &read_header)
+{
+ input.next_token();
+ // Read the header
+ if (input.consume("/dts-v1/;"))
+ {
+ read_header = true;
+ }
+ input.next_token();
input.next_token();
if (!read_header)
{
input.parse_error("Expected /dts-v1/; version string");
}
+ while(parse_include(input, dir, roots, depfile, read_header)) {}
// Read any memory reservations
while(input.consume("/memreserve/"))
{
unsigned long long start, len;
input.next_token();
// Read the start and length.
- if (!(input.consume_integer(start) &&
+ if (!(input.consume_integer_expression(start) &&
(input.next_token(),
- input.consume_integer(len))))
+ input.consume_integer_expression(len))))
{
input.parse_error("Expected size on /memreserve/ node.");
}
@@ -1259,6 +1282,7 @@ device_tree::parse_file(input_buffer &input,
reservations.push_back(reservation(start, len));
}
input.next_token();
+ while(parse_include(input, dir, roots, depfile, read_header)) {}
while (valid && !input.finished())
{
node_ptr n;
@@ -1287,11 +1311,12 @@ device_tree::parse_file(input_buffer &input,
valid = false;
}
input.next_token();
+ while(parse_include(input, dir, roots, depfile, read_header)) {}
}
}
input_buffer*
-device_tree::buffer_for_file(const char *path)
+device_tree::buffer_for_file(const char *path, bool warn)
{
if (string(path) == string("-"))
{
@@ -1306,7 +1331,10 @@ device_tree::buffer_for_file(const char *path)
int source = open(path, O_RDONLY);
if (source == -1)
{
- fprintf(stderr, "Unable to open file '%s'. %s\n", path, strerror(errno));
+ if (warn)
+ {
+ fprintf(stderr, "Unable to open file '%s'. %s\n", path, strerror(errno));
+ }
return 0;
}
struct stat st;
@@ -1447,7 +1475,7 @@ device_tree::write_dts(int fd)
}
void
-device_tree::parse_dtb(const char *fn, FILE *depfile)
+device_tree::parse_dtb(const char *fn, FILE *)
{
input_buffer *in = buffer_for_file(fn);
if (in == 0)
OpenPOWER on IntegriCloud