Author: theraven
Date: Mon Aug 19 12:37:13 2013
New Revision: 254522
URL: http://svnweb.freebsd.org/changeset/base/254522

Log:
  Add support for parameterised device tree sources to the device tree compiler.
  
  Reviewed by:  brooks
  Sponsored by: DARPA, AFRL

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

Modified: head/usr.bin/dtc/dtc.1
==============================================================================
--- head/usr.bin/dtc/dtc.1      Mon Aug 19 12:30:18 2013        (r254521)
+++ head/usr.bin/dtc/dtc.1      Mon Aug 19 12:37:13 2013        (r254522)
@@ -51,6 +51,7 @@
 .Op Fl p Ar bytes
 .Op Fl V Ar blob_version
 .Op Fl W Ar [no-]checker_name
+.Op Fl P Ar predefined_properties
 .Ar input_file
 .Sh DESCRIPTION
 The
@@ -132,6 +133,22 @@ The ASCII representation of the FDT.
 .El
 .It Fl o Ar output_file
 The file to which to write the output.
+.It Fl P Ar predefined_macro
+Defines a macro, in the form
+.Ar name=value
+or
+.Ar name
+to be used for device tree source files that contain conditional components.
+This tool supports two extensions to the standard to support conditional
+compilation of device trees.
+The first is an 
+.Ar /include/if [property]/ "file.dts"
+directive that is allowed at the start of a file and which will only include
+the specified file if it the specified property is passed with this flag.
+The second is the 
+.Ar $NAME
+format for property values.
+These allow property value to be specified on the command line.
 .It Fl R Ar entries
 The number of empty reservation table entries to pad the table with.
 This is

Modified: head/usr.bin/dtc/dtc.cc
==============================================================================
--- head/usr.bin/dtc/dtc.cc     Mon Aug 19 12:30:18 2013        (r254521)
+++ head/usr.bin/dtc/dtc.cc     Mon Aug 19 12:37:13 2013        (r254522)
@@ -100,7 +100,7 @@ main(int argc, char **argv)
        clock_t c0 = clock();
        class device_tree tree;
        fdt::checking::check_manager checks;
-       const char *options = "hqI:O:o:V:d:R:S:p:b:fisvH:W:E:D";
+       const char *options = "hqI:O:o:V:d:R:S:p:b:fisvH:W:E:DP:";
 
        // Don't forget to update the man page if any more options are added.
        while ((ch = getopt(argc, argv, options)) != -1)
@@ -267,6 +267,13 @@ main(int argc, char **argv)
                case 'p':
                        tree.set_blob_padding(strtoll(optarg, 0, 10));
                        break;
+               case 'P':
+                       if (!tree.parse_define(optarg))
+                       {
+                               fprintf(stderr, "Invalid predefine value %s\n",
+                                       optarg);
+                       }
+                       break;
                default:
                        fprintf(stderr, "Unknown option %c\n", ch);
                        return EXIT_FAILURE;

Modified: head/usr.bin/dtc/fdt.cc
==============================================================================
--- head/usr.bin/dtc/fdt.cc     Mon Aug 19 12:30:18 2013        (r254521)
+++ head/usr.bin/dtc/fdt.cc     Mon Aug 19 12:37:13 2013        (r254522)
@@ -382,13 +382,45 @@ property::property(input_buffer &structs
        values.push_back(v);
 }
 
