Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Aug 2013 12:37:13 +0000 (UTC)
From:      David Chisnall <theraven@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r254522 - head/usr.bin/dtc
Message-ID:  <201308191237.r7JCbDGH037353@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308191237.r7JCbDGH037353>