Author: kevans
Date: Thu Mar 28 03:48:51 2019
New Revision: 345628
URL: https://svnweb.freebsd.org/changeset/base/345628

Log:
  dtc(1): Update to 1a79f5f26631
  
  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
  
  Reported by:  strejda [0]
  MFC after:    1 week

Modified:
  head/usr.bin/dtc/dtb.cc
  head/usr.bin/dtc/dtb.hh
  head/usr.bin/dtc/dtc.1
  head/usr.bin/dtc/dtc.cc
  head/usr.bin/dtc/fdt.cc
  head/usr.bin/dtc/fdt.hh
  head/usr.bin/dtc/input_buffer.cc
  head/usr.bin/dtc/util.hh

Modified: head/usr.bin/dtc/dtb.cc
==============================================================================
--- head/usr.bin/dtc/dtb.cc     Thu Mar 28 03:31:51 2019        (r345627)
+++ head/usr.bin/dtc/dtb.cc     Thu Mar 28 03:48:51 2019        (r345628)
@@ -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: head/usr.bin/dtc/dtb.hh
==============================================================================
--- head/usr.bin/dtc/dtb.hh     Thu Mar 28 03:31:51 2019        (r345627)
+++ head/usr.bin/dtc/dtb.hh     Thu Mar 28 03:48:51 2019        (r345628)
@@ -109,6 +109,8 @@ inline const char *token_type_name(token_type t)
                        return "FDT_END";
        }
        assert(0);
+       // Not reached.
+       return nullptr;
 }
 
 /**

Modified: head/usr.bin/dtc/dtc.1
==============================================================================
--- head/usr.bin/dtc/dtc.1      Thu Mar 28 03:31:51 2019        (r345627)
+++ head/usr.bin/dtc/dtc.1      Thu Mar 28 03:48:51 2019        (r345628)
@@ -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: head/usr.bin/dtc/dtc.cc
==============================================================================
--- head/usr.bin/dtc/dtc.cc     Thu Mar 28 03:31:51 2019        (r345627)
+++ head/usr.bin/dtc/dtc.cc     Thu Mar 28 03:48:51 2019        (r345628)
@@ -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: head/usr.bin/dtc/fdt.cc
==============================================================================
--- head/usr.bin/dtc/fdt.cc     Thu Mar 28 03:31:51 2019        (r345627)
+++ head/usr.bin/dtc/fdt.cc     Thu Mar 28 03:48:51 2019        (r345628)
@@ -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: head/usr.bin/dtc/fdt.hh
==============================================================================
--- head/usr.bin/dtc/fdt.hh     Thu Mar 28 03:31:51 2019        (r345627)
+++ head/usr.bin/dtc/fdt.hh     Thu Mar 28 03:48:51 2019        (r345628)
@@ -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: head/usr.bin/dtc/input_buffer.cc
==============================================================================
--- head/usr.bin/dtc/input_buffer.cc    Thu Mar 28 03:31:51 2019        
(r345627)
+++ head/usr.bin/dtc/input_buffer.cc    Thu Mar 28 03:48:51 2019        
(r345628)
@@ -126,7 +126,7 @@ mmap_input_buffer::~mmap_input_buffer()
 {
        if (buffer != 0)
        {
-               munmap((void*)buffer, size);
+               munmap(const_cast<char*>(buffer), size);
        }
 }
 

Modified: head/usr.bin/dtc/util.hh
==============================================================================
--- head/usr.bin/dtc/util.hh    Thu Mar 28 03:31:51 2019        (r345627)
+++ head/usr.bin/dtc/util.hh    Thu Mar 28 03:48:51 2019        (r345628)
@@ -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 {
 
 /**
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to