svn commit: r345880 - stable/12/usr.bin/dtc
Rodney W. Grimes
freebsd at gndrsh.dnsmgr.net
Thu Apr 4 17:36:17 UTC 2019
> Author: kevans
> Date: Thu Apr 4 17:26:35 2019
> New Revision: 345880
> URL: https://svnweb.freebsd.org/changeset/base/345880
>
> Log:
> dtc(1): Update to 1a79f5f26631
Is there someway to update the quality of this pointer?
When googled it tends to loop back to FreeBSD.org stuff.
Thanks,
Rod
> Highlights:
> - Bugfix for order in which /delete-node/ and /delete-property/ are
> processed [0]
> - /omit-if-no-ref/ support has been added (used only by U-Boot at this
> point, in theory)
> - GPL dtc compat version bumped to 1.4.7
> - Various small fixes and compatibility improvements
>
> Modified:
> stable/12/usr.bin/dtc/dtb.cc
> stable/12/usr.bin/dtc/dtb.hh
> stable/12/usr.bin/dtc/dtc.1
> stable/12/usr.bin/dtc/dtc.cc
> stable/12/usr.bin/dtc/fdt.cc
> stable/12/usr.bin/dtc/fdt.hh
> stable/12/usr.bin/dtc/input_buffer.cc
> stable/12/usr.bin/dtc/util.hh
> Directory Properties:
> stable/12/ (props changed)
>
> Modified: stable/12/usr.bin/dtc/dtb.cc
> ==============================================================================
> --- stable/12/usr.bin/dtc/dtb.cc Thu Apr 4 17:24:57 2019 (r345879)
> +++ stable/12/usr.bin/dtc/dtb.cc Thu Apr 4 17:26:35 2019 (r345880)
> @@ -37,9 +37,33 @@
> #include <inttypes.h>
> #include <stdio.h>
> #include <unistd.h>
> +#include <errno.h>
>
> using std::string;
>
> +namespace {
> +
> +void write(dtc::byte_buffer &buffer, int fd)
> +{
> + size_t size = buffer.size();
> + uint8_t *data = buffer.data();
> + while (size > 0)
> + {
> + ssize_t r = ::write(fd, data, size);
> + if (r >= 0)
> + {
> + data += r;
> + size -= r;
> + }
> + else if (errno != EAGAIN)
> + {
> + fprintf(stderr, "Writing to file failed\n");
> + exit(-1);
> + }
> + }
> +}
> +}
> +
> namespace dtc
> {
> namespace dtb
> @@ -90,8 +114,7 @@ binary_writer::write_data(uint64_t v)
> void
> binary_writer::write_to_file(int fd)
> {
> - // FIXME: Check return
> - write(fd, buffer.data(), buffer.size());
> + write(buffer, fd);
> }
>
> uint32_t
> @@ -222,8 +245,7 @@ asm_writer::write_data(uint64_t v)
> void
> asm_writer::write_to_file(int fd)
> {
> - // FIXME: Check return
> - write(fd, buffer.data(), buffer.size());
> + write(buffer, fd);
> }
>
> uint32_t
>
> Modified: stable/12/usr.bin/dtc/dtb.hh
> ==============================================================================
> --- stable/12/usr.bin/dtc/dtb.hh Thu Apr 4 17:24:57 2019 (r345879)
> +++ stable/12/usr.bin/dtc/dtb.hh Thu Apr 4 17:26:35 2019 (r345880)
> @@ -109,6 +109,8 @@ inline const char *token_type_name(token_type t)
> return "FDT_END";
> }
> assert(0);
> + // Not reached.
> + return nullptr;
> }
>
> /**
>
> Modified: stable/12/usr.bin/dtc/dtc.1
> ==============================================================================
> --- stable/12/usr.bin/dtc/dtc.1 Thu Apr 4 17:24:57 2019 (r345879)
> +++ stable/12/usr.bin/dtc/dtc.1 Thu Apr 4 17:26:35 2019 (r345880)
> @@ -30,7 +30,7 @@
> .\"
> .\" $FreeBSD$
> .\"/
> -.Dd April 7, 2018
> +.Dd March 27, 2019
> .Dt DTC 1
> .Os
> .Sh NAME
> @@ -304,7 +304,18 @@ Overlay blobs can be applied at boot time by setting
> in
> .Xr loader.conf 5 .
> Multiple overlays may be specified, and they will be applied in the order given.
> -.El
> +.Sh NODE OMISSION
> +This utility supports the
> +.Va /omit-if-no-ref/
> +statement to mark nodes for omission if they are ultimately not referenced
> +elsewhere in the device tree.
> +This may be used in more space-constrained environments to remove nodes that may
> +not be applicable to the specific device the tree is being compiled for.
> +.Pp
> +When the
> +.Fl @
> +flag is used to write symbols, nodes with labels will be considered referenced
> +and will not be removed from the tree.
> .Sh EXAMPLES
> The command:
> .Pp
> @@ -403,7 +414,11 @@ A dtc tool first appeared in
> This version of the tool first appeared in
> .Fx 10.0 .
> .Sh AUTHORS
> -.An David T. Chisnall
> +.Nm
> +was written by
> +.An David T. Chisnall .
> +Some features were added later by
> +.An Kyle Evans .
> .Pp
> Note: The fact that the tool and the author share the same initials is entirely
> coincidental.
>
> Modified: stable/12/usr.bin/dtc/dtc.cc
> ==============================================================================
> --- stable/12/usr.bin/dtc/dtc.cc Thu Apr 4 17:24:57 2019 (r345879)
> +++ stable/12/usr.bin/dtc/dtc.cc Thu Apr 4 17:26:35 2019 (r345880)
> @@ -38,6 +38,7 @@
> #include <limits.h>
> #include <stdio.h>
> #include <stdlib.h>
> +#include <string.h>
> #include <time.h>
> #include <unistd.h>
>
> @@ -65,7 +66,7 @@ int version_minor_compatible = 4;
> * The current patch level of the tool.
> */
> int version_patch = 0;
> -int version_patch_compatible = 0;
> +int version_patch_compatible = 7;
>
> void usage(const string &argv0)
> {
> @@ -105,7 +106,7 @@ main(int argc, char **argv)
> bool debug_mode = false;
> auto write_fn = &device_tree::write_binary;
> auto read_fn = &device_tree::parse_dts;
> - uint32_t boot_cpu;
> + uint32_t boot_cpu = 0;
> bool boot_cpu_specified = false;
> bool keep_going = false;
> bool sort = false;
>
> Modified: stable/12/usr.bin/dtc/fdt.cc
> ==============================================================================
> --- stable/12/usr.bin/dtc/fdt.cc Thu Apr 4 17:24:57 2019 (r345879)
> +++ stable/12/usr.bin/dtc/fdt.cc Thu Apr 4 17:26:35 2019 (r345880)
> @@ -46,6 +46,7 @@
> #include <libgen.h>
> #include <stdio.h>
> #include <stdlib.h>
> +#include <string.h>
> #include <unistd.h>
> #include <sys/types.h>
> #include <sys/stat.h>
> @@ -491,6 +492,7 @@ property::property(text_input_buffer &input,
> break;
> }
> }
> + [[fallthrough]];
> default:
> input.parse_error("Invalid property value.");
> valid = false;
> @@ -622,6 +624,7 @@ property_value::try_to_merge(property_value &other)
> return false;
> case EMPTY:
> *this = other;
> + [[fallthrough]];
> case STRING:
> case STRING_LIST:
> case CROSS_REFERENCE:
> @@ -846,6 +849,7 @@ node_ptr node::create_special_node(const string &name,
> }
>
> node::node(text_input_buffer &input,
> + device_tree &tree,
> string &&n,
> std::unordered_set<string> &&l,
> string &&a,
> @@ -862,6 +866,9 @@ node::node(text_input_buffer &input,
> // flag set if we find any characters that are only in
> // the property name character set, not the node
> bool is_property = false;
> + // flag set if our node is marked as /omit-if-no-ref/ to be
> + // garbage collected later if nothing references it
> + bool marked_omit_if_no_ref = false;
> string child_name, child_address;
> std::unordered_set<string> child_labels;
> auto parse_delete = [&](const char *expected, bool at)
> @@ -908,6 +915,12 @@ node::node(text_input_buffer &input,
> }
> continue;
> }
> + if (input.consume("/omit-if-no-ref/"))
> + {
> + input.next_token();
> + marked_omit_if_no_ref = true;
> + tree.set_needs_garbage_collection();
> + }
> child_name = parse_name(input, is_property,
> "Expected property or node name");
> while (input.consume(':'))
> @@ -943,10 +956,11 @@ node::node(text_input_buffer &input,
> }
> else if (!is_property && *input == ('{'))
> {
> - node_ptr child = node::parse(input, std::move(child_name),
> + node_ptr child = node::parse(input, tree, std::move(child_name),
> std::move(child_labels), std::move(child_address), defines);
> if (child)
> {
> + child->omit_if_no_ref = marked_omit_if_no_ref;
> children.push_back(std::move(child));
> }
> else
> @@ -998,12 +1012,14 @@ node::sort()
>
> node_ptr
> node::parse(text_input_buffer &input,
> + device_tree &tree,
> string &&name,
> string_set &&label,
> string &&address,
> define_map *defines)
> {
> node_ptr n(new node(input,
> + tree,
> std::move(name),
> std::move(label),
> std::move(address),
> @@ -1046,6 +1062,30 @@ node::merge_node(node_ptr &other)
> {
> labels.insert(l);
> }
> + children.erase(std::remove_if(children.begin(), children.end(),
> + [&](const node_ptr &p) {
> + string full_name = p->name;
> + if (p->unit_address != string())
> + {
> + full_name += '@';
> + full_name += p->unit_address;
> + }
> + if (other->deleted_children.count(full_name) > 0)
> + {
> + other->deleted_children.erase(full_name);
> + return true;
> + }
> + return false;
> + }), children.end());
> + props.erase(std::remove_if(props.begin(), props.end(),
> + [&](const property_ptr &p) {
> + if (other->deleted_props.count(p->get_key()) > 0)
> + {
> + other->deleted_props.erase(p->get_key());
> + return true;
> + }
> + return false;
> + }), props.end());
> // Note: this is an O(n*m) operation. It might be sensible to
> // optimise this if we find that there are nodes with very
> // large numbers of properties, but for typical usage the
> @@ -1085,30 +1125,6 @@ node::merge_node(node_ptr &other)
> children.push_back(std::move(c));
> }
> }
> - children.erase(std::remove_if(children.begin(), children.end(),
> - [&](const node_ptr &p) {
> - string full_name = p->name;
> - if (p->unit_address != string())
> - {
> - full_name += '@';
> - full_name += p->unit_address;
> - }
> - if (other->deleted_children.count(full_name) > 0)
> - {
> - other->deleted_children.erase(full_name);
> - return true;
> - }
> - return false;
> - }), children.end());
> - props.erase(std::remove_if(props.begin(), props.end(),
> - [&](const property_ptr &p) {
> - if (other->deleted_props.count(p->get_key()) > 0)
> - {
> - other->deleted_props.erase(p->get_key());
> - return true;
> - }
> - return false;
> - }), props.end());
> }
>
> void
> @@ -1187,6 +1203,7 @@ device_tree::collect_names_recursive(node_ptr &n, node
> {
> node_names.insert(std::make_pair(name, n.get()));
> node_paths.insert(std::make_pair(name, path));
> + ordered_node_paths.push_back({name, path});
> }
> else
> {
> @@ -1243,6 +1260,7 @@ device_tree::collect_names()
> node_path p;
> node_names.clear();
> node_paths.clear();
> + ordered_node_paths.clear();
> cross_references.clear();
> fixups.clear();
> collect_names_recursive(root, p);
> @@ -1353,7 +1371,6 @@ device_tree::resolve_cross_references(uint32_t &phandl
> return node::VISIT_RECURSE;
> }, nullptr);
> assert(sorted_phandles.size() == fixups.size());
> -
> for (auto &i : sorted_phandles)
> {
> string target_name = i.get().val.string_data;
> @@ -1441,7 +1458,104 @@ device_tree::resolve_cross_references(uint32_t &phandl
> }
> }
>
> +bool
> +device_tree::garbage_collect_marked_nodes()
> +{
> + std::unordered_set<node*> previously_referenced_nodes;
> + std::unordered_set<node*> newly_referenced_nodes;
>
> + auto mark_referenced_nodes_used = [&](node &n)
> + {
> + for (auto &p : n.properties())
> + {
> + for (auto &v : *p)
> + {
> + if (v.is_phandle())
> + {
> + node *nx = node_names[v.string_data];
> + if (nx == nullptr)
> + {
> + // Try it again, but as a path
> + for (auto &s : node_paths)
> + {
> + if (v.string_data == s.second.to_string())
> + {
> + nx = node_names[s.first];
> + break;
> + }
> + }
> + }
> + if (nx == nullptr)
> + {
> + // Couldn't resolve this one?
> + continue;
> + }
> + // Only mark those currently unmarked
> + if (!nx->used)
> + {
> + nx->used = 1;
> + newly_referenced_nodes.insert(nx);
> + }
> + }
> + }
> + }
> + };
> +
> + // Seed our referenced nodes with those that have been seen by a node that
> + // either will not be omitted if it's unreferenced or has a symbol.
> + // Nodes with symbols are explicitly not garbage collected because they may
> + // be expected for referencing by an overlay, and we do not want surprises
> + // there.
> + root->visit([&](node &n, node *) {
> + if (!n.omit_if_no_ref || (write_symbols && !n.labels.empty()))
> + {
> + mark_referenced_nodes_used(n);
> + }
> + // Recurse as normal
> + return node::VISIT_RECURSE;
> + }, nullptr);
> +
> + while (!newly_referenced_nodes.empty())
> + {
> + previously_referenced_nodes = std::move(newly_referenced_nodes);
> + for (auto *n : previously_referenced_nodes)
> + {
> + mark_referenced_nodes_used(*n);
> + }
> + }
> +
> + previously_referenced_nodes.clear();
> + bool children_deleted = false;
> +
> + // Delete
> + root->visit([&](node &n, node *) {
> + bool gc_children = false;
> +
> + for (auto &cn : n.child_nodes())
> + {
> + if (cn->omit_if_no_ref && !cn->used)
> + {
> + gc_children = true;
> + break;
> + }
> + }
> +
> + if (gc_children)
> + {
> + children_deleted = true;
> + n.delete_children_if([](node_ptr &nx) {
> + return (nx->omit_if_no_ref && !nx->used);
> + });
> +
> + return node::VISIT_CONTINUE;
> + }
> +
> + return node::VISIT_RECURSE;
> + }, nullptr);
> +
> + return children_deleted;
> +}
> +
> void
> device_tree::parse_file(text_input_buffer &input,
> std::vector<node_ptr> &roots,
> @@ -1486,7 +1600,7 @@ device_tree::parse_file(text_input_buffer &input,
> if (input.consume('/'))
> {
> input.next_token();
> - n = node::parse(input, string(), string_set(), string(), &defines);
> + n = node::parse(input, *this, string(), string_set(), string(), &defines);
> }
> else if (input.consume('&'))
> {
> @@ -1507,7 +1621,7 @@ device_tree::parse_file(text_input_buffer &input,
> name = input.parse_node_name();
> }
> input.next_token();
> - n = node::parse(input, std::move(name), string_set(), string(), &defines);
> + n = node::parse(input, *this, std::move(name), string_set(), string(), &defines);
> n->name_is_path_reference = name_is_path_reference;
> }
> else
> @@ -1890,6 +2004,12 @@ device_tree::parse_dts(const string &fn, FILE *depfile
> }
> }
> collect_names();
> + // Return value indicates whether we've dirtied the tree or not and need to
> + // recollect names
> + if (garbage_collect && garbage_collect_marked_nodes())
> + {
> + collect_names();
> + }
> uint32_t phandle = 1;
> // If we're writing symbols, go ahead and assign phandles to the entire
> // tree. We'll do this before we resolve cross references, just to keep
> @@ -1906,8 +2026,14 @@ device_tree::parse_dts(const string &fn, FILE *depfile
> // referenced by other plugins, so we create a __symbols__ node inside
> // the root that contains mappings (properties) from label names to
> // paths.
> - for (auto &s : node_paths)
> + for (auto i=ordered_node_paths.rbegin(), e=ordered_node_paths.rend() ; i!=e ; ++i)
> {
> + auto &s = *i;
> + if (node_paths.find(s.first) == node_paths.end())
> + {
> + // Erased node, skip it.
> + continue;
> + }
> property_value v;
> v.string_data = s.second.to_string();
> v.type = property_value::STRING;
> @@ -1986,19 +2112,23 @@ device_tree::parse_dts(const string &fn, FILE *depfile
> {
> if (c->name == p.first)
> {
> - string path = p.first;
> - if (!(p.second.empty()))
> + if (c->unit_address == p.second)
> {
> - path += '@';
> - path += p.second;
> + n = c.get();
> + found = true;
> + break;
> }
> - n->add_child(node::create_special_node(path, symbols));
> - n = (--n->child_end())->get();
> }
> }
> if (!found)
> {
> - n->add_child(node::create_special_node(p.first, symbols));
> + string path = p.first;
> + if (!(p.second.empty()))
> + {
> + path += '@';
> + path += p.second;
> + }
> + n->add_child(node::create_special_node(path, symbols));
> n = (--n->child_end())->get();
> }
> }
>
> Modified: stable/12/usr.bin/dtc/fdt.hh
> ==============================================================================
> --- stable/12/usr.bin/dtc/fdt.hh Thu Apr 4 17:24:57 2019 (r345879)
> +++ stable/12/usr.bin/dtc/fdt.hh Thu Apr 4 17:26:35 2019 (r345880)
> @@ -56,6 +56,7 @@ namespace fdt
> {
> class property;
> class node;
> +class device_tree;
> /**
> * Type for (owned) pointers to properties.
> */
> @@ -418,6 +419,17 @@ class node
> */
> std::string unit_address;
> /**
> + * A flag indicating that this node has been marked /omit-if-no-ref/ and
> + * will be omitted if it is not referenced, either directly or indirectly,
> + * by a node that is not similarly denoted.
> + */
> + bool omit_if_no_ref = false;
> + /**
> + * A flag indicating that this node has been referenced, either directly
> + * or indirectly, by a node that is not marked /omit-if-no-ref/.
> + */
> + bool used = false;
> + /**
> * The type for the property vector.
> */
> typedef std::vector<property_ptr> property_vector;
> @@ -507,6 +519,7 @@ class node
> * already been parsed.
> */
> node(text_input_buffer &input,
> + device_tree &tree,
> std::string &&n,
> std::unordered_set<std::string> &&l,
> std::string &&a,
> @@ -603,6 +616,7 @@ class node
> * have been parsed.
> */
> static node_ptr parse(text_input_buffer &input,
> + device_tree &tree,
> std::string &&name,
> std::unordered_set<std::string> &&label=std::unordered_set<std::string>(),
> std::string &&address=std::string(),
> @@ -640,6 +654,13 @@ class node
> children.push_back(std::move(n));
> }
> /**
> + * Deletes any children from this node.
> + */
> + inline void delete_children_if(bool (*predicate)(node_ptr &))
> + {
> + children.erase(std::remove_if(children.begin(), children.end(), predicate), children.end());
> + }
> + /**
> * Merges a node into this one. Any properties present in both are
> * overridden, any properties present in only one are preserved.
> */
> @@ -710,6 +731,11 @@ class device_tree
> */
> bool valid = true;
> /**
> + * Flag indicating that this tree requires garbage collection. This will be
> + * set to true if a node marked /omit-if-no-ref/ is encountered.
> + */
> + bool garbage_collect = false;
> + /**
> * Type used for memory reservations. A reservation is two 64-bit
> * values indicating a base address and length in memory that the
> * kernel should not use. The high 32 bits are ignored on 32-bit
> @@ -736,6 +762,12 @@ class device_tree
> */
> std::unordered_map<std::string, node_path> node_paths;
> /**
> + * All of the elements in `node_paths` in the order that they were
> + * created. This is used for emitting the `__symbols__` section, where
> + * we want to guarantee stable ordering.
> + */
> + std::vector<std::pair<std::string, node_path>> ordered_node_paths;
> + /**
> * A collection of property values that are references to other nodes.
> * These should be expanded to the full path of their targets.
> */
> @@ -847,10 +879,20 @@ class device_tree
> * node must have their values replaced by either the node path or
> * phandle value. The phandle parameter holds the next phandle to be
> * assigned, should the need arise. It will be incremented upon each
> - * assignment of a phandle.
> + * assignment of a phandle. Garbage collection of unreferenced nodes
> + * marked for "delete if unreferenced" will also occur here.
> */
> void resolve_cross_references(uint32_t &phandle);
> /**
> + * Garbage collects nodes that have been marked /omit-if-no-ref/ and do not
> + * have any references to them from nodes that are similarly marked. This
> + * is a fairly expensive operation. The return value indicates whether the
> + * tree has been dirtied as a result of this operation, so that the caller
> + * may take appropriate measures to bring the device tree into a consistent
> + * state as needed.
> + */
> + bool garbage_collect_marked_nodes();
> + /**
> * Parses a dts file in the given buffer and adds the roots to the parsed
> * set. The `read_header` argument indicates whether the header has
> * already been read. Some dts files place the header in an include,
> @@ -931,6 +973,14 @@ class device_tree
> inline bool is_valid()
> {
> return valid;
> + }
> + /**
> + * Mark this tree as needing garbage collection, because an /omit-if-no-ref/
> + * node has been encountered.
> + */
> + void set_needs_garbage_collection()
> + {
> + garbage_collect = true;
> }
> /**
> * Sets the format for writing phandle properties.
>
> Modified: stable/12/usr.bin/dtc/input_buffer.cc
> ==============================================================================
> --- stable/12/usr.bin/dtc/input_buffer.cc Thu Apr 4 17:24:57 2019 (r345879)
> +++ stable/12/usr.bin/dtc/input_buffer.cc Thu Apr 4 17:26:35 2019 (r345880)
> @@ -126,7 +126,7 @@ mmap_input_buffer::~mmap_input_buffer()
> {
> if (buffer != 0)
> {
> - munmap((void*)buffer, size);
> + munmap(const_cast<char*>(buffer), size);
> }
> }
>
>
> Modified: stable/12/usr.bin/dtc/util.hh
> ==============================================================================
> --- stable/12/usr.bin/dtc/util.hh Thu Apr 4 17:24:57 2019 (r345879)
> +++ stable/12/usr.bin/dtc/util.hh Thu Apr 4 17:26:35 2019 (r345880)
> @@ -47,6 +47,38 @@
> #endif
> #endif
>
> +#ifdef MISSING_DIGITTOINT
> +namespace
> +{
> + /**
> + * Glibc doesn't have a definition of digittoint, so provide our own.
> + */
> + inline int digittoint(int c)
> + {
> + switch (c)
> + {
> + default:
> + case '0': return 0;
> + case '1': return 1;
> + case '2': return 2;
> + case '3': return 3;
> + case '4': return 4;
> + case '5': return 5;
> + case '6': return 6;
> + case '7': return 7;
> + case '8': return 8;
> + case '9': return 9;
> + case 'a': return 10;
> + case 'b': return 11;
> + case 'c': return 12;
> + case 'd': return 13;
> + case 'e': return 14;
> + case 'f': return 15;
> + }
> + }
> +}
> +#endif
> +
> namespace dtc {
>
> /**
>
>
--
Rod Grimes rgrimes at freebsd.org
More information about the svn-src-stable-12
mailing list