mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-06 17:18:32 +00:00
dtc: Sync with upstream commit 26a0fe5
- 0206c0f ("Handle top-level /delete-node/ directives.") - d612a9e ("Remove C++11 standard constrain") - Remove extra white lines after the $FreeBSD$ tag removal Reviewed by: kevans (earlier), theraven, emaste Differential Revision: https://reviews.freebsd.org/D41482
This commit is contained in:
parent
e6dc6a2723
commit
29a55fd09b
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
Notes for people hacking on dtc
|
Notes for people hacking on dtc
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
PROG_CXX=dtc
|
PROG_CXX=dtc
|
||||||
SRCS= dtc.cc input_buffer.cc string.cc dtb.cc fdt.cc checking.cc
|
SRCS= dtc.cc input_buffer.cc string.cc dtb.cc fdt.cc checking.cc
|
||||||
MAN= dtc.1
|
MAN= dtc.1
|
||||||
|
@ -7,8 +6,6 @@ WARNS?= 3
|
||||||
|
|
||||||
CXXFLAGS+= -fno-rtti -fno-exceptions
|
CXXFLAGS+= -fno-rtti -fno-exceptions
|
||||||
|
|
||||||
CXXSTD= c++11
|
|
||||||
|
|
||||||
NO_SHARED?=NO
|
NO_SHARED?=NO
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
|
|
@ -861,7 +861,15 @@ node::node(const string &n,
|
||||||
node_ptr node::create_special_node(const string &name,
|
node_ptr node::create_special_node(const string &name,
|
||||||
const std::vector<property_ptr> &props)
|
const std::vector<property_ptr> &props)
|
||||||
{
|
{
|
||||||
node_ptr n(new node(name, props));
|
// Work around for the fact that we can't call make_shared on something
|
||||||
|
// with a private constructor. Instead create a subclass with a public
|
||||||
|
// constructor that is visible only in this function and construct that
|
||||||
|
// instead.
|
||||||
|
struct constructable_node : public node
|
||||||
|
{
|
||||||
|
constructable_node(const string &n, const std::vector<property_ptr> &p) : node(n, p) {}
|
||||||
|
};
|
||||||
|
node_ptr n{std::make_shared<constructable_node>(name, props)};
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1035,12 +1043,31 @@ node::parse(text_input_buffer &input,
|
||||||
string &&address,
|
string &&address,
|
||||||
define_map *defines)
|
define_map *defines)
|
||||||
{
|
{
|
||||||
node_ptr n(new node(input,
|
// Work around for the fact that we can't call make_shared on something
|
||||||
tree,
|
// with a private constructor. Instead create a subclass with a public
|
||||||
std::move(name),
|
// constructor that is visible only in this function and construct that
|
||||||
std::move(label),
|
// instead.
|
||||||
std::move(address),
|
struct constructable_node : public node
|
||||||
defines));
|
{
|
||||||
|
constructable_node(text_input_buffer &input,
|
||||||
|
device_tree &tree,
|
||||||
|
std::string &&n,
|
||||||
|
std::unordered_set<std::string> &&l,
|
||||||
|
std::string &&a,
|
||||||
|
define_map*m) : node(input,
|
||||||
|
tree,
|
||||||
|
std::move(n),
|
||||||
|
std::move(l),
|
||||||
|
std::move(a),
|
||||||
|
m)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
node_ptr n{std::make_shared<constructable_node>(input,
|
||||||
|
tree,
|
||||||
|
std::move(name),
|
||||||
|
std::move(label),
|
||||||
|
std::move(address),
|
||||||
|
defines)};
|
||||||
if (!n->valid)
|
if (!n->valid)
|
||||||
{
|
{
|
||||||
n = 0;
|
n = 0;
|
||||||
|
@ -1208,7 +1235,7 @@ node::write_dts(FILE *file, int indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
device_tree::collect_names_recursive(node_ptr &n, node_path &path)
|
device_tree::collect_names_recursive(node_ptr parent, node_ptr n, node_path &path)
|
||||||
{
|
{
|
||||||
path.push_back(std::make_pair(n->name, n->unit_address));
|
path.push_back(std::make_pair(n->name, n->unit_address));
|
||||||
for (const string &name : n->labels)
|
for (const string &name : n->labels)
|
||||||
|
@ -1218,9 +1245,13 @@ device_tree::collect_names_recursive(node_ptr &n, node_path &path)
|
||||||
auto iter = node_names.find(name);
|
auto iter = node_names.find(name);
|
||||||
if (iter == node_names.end())
|
if (iter == node_names.end())
|
||||||
{
|
{
|
||||||
node_names.insert(std::make_pair(name, n.get()));
|
node_names.insert(std::make_pair(name, n));
|
||||||
node_paths.insert(std::make_pair(name, path));
|
node_paths.insert(std::make_pair(name, path));
|
||||||
ordered_node_paths.push_back({name, path});
|
ordered_node_paths.push_back({name, path});
|
||||||
|
if (parent)
|
||||||
|
{
|
||||||
|
node_name_parents.insert({name, parent});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1236,7 +1267,7 @@ device_tree::collect_names_recursive(node_ptr &n, node_path &path)
|
||||||
}
|
}
|
||||||
for (auto &c : n->child_nodes())
|
for (auto &c : n->child_nodes())
|
||||||
{
|
{
|
||||||
collect_names_recursive(c, path);
|
collect_names_recursive(n, c, path);
|
||||||
}
|
}
|
||||||
// Now we collect the phandles and properties that reference
|
// Now we collect the phandles and properties that reference
|
||||||
// other nodes.
|
// other nodes.
|
||||||
|
@ -1264,7 +1295,7 @@ device_tree::collect_names_recursive(node_ptr &n, node_path &path)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint32_t phandle = p->begin()->get_as_uint32();
|
uint32_t phandle = p->begin()->get_as_uint32();
|
||||||
used_phandles.insert(std::make_pair(phandle, n.get()));
|
used_phandles.insert(std::make_pair(phandle, n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1280,11 +1311,11 @@ device_tree::collect_names()
|
||||||
ordered_node_paths.clear();
|
ordered_node_paths.clear();
|
||||||
cross_references.clear();
|
cross_references.clear();
|
||||||
fixups.clear();
|
fixups.clear();
|
||||||
collect_names_recursive(root, p);
|
collect_names_recursive(nullptr, root, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
property_ptr
|
property_ptr
|
||||||
device_tree::assign_phandle(node *n, uint32_t &phandle)
|
device_tree::assign_phandle(node_ptr n, uint32_t &phandle)
|
||||||
{
|
{
|
||||||
// If there is an existing phandle, use it
|
// If there is an existing phandle, use it
|
||||||
property_ptr p = n->get_property("phandle");
|
property_ptr p = n->get_property("phandle");
|
||||||
|
@ -1329,11 +1360,11 @@ device_tree::assign_phandle(node *n, uint32_t &phandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
device_tree::assign_phandles(node_ptr &n, uint32_t &next)
|
device_tree::assign_phandles(node_ptr n, uint32_t &next)
|
||||||
{
|
{
|
||||||
if (!n->labels.empty())
|
if (!n->labels.empty())
|
||||||
{
|
{
|
||||||
assign_phandle(n.get(), next);
|
assign_phandle(n, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &c : n->child_nodes())
|
for (auto &c : n->child_nodes())
|
||||||
|
@ -1391,14 +1422,14 @@ device_tree::resolve_cross_references(uint32_t &phandle)
|
||||||
for (auto &i : sorted_phandles)
|
for (auto &i : sorted_phandles)
|
||||||
{
|
{
|
||||||
string target_name = i.get().val.string_data;
|
string target_name = i.get().val.string_data;
|
||||||
node *target = nullptr;
|
node_ptr target;
|
||||||
string possible;
|
string possible;
|
||||||
// If the node name is a path, then look it up by following the path,
|
// If the node name is a path, then look it up by following the path,
|
||||||
// otherwise jump directly to the named node.
|
// otherwise jump directly to the named node.
|
||||||
if (target_name[0] == '/')
|
if (target_name[0] == '/')
|
||||||
{
|
{
|
||||||
string path;
|
string path;
|
||||||
target = root.get();
|
target = root;
|
||||||
std::istringstream ss(target_name);
|
std::istringstream ss(target_name);
|
||||||
string path_element;
|
string path_element;
|
||||||
// Read the leading /
|
// Read the leading /
|
||||||
|
@ -1412,14 +1443,14 @@ device_tree::resolve_cross_references(uint32_t &phandle)
|
||||||
string node_name, node_address;
|
string node_name, node_address;
|
||||||
std::getline(nss, node_name, '@');
|
std::getline(nss, node_name, '@');
|
||||||
std::getline(nss, node_address, '@');
|
std::getline(nss, node_address, '@');
|
||||||
node *next = nullptr;
|
node_ptr next;
|
||||||
for (auto &c : target->child_nodes())
|
for (auto &c : target->child_nodes())
|
||||||
{
|
{
|
||||||
if (c->name == node_name)
|
if (c->name == node_name)
|
||||||
{
|
{
|
||||||
if (c->unit_address == node_address)
|
if (c->unit_address == node_address)
|
||||||
{
|
{
|
||||||
next = c.get();
|
next = c;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1478,8 +1509,8 @@ device_tree::resolve_cross_references(uint32_t &phandle)
|
||||||
bool
|
bool
|
||||||
device_tree::garbage_collect_marked_nodes()
|
device_tree::garbage_collect_marked_nodes()
|
||||||
{
|
{
|
||||||
std::unordered_set<node*> previously_referenced_nodes;
|
std::unordered_set<node_ptr> previously_referenced_nodes;
|
||||||
std::unordered_set<node*> newly_referenced_nodes;
|
std::unordered_set<node_ptr> newly_referenced_nodes;
|
||||||
|
|
||||||
auto mark_referenced_nodes_used = [&](node &n)
|
auto mark_referenced_nodes_used = [&](node &n)
|
||||||
{
|
{
|
||||||
|
@ -1489,7 +1520,7 @@ device_tree::garbage_collect_marked_nodes()
|
||||||
{
|
{
|
||||||
if (v.is_phandle())
|
if (v.is_phandle())
|
||||||
{
|
{
|
||||||
node *nx = node_names[v.string_data];
|
node_ptr nx = node_names[v.string_data];
|
||||||
if (nx == nullptr)
|
if (nx == nullptr)
|
||||||
{
|
{
|
||||||
// Try it again, but as a path
|
// Try it again, but as a path
|
||||||
|
@ -1534,8 +1565,9 @@ device_tree::garbage_collect_marked_nodes()
|
||||||
|
|
||||||
while (!newly_referenced_nodes.empty())
|
while (!newly_referenced_nodes.empty())
|
||||||
{
|
{
|
||||||
previously_referenced_nodes = std::move(newly_referenced_nodes);
|
previously_referenced_nodes = newly_referenced_nodes;
|
||||||
for (auto *n : previously_referenced_nodes)
|
newly_referenced_nodes.clear();
|
||||||
|
for (auto &n : previously_referenced_nodes)
|
||||||
{
|
{
|
||||||
mark_referenced_nodes_used(*n);
|
mark_referenced_nodes_used(*n);
|
||||||
}
|
}
|
||||||
|
@ -1617,7 +1649,38 @@ device_tree::parse_file(text_input_buffer &input,
|
||||||
while (valid && !input.finished())
|
while (valid && !input.finished())
|
||||||
{
|
{
|
||||||
node_ptr n;
|
node_ptr n;
|
||||||
if (input.consume('/'))
|
if (input.consume("/delete-node/"))
|
||||||
|
{
|
||||||
|
// Top-level /delete-node/ directives refer to references that must
|
||||||
|
// be deleted later.
|
||||||
|
input.next_token();
|
||||||
|
auto expect = [&](auto token, const char *msg)
|
||||||
|
{
|
||||||
|
if (!input.consume(token))
|
||||||
|
{
|
||||||
|
input.parse_error(msg);
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
input.next_token();
|
||||||
|
return valid;
|
||||||
|
};
|
||||||
|
if (expect('&', "Expected reference after top-level /delete-node/."))
|
||||||
|
{
|
||||||
|
string ref = input.parse_node_name();
|
||||||
|
if (ref == string())
|
||||||
|
{
|
||||||
|
input.parse_error("Expected label name for top-level /delete-node/.");
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deletions.push_back(std::move(ref));
|
||||||
|
}
|
||||||
|
expect(';', "Missing semicolon.");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (input.consume('/'))
|
||||||
{
|
{
|
||||||
input.next_token();
|
input.next_token();
|
||||||
n = node::parse(input, *this, string(), string_set(), string(), &defines);
|
n = node::parse(input, *this, string(), string_set(), string(), &defines);
|
||||||
|
@ -1732,7 +1795,7 @@ device_tree::write(int fd)
|
||||||
strings_writer.write_to_file(fd);
|
strings_writer.write_to_file(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
node*
|
node_ptr
|
||||||
device_tree::referenced_node(property_value &v)
|
device_tree::referenced_node(property_value &v)
|
||||||
{
|
{
|
||||||
if (v.is_phandle())
|
if (v.is_phandle())
|
||||||
|
@ -2032,6 +2095,19 @@ device_tree::parse_dts(const string &fn, FILE *depfile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
collect_names();
|
collect_names();
|
||||||
|
for (auto &ref : deletions)
|
||||||
|
{
|
||||||
|
auto parent = node_name_parents[ref];
|
||||||
|
auto node = node_names[ref];
|
||||||
|
if (!parent)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Top-level /delete-node/ directive refers to label %s, which is not found.\n", ref.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent->delete_children_if([&](node_ptr &child) { return child == node; });
|
||||||
|
}
|
||||||
|
}
|
||||||
// Return value indicates whether we've dirtied the tree or not and need to
|
// Return value indicates whether we've dirtied the tree or not and need to
|
||||||
// recollect names
|
// recollect names
|
||||||
if (garbage_collect && garbage_collect_marked_nodes())
|
if (garbage_collect && garbage_collect_marked_nodes())
|
||||||
|
@ -2127,7 +2203,7 @@ device_tree::parse_dts(const string &fn, FILE *depfile)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
node *n = local_fixups.get();
|
node_ptr n = local_fixups;
|
||||||
for (auto &p : i.path)
|
for (auto &p : i.path)
|
||||||
{
|
{
|
||||||
// Skip the implicit root
|
// Skip the implicit root
|
||||||
|
@ -2142,7 +2218,7 @@ device_tree::parse_dts(const string &fn, FILE *depfile)
|
||||||
{
|
{
|
||||||
if (c->unit_address == p.second)
|
if (c->unit_address == p.second)
|
||||||
{
|
{
|
||||||
n = c.get();
|
n = c;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2157,7 +2233,7 @@ device_tree::parse_dts(const string &fn, FILE *depfile)
|
||||||
path += p.second;
|
path += p.second;
|
||||||
}
|
}
|
||||||
n->add_child(node::create_special_node(path, symbols));
|
n->add_child(node::create_special_node(path, symbols));
|
||||||
n = (--n->child_end())->get();
|
n = *(--(n->child_end()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(n);
|
assert(n);
|
||||||
|
|
|
@ -71,7 +71,7 @@ typedef std::shared_ptr<property> property_ptr;
|
||||||
/**
|
/**
|
||||||
* Owning pointer to a node.
|
* Owning pointer to a node.
|
||||||
*/
|
*/
|
||||||
typedef std::unique_ptr<node> node_ptr;
|
typedef std::shared_ptr<node> node_ptr;
|
||||||
/**
|
/**
|
||||||
* Map from macros to property pointers.
|
* Map from macros to property pointers.
|
||||||
*/
|
*/
|
||||||
|
@ -663,7 +663,7 @@ class node
|
||||||
/**
|
/**
|
||||||
* Deletes any children from this node.
|
* Deletes any children from this node.
|
||||||
*/
|
*/
|
||||||
inline void delete_children_if(bool (*predicate)(node_ptr &))
|
inline void delete_children_if(std::function<bool(node_ptr &)> predicate)
|
||||||
{
|
{
|
||||||
children.erase(std::remove_if(children.begin(), children.end(), predicate), children.end());
|
children.erase(std::remove_if(children.begin(), children.end(), predicate), children.end());
|
||||||
}
|
}
|
||||||
|
@ -761,7 +761,11 @@ class device_tree
|
||||||
* Mapping from names to nodes. Only unambiguous names are recorded,
|
* Mapping from names to nodes. Only unambiguous names are recorded,
|
||||||
* duplicate names are stored as (node*)-1.
|
* duplicate names are stored as (node*)-1.
|
||||||
*/
|
*/
|
||||||
std::unordered_map<std::string, node*> node_names;
|
std::unordered_map<std::string, node_ptr> node_names;
|
||||||
|
/**
|
||||||
|
* Mapping from names to the nodes that contain them.
|
||||||
|
*/
|
||||||
|
std::unordered_map<std::string, node_ptr> node_name_parents;
|
||||||
/**
|
/**
|
||||||
* A map from labels to node paths. When resolving cross references,
|
* A map from labels to node paths. When resolving cross references,
|
||||||
* we look up referenced nodes in this and replace the cross reference
|
* we look up referenced nodes in this and replace the cross reference
|
||||||
|
@ -779,6 +783,10 @@ class device_tree
|
||||||
* These should be expanded to the full path of their targets.
|
* These should be expanded to the full path of their targets.
|
||||||
*/
|
*/
|
||||||
std::vector<property_value*> cross_references;
|
std::vector<property_value*> cross_references;
|
||||||
|
/**
|
||||||
|
* Labels collected from top-level /delete-node/ directives.
|
||||||
|
*/
|
||||||
|
std::vector<std::string> deletions;
|
||||||
/**
|
/**
|
||||||
* The location of something requiring a fixup entry.
|
* The location of something requiring a fixup entry.
|
||||||
*/
|
*/
|
||||||
|
@ -827,7 +835,7 @@ class device_tree
|
||||||
* find phandles that were provided by the user explicitly when we are
|
* find phandles that were provided by the user explicitly when we are
|
||||||
* doing checking.
|
* doing checking.
|
||||||
*/
|
*/
|
||||||
std::unordered_map<uint32_t, node*> used_phandles;
|
std::unordered_map<uint32_t, node_ptr> used_phandles;
|
||||||
/**
|
/**
|
||||||
* Paths to search for include files. This contains a set of
|
* Paths to search for include files. This contains a set of
|
||||||
* nul-terminated strings, which are not owned by this class and so
|
* nul-terminated strings, which are not owned by this class and so
|
||||||
|
@ -864,19 +872,19 @@ class device_tree
|
||||||
* used in resolving cross references. Also collects phandle
|
* used in resolving cross references. Also collects phandle
|
||||||
* properties that have been explicitly added.
|
* properties that have been explicitly added.
|
||||||
*/
|
*/
|
||||||
void collect_names_recursive(node_ptr &n, node_path &path);
|
void collect_names_recursive(node_ptr parent, node_ptr n, node_path &path);
|
||||||
/**
|
/**
|
||||||
* Assign a phandle property to a single node. The next parameter
|
* Assign a phandle property to a single node. The next parameter
|
||||||
* holds the phandle to be assigned, and will be incremented upon
|
* holds the phandle to be assigned, and will be incremented upon
|
||||||
* assignment.
|
* assignment.
|
||||||
*/
|
*/
|
||||||
property_ptr assign_phandle(node *n, uint32_t &next);
|
property_ptr assign_phandle(node_ptr n, uint32_t &next);
|
||||||
/**
|
/**
|
||||||
* Assign phandle properties to all nodes that have been referenced and
|
* Assign phandle properties to all nodes that have been referenced and
|
||||||
* require one. This method will recursively visit the tree starting at
|
* require one. This method will recursively visit the tree starting at
|
||||||
* the node that it is passed.
|
* the node that it is passed.
|
||||||
*/
|
*/
|
||||||
void assign_phandles(node_ptr &n, uint32_t &next);
|
void assign_phandles(node_ptr n, uint32_t &next);
|
||||||
/**
|
/**
|
||||||
* Calls the recursive version of this method on every root node.
|
* Calls the recursive version of this method on every root node.
|
||||||
*/
|
*/
|
||||||
|
@ -925,7 +933,7 @@ class device_tree
|
||||||
* is in source form, then we have a string that we can use to index
|
* is in source form, then we have a string that we can use to index
|
||||||
* the cross_references array and so we can just look that up.
|
* the cross_references array and so we can just look that up.
|
||||||
*/
|
*/
|
||||||
node *referenced_node(property_value &v);
|
node_ptr referenced_node(property_value &v);
|
||||||
/**
|
/**
|
||||||
* Writes this FDT as a DTB to the specified output.
|
* Writes this FDT as a DTB to the specified output.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue