Add support for parameterised device tree sources to the device tree compiler.
Reviewed by: brooks Sponsored by: DARPA, AFRL
This commit is contained in:
parent
678d7b9461
commit
88169e0388
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
@ -262,6 +264,10 @@ class property
|
||||
* follow their interpretation for compatibility.
|
||||
*/
|
||||
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.
|
||||
@ -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
|
||||
@ -616,6 +629,10 @@ class device_tree
|
||||
* must be freed separately.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -773,6 +790,10 @@ class device_tree
|
||||
{
|
||||
blob_padding = p;
|
||||
}
|
||||
/**
|
||||
* Parses a predefined macro value.
|
||||
*/
|
||||
bool parse_define(const char *def);
|
||||
};
|
||||
|
||||
} // namespace fdt
|
||||
|
Loading…
Reference in New Issue
Block a user