Commit fc14dad7 authored by David Gibson's avatar David Gibson

Initial commit

parents
This diff is collapsed.
TARGETS = dtc
CFLAGS = -Wall -g
OBJS = dtc.o livetree.o flattree.o data.o treesource.o fstree.o \
y.tab.o lex.yy.o
all: $(TARGETS)
dtc: $(OBJS)
$(LINK.c) -o $@ $^
$(OBJS): dtc.h
y.tab.c y.tab.h: dtc-parser.y
$(YACC) -d $<
lex.yy.c: dtc-lexer.l
$(LEX) $<
lex.yy.o: lex.yy.c y.tab.h
dtc-parser.c: dtc-lexer.c
check: all
cd tests && $(MAKE) check
clean:
rm -f *~ *.o a.out core $(TARGETS)
rm -f *.tab.[ch] lex.yy.c
rm -f *.i *.output vgcore.*
cd tests && $(MAKE) clean
- Bugfixes:
- Error handling / reporting
* Report line/column numbers for syntax errors
* Better categorization of errors into severity levels
- Generate mem reserve map
* Command line options to place a number of blank entries to be
filled in by bootloader
* memory reserve section in source
- Testsuite
- Actually number releases, revision control, all that kind of jazz
- Labels:
Allow labels in tree source, which will be propogated and
exported as symbols in asm output
- Autogenerate phandles
Allow property values to contain a reference to another node
(by path or label) which will be turned into a phandle for that node
in the output.
/* regexps for lexing comments are.. tricky. Check if we've actually
* got it right */
/ {
// line comment
prop1;
/* comment */
prop2;
/* multiline
notaprop1;
comment */
prop3;
/**/
prop4;
/***/
prop5;
/****/
prop6;
/* another
* multiline
* comment */
prop7;
/* yet
* another
* multline
* comment
*/
prop8;
/** try this */
prop9;
/* and this **/
};
/* final comment */
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
#if 0
static struct data data_init_buf(char *buf, int len)
{
struct data d;
d.asize = 0;
d.len = len;
d.val = buf;
return d;
}
struct data data_ref_string(char *str)
{
return data_init_buf(str, strlen(str)+1);
}
#endif
void data_free(struct data d)
{
assert(!d.val || d.asize);
if (d.val)
free(d.val);
}
struct data data_grow_for(struct data d, int xlen)
{
struct data nd;
int newsize;
/* we must start with an allocated datum */
assert(!d.val || d.asize);
if (xlen == 0)
return d;
newsize = xlen;
while ((d.len + xlen) > newsize)
newsize *= 2;
nd.asize = newsize;
nd.val = xrealloc(d.val, newsize);
nd.len = d.len;
assert(nd.asize >= (d.len + xlen));
return nd;
}
struct data data_copy_mem(char *mem, int len)
{
struct data d;
d = data_grow_for(empty_data, len);
d.len = len;
memcpy(d.val, mem, len);
return d;
}
char hexval(char c)
{
switch (c) {
case '0' ... '9':
return c - '0';
case 'a' ... 'f':
return c - 'a';
case 'A' ... 'F':
return c - 'A';
default:
assert(0);
}
}
char get_oct_char(char *s, int *i)
{
char x[4];
char *endx;
long val;
x[3] = '\0';
x[0] = s[(*i)];
if (x[0]) {
x[1] = s[(*i)+1];
if (x[1])
x[2] = s[(*i)+2];
}
val = strtol(x, &endx, 8);
if ((endx - x) == 0)
fprintf(stderr, "Empty \\nnn escape\n");
(*i) += endx - x;
return val;
}
char get_hex_char(char *s, int *i)
{
char x[3];
char *endx;
long val;
x[2] = '\0';
x[0] = s[(*i)];
if (x[0])
x[1] = s[(*i)+1];
val = strtol(x, &endx, 16);
if ((endx - x) == 0)
fprintf(stderr, "Empty \\x escape\n");
(*i) += endx - x;
return val;
}
struct data data_copy_escape_string(char *s, int len)
{
int i = 0;
struct data d;
char *q;
d = data_grow_for(empty_data, strlen(s)+1);
q = d.val;
while (i < len) {
char c = s[i++];
if (c != '\\') {
q[d.len++] = c;
continue;
}
c = s[i++];
assert(c);
switch (c) {
case 't':
q[d.len++] = '\t';
break;
case 'n':
q[d.len++] = '\n';
break;
case 'r':
q[d.len++] = '\r';
break;
case '0' ... '7':
i--; /* need to re-read the first digit as
* part of the octal value */
q[d.len++] = get_oct_char(s, &i);
break;
case 'x':
q[d.len++] = get_hex_char(s, &i);
break;
default:
q[d.len++] = c;
}
}
q[d.len++] = '\0';
return d;
}
struct data data_copy_file(FILE *f, size_t len)
{
struct data d;
d = data_grow_for(empty_data, len);
d.len = len;
fread(d.val, len, 1, f);
return d;
}
struct data data_append_data(struct data d, void *p, int len)
{
d = data_grow_for(d, len);
memcpy(d.val + d.len, p, len);
d.len += len;
return d;
}
struct data data_append_cell(struct data d, cell_t word)
{
cell_t beword = cpu_to_be32(word);
return data_append_data(d, &beword, sizeof(beword));
}
struct data data_append_byte(struct data d, uint8_t byte)
{
return data_append_data(d, &byte, 1);
}
struct data data_append_zeroes(struct data d, int len)
{
d = data_grow_for(d, len);
memset(d.val + d.len, 0, len);
d.len += len;
return d;
}
struct data data_append_align(struct data d, int align)
{
int newlen = ALIGN(d.len, align);
return data_append_zeroes(d, newlen - d.len);
}
int data_is_one_string(struct data d)
{
int i;
int len = d.len;
if (len == 0)
return 0;
for (i = 0; i < len-1; i++)
if (d.val[i] == '\0')
return 0;
if (d.val[len-1] != '\0')
return 0;
return 1;
}
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
%option noyywrap
%x CELLDATA
%x BYTESTRING
PROPCHAR [a-zA-Z0-9,._+*#?-]
UNITCHAR [0-9a-f,]
WS [ \t\n]
%%
%{
#include "dtc.h"
#include "y.tab.h"
#undef LEXDEBUG 1
%}
\"[^"]*\" {
#ifdef LEXDEBUG
fprintf(stderr, "String: %s\n", yytext);
#endif
yylval.data = data_copy_escape_string(yytext+1,
yyleng-2);
return DT_STRING;
}
<CELLDATA>[0-9a-fA-F]+ {
if (yyleng > 2*sizeof(yylval.cval)) {
fprintf(stderr,
"Cell value %s too long\n", yytext);
}
yylval.cval = strtol(yytext, NULL, 16);
#ifdef LEXDEBUG
fprintf(stderr, "Cell: %x\n", yylval.cval);
#endif
return DT_CELL;
}
<CELLDATA>">" {
#ifdef LEXDEBUG
fprintf(stderr, "/CELLDATA\n");
#endif
BEGIN(INITIAL);
return '>';
}
<BYTESTRING>[0-9a-fA-F]{2} {
yylval.byte = strtol(yytext, NULL, 16);
#ifdef LEXDEBUG
fprintf(stderr, "Byte: %02x\n", (int)yylval.byte);
#endif
return DT_BYTE;
}
<BYTESTRING>"]" {
#ifdef LEXDEBUG
fprintf(stderr, "/BYTESTRING\n");
#endif
BEGIN(INITIAL);
return ']';
}
{PROPCHAR}+(@{UNITCHAR}+)?/{WS}*\{ {
#ifdef LEXDEBUG
fprintf(stderr, "NodeName: %s\n", yytext);
#endif
yylval.str = strdup(yytext);
return DT_NODENAME;
}
{PROPCHAR}+ {
#ifdef LEXDEBUG
fprintf(stderr, "PropName: %s\n", yytext);
#endif
yylval.str = strdup(yytext);
return DT_PROPNAME;
}
<*>{WS}+ /* eat whitespace */
<*>"/*"([^*]|\*+[^*/])*\*+"/" {
#ifdef LEXDEBUG
fprintf(stderr, "Comment: %s\n", yytext);
/* eat comments */
#endif
}
<*>"//".*\n /* eat line comments */
. {
switch (yytext[0]) {
case '<':
#ifdef LEXDEBUG
fprintf(stderr, "CELLDATA\n");
#endif
BEGIN(CELLDATA);
break;
case '[':
#ifdef LEXDEBUG
fprintf(stderr, "BYTESTRING\n");
#endif
BEGIN(BYTESTRING);
break;
default:
#ifdef LEXDEBUG
fprintf(stderr, "Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
#endif
break;
}
return yytext[0];
}
%%
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
%{
#include "dtc.h"
int yylex (void);
void yyerror (char const *);
extern struct node *device_tree;
%}
%union {
cell_t cval;
uint8_t byte;
char *str;
struct data data;
struct property *prop;
struct property *proplist;
struct node *node;
struct node *nodelist;
int datalen;
int hexlen;
}
%token <str> DT_PROPNAME
%token <str> DT_NODENAME
%token <cval> DT_CELL
%token <byte> DT_BYTE
%token <data> DT_STRING
%token <str> DT_UNIT
%type <data> propdata
%type <data> celllist
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist
%type <node> nodedef
%type <node> subnode
%type <nodelist> subnodes
%%
devicetree: {
assert(device_tree == NULL);
} '/' nodedef { device_tree = name_node($3, ""); }
;
nodedef: '{' proplist subnodes '}' ';' {
$$ = build_node($2, $3);
}
;
proplist: propdef proplist {
$$ = chain_property($1, $2);
}
| /* empty */ {
$$ = NULL;
}
;
propdef: DT_PROPNAME '=' propdata ';' {
$$ = build_property($1, $3);
}
| DT_PROPNAME ';' {
$$ = build_empty_property($1);
}
;
propdata: DT_STRING { $$ = $1; }
| '<' celllist '>' { $$ = $2; }
| '[' bytestring ']' { $$ = $2; }
;
celllist: celllist DT_CELL { $$ = data_append_cell($1, $2); }
| /* empty */ { $$ = empty_data; }
;
bytestring: bytestring DT_BYTE { $$ = data_append_byte($1, $2); }
| /* empty */ { $$ = empty_data; }
;
subnodes: subnode subnodes {
$$ = chain_node($1, $2);
}
| /* empty */ { $$ = NULL; }
;
subnode: DT_NODENAME nodedef { $$ = name_node($2, $1); }
;
%%
void yyerror (char const *s)
{
fprintf (stderr, "%s\n", s);
}
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
char *join_path(char *path, char *name)
{
int lenp = strlen(path);
int lenn = strlen(name);
int len;
int needslash = 1;
char *str;
len = lenp + lenn + 2;
if ((lenp > 0) && (path[lenp-1] == '/')) {
needslash = 0;
len--;
}
str = xmalloc(len);
memcpy(str, path, lenp);
if (needslash) {
str[lenp] = '/';
lenp++;
}
memcpy(str+lenp, name, lenn+1);
return str;
}
void fill_fullpaths(struct node *tree, char *prefix)
{
struct node *child;
char *unit;
tree->fullpath = join_path(prefix, tree->name);
unit = strchr(tree->name, '@');
if (unit)
tree->basenamelen = unit - tree->name;
else
tree->basenamelen = strlen(tree->name);
for_each_child(tree, child)
fill_fullpaths(child, tree->fullpath);
}
static FILE *dtc_open_file(char *fname)
{
FILE *f;
if (streq(fname, "-"))
f = stdin;
else
f = fopen(fname, "r");
if (! f)
die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
return f;
}
static void usage(void)
{
fprintf(stderr, "Usage:\n");
fprintf(stderr, "\tdtc [options] <input file>\n");
fprintf(stderr, "\nOptions:\n");
fprintf(stderr, "\t-I <input format>\n");
fprintf(stderr, "\t\tInput formats are:\n");
fprintf(stderr, "\t\t\tdts - device tree source text\n");
fprintf(stderr, "\t\t\tdtb - device tree blob\n");
fprintf(stderr, "\t\t\tfs - /proc/device-tree style directory\n");
fprintf(stderr, "\t-O <output format>\n");
fprintf(stderr, "\t\tOutput formats are:\n");
fprintf(stderr, "\t\t\tdts - device tree source text\n");
fprintf(stderr, "\t\t\tdtb - device tree blob\n");
fprintf(stderr, "\t\t\tasm - assembler source\n");
fprintf(stderr, "\t-V <output version>\n");
fprintf(stderr, "\t\tBlob version to produce, defaults to 3 (relevant for dtb\n\t\tand asm output only)\n");
fprintf(stderr, "\t-R <number>\n");
fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n");
fprintf(stderr, "\t-f\n");
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
exit(2);
}
int main(int argc, char *argv[])
{
struct node *dt;
char *inform = "dts";
char *outform = "dts";
char *outname = "-";
int force = 0;
char *arg;
int opt;
FILE *inf = NULL;
FILE *outf = NULL;
int outversion = 3;
int reservenum = 1;
while ((opt = getopt(argc, argv, "I:O:o:V:R:f")) != EOF) {
switch (opt) {
case 'I':
inform = optarg;
break;
case 'O':
outform = optarg;
break;
case 'o':
outname = optarg;
break;
case 'V':
outversion = strtol(optarg, NULL, 0);
break;
case 'R':
reservenum = strtol(optarg, NULL, 0);
break;
case 'f':
force = 1;
break;
default:
usage();
}
}
if (argc > (optind+1))
usage();
else if (argc < (optind+1))
arg = "-";
else
arg = argv[optind];
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
inform, outform, arg);
if (streq(inform, "dts")) {
inf = dtc_open_file(arg);
dt = dt_from_source(inf);
} else if (streq(inform, "fs")) {
dt = dt_from_fs(arg);
} else if(streq(inform, "dtb")) {
inf = dtc_open_file(arg);
dt = dt_from_blob(inf);
} else {
die("Unknown input format \"%s\"\n", inform);
}
if (inf && (inf != stdin))
fclose(inf);
if (! dt)
die("Couldn't read input tree\n");
if (! check_device_tree(dt)) {
fprintf(stderr, "Input tree has errors\n");
if (! force)
exit(1);
}
if (streq(outname, "-")) {