From owner-svn-src-stable-12@freebsd.org Thu Apr 4 17:36:17 2019 Return-Path: Delivered-To: svn-src-stable-12@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 9BCE8153C49F; Thu, 4 Apr 2019 17:36:17 +0000 (UTC) (envelope-from freebsd@gndrsh.dnsmgr.net) Received: from gndrsh.dnsmgr.net (br1.CN84in.dnsmgr.net [69.59.192.140]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id BEF9E846C1; Thu, 4 Apr 2019 17:36:16 +0000 (UTC) (envelope-from freebsd@gndrsh.dnsmgr.net) Received: from gndrsh.dnsmgr.net (localhost [127.0.0.1]) by gndrsh.dnsmgr.net (8.13.3/8.13.3) with ESMTP id x34HaF2b034356; Thu, 4 Apr 2019 10:36:15 -0700 (PDT) (envelope-from freebsd@gndrsh.dnsmgr.net) Received: (from freebsd@localhost) by gndrsh.dnsmgr.net (8.13.3/8.13.3/Submit) id x34HaFb3034355; Thu, 4 Apr 2019 10:36:15 -0700 (PDT) (envelope-from freebsd) From: "Rodney W. Grimes" Message-Id: <201904041736.x34HaFb3034355@gndrsh.dnsmgr.net> Subject: Re: svn commit: r345880 - stable/12/usr.bin/dtc In-Reply-To: <201904041726.x34HQZrp034444@repo.freebsd.org> To: Kyle Evans Date: Thu, 4 Apr 2019 10:36:15 -0700 (PDT) CC: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Reply-To: rgrimes@freebsd.org X-Mailer: ELM [version 2.4ME+ PL121h (25)] MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII X-Rspamd-Queue-Id: BEF9E846C1 X-Spamd-Bar: ------ Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-6.92 / 15.00]; NEURAL_HAM_MEDIUM(-1.00)[-1.000,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; REPLY(-4.00)[]; NEURAL_HAM_SHORT(-0.92)[-0.923,0] X-BeenThere: svn-src-stable-12@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for only the 12-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Apr 2019 17:36:17 -0000 > 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 > #include > #include > +#include > > 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 > #include > #include > +#include > #include > #include > > @@ -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 > #include > #include > +#include > #include > #include > #include > @@ -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 &&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 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 previously_referenced_nodes; > + std::unordered_set 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 &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_vector; > @@ -507,6 +519,7 @@ class node > * already been parsed. > */ > node(text_input_buffer &input, > + device_tree &tree, > std::string &&n, > std::unordered_set &&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 &&label=std::unordered_set(), > 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 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> 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(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@freebsd.org