Browse Source

Rudimentary phandle reference support.

main
David Gibson 20 years ago
parent
commit
81f2e89c75
  1. 34
      data.c
  2. 64
      dtc-lexer.l
  3. 4
      dtc-parser.y
  4. 15
      dtc.h
  5. 2
      flattree.c
  6. 97
      livetree.c
  7. 11
      test.dts

34
data.c

@ -38,8 +38,25 @@ struct data data_ref_string(char *str)
} }
#endif #endif


void fixup_free(struct fixup *f)
{
free(f->ref);
free(f);
}

void data_free(struct data d) 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); assert(!d.val || d.asize);


if (d.val) if (d.val)
@ -65,6 +82,7 @@ struct data data_grow_for(struct data d, int xlen)
nd.asize = newsize; nd.asize = newsize;
nd.val = xrealloc(d.val, newsize); nd.val = xrealloc(d.val, newsize);
nd.len = d.len; nd.len = d.len;
nd.refs = d.refs;


assert(nd.asize >= (d.len + xlen)); 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); 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 data_is_one_string(struct data d)
{ {
int i; int i;

64
dtc-lexer.l

@ -27,6 +27,8 @@ PROPCHAR [a-zA-Z0-9,._+*#?-]
UNITCHAR [0-9a-f,] UNITCHAR [0-9a-f,]
WS [ \t\n] WS [ \t\n]


REFCHAR ({PROPCHAR}|{UNITCHAR}|[/@])

%% %%


%{ %{
@ -34,14 +36,18 @@ WS [ \t\n]


#include "dtc-parser.tab.h" #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 DPRINT("String: %s\n", yytext);
fprintf(stderr, "String: %s\n", yytext);
#endif
yylval.data = data_copy_escape_string(yytext+1, yylval.data = data_copy_escape_string(yytext+1,
yyleng-2); yyleng-2);
return DT_STRING; return DT_STRING;
@ -53,57 +59,49 @@ WS [ \t\n]
"Cell value %s too long\n", yytext); "Cell value %s too long\n", yytext);
} }
yylval.cval = strtol(yytext, NULL, 16); yylval.cval = strtol(yytext, NULL, 16);
#ifdef LEXDEBUG DPRINT("Cell: %x\n", yylval.cval);
fprintf(stderr, "Cell: %x\n", yylval.cval);
#endif
return DT_CELL; return DT_CELL;
} }


<CELLDATA>">" { <CELLDATA>">" {
#ifdef LEXDEBUG DPRINT("/CELLDATA\n");
fprintf(stderr, "/CELLDATA\n");
#endif
BEGIN(INITIAL); BEGIN(INITIAL);
return '>'; return '>';
} }


<CELLDATA>\&{REFCHAR}* {
DPRINT("Ref: %s\n", yytext+1);
yylval.str = strdup(yytext+1);
return DT_REF;
}

<BYTESTRING>[0-9a-fA-F]{2} { <BYTESTRING>[0-9a-fA-F]{2} {
yylval.byte = strtol(yytext, NULL, 16); yylval.byte = strtol(yytext, NULL, 16);
#ifdef LEXDEBUG DPRINT("Byte: %02x\n", (int)yylval.byte);
fprintf(stderr, "Byte: %02x\n", (int)yylval.byte);
#endif
return DT_BYTE; return DT_BYTE;
} }


<BYTESTRING>"]" { <BYTESTRING>"]" {
#ifdef LEXDEBUG DPRINT("/BYTESTRING\n");
fprintf(stderr, "/BYTESTRING\n");
#endif
BEGIN(INITIAL); BEGIN(INITIAL);
return ']'; return ']';
} }


{PROPCHAR}+ { {PROPCHAR}+ {
#ifdef LEXDEBUG DPRINT("PropName: %s\n", yytext);
fprintf(stderr, "PropName: %s\n", yytext);
#endif
yylval.str = strdup(yytext); yylval.str = strdup(yytext);
return DT_PROPNAME; return DT_PROPNAME;
} }


