Rudimentary phandle reference support.
parent
4102d840d9
commit
81f2e89c75
34
data.c
34
data.c
|
@ -38,8 +38,25 @@ struct data data_ref_string(char *str)
|
|||
}
|
||||
#endif
|
||||
|
||||
void fixup_free(struct fixup *f)
|
||||
{
|
||||
free(f->ref);
|
||||
free(f);
|
||||
}
|
||||
|
||||
void data_free(struct data d)
|
||||
{
|
||||
struct fixup *f;
|
||||
|
||||
f = d.refs;
|
||||
while (f) {
|
||||
struct fixup *nf;
|
||||
|
||||
nf = f->next;
|
||||
fixup_free(f);
|
||||
f = nf;
|
||||
}
|
||||
|
||||
assert(!d.val || d.asize);
|
||||
|
||||
if (d.val)
|
||||
|
@ -65,6 +82,7 @@ struct data data_grow_for(struct data d, int xlen)
|
|||
nd.asize = newsize;
|
||||
nd.val = xrealloc(d.val, newsize);
|
||||
nd.len = d.len;
|
||||
nd.refs = d.refs;
|
||||
|
||||
assert(nd.asize >= (d.len + xlen));
|
||||
|
||||
|
@ -231,6 +249,22 @@ struct data data_append_align(struct data d, int align)
|
|||
return data_append_zeroes(d, newlen - d.len);
|
||||
}
|
||||
|
||||
struct data data_add_fixup(struct data d, char *ref)
|
||||
{
|
||||
struct fixup *f;
|
||||
struct data nd;
|
||||
|
||||
f = xmalloc(sizeof(*f));
|
||||
f->offset = d.len;
|
||||
f->ref = ref;
|
||||
f->next = d.refs;
|
||||
|
||||
nd = d;
|
||||
nd.refs = f;
|
||||
|
||||
return nd;
|
||||
}
|
||||
|
||||
int data_is_one_string(struct data d)
|
||||
{
|
||||
int i;
|
||||
|
|
64
dtc-lexer.l
64
dtc-lexer.l
|
@ -27,6 +27,8 @@ PROPCHAR [a-zA-Z0-9,._+*#?-]
|
|||
UNITCHAR [0-9a-f,]
|
||||
WS [ \t\n]
|
||||
|
||||
REFCHAR ({PROPCHAR}|{UNITCHAR}|[/@])
|
||||
|
||||
%%
|
||||
|
||||
%{
|
||||
|
@ -34,14 +36,18 @@ WS [ \t\n]
|
|||
|
||||
#include "dtc-parser.tab.h"
|
||||
|
||||
/*#define LEXDEBUG 1 */
|
||||
/*#define LEXDEBUG 1*/
|
||||
|
||||
#ifdef LEXDEBUG
|
||||
#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DPRINT(fmt, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
%}
|
||||
|
||||
\"[^"]*\" {
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "String: %s\n", yytext);
|
||||
#endif
|
||||
DPRINT("String: %s\n", yytext);
|
||||
yylval.data = data_copy_escape_string(yytext+1,
|
||||
yyleng-2);
|
||||
return DT_STRING;
|
||||
|
@ -53,57 +59,49 @@ WS [ \t\n]
|
|||
"Cell value %s too long\n", yytext);
|
||||
}
|
||||
yylval.cval = strtol(yytext, NULL, 16);
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "Cell: %x\n", yylval.cval);
|
||||
#endif
|
||||
DPRINT("Cell: %x\n", yylval.cval);
|
||||
return DT_CELL;
|
||||
}
|
||||
|
||||
<CELLDATA>">" {
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "/CELLDATA\n");
|
||||
#endif
|
||||
DPRINT("/CELLDATA\n");
|
||||
BEGIN(INITIAL);
|
||||
return '>';
|
||||
}
|
||||
|
||||
<CELLDATA>\&{REFCHAR}* {
|
||||
DPRINT("Ref: %s\n", yytext+1);
|
||||
yylval.str = strdup(yytext+1);
|
||||
return DT_REF;
|
||||
}
|
||||
|
||||
<BYTESTRING>[0-9a-fA-F]{2} {
|
||||
yylval.byte = strtol(yytext, NULL, 16);
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "Byte: %02x\n", (int)yylval.byte);
|
||||
#endif
|
||||
DPRINT("Byte: %02x\n", (int)yylval.byte);
|
||||
return DT_BYTE;
|
||||
}
|
||||
|
||||
<BYTESTRING>"]" {
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "/BYTESTRING\n");
|
||||
#endif
|
||||
DPRINT("/BYTESTRING\n");
|
||||
BEGIN(INITIAL);
|
||||
return ']';
|
||||
}
|
||||
|
||||
{PROPCHAR}+ {
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "PropName: %s\n", yytext);
|
||||
#endif
|
||||
DPRINT("PropName: %s\n", yytext);
|
||||
yylval.str = strdup(yytext);
|
||||
return DT_PROPNAME;
|
||||
}
|
||||
|
||||
{PROPCHAR}+(@{UNITCHAR}+)? {
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "NodeName: %s\n", yytext);
|
||||
#endif
|
||||
DPRINT("NodeName: %s\n", yytext);
|
||||
yylval.str = strdup(yytext);
|
||||
return DT_NODENAME;
|
||||
}
|
||||
|
||||
|
||||
[a-zA-Z_][a-zA-Z0-9_]*: {
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "Label: %s\n", yytext);
|
||||
#endif
|
||||
DPRINT("Label: %s\n", yytext);
|
||||
yylval.str = strdup(yytext);
|
||||
yylval.str[yyleng-1] = '\0';
|
||||
return DT_LABEL;
|
||||
|
@ -112,10 +110,8 @@ WS [ \t\n]
|
|||
<*>{WS}+ /* eat whitespace */
|
||||
|
||||
<*>"/*"([^*]|\*+[^*/])*\*+"/" {
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "Comment: %s\n", yytext);
|
||||
DPRINT("Comment: %s\n", yytext);
|
||||
/* eat comments */
|
||||
#endif
|
||||
}
|
||||
|
||||
<*>"//".*\n /* eat line comments */
|
||||
|
@ -123,23 +119,17 @@ WS [ \t\n]
|
|||
. {
|
||||
switch (yytext[0]) {
|
||||
case '<':
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "CELLDATA\n");
|
||||
#endif
|
||||
DPRINT("CELLDATA\n");
|
||||
BEGIN(CELLDATA);
|
||||
break;
|
||||
case '[':
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "BYTESTRING\n");
|
||||
#endif
|
||||
DPRINT("BYTESTRING\n");
|
||||
BEGIN(BYTESTRING);
|
||||
break;
|
||||
default:
|
||||
|
||||
#ifdef LEXDEBUG
|
||||
fprintf(stderr, "Char: %c (\\x%02x)\n", yytext[0],
|
||||
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
|
||||
(unsigned)yytext[0]);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ extern struct node *device_tree;
|
|||
%token <data> DT_STRING
|
||||
%token <str> DT_UNIT
|
||||
%token <str> DT_LABEL
|
||||
%token <str> DT_REF
|
||||
|
||||
%type <data> propdata
|
||||
%type <data> celllist
|
||||
|
@ -97,6 +98,9 @@ propdata: DT_STRING { $$ = $1; }
|
|||
;
|
||||
|
||||
celllist: celllist DT_CELL { $$ = data_append_cell($1, $2); }
|
||||
| celllist DT_REF {
|
||||
$$ = data_append_cell(data_add_fixup($1, $2), -1);
|
||||
}
|
||||
| /* empty */ { $$ = empty_data; }
|
||||
;
|
||||
|
||||
|
|
15
dtc.h
15
dtc.h
|
@ -76,18 +76,29 @@ typedef u32 cell_t;
|
|||
|
||||
|
||||
#define streq(a, b) (strcmp((a), (b)) == 0)
|
||||
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
|
||||
|
||||
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
/* Data blobs */
|
||||
struct fixup {
|
||||
int offset;
|
||||
char *ref;
|
||||
struct fixup *next;
|
||||
};
|
||||
|
||||
struct data {
|
||||
int len;
|
||||
char *val;
|
||||
int asize;
|
||||
struct fixup *refs;
|
||||
};
|
||||
|
||||
#define empty_data ((struct data){.len = 0, .val = NULL, .asize = 0})
|
||||
#define empty_data \
|
||||
((struct data){.len = 0, .val = NULL, .asize = 0, .refs = NULL})
|
||||
|
||||
void fixup_free(struct fixup *f);
|
||||
void data_free(struct data d);
|
||||
|
||||
struct data data_grow_for(struct data d, int xlen);
|
||||
|
@ -102,6 +113,8 @@ struct data data_append_byte(struct data d, uint8_t byte);
|
|||
struct data data_append_zeroes(struct data d, int len);
|
||||
struct data data_append_align(struct data d, int align);
|
||||
|
||||
struct data data_add_fixup(struct data d, char *ref);
|
||||
|
||||
int data_is_one_string(struct data d);
|
||||
|
||||
/* DT constraints */
|
||||
|
|
|
@ -598,7 +598,7 @@ static char *nodename_from_path(char *ppath, char *cpath)
|
|||
if ((plen == 0) && streq(ppath, "/"))
|
||||
return strdup(lslash+1);
|
||||
|
||||
if (strncmp(ppath, cpath, plen) != 0)
|
||||
if (! strneq(ppath, cpath, plen))
|
||||
return NULL;
|
||||
|
||||
return strdup(lslash+1);
|
||||
|
|
97
livetree.c
97
livetree.c
|
@ -43,9 +43,7 @@ struct property *build_empty_property(char *name, char *label)
|
|||
struct property *new = xmalloc(sizeof(*new));
|
||||
|
||||
new->name = name;
|
||||
new->val.len = 0;
|
||||
new->val.val = NULL;
|
||||
|
||||
new->val = empty_data;
|
||||
new->next = NULL;
|
||||
|
||||
new->label = label;
|
||||
|
@ -141,8 +139,30 @@ static struct node *get_subnode(struct node *node, char *nodename)
|
|||
{
|
||||
struct node *child;
|
||||
|
||||
for_each_child(node, child) {
|
||||
if (strcmp(child->name, nodename) == 0)
|
||||
for_each_child(node, child)
|
||||
if (streq(child->name, nodename))
|
||||
return child;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct node *get_node_by_path(struct node *tree, char *path)
|
||||
{
|
||||
char *p;
|
||||
struct node *child;
|
||||
|
||||
if (!path || ! (*path))
|
||||
return tree;
|
||||
|
||||
while (path[0] == '/')
|
||||
path++;
|
||||
|
||||
p = strchr(path, '/');
|
||||
|
||||
for_each_child(tree, child) {
|
||||
if (p && strneq(path, child->name, p-path))
|
||||
return get_node_by_path(child, p+1);
|
||||
else if (!p && streq(path, child->name))
|
||||
return child;
|
||||
}
|
||||
|
||||
|
@ -209,7 +229,7 @@ static int must_be_string(struct property *prop, struct node *node)
|
|||
static int name_prop_check(struct property *prop, struct node *node)
|
||||
{
|
||||
if ((prop->val.len != node->basenamelen+1)
|
||||
|| (strncmp(prop->val.val, node->name, node->basenamelen) != 0)) {
|
||||
|| !strneq(prop->val.val, node->name, node->basenamelen)) {
|
||||
ERRMSG("name property \"%s\" does not match node basename in %s\n",
|
||||
prop->val.val,
|
||||
node->fullpath);
|
||||
|
@ -469,7 +489,7 @@ static int check_memory(struct node *root)
|
|||
int ok = 1;
|
||||
|
||||
for_each_child(root, mem) {
|
||||
if (strncmp(mem->name, "memory", mem->basenamelen) != 0)
|
||||
if (! strneq(mem->name, "memory", mem->basenamelen))
|
||||
continue;
|
||||
|
||||
nnodes++;
|
||||
|
@ -573,6 +593,67 @@ static int check_phandles(struct node *root, struct node *node)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static cell_t get_node_phandle(struct node *root, struct node *node)
|
||||
{
|
||||
static cell_t phandle = 1; /* FIXME: ick, static local */
|
||||
|
||||
fprintf(stderr, "get_node_phandle(%s) phandle=%x\n",
|
||||
node->fullpath, node->phandle);
|
||||
|
||||
if ((node->phandle != 0) && (node->phandle != -1))
|
||||
return node->phandle;
|
||||
|
||||
assert(! get_property(node, "linux,phandle"));
|
||||
|
||||
while (get_node_by_phandle(root, phandle))
|
||||
phandle++;
|
||||
|
||||
node->phandle = phandle;
|
||||
add_property(node,
|
||||
build_property("linux,phandle",
|
||||
data_append_cell(empty_data, phandle),
|
||||
NULL));
|
||||
|
||||
return node->phandle;
|
||||
}
|
||||
|
||||
static void apply_fixup(struct node *root, struct property *prop,
|
||||
struct fixup *f)
|
||||
{
|
||||
struct node *refnode;
|
||||
cell_t phandle;
|
||||
|
||||
refnode = get_node_by_path(root, f->ref);
|
||||
if (! refnode)
|
||||
die("Reference to non-existent node \"%s\"\n", f->ref);
|
||||
|
||||
phandle = get_node_phandle(root, refnode);
|
||||
|
||||
assert(f->offset + sizeof(cell_t) <= prop->val.len);
|
||||
|
||||
*((cell_t *)(prop->val.val + f->offset)) = cpu_to_be32(phandle);
|
||||
}
|
||||
|
||||
static void fixup_phandles(struct node *root, struct node *node)
|
||||
{
|
||||
struct property *prop;
|
||||
struct node *child;
|
||||
|
||||
for_each_property(node, prop) {
|
||||
struct fixup *f = prop->val.refs;
|
||||
|
||||
while (f) {
|
||||
apply_fixup(root, prop, f);
|
||||
prop->val.refs = f->next;
|
||||
fixup_free(f);
|
||||
f = prop->val.refs;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_child(node, child)
|
||||
fixup_phandles(root, child);
|
||||
}
|
||||
|
||||
int check_device_tree(struct node *dt)
|
||||
{
|
||||
int ok = 1;
|
||||
|
@ -583,6 +664,8 @@ int check_device_tree(struct node *dt)
|
|||
ok = ok && check_addr_size_reg(dt, -1, -1);
|
||||
ok = ok && check_phandles(dt, dt);
|
||||
|
||||
fixup_phandles(dt, dt);
|
||||
|
||||
if (! ok)
|
||||
return 0;
|
||||
|
||||
|
|
11
test.dts
11
test.dts
|
@ -2,19 +2,19 @@
|
|||
model = "MyBoardName";
|
||||
compatible = "MyBoardFamilyName";
|
||||
#address-cells = <2>;
|
||||
label1: #size-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
label2: cpus {
|
||||
cpus {
|
||||
linux,phandle = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
PowerPC,970@0 {
|
||||
linux,phandle = <3>;
|
||||
name = "PowerPC,970";
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
clock-frequency = <5f5e1000>;
|
||||
linux,boot-cpu;
|
||||
linux,phandle = <2>;
|
||||
i-cache-size = <10000>;
|
||||
d-cache-size = <8000>;
|
||||
};
|
||||
|
@ -24,18 +24,17 @@
|
|||
randomnode {
|
||||
string = "\xff\0stuffstuff\t\t\t\n\n\n";
|
||||
blob = [0a 0b 0c 0d de ea ad be ef];
|
||||
ref = < &/memory@0 >;
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <00000000 00000000 00000000 20000000>;
|
||||
linux,phandle = <3>;
|
||||
memreg: reg = <00000000 00000000 00000000 20000000>;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "root=/dev/sda2";
|
||||
linux,platform = <00000600>;
|
||||
linux,phandle = <4>;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue