From 81f2e89c7551ef44a6203ab1cbb8228d09202572 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 16 Jun 2005 17:04:00 +1000 Subject: [PATCH] Rudimentary phandle reference support. --- data.c | 34 ++++++++++++++++++ dtc-lexer.l | 64 +++++++++++++++------------------- dtc-parser.y | 4 +++ dtc.h | 15 +++++++- flattree.c | 2 +- livetree.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++---- test.dts | 11 +++--- 7 files changed, 175 insertions(+), 52 deletions(-) diff --git a/data.c b/data.c index aef8c36..3c7de18 100644 --- a/data.c +++ b/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; diff --git a/dtc-lexer.l b/dtc-lexer.l index 4819e54..58fe27c 100644 --- a/dtc-lexer.l +++ b/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; } ">" { -#ifdef LEXDEBUG - fprintf(stderr, "/CELLDATA\n"); -#endif + DPRINT("/CELLDATA\n"); BEGIN(INITIAL); return '>'; } +\&{REFCHAR}* { + DPRINT("Ref: %s\n", yytext+1); + yylval.str = strdup(yytext+1); + return DT_REF; + } + [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; } "]" { -#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; } diff --git a/dtc-parser.y b/dtc-parser.y index 785acd1..ade5dea 100644 --- a/dtc-parser.y +++ b/dtc-parser.y @@ -48,6 +48,7 @@ extern struct node *device_tree; %token DT_STRING %token DT_UNIT %token DT_LABEL +%token DT_REF %type propdata %type 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; } ; diff --git a/dtc.h b/dtc.h index cbd5eb7..0a190d8 100644 --- a/dtc.h +++ b/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 */ diff --git a/flattree.c b/flattree.c index f5b7ca1..28427ab 100644 --- a/flattree.c +++ b/flattree.c @@ -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); diff --git a/livetree.c b/livetree.c index 04f5228..93387c4 100644 --- a/livetree.c +++ b/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; diff --git a/test.dts b/test.dts index dce7c52..e89632c 100644 --- a/test.dts +++ b/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>; }; };