{PROPCHAR}+(@{UNITCHAR}+)? { {PROPCHAR}+(@{UNITCHAR}+)? {
#ifdef LEXDEBUG DPRINT("NodeName: %s\n", yytext);
fprintf(stderr, "NodeName: %s\n", yytext);
#endif
yylval.str = strdup(yytext); yylval.str = strdup(yytext);
return DT_NODENAME; return DT_NODENAME;
} }




[a-zA-Z_][a-zA-Z0-9_]*: { [a-zA-Z_][a-zA-Z0-9_]*: {
#ifdef LEXDEBUG DPRINT("Label: %s\n", yytext);
fprintf(stderr, "Label: %s\n", yytext);
#endif
yylval.str = strdup(yytext); yylval.str = strdup(yytext);
yylval.str[yyleng-1] = '\0'; yylval.str[yyleng-1] = '\0';
return DT_LABEL; return DT_LABEL;
@ -112,10 +110,8 @@ WS [ \t\n]
<*>{WS}+ /* eat whitespace */ <*>{WS}+ /* eat whitespace */


<*>"/*"([^*]|\*+[^*/])*\*+"/" { <*>"/*"([^*]|\*+[^*/])*\*+"/" {
#ifdef LEXDEBUG DPRINT("Comment: %s\n", yytext);
fprintf(stderr, "Comment: %s\n", yytext);
/* eat comments */ /* eat comments */
#endif
} }


<*>"//".*\n /* eat line comments */ <*>"//".*\n /* eat line comments */
@ -123,23 +119,17 @@ WS [ \t\n]
. { . {
switch (yytext[0]) { switch (yytext[0]) {
case '<': case '<':
#ifdef LEXDEBUG DPRINT("CELLDATA\n");
fprintf(stderr, "CELLDATA\n");
#endif
BEGIN(CELLDATA); BEGIN(CELLDATA);
break; break;
case '[': case '[':
#ifdef LEXDEBUG DPRINT("BYTESTRING\n");
fprintf(stderr, "BYTESTRING\n");
#endif
BEGIN(BYTESTRING); BEGIN(BYTESTRING);
break; break;
default: default:


#ifdef LEXDEBUG DPRINT("Char: %c (\\x%02x)\n", yytext[0],
fprintf(stderr, "Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]); (unsigned)yytext[0]);
#endif
break; break;
} }



4
dtc-parser.y

@ -48,6 +48,7 @@ extern struct node *device_tree;
%token <data> DT_STRING %token <data> DT_STRING
%token <str> DT_UNIT %token <str> DT_UNIT
%token <str> DT_LABEL %token <str> DT_LABEL
%token <str> DT_REF


%type <data> propdata %type <data> propdata
%type <data> celllist %type <data> celllist
@ -97,6 +98,9 @@ propdata: DT_STRING { $$ = $1; }
; ;


celllist: celllist DT_CELL { $$ = data_append_cell($1, $2); } celllist: celllist DT_CELL { $$ = data_append_cell($1, $2); }
| celllist DT_REF {
$$ = data_append_cell(data_add_fixup($1, $2), -1);
}
| /* empty */ { $$ = empty_data; } | /* empty */ { $$ = empty_data; }
; ;



15
dtc.h

@ -76,18 +76,29 @@ typedef u32 cell_t;




#define streq(a, b) (strcmp((a), (b)) == 0) #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 ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))


/* Data blobs */ /* Data blobs */
struct fixup {
int offset;
char *ref;
struct fixup *next;
};

struct data { struct data {
int len; int len;
char *val; char *val;
int asize; 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); void data_free(struct data d);


struct data data_grow_for(struct data d, int xlen); 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_zeroes(struct data d, int len);
struct data data_append_align(struct data d, int align); 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); int data_is_one_string(struct data d);


/* DT constraints */ /* DT constraints */

2
flattree.c

@ -598,7 +598,7 @@ static char *nodename_from_path(char *ppath, char *cpath)
if ((plen == 0) && streq(ppath, "/")) if ((plen == 0) && streq(ppath, "/"))
return strdup(lslash+1); return strdup(lslash+1);


if (strncmp(ppath, cpath, plen) != 0) if (! strneq(ppath, cpath, plen))
return NULL; return NULL;
return strdup(lslash+1); return strdup(lslash+1);

97
livetree.c

@ -43,9 +43,7 @@ struct property *build_empty_property(char *name, char *label)
struct property *new = xmalloc(sizeof(*new)); struct property *new = xmalloc(sizeof(*new));


new->name = name; new->name = name;
new->val.len = 0; new->val = empty_data;
new->val.val = NULL;

new->next = NULL; new->next = NULL;


new->label = label; new->label = label;
@ -141,8 +139,30 @@ static struct node *get_subnode(struct node *node, char *nodename)
{ {
struct node *child; struct node *child;


for_each_child(node, child) { for_each_child(node, child)
if (strcmp(child->name, nodename) == 0) 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; 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) static int name_prop_check(struct property *prop, struct node *node)
{ {
if ((prop->val.len != node->basenamelen+1) 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", ERRMSG("name property \"%s\" does not match node basename in %s\n",
prop->val.val, prop->val.val,
node->fullpath); node->fullpath);
@ -469,7 +489,7 @@ static int check_memory(struct node *root)
int ok = 1; int ok = 1;


for_each_child(root, mem) { for_each_child(root, mem) {
if (strncmp(mem->name, "memory", mem->basenamelen) != 0) if (! strneq(mem->name, "memory", mem->basenamelen))
continue; continue;


nnodes++; nnodes++;
@ -573,6 +593,67 @@ static int check_phandles(struct node *root, struct node *node)
return 1; 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 check_device_tree(struct node *dt)
{ {
int ok = 1; 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_addr_size_reg(dt, -1, -1);
ok = ok && check_phandles(dt, dt); ok = ok && check_phandles(dt, dt);


fixup_phandles(dt, dt);

if (! ok) if (! ok)
return 0; return 0;



11
test.dts

@ -2,19 +2,19 @@
model = "MyBoardName"; model = "MyBoardName";
compatible = "MyBoardFamilyName"; compatible = "MyBoardFamilyName";
#address-cells = <2>; #address-cells = <2>;
label1: #size-cells = <2>; #size-cells = <2>;


label2: cpus { cpus {
linux,phandle = <1>; linux,phandle = <1>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
PowerPC,970@0 { PowerPC,970@0 {
linux,phandle = <3>;
name = "PowerPC,970"; name = "PowerPC,970";
device_type = "cpu"; device_type = "cpu";
reg = <0>; reg = <0>;
clock-frequency = <5f5e1000>; clock-frequency = <5f5e1000>;
linux,boot-cpu; linux,boot-cpu;
linux,phandle = <2>;
i-cache-size = <10000>; i-cache-size = <10000>;
d-cache-size = <8000>; d-cache-size = <8000>;
}; };
@ -24,18 +24,17 @@
randomnode { randomnode {
string = "\xff\0stuffstuff\t\t\t\n\n\n"; string = "\xff\0stuffstuff\t\t\t\n\n\n";
blob = [0a 0b 0c 0d de ea ad be ef]; blob = [0a 0b 0c 0d de ea ad be ef];
ref = < &/memory@0 >;
}; };


memory@0 { memory@0 {
device_type = "memory"; device_type = "memory";
reg = <00000000 00000000 00000000 20000000>; memreg: reg = <00000000 00000000 00000000 20000000>;
linux,phandle = <3>;
}; };


chosen { chosen {
bootargs = "root=/dev/sda2"; bootargs = "root=/dev/sda2";
linux,platform = <00000600>; linux,platform = <00000600>;
linux,phandle = <4>;
}; };


}; };

Loading…
Cancel
Save