Browse Source

Support for specifying memreserve ranges in the source format, based on

a patch by Jon Loeliger <jdl AT freescale.com>, although tweaked
substantially.
main
David Gibson 20 years ago
parent
commit
f0517db250
  1. 2
      Makefile
  2. 7
      data.c
  3. 26
      dtc-lexer.l
  4. 39
      dtc-parser.y
  5. 18
      dtc.c
  6. 38
      dtc.h
  7. 109
      flattree.c
  8. 4
      fstree.c
  9. 12
      livetree.c
  10. 4
      test.dts
  11. 51
      treesource.c

2
Makefile

@ -14,7 +14,7 @@ dtc: $(OBJS) @@ -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) $<

7
data.c

@ -229,6 +229,13 @@ struct data data_append_cell(struct data d, cell_t word) @@ -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);

26
dtc-lexer.l

@ -22,6 +22,7 @@ @@ -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}|[/@]) @@ -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}|[/@]) @@ -116,7 +140,7 @@ REFCHAR ({PROPCHAR}|{UNITCHAR}|[/@])

<*>"//".*\n /* eat line comments */

. {
<*>. {
switch (yytext[0]) {
case '<':
DPRINT("CELLDATA\n");

39
dtc-parser.y

@ -24,7 +24,7 @@ @@ -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; @@ -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; @@ -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; @@ -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 '}' ';' {

18
dtc.c

@ -102,7 +102,7 @@ static void usage(void) @@ -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[]) @@ -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[]) @@ -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[]) @@ -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 {

38
dtc.h

@ -31,6 +31,10 @@ @@ -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; @@ -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); @@ -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); @@ -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); @@ -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 { @@ -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 */


109
flattree.c

@ -287,11 +287,12 @@ static void flatten_tree(struct node *tree, struct emitter *emit, @@ -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, @@ -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) @@ -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) @@ -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) @@ -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) @@ -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, @@ -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, @@ -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) @@ -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) @@ -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) @@ -787,5 +854,5 @@ struct node *dt_from_blob(FILE *f)

free(blob);

return tree;
return build_boot_info(mem_reserve_data, tree);
}

4
fstree.c

@ -80,7 +80,7 @@ static struct node *read_fstree(char *dirname) @@ -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) @@ -89,6 +89,6 @@ struct node *dt_from_fs(char *dirname)

fill_fullpaths(tree, "");

return tree;
return build_boot_info(empty_data, tree);
}


12
livetree.c

@ -665,3 +665,15 @@ int check_device_tree(struct node *dt) @@ -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;
}

4
test.dts

@ -1,3 +1,7 @@ @@ -1,3 +1,7 @@
/memreserve/ 1000000000000000 0000000002000000;
/memreserve/ 2000000000000000-20ffffffffffffff;
/memreserve/ 0-13;

/ {
model = "MyBoardName";
compatible = "MyBoardFamilyName";

51
treesource.c

@ -20,20 +20,35 @@ @@ -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) @@ -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) @@ -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);
}


Loading…
Cancel
Save