summaryrefslogtreecommitdiffstats
path: root/usr.bin
diff options
context:
space:
mode:
authortheraven <theraven@FreeBSD.org>2013-08-19 12:37:13 +0000
committertheraven <theraven@FreeBSD.org>2013-08-19 12:37:13 +0000
commita84c641767af511112a0ead58df9bf7937868cde (patch)
treeb8f9cd2ad6c4fae5354dc0d9ad5c112b31c3da31 /usr.bin
parent61082833e74ee0e5aecb11f25f544bf662618e6b (diff)
downloadFreeBSD-src-a84c641767af511112a0ead58df9bf7937868cde.zip
FreeBSD-src-a84c641767af511112a0ead58df9bf7937868cde.tar.gz
Add support for parameterised device tree sources to the device tree compiler.
Reviewed by: brooks Sponsored by: DARPA, AFRL
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/dtc/dtc.117
-rw-r--r--usr.bin/dtc/dtc.cc9
-rw-r--r--usr.bin/dtc/fdt.cc108
-rw-r--r--usr.bin/dtc/fdt.hh29
4 files changed, 145 insertions, 18 deletions
diff --git a/usr.bin/dtc/dtc.1 b/usr.bin/dtc/dtc.1
index 9724787..050bb70 100644
--- a/usr.bin/dtc/dtc.1
+++ b/usr.bin/dtc/dtc.1
@@ -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
diff --git a/usr.bin/dtc/dtc.cc b/usr.bin/dtc/dtc.cc
index cffb3eb..c04f016 100644
--- a/usr.bin/dtc/dtc.cc
+++ b/usr.bin/dtc/dtc.cc
@@ -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;
diff --git a/usr.bin/dtc/fdt.cc b/usr.bin/dtc/fdt.cc
index 6f27c9c..eb944fc 100644
--- a/usr.bin/dtc/fdt.cc
+++ b/usr.bin/dtc/fdt.cc
@@ -382,13 +382,45 @@ property::property(input_buffer &structs, input_buffer &strings)
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, string k, string l) : key(k), label(l),
}
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 &structs, input_buffer &strings)
}
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_buffer &strings) : valid(true)
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, string l, string a) :
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, string l, string a) :
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 &input, std::vector<node*> &roots)
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, FILE *depfile)
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, FILE *depfile)
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, FILE *depfile)
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
diff --git a/usr.bin/dtc/fdt.hh b/usr.bin/dtc/fdt.hh
index b00ea48..3ac1084 100644
--- a/usr.bin/dtc/fdt.hh
+++ b/usr.bin/dtc/fdt.hh
@@ -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
OpenPOWER on IntegriCloud