diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | data.c | 7 | ||||
-rw-r--r-- | dtc-lexer.l | 26 | ||||
-rw-r--r-- | dtc-parser.y | 39 | ||||
-rw-r--r-- | dtc.c | 18 | ||||
-rw-r--r-- | dtc.h | 38 | ||||
-rw-r--r-- | flattree.c | 109 | ||||
-rw-r--r-- | fstree.c | 4 | ||||
-rw-r--r-- | livetree.c | 12 | ||||
-rw-r--r-- | test.dts | 4 | ||||
-rw-r--r-- | treesource.c | 51 |
11 files changed, 257 insertions, 53 deletions
@@ -14,7 +14,7 @@ dtc: $(OBJS) $(LINK.c) -o $@ $^ dtc-parser.tab.c dtc-parser.tab.h dtc-parser.output: dtc-parser.y - $(BISON) -d -v $< + $(BISON) -d $< lex.yy.c: dtc-lexer.l $(LEX) $< @@ -229,6 +229,13 @@ struct data data_append_cell(struct data d, cell_t word) return data_append_data(d, &beword, sizeof(beword)); } +struct data data_append_addr(struct data d, u64 addr) +{ + u64 beaddr = cpu_to_be64(addr); + + return data_append_data(d, &beaddr, sizeof(beaddr)); +} + struct data data_append_byte(struct data d, uint8_t byte) { return data_append_data(d, &byte, 1); diff --git a/dtc-lexer.l b/dtc-lexer.l index 0f94dfc..cd3229f 100644 --- a/dtc-lexer.l +++ b/dtc-lexer.l @@ -22,6 +22,7 @@ %x CELLDATA %x BYTESTRING +%x MEMRESERVE PROPCHAR [a-zA-Z0-9,._+*#?-] UNITCHAR [0-9a-f,] @@ -53,6 +54,29 @@ REFCHAR ({PROPCHAR}|{UNITCHAR}|[/@]) return DT_STRING; } +"/memreserve/" { + DPRINT("Keyword: /memreserve/\n"); + BEGIN(MEMRESERVE); + return DT_MEMRESERVE; + } + +<MEMRESERVE>[0-9a-fA-F]+ { + if (yyleng > 2*sizeof(yylval.addr)) { + fprintf(stderr, "Address value %s too large\n", + yytext); + } + yylval.addr = (u64) strtoull(yytext, NULL, 16); + DPRINT("Addr: %llx\n", + (unsigned long long)yylval.addr); + return DT_ADDR; + } + +<MEMRESERVE>";" { + DPRINT("/MEMRESERVE\n"); + BEGIN(INITIAL); + return ';'; + } + <CELLDATA>[0-9a-fA-F]+ { if (yyleng > 2*sizeof(yylval.cval)) { fprintf(stderr, @@ -116,7 +140,7 @@ REFCHAR ({PROPCHAR}|{UNITCHAR}|[/@]) <*>"//".*\n /* eat line comments */ -. { +<*>. { switch (yytext[0]) { case '<': DPRINT("CELLDATA\n"); diff --git a/dtc-parser.y b/dtc-parser.y index e833627..66e243d 100644 --- a/dtc-parser.y +++ b/dtc-parser.y @@ -24,7 +24,7 @@ int yylex (void); void yyerror (char const *); -extern struct node *device_tree; +extern struct boot_info *the_boot_info; %} @@ -39,8 +39,12 @@ extern struct node *device_tree; struct node *nodelist; int datalen; int hexlen; + u64 addr; + struct reserve_entry re; } +%token DT_MEMRESERVE +%token <addr> DT_ADDR %token <str> DT_PROPNAME %token <str> DT_NODENAME %token <cval> DT_CELL @@ -51,11 +55,14 @@ extern struct node *device_tree; %token <str> DT_REF %type <data> propdata +%type <re> memreserve +%type <data> memreserves %type <data> celllist %type <data> bytestring %type <prop> propdef %type <proplist> proplist +%type <node> devicetree %type <node> nodedef %type <node> subnode %type <nodelist> subnodes @@ -66,9 +73,33 @@ extern struct node *device_tree; %% -devicetree: { - assert(device_tree == NULL); - } '/' nodedef { device_tree = name_node($3, "", NULL); } +sourcefile: memreserves devicetree { + the_boot_info = build_boot_info($1, $2); + } + ; + +memreserves: memreserves memreserve { + $$ = data_append_addr(data_append_addr($1, $2.address), + $2.size); + } + | /* empty */ { + $$ = empty_data; + } + ; + +memreserve: DT_MEMRESERVE DT_ADDR DT_ADDR ';' { + $$.address = $2; + $$.size = $3; + } + | DT_MEMRESERVE DT_ADDR '-' DT_ADDR ';' { + $$.address = $2; + $$.size = $4 - $2 + 1; + } + ; + +devicetree: '/' nodedef { + $$ = name_node($2, "", NULL); + } ; nodedef: '{' proplist subnodes '}' ';' { @@ -102,7 +102,7 @@ static void usage(void) int main(int argc, char *argv[]) { - struct node *dt; + struct boot_info *bi; char *inform = "dts"; char *outform = "dts"; char *outname = "-"; @@ -151,12 +151,12 @@ int main(int argc, char *argv[]) if (streq(inform, "dts")) { inf = dtc_open_file(arg); - dt = dt_from_source(inf); + bi = dt_from_source(inf); } else if (streq(inform, "fs")) { - dt = dt_from_fs(arg); + bi = dt_from_fs(arg); } else if(streq(inform, "dtb")) { inf = dtc_open_file(arg); - dt = dt_from_blob(inf); + bi = dt_from_blob(inf); } else { die("Unknown input format \"%s\"\n", inform); } @@ -164,10 +164,10 @@ int main(int argc, char *argv[]) if (inf && (inf != stdin)) fclose(inf); - if (! dt) + if (! bi || ! bi->dt) die("Couldn't read input tree\n"); - if (! check_device_tree(dt)) { + if (! check_device_tree(bi->dt)) { fprintf(stderr, "Input tree has errors\n"); if (! force) exit(1); @@ -183,11 +183,11 @@ int main(int argc, char *argv[]) } if (streq(outform, "dts")) { - write_tree_source(outf, dt, 0); + write_tree_source(outf, bi); } else if (streq(outform, "dtb")) { - write_dt_blob(outf, dt, outversion, reservenum); + write_dt_blob(outf, bi, outversion); } else if (streq(outform, "asm")) { - write_dt_asm(outf, dt, outversion, reservenum); + write_dt_asm(outf, bi, outversion); } else if (streq(outform, "null")) { /* do nothing */ } else { @@ -31,6 +31,10 @@ #include <errno.h> #include <unistd.h> #include <netinet/in.h> +#include <endian.h> +#include <byteswap.h> + +#include "flat_dt.h" static inline void die(char * str, ...) { @@ -74,7 +78,13 @@ typedef u32 cell_t; #define cpu_to_be32(x) htonl(x) #define be32_to_cpu(x) ntohl(x) - +#if __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_be64(x) (x) +#define be64_to_cpu(x) (x) +#else +#define cpu_to_be64(x) bswap_64(x) +#define be64_to_cpu(x) bswap_64(x) +#endif #define streq(a, b) (strcmp((a), (b)) == 0) #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) @@ -110,6 +120,7 @@ struct data data_copy_file(FILE *f, size_t len); struct data data_append_data(struct data d, void *p, int len); struct data data_append_cell(struct data d, cell_t word); +struct data data_append_addr(struct data d, u64 addr); 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); @@ -118,6 +129,8 @@ struct data data_add_fixup(struct data d, char *ref); int data_is_one_string(struct data d); +struct data build_mem_reserve(struct data d); + /* DT constraints */ #define MAX_PROPNAME_LEN 31 @@ -168,6 +181,16 @@ void add_child(struct node *parent, struct node *child); int check_device_tree(struct node *dt); +/* Boot info (tree plus memreserve information */ + +struct boot_info { + struct data mem_reserve_data; /* mem reserve from header */ + struct node *dt; /* the device tree */ +}; + +struct boot_info *build_boot_info(struct data mem_reserve_data, + struct node *tree); + /* Flattened trees */ enum flat_dt_format { @@ -175,20 +198,19 @@ enum flat_dt_format { FFMT_ASM, }; -void write_dt_blob(FILE *f, struct node *tree, int version, int reservenum); -void write_dt_asm(FILE *f, struct node *tree, int version, int reservenum); +void write_dt_blob(FILE *f, struct boot_info *bi, int version); +void write_dt_asm(FILE *f, struct boot_info *bi, int version); -struct node *dt_from_blob(FILE *f); +struct boot_info *dt_from_blob(FILE *f); /* Tree source */ -void write_tree_source(FILE *f, struct node *tree, int level); - -struct node *dt_from_source(FILE *f); +void write_tree_source(FILE *f, struct boot_info *bi); +struct boot_info *dt_from_source(FILE *f); /* FS trees */ -struct node *dt_from_fs(char *dirname); +struct boot_info *dt_from_fs(char *dirname); /* misc */ @@ -287,11 +287,12 @@ static void flatten_tree(struct node *tree, struct emitter *emit, } static void make_bph(struct boot_param_header *bph, - struct version_info *vi, - int reservenum, - int dtsize, int strsize) + struct version_info *vi, + struct data *mem_reserve_data, + int dtsize, int strsize) { int reserve_off; + int reservenum = mem_reserve_data->len / sizeof(struct reserve_entry); int reservesize = (reservenum+1) * sizeof(struct reserve_entry); memset(bph, 0xff, sizeof(*bph)); @@ -316,14 +317,14 @@ static void make_bph(struct boot_param_header *bph, bph->size_dt_strings = cpu_to_be32(strsize); } -void write_dt_blob(FILE *f, struct node *tree, int version, int reservenum) +void write_dt_blob(FILE *f, struct boot_info *bi, int version) { struct version_info *vi = NULL; int i; struct data dtbuf = empty_data; struct data strbuf = empty_data; struct boot_param_header bph; - struct reserve_entry re = {.address = 0, .size = 0}; + struct reserve_entry termre = {.address = 0, .size = 0}; for (i = 0; i < ARRAY_SIZE(version_table); i++) { if (version_table[i].version == version) @@ -335,10 +336,11 @@ void write_dt_blob(FILE *f, struct node *tree, int version, int reservenum) dtbuf = empty_data; strbuf = empty_data; - flatten_tree(tree, &bin_emitter, &dtbuf, &strbuf, vi); + flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi); bin_emit_cell(&dtbuf, OF_DT_END); - make_bph(&bph, vi, reservenum, dtbuf.len, strbuf.len); + /* Make header */ + make_bph(&bph, vi, &bi->mem_reserve_data, dtbuf.len, strbuf.len); fwrite(&bph, vi->hdr_size, 1, f); @@ -346,8 +348,15 @@ void write_dt_blob(FILE *f, struct node *tree, int version, int reservenum) for (i = vi->hdr_size; i < be32_to_cpu(bph.off_mem_rsvmap); i++) fputc(0, f); - for (i = 0; i < reservenum+1; i++) - fwrite(&re, sizeof(re), 1, f); + /* + * Reserve map entries. + * Since the blob is relocatable, the address of the map is not + * determinable here, so no entry is made for the DT itself. + * Each entry is an (address, size) pair of u64 values. + * Always supply a zero-sized temination entry. + */ + fwrite(bi->mem_reserve_data.val, bi->mem_reserve_data.len, 1, f); + fwrite(&termre, sizeof(termre), 1, f); fwrite(dtbuf.val, dtbuf.len, 1, f); fwrite(strbuf.val, strbuf.len, 1, f); @@ -373,7 +382,7 @@ void dump_stringtable_asm(FILE *f, struct data strbuf) } } -void write_dt_asm(FILE *f, struct node *tree, int version, int reservenum) +void write_dt_asm(FILE *f, struct boot_info *bi, int version) { struct version_info *vi = NULL; int i; @@ -417,20 +426,30 @@ void write_dt_asm(FILE *f, struct node *tree, int version, int reservenum) fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n", symprefix, symprefix); - /* align the reserve map to a doubleword boundary */ + /* + * Reserve map entries. + * Align the reserve map to a doubleword boundary. + * Each entry is an (address, size) pair of u64 values. + * Since the ASM file variant can relocate and compute the address + * and size of the the device tree itself, and an entry for it. + * Always supply a zero-sized temination entry. + */ asm_emit_align(f, 8); emit_label(f, symprefix, "reserve_map"); - /* reserve map entry for the device tree itself */ fprintf(f, "\t.long\t0, _%s_blob_start\n", symprefix); fprintf(f, "\t.long\t0, _%s_blob_end - _%s_blob_start\n", symprefix, symprefix); - for (i = 0; i < reservenum+1; i++) { - fprintf(f, "\t.llong\t0\n"); - fprintf(f, "\t.llong\t0\n"); + + if (bi->mem_reserve_data.len > 0) { + fprintf(f, "/* Memory reserve map from source file */\n"); + asm_emit_data(f, bi->mem_reserve_data); } + fprintf(f, "\t.llong\t0\n"); + fprintf(f, "\t.llong\t0\n"); + emit_label(f, symprefix, "struct_start"); - flatten_tree(tree, &asm_emitter, f, &strbuf, vi); + flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi); fprintf(f, "\t.long\tOF_DT_END\n"); emit_label(f, symprefix, "struct_end"); @@ -561,6 +580,43 @@ struct property *flat_read_property(struct inbuf *dtbuf, struct inbuf *strbuf, return build_property(name, val, NULL); } + +static struct data flat_read_mem_reserve(struct inbuf *inb) +{ + char *p; + int len = 0; + int done = 0; + cell_t cells[4]; + struct data d; + + d = empty_data; + + /* + * Each entry is a pair of u64 (addr, size) values for 4 cell_t's. + * List terminates at an entry with size equal to zero. + * + * First pass, count entries. + */ + p = inb->ptr; + do { + flat_read_chunk(inb, &cells[0], 4 * sizeof(cell_t)); + if (cells[2] == 0 && cells[3] == 0) { + done = 1; + } else { + ++len; + } + } while (!done); + + /* + * Back up for pass two, reading the whole data value. + */ + inb->ptr = p; + d = flat_read_data(inb, len * 4 * sizeof(cell_t)); + + return d; +} + + static char *nodename_from_path(char *ppath, char *cpath) { char *lslash; @@ -668,15 +724,19 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, return node; } -struct node *dt_from_blob(FILE *f) + +struct boot_info *dt_from_blob(FILE *f) { - u32 magic, totalsize, off_dt, off_str, version, size_str; + u32 magic, totalsize, version, size_str; + u32 off_dt, off_str, off_mem_rsvmap; int rc; char *blob; struct boot_param_header *bph; char *p; struct inbuf dtbuf, strbuf; + struct inbuf memresvbuf; int sizeleft; + struct data mem_reserve_data; struct node *tree; u32 val; int flags = 0; @@ -735,18 +795,21 @@ struct node *dt_from_blob(FILE *f) off_dt = be32_to_cpu(bph->off_dt_struct); off_str = be32_to_cpu(bph->off_dt_strings); + off_mem_rsvmap = be32_to_cpu(bph->off_mem_rsvmap); version = be32_to_cpu(bph->version); fprintf(stderr, "\tmagic:\t\t\t0x%x\n", magic); fprintf(stderr, "\ttotalsize:\t\t%d\n", totalsize); fprintf(stderr, "\toff_dt_struct:\t\t0x%x\n", off_dt); fprintf(stderr, "\toff_dt_strings:\t\t0x%x\n", off_str); - fprintf(stderr, "\toff_mem_rsvmap:\t\t0x%x\n", - be32_to_cpu(bph->off_mem_rsvmap)); + fprintf(stderr, "\toff_mem_rsvmap:\t\t0x%x\n", off_mem_rsvmap); fprintf(stderr, "\tversion:\t\t0x%x\n", version ); fprintf(stderr, "\tlast_comp_version:\t0x%x\n", be32_to_cpu(bph->last_comp_version)); + if (off_mem_rsvmap >= totalsize) + die("Mem Reserve structure offset exceeds total size\n"); + if (off_dt >= totalsize) die("DT structure offset exceeds total size\n"); @@ -768,12 +831,16 @@ struct node *dt_from_blob(FILE *f) flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN; } + inbuf_init(&memresvbuf, + blob + off_mem_rsvmap, blob + totalsize); inbuf_init(&dtbuf, blob + off_dt, blob + totalsize); inbuf_init(&strbuf, blob + off_str, blob + totalsize); if (version >= 3) strbuf.limit = strbuf.base + size_str; + mem_reserve_data = flat_read_mem_reserve(&memresvbuf); + val = flat_read_word(&dtbuf); if (val != OF_DT_BEGIN_NODE) @@ -787,5 +854,5 @@ struct node *dt_from_blob(FILE *f) free(blob); - return tree; + return build_boot_info(mem_reserve_data, tree); } @@ -80,7 +80,7 @@ static struct node *read_fstree(char *dirname) return tree; } -struct node *dt_from_fs(char *dirname) +struct boot_info *dt_from_fs(char *dirname) { struct node *tree; @@ -89,6 +89,6 @@ struct node *dt_from_fs(char *dirname) fill_fullpaths(tree, ""); - return tree; + return build_boot_info(empty_data, tree); } @@ -665,3 +665,15 @@ int check_device_tree(struct node *dt) return 1; } + +struct boot_info *build_boot_info(struct data mem_reserve_data, + struct node *tree) +{ + struct boot_info *bi; + + bi = xmalloc(sizeof(*bi)); + bi->mem_reserve_data = mem_reserve_data; + bi->dt = tree; + + return bi; +} @@ -1,3 +1,7 @@ +/memreserve/ 1000000000000000 0000000002000000; +/memreserve/ 2000000000000000-20ffffffffffffff; +/memreserve/ 0-13; + / { model = "MyBoardName"; compatible = "MyBoardFamilyName"; diff --git a/treesource.c b/treesource.c index 6b0c974..ee0a7b8 100644 --- a/treesource.c +++ b/treesource.c @@ -20,20 +20,35 @@ #include "dtc.h" -struct node *device_tree; - extern FILE *yyin; extern int yyparse(void); +extern void yyerror(char const *); + +struct boot_info *the_boot_info; + +struct data build_mem_reserve(struct data d) +{ + /* + * FIXME: Should reconcile the -R parameter here now? + */ + if (d.len % 16 != 0) { + yyerror("Memory Reserve entries are <u64 addr, u64 size>\n"); + } + return d; +} + -struct node *dt_from_source(FILE *f) +struct boot_info *dt_from_source(FILE *f) { + the_boot_info = NULL; + yyin = f; if (yyparse() != 0) return NULL; - fill_fullpaths(device_tree, ""); + fill_fullpaths(the_boot_info->dt, ""); - return device_tree; + return the_boot_info; } static void write_prefix(FILE *f, int level) @@ -75,7 +90,8 @@ static enum proptype guess_type(struct property *prop) } -void write_tree_source(FILE *f, struct node *tree, int level) + +void write_tree_source_node(FILE *f, struct node *tree, int level) { struct property *prop; struct node *child; @@ -133,8 +149,29 @@ void write_tree_source(FILE *f, struct node *tree, int level) } for_each_child(tree, child) { fprintf(f, "\n"); - write_tree_source(f, child, level+1); + write_tree_source_node(f, child, level+1); } write_prefix(f, level); fprintf(f, "};\n"); } + + +void write_tree_source(FILE *f, struct boot_info *bi) +{ + int i; + + assert((bi->mem_reserve_data.len % sizeof(struct reserve_entry)) == 0); + for (i = 0; + i < (bi->mem_reserve_data.len / sizeof(struct reserve_entry)); + i++) { + struct reserve_entry *re = ((struct reserve_entry *) + bi->mem_reserve_data.val) + i; + + fprintf(f, "/memreserve/\t%016llx-%016llx;\n", + (unsigned long long)re->address, + (unsigned long long)re->address + re->size - 1); + } + + write_tree_source_node(f, bi->dt, 0); +} + |