-property::property(input_buffer &input, string k, string l) : key(k), label(l),
-       valid(true)
+void property::parse_define(input_buffer &input, define_map *defines)
+{
+       input.consume('$');
+       if (!defines)
+       {
+               input.parse_error("No predefined properties to match name\n");
+               valid = false;
+               return;
+       }
+       string name = string::parse_property_name(input);
+       define_map::iterator found;
+       if ((name == string()) ||
+           ((found = defines->find(name)) == defines->end()))
+       {
+               input.parse_error("Undefined property name\n");
+               valid = false;
+               return;
+       }
+       values.push_back((*found).second->values[0]);
+}
+
+property::property(input_buffer &input,
+                   string k,
+                   string l,
+                   bool semicolonTerminated,
+                   define_map *defines) : key(k), label(l), valid(true)
 {
        do {
                input.next_token();
                switch (input[0])
                {
+                       case '$':
+                       {
+                               parse_define(input, defines);
+                               if (valid)
+                               {
+                                       break;
+                               }
+                       }
                        default:
                                input.parse_error("Invalid property value.");
                                valid = false;
@@ -412,7 +444,7 @@ property::property(input_buffer &input, 
                }
                input.next_token();
        } while (input.consume(','));
-       if (!input.consume(';'))
+       if (semicolonTerminated && !input.consume(';'))
        {
                input.parse_error("Expected ; at end of property");
                valid = false;
@@ -432,9 +464,10 @@ property::parse_dtb(input_buffer &struct
 }
 
 property*
-property::parse(input_buffer &input, string key, string label)
+property::parse(input_buffer &input, string key, string label,
+                bool semicolonTerminated, define_map *defines)
 {
-       property *p = new property(input, key, label);
+       property *p = new property(input, key, label, semicolonTerminated, 
defines);
        if (!p->valid)
        {
                delete p;
@@ -591,7 +624,7 @@ node::node(input_buffer &structs, input_
        return;
 }
 
-node::node(input_buffer &input, string n, string l, string a) : 
+node::node(input_buffer &input, string n, string l, string a, define_map 
*defines) : 
        label(l), name(n), unit_address(a), valid(true)
 {
        if (!input.consume('{'))
@@ -628,7 +661,7 @@ node::node(input_buffer &input, string n
                if (input.consume('='))
                {
                        property *p= property::parse(input, child_name,
-                                       child_label);
+                                       child_label, true, defines);
                        if (p == 0)
                        {
                                valid = false;
@@ -641,7 +674,7 @@ node::node(input_buffer &input, string n
                else if (!is_property && input[0] == ('{'))
                {
                        node *child = node::parse(input, child_name,
-                                       child_label, child_address);
+                                       child_label, child_address, defines);
                        if (child)
                        {
                                children.push_back(child);
@@ -693,9 +726,13 @@ node::sort()
 }
 
 node*
-node::parse(input_buffer &input, string name, string label, string address)
+node::parse(input_buffer &input,
+            string name,
+            string label,
+            string address,
+            define_map *defines)
 {
-       node *n = new node(input, name, label, address);
+       node *n = new node(input, name, label, address, defines);
        if (!n->valid)
        {
                delete n;
@@ -1008,7 +1045,7 @@ device_tree::parse_roots(input_buffer &i
        while (valid && input.consume('/'))
        {
                input.next_token();
-               node *n = node::parse(input, string("", 1));
+               node *n = node::parse(input, string("", 1), string(), string(), 
&defines);
                if (n)
                {
                        roots.push_back(n);
@@ -1241,6 +1278,18 @@ device_tree::parse_dts(const char *fn, F
        input.next_token();
        while(input.consume("/include/"))
        {
+               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('"'))
                {
@@ -1259,6 +1308,14 @@ device_tree::parse_dts(const char *fn, F
                include_file[dir_length] = '/';
                memcpy(include_file+dir_length+1, file, length);
                include_file[dir_length+length+1] = 0;
+
+               input.consume(include_file+dir_length+1);
+               input.consume('"');
+               if (!reallyInclude)
+               {
+                       continue;
+               }
+
                input_buffer *include_buffer = buffer_for_file(include_file);
 
                if (include_buffer == 0)
@@ -1292,8 +1349,6 @@ device_tree::parse_dts(const char *fn, F
                        return;
                }
                input_buffer &include = *include_buffer;
-               input.consume(include_file+dir_length+1);
-               input.consume('"');
                free((void*)include_file);
 
                if (!read_header)
@@ -1361,6 +1416,33 @@ device_tree::~device_tree()
                delete buffers.back();
                buffers.pop_back();
        }
+       for (define_map::iterator i=defines.begin(), e=defines.end() ;
+            i!=e ; ++i)
+       {
+               delete i->second;
+       }
+}
+
+bool device_tree::parse_define(const char *def)
+{
+       char *val = strchr(def, '=');
+       if (!val)
+       {
+               if (strlen(def) != 0)
+               {
+                       string name(def);
+                       defines[name];
+                       return true;
+               }
+               return false;
+       }
+       string name(def, val-def);
+       val++;
+       input_buffer in = input_buffer(val, strlen(val));
+       property *p = property::parse(in, name, string(), false);
+       if (p)
+               defines[name] = p;
+       return p;
 }
 
 } // namespace fdt

Modified: head/usr.bin/dtc/fdt.hh
==============================================================================
--- head/usr.bin/dtc/fdt.hh     Mon Aug 19 12:30:18 2013        (r254521)
+++ head/usr.bin/dtc/fdt.hh     Mon Aug 19 12:37:13 2013        (r254522)
@@ -48,6 +48,8 @@ class string_table;
 
 namespace fdt
 {
+class property;
+typedef std::map<string, property*> define_map;
 /**
  * Properties may contain a number of different value, each with a different
  * label.  This class encapsulates a single value.
@@ -263,6 +265,10 @@ class property
         */
        void parse_reference(input_buffer &input);
        /**
+        * Parse a predefined macro definition for a property.
+        */
+       void parse_define(input_buffer &input, define_map *defines);
+       /**
         * Constructs a new property from two input buffers, pointing to the
         * struct and strings tables in the device tree blob, respectively.
         * The structs input buffer is assumed to have just consumed the
@@ -272,7 +278,11 @@ class property
        /**
         * Parses a new property from the input buffer.  
         */
-       property(input_buffer &input, string k, string l);
+       property(input_buffer &input,
+                string k,
+                string l,
+                bool terminated,
+                define_map *defines);
        public:
        /**
         * Creates an empty property.
@@ -298,7 +308,9 @@ class property
         */
        static property* parse(input_buffer &input,
                               string key,
-                              string label=string());
+                              string label=string(),
+                              bool semicolonTerminated=true,
+                              define_map *defines=0);
        /**
         * Iterator type used for accessing the values of a property.
         */
@@ -398,7 +410,7 @@ class node
         * node.  The name, and optionally label and unit address, should have
         * already been parsed.
         */
-       node(input_buffer &input, string n, string l, string a);
+       node(input_buffer &input, string n, string l, string a, define_map*);
        /**
         * Comparison function for properties, used when sorting the properties
         * vector.  Orders the properties based on their names.
@@ -476,7 +488,8 @@ class node
        static node* parse(input_buffer &input,
                           string name,
                           string label=string(),
-                          string address=string());
+                          string address=string(),
+                          define_map *defines=0);
        /**
         * Factory method for constructing a new node.  Attempts to parse a
         * node in DTB format from the input, and returns it on success.  On
@@ -617,6 +630,10 @@ class device_tree
         */
        std::vector<const char*> include_paths;
        /**
+        * Dictionary of predefined macros provided on the command line.
+        */
+       define_map               defines;
+       /**
         * The default boot CPU, specified in the device tree header.
         */
        uint32_t boot_cpu;
@@ -773,6 +790,10 @@ class device_tree
        {
                blob_padding = p;
        }
+       /**
+        * Parses a predefined macro value.
+        */
+       bool parse_define(const char *def);
 };
 
 } // namespace fdt
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to