symbian-qemu-0.9.1-12/dtc-trunk/flattree.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
       
     3  *
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU General Public License as
       
     7  * published by the Free Software Foundation; either version 2 of the
       
     8  * License, or (at your option) any later version.
       
     9  *
       
    10  *  This program is distributed in the hope that it will be useful,
       
    11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  *  General Public License for more details.
       
    14  *
       
    15  *  You should have received a copy of the GNU General Public License
       
    16  *  along with this program; if not, write to the Free Software
       
    17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
       
    18  *                                                                   USA
       
    19  */
       
    20 
       
    21 #include "dtc.h"
       
    22 #include "srcpos.h"
       
    23 
       
    24 #ifdef _WIN32
       
    25 #include <fcntl.h>
       
    26 #include <io.h>
       
    27 #endif
       
    28 
       
    29 #define FTF_FULLPATH	0x1
       
    30 #define FTF_VARALIGN	0x2
       
    31 #define FTF_NAMEPROPS	0x4
       
    32 #define FTF_BOOTCPUID	0x8
       
    33 #define FTF_STRTABSIZE	0x10
       
    34 #define FTF_STRUCTSIZE	0x20
       
    35 #define FTF_NOPS	0x40
       
    36 
       
    37 static struct version_info {
       
    38 	int version;
       
    39 	int last_comp_version;
       
    40 	int hdr_size;
       
    41 	int flags;
       
    42 } version_table[] = {
       
    43 	{1, 1, FDT_V1_SIZE,
       
    44 	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS},
       
    45 	{2, 1, FDT_V2_SIZE,
       
    46 	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID},
       
    47 	{3, 1, FDT_V3_SIZE,
       
    48 	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
       
    49 	{16, 16, FDT_V3_SIZE,
       
    50 	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
       
    51 	{17, 16, FDT_V17_SIZE,
       
    52 	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
       
    53 };
       
    54 
       
    55 struct emitter {
       
    56 	void (*cell)(void *, cell_t);
       
    57 	void (*string)(void *, char *, int);
       
    58 	void (*align)(void *, int);
       
    59 	void (*data)(void *, struct data);
       
    60 	void (*beginnode)(void *, const char *);
       
    61 	void (*endnode)(void *, const char *);
       
    62 	void (*property)(void *, const char *);
       
    63 };
       
    64 
       
    65 static void bin_emit_cell(void *e, cell_t val)
       
    66 {
       
    67 	struct data *dtbuf = e;
       
    68 
       
    69 	*dtbuf = data_append_cell(*dtbuf, val);
       
    70 }
       
    71 
       
    72 static void bin_emit_string(void *e, char *str, int len)
       
    73 {
       
    74 	struct data *dtbuf = e;
       
    75 
       
    76 	if (len == 0)
       
    77 		len = strlen(str);
       
    78 
       
    79 	*dtbuf = data_append_data(*dtbuf, str, len);
       
    80 	*dtbuf = data_append_byte(*dtbuf, '\0');
       
    81 }
       
    82 
       
    83 static void bin_emit_align(void *e, int a)
       
    84 {
       
    85 	struct data *dtbuf = e;
       
    86 
       
    87 	*dtbuf = data_append_align(*dtbuf, a);
       
    88 }
       
    89 
       
    90 static void bin_emit_data(void *e, struct data d)
       
    91 {
       
    92 	struct data *dtbuf = e;
       
    93 
       
    94 	*dtbuf = data_append_data(*dtbuf, d.val, d.len);
       
    95 }
       
    96 
       
    97 static void bin_emit_beginnode(void *e, const char *label)
       
    98 {
       
    99 	bin_emit_cell(e, FDT_BEGIN_NODE);
       
   100 }
       
   101 
       
   102 static void bin_emit_endnode(void *e, const char *label)
       
   103 {
       
   104 	bin_emit_cell(e, FDT_END_NODE);
       
   105 }
       
   106 
       
   107 static void bin_emit_property(void *e, const char *label)
       
   108 {
       
   109 	bin_emit_cell(e, FDT_PROP);
       
   110 }
       
   111 
       
   112 static struct emitter bin_emitter = {
       
   113 	.cell = bin_emit_cell,
       
   114 	.string = bin_emit_string,
       
   115 	.align = bin_emit_align,
       
   116 	.data = bin_emit_data,
       
   117 	.beginnode = bin_emit_beginnode,
       
   118 	.endnode = bin_emit_endnode,
       
   119 	.property = bin_emit_property,
       
   120 };
       
   121 
       
   122 static void emit_label(FILE *f, const char *prefix, const char *label)
       
   123 {
       
   124 	fprintf(f, "\t.globl\t%s_%s\n", prefix, label);
       
   125 	fprintf(f, "%s_%s:\n", prefix, label);
       
   126 	fprintf(f, "_%s_%s:\n", prefix, label);
       
   127 }
       
   128 
       
   129 static void emit_offset_label(FILE *f, const char *label, int offset)
       
   130 {
       
   131 	fprintf(f, "\t.globl\t%s\n", label);
       
   132 	fprintf(f, "%s\t= . + %d\n", label, offset);
       
   133 }
       
   134 
       
   135 static void asm_emit_cell(void *e, cell_t val)
       
   136 {
       
   137 	FILE *f = e;
       
   138 
       
   139 	fprintf(f, "\t.long\t0x%x\n", val);
       
   140 }
       
   141 
       
   142 static void asm_emit_string(void *e, char *str, int len)
       
   143 {
       
   144 	FILE *f = e;
       
   145 	char c = 0;
       
   146 
       
   147 	if (len != 0) {
       
   148 		/* XXX: ewww */
       
   149 		c = str[len];
       
   150 		str[len] = '\0';
       
   151 	}
       
   152 
       
   153 	fprintf(f, "\t.string\t\"%s\"\n", str);
       
   154 
       
   155 	if (len != 0) {
       
   156 		str[len] = c;
       
   157 	}
       
   158 }
       
   159 
       
   160 static void asm_emit_align(void *e, int a)
       
   161 {
       
   162 	FILE *f = e;
       
   163 
       
   164 	fprintf(f, "\t.balign\t%d\n", a);
       
   165 }
       
   166 
       
   167 static void asm_emit_data(void *e, struct data d)
       
   168 {
       
   169 	FILE *f = e;
       
   170 	int off = 0;
       
   171 	struct marker *m = d.markers;
       
   172 
       
   173 	for_each_marker_of_type(m, LABEL)
       
   174 		emit_offset_label(f, m->ref, m->offset);
       
   175 
       
   176 	while ((d.len - off) >= sizeof(uint32_t)) {
       
   177 		fprintf(f, "\t.long\t0x%x\n",
       
   178 			fdt32_to_cpu(*((uint32_t *)(d.val+off))));
       
   179 		off += sizeof(uint32_t);
       
   180 	}
       
   181 
       
   182 	while ((d.len - off) >= 1) {
       
   183 		fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
       
   184 		off += 1;
       
   185 	}
       
   186 
       
   187 	assert(off == d.len);
       
   188 }
       
   189 
       
   190 static void asm_emit_beginnode(void *e, const char *label)
       
   191 {
       
   192 	FILE *f = e;
       
   193 
       
   194 	if (label) {
       
   195 		fprintf(f, "\t.globl\t%s\n", label);
       
   196 		fprintf(f, "%s:\n", label);
       
   197 	}
       
   198 	fprintf(f, "\t.long\tFDT_BEGIN_NODE\n");
       
   199 }
       
   200 
       
   201 static void asm_emit_endnode(void *e, const char *label)
       
   202 {
       
   203 	FILE *f = e;
       
   204 
       
   205 	fprintf(f, "\t.long\tFDT_END_NODE\n");
       
   206 	if (label) {
       
   207 		fprintf(f, "\t.globl\t%s_end\n", label);
       
   208 		fprintf(f, "%s_end:\n", label);
       
   209 	}
       
   210 }
       
   211 
       
   212 static void asm_emit_property(void *e, const char *label)
       
   213 {
       
   214 	FILE *f = e;
       
   215 
       
   216 	if (label) {
       
   217 		fprintf(f, "\t.globl\t%s\n", label);
       
   218 		fprintf(f, "%s:\n", label);
       
   219 	}
       
   220 	fprintf(f, "\t.long\tFDT_PROP\n");
       
   221 }
       
   222 
       
   223 static struct emitter asm_emitter = {
       
   224 	.cell = asm_emit_cell,
       
   225 	.string = asm_emit_string,
       
   226 	.align = asm_emit_align,
       
   227 	.data = asm_emit_data,
       
   228 	.beginnode = asm_emit_beginnode,
       
   229 	.endnode = asm_emit_endnode,
       
   230 	.property = asm_emit_property,
       
   231 };
       
   232 
       
   233 static int stringtable_insert(struct data *d, const char *str)
       
   234 {
       
   235 	int i;
       
   236 
       
   237 	/* FIXME: do this more efficiently? */
       
   238 
       
   239 	for (i = 0; i < d->len; i++) {
       
   240 		if (streq(str, d->val + i))
       
   241 			return i;
       
   242 	}
       
   243 
       
   244 	*d = data_append_data(*d, str, strlen(str)+1);
       
   245 	return i;
       
   246 }
       
   247 
       
   248 static void flatten_tree(struct node *tree, struct emitter *emit,
       
   249 			 void *etarget, struct data *strbuf,
       
   250 			 struct version_info *vi)
       
   251 {
       
   252 	struct property *prop;
       
   253 	struct node *child;
       
   254 	int seen_name_prop = 0;
       
   255 
       
   256 	emit->beginnode(etarget, tree->label);
       
   257 
       
   258 	if (vi->flags & FTF_FULLPATH)
       
   259 		emit->string(etarget, tree->fullpath, 0);
       
   260 	else
       
   261 		emit->string(etarget, tree->name, 0);
       
   262 
       
   263 	emit->align(etarget, sizeof(cell_t));
       
   264 
       
   265 	for_each_property(tree, prop) {
       
   266 		int nameoff;
       
   267 
       
   268 		if (streq(prop->name, "name"))
       
   269 			seen_name_prop = 1;
       
   270 
       
   271 		nameoff = stringtable_insert(strbuf, prop->name);
       
   272 
       
   273 		emit->property(etarget, prop->label);
       
   274 		emit->cell(etarget, prop->val.len);
       
   275 		emit->cell(etarget, nameoff);
       
   276 
       
   277 		if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8))
       
   278 			emit->align(etarget, 8);
       
   279 
       
   280 		emit->data(etarget, prop->val);
       
   281 		emit->align(etarget, sizeof(cell_t));
       
   282 	}
       
   283 
       
   284 	if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) {
       
   285 		emit->property(etarget, NULL);
       
   286 		emit->cell(etarget, tree->basenamelen+1);
       
   287 		emit->cell(etarget, stringtable_insert(strbuf, "name"));
       
   288 
       
   289 		if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8))
       
   290 			emit->align(etarget, 8);
       
   291 
       
   292 		emit->string(etarget, tree->name, tree->basenamelen);
       
   293 		emit->align(etarget, sizeof(cell_t));
       
   294 	}
       
   295 
       
   296 	for_each_child(tree, child) {
       
   297 		flatten_tree(child, emit, etarget, strbuf, vi);
       
   298 	}
       
   299 
       
   300 	emit->endnode(etarget, tree->label);
       
   301 }
       
   302 
       
   303 static struct data flatten_reserve_list(struct reserve_info *reservelist,
       
   304 				 struct version_info *vi)
       
   305 {
       
   306 	struct reserve_info *re;
       
   307 	struct data d = empty_data;
       
   308 	static struct fdt_reserve_entry null_re = {0,0};
       
   309 	int    j;
       
   310 
       
   311 	for (re = reservelist; re; re = re->next) {
       
   312 		d = data_append_re(d, &re->re);
       
   313 	}
       
   314 	/*
       
   315 	 * Add additional reserved slots if the user asked for them.
       
   316 	 */
       
   317 	for (j = 0; j < reservenum; j++) {
       
   318 		d = data_append_re(d, &null_re);
       
   319 	}
       
   320 
       
   321 	return d;
       
   322 }
       
   323 
       
   324 static void make_fdt_header(struct fdt_header *fdt,
       
   325 			    struct version_info *vi,
       
   326 			    int reservesize, int dtsize, int strsize,
       
   327 			    int boot_cpuid_phys)
       
   328 {
       
   329 	int reserve_off;
       
   330 
       
   331 	reservesize += sizeof(struct fdt_reserve_entry);
       
   332 
       
   333 	memset(fdt, 0xff, sizeof(*fdt));
       
   334 
       
   335 	fdt->magic = cpu_to_fdt32(FDT_MAGIC);
       
   336 	fdt->version = cpu_to_fdt32(vi->version);
       
   337 	fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
       
   338 
       
   339 	/* Reserve map should be doubleword aligned */
       
   340 	reserve_off = ALIGN(vi->hdr_size, 8);
       
   341 
       
   342 	fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off);
       
   343 	fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize);
       
   344 	fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize
       
   345 					  + dtsize);
       
   346 	fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize);
       
   347 
       
   348 	if (vi->flags & FTF_BOOTCPUID)
       
   349 		fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys);
       
   350 	if (vi->flags & FTF_STRTABSIZE)
       
   351 		fdt->size_dt_strings = cpu_to_fdt32(strsize);
       
   352 	if (vi->flags & FTF_STRUCTSIZE)
       
   353 		fdt->size_dt_struct = cpu_to_fdt32(dtsize);
       
   354 }
       
   355 
       
   356 void dt_to_blob(FILE *f, struct boot_info *bi, int version)
       
   357 {
       
   358 	struct version_info *vi = NULL;
       
   359 	int i;
       
   360 	struct data blob       = empty_data;
       
   361 	struct data reservebuf = empty_data;
       
   362 	struct data dtbuf      = empty_data;
       
   363 	struct data strbuf     = empty_data;
       
   364 	struct fdt_header fdt;
       
   365 	int padlen = 0;
       
   366 
       
   367 	for (i = 0; i < ARRAY_SIZE(version_table); i++) {
       
   368 		if (version_table[i].version == version)
       
   369 			vi = &version_table[i];
       
   370 	}
       
   371 	if (!vi)
       
   372 		die("Unknown device tree blob version %d\n", version);
       
   373 
       
   374 	flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
       
   375 	bin_emit_cell(&dtbuf, FDT_END);
       
   376 
       
   377 	reservebuf = flatten_reserve_list(bi->reservelist, vi);
       
   378 
       
   379 	/* Make header */
       
   380 	make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
       
   381 			bi->boot_cpuid_phys);
       
   382 
       
   383 	/*
       
   384 	 * If the user asked for more space than is used, adjust the totalsize.
       
   385 	 */
       
   386 	if (minsize > 0) {
       
   387 		padlen = minsize - fdt32_to_cpu(fdt.totalsize);
       
   388 		if ((padlen < 0) && (quiet < 1))
       
   389 			fprintf(stderr,
       
   390 				"Warning: blob size %d >= minimum size %d\n",
       
   391 				fdt32_to_cpu(fdt.totalsize), minsize);
       
   392 	}
       
   393 
       
   394 	if (padsize > 0)
       
   395 		padlen = padsize;
       
   396 
       
   397 	if (padlen > 0) {
       
   398 		int tsize = fdt32_to_cpu(fdt.totalsize);
       
   399 		tsize += padlen;
       
   400 		fdt.totalsize = cpu_to_fdt32(tsize);
       
   401 	}
       
   402 
       
   403 	/*
       
   404 	 * Assemble the blob: start with the header, add with alignment
       
   405 	 * the reserve buffer, add the reserve map terminating zeroes,
       
   406 	 * the device tree itself, and finally the strings.
       
   407 	 */
       
   408 	blob = data_append_data(blob, &fdt, vi->hdr_size);
       
   409 	blob = data_append_align(blob, 8);
       
   410 	blob = data_merge(blob, reservebuf);
       
   411 	blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
       
   412 	blob = data_merge(blob, dtbuf);
       
   413 	blob = data_merge(blob, strbuf);
       
   414 
       
   415 	/*
       
   416 	 * If the user asked for more space than is used, pad out the blob.
       
   417 	 */
       
   418 	if (padlen > 0)
       
   419 		blob = data_append_zeroes(blob, padlen);
       
   420 
       
   421 	fwrite(blob.val, blob.len, 1, f);
       
   422 
       
   423 	if (ferror(f))
       
   424 		die("Error writing device tree blob: %s\n", strerror(errno));
       
   425 
       
   426 	/*
       
   427 	 * data_merge() frees the right-hand element so only the blob
       
   428 	 * remains to be freed.
       
   429 	 */
       
   430 	data_free(blob);
       
   431 }
       
   432 
       
   433 static void dump_stringtable_asm(FILE *f, struct data strbuf)
       
   434 {
       
   435 	const char *p;
       
   436 	int len;
       
   437 
       
   438 	p = strbuf.val;
       
   439 
       
   440 	while (p < (strbuf.val + strbuf.len)) {
       
   441 		len = strlen(p);
       
   442 		fprintf(f, "\t.string \"%s\"\n", p);
       
   443 		p += len+1;
       
   444 	}
       
   445 }
       
   446 
       
   447 void dt_to_asm(FILE *f, struct boot_info *bi, int version)
       
   448 {
       
   449 	struct version_info *vi = NULL;
       
   450 	int i;
       
   451 	struct data strbuf = empty_data;
       
   452 	struct reserve_info *re;
       
   453 	const char *symprefix = "dt";
       
   454 
       
   455 	for (i = 0; i < ARRAY_SIZE(version_table); i++) {
       
   456 		if (version_table[i].version == version)
       
   457 			vi = &version_table[i];
       
   458 	}
       
   459 	if (!vi)
       
   460 		die("Unknown device tree blob version %d\n", version);
       
   461 
       
   462 	fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
       
   463 	fprintf(f, "#define FDT_MAGIC 0x%x\n", FDT_MAGIC);
       
   464 	fprintf(f, "#define FDT_BEGIN_NODE 0x%x\n", FDT_BEGIN_NODE);
       
   465 	fprintf(f, "#define FDT_END_NODE 0x%x\n", FDT_END_NODE);
       
   466 	fprintf(f, "#define FDT_PROP 0x%x\n", FDT_PROP);
       
   467 	fprintf(f, "#define FDT_END 0x%x\n", FDT_END);
       
   468 	fprintf(f, "\n");
       
   469 
       
   470 	emit_label(f, symprefix, "blob_start");
       
   471 	emit_label(f, symprefix, "header");
       
   472 	fprintf(f, "\t.long\tFDT_MAGIC\t\t\t\t/* magic */\n");
       
   473 	fprintf(f, "\t.long\t_%s_blob_abs_end - _%s_blob_start\t/* totalsize */\n",
       
   474 		symprefix, symprefix);
       
   475 	fprintf(f, "\t.long\t_%s_struct_start - _%s_blob_start\t/* off_dt_struct */\n",
       
   476 		symprefix, symprefix);
       
   477 	fprintf(f, "\t.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n",
       
   478 		symprefix, symprefix);
       
   479 	fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n",
       
   480 		symprefix, symprefix);
       
   481 	fprintf(f, "\t.long\t%d\t\t\t\t\t/* version */\n", vi->version);
       
   482 	fprintf(f, "\t.long\t%d\t\t\t\t\t/* last_comp_version */\n",
       
   483 		vi->last_comp_version);
       
   484 
       
   485 	if (vi->flags & FTF_BOOTCPUID)
       
   486 		fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n",
       
   487 			bi->boot_cpuid_phys);
       
   488 
       
   489 	if (vi->flags & FTF_STRTABSIZE)
       
   490 		fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n",
       
   491 			symprefix, symprefix);
       
   492 
       
   493 	if (vi->flags & FTF_STRUCTSIZE)
       
   494 		fprintf(f, "\t.long\t_%s_struct_end - _%s_struct_start\t/* size_dt_struct */\n",
       
   495 			symprefix, symprefix);
       
   496 
       
   497 	/*
       
   498 	 * Reserve map entries.
       
   499 	 * Align the reserve map to a doubleword boundary.
       
   500 	 * Each entry is an (address, size) pair of u64 values.
       
   501 	 * Always supply a zero-sized temination entry.
       
   502 	 */
       
   503 	asm_emit_align(f, 8);
       
   504 	emit_label(f, symprefix, "reserve_map");
       
   505 
       
   506 	fprintf(f, "/* Memory reserve map from source file */\n");
       
   507 
       
   508 	/*
       
   509 	 * Use .long on high and low halfs of u64s to avoid .quad
       
   510 	 * as it appears .quad isn't available in some assemblers.
       
   511 	 */
       
   512 	for (re = bi->reservelist; re; re = re->next) {
       
   513 		if (re->label) {
       
   514 			fprintf(f, "\t.globl\t%s\n", re->label);
       
   515 			fprintf(f, "%s:\n", re->label);
       
   516 		}
       
   517 		fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
       
   518 			(unsigned int)(re->re.address >> 32),
       
   519 			(unsigned int)(re->re.address & 0xffffffff));
       
   520 		fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
       
   521 			(unsigned int)(re->re.size >> 32),
       
   522 			(unsigned int)(re->re.size & 0xffffffff));
       
   523 	}
       
   524 	for (i = 0; i < reservenum; i++) {
       
   525 		fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
       
   526 	}
       
   527 
       
   528 	fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
       
   529 
       
   530 	emit_label(f, symprefix, "struct_start");
       
   531 	flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
       
   532 	fprintf(f, "\t.long\tFDT_END\n");
       
   533 	emit_label(f, symprefix, "struct_end");
       
   534 
       
   535 	emit_label(f, symprefix, "strings_start");
       
   536 	dump_stringtable_asm(f, strbuf);
       
   537 	emit_label(f, symprefix, "strings_end");
       
   538 
       
   539 	emit_label(f, symprefix, "blob_end");
       
   540 
       
   541 	/*
       
   542 	 * If the user asked for more space than is used, pad it out.
       
   543 	 */
       
   544 	if (minsize > 0) {
       
   545 		fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n",
       
   546 			minsize, symprefix, symprefix);
       
   547 	}
       
   548 	if (padsize > 0) {
       
   549 		fprintf(f, "\t.space\t%d, 0\n", padsize);
       
   550 	}
       
   551 	emit_label(f, symprefix, "blob_abs_end");
       
   552 
       
   553 	data_free(strbuf);
       
   554 }
       
   555 
       
   556 struct inbuf {
       
   557 	char *base, *limit, *ptr;
       
   558 };
       
   559 
       
   560 static void inbuf_init(struct inbuf *inb, void *base, void *limit)
       
   561 {
       
   562 	inb->base = base;
       
   563 	inb->limit = limit;
       
   564 	inb->ptr = inb->base;
       
   565 }
       
   566 
       
   567 static void flat_read_chunk(struct inbuf *inb, void *p, int len)
       
   568 {
       
   569 	if ((inb->ptr + len) > inb->limit)
       
   570 		die("Premature end of data parsing flat device tree\n");
       
   571 
       
   572 	memcpy(p, inb->ptr, len);
       
   573 
       
   574 	inb->ptr += len;
       
   575 }
       
   576 
       
   577 static uint32_t flat_read_word(struct inbuf *inb)
       
   578 {
       
   579 	uint32_t val;
       
   580 
       
   581 	assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
       
   582 
       
   583 	flat_read_chunk(inb, &val, sizeof(val));
       
   584 
       
   585 	return fdt32_to_cpu(val);
       
   586 }
       
   587 
       
   588 static void flat_realign(struct inbuf *inb, int align)
       
   589 {
       
   590 	int off = inb->ptr - inb->base;
       
   591 
       
   592 	inb->ptr = inb->base + ALIGN(off, align);
       
   593 	if (inb->ptr > inb->limit)
       
   594 		die("Premature end of data parsing flat device tree\n");
       
   595 }
       
   596 
       
   597 static char *flat_read_string(struct inbuf *inb)
       
   598 {
       
   599 	int len = 0;
       
   600 	const char *p = inb->ptr;
       
   601 	char *str;
       
   602 
       
   603 	do {
       
   604 		if (p >= inb->limit)
       
   605 			die("Premature end of data parsing flat device tree\n");
       
   606 		len++;
       
   607 	} while ((*p++) != '\0');
       
   608 
       
   609 	str = strdup(inb->ptr);
       
   610 
       
   611 	inb->ptr += len;
       
   612 
       
   613 	flat_realign(inb, sizeof(uint32_t));
       
   614 
       
   615 	return str;
       
   616 }
       
   617 
       
   618 static struct data flat_read_data(struct inbuf *inb, int len)
       
   619 {
       
   620 	struct data d = empty_data;
       
   621 
       
   622 	if (len == 0)
       
   623 		return empty_data;
       
   624 
       
   625 	d = data_grow_for(d, len);
       
   626 	d.len = len;
       
   627 
       
   628 	flat_read_chunk(inb, d.val, len);
       
   629 
       
   630 	flat_realign(inb, sizeof(uint32_t));
       
   631 
       
   632 	return d;
       
   633 }
       
   634 
       
   635 static char *flat_read_stringtable(struct inbuf *inb, int offset)
       
   636 {
       
   637 	const char *p;
       
   638 
       
   639 	p = inb->base + offset;
       
   640 	while (1) {
       
   641 		if (p >= inb->limit || p < inb->base)
       
   642 			die("String offset %d overruns string table\n",
       
   643 			    offset);
       
   644 
       
   645 		if (*p == '\0')
       
   646 			break;
       
   647 
       
   648 		p++;
       
   649 	}
       
   650 
       
   651 	return strdup(inb->base + offset);
       
   652 }
       
   653 
       
   654 static struct property *flat_read_property(struct inbuf *dtbuf,
       
   655 					   struct inbuf *strbuf, int flags)
       
   656 {
       
   657 	uint32_t proplen, stroff;
       
   658 	char *name;
       
   659 	struct data val;
       
   660 
       
   661 	proplen = flat_read_word(dtbuf);
       
   662 	stroff = flat_read_word(dtbuf);
       
   663 
       
   664 	name = flat_read_stringtable(strbuf, stroff);
       
   665 
       
   666 	if ((flags & FTF_VARALIGN) && (proplen >= 8))
       
   667 		flat_realign(dtbuf, 8);
       
   668 
       
   669 	val = flat_read_data(dtbuf, proplen);
       
   670 
       
   671 	return build_property(name, val, NULL);
       
   672 }
       
   673 
       
   674 
       
   675 static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
       
   676 {
       
   677 	struct reserve_info *reservelist = NULL;
       
   678 	struct reserve_info *new;
       
   679 	const char *p;
       
   680 	struct fdt_reserve_entry re;
       
   681 
       
   682 	/*
       
   683 	 * Each entry is a pair of u64 (addr, size) values for 4 cell_t's.
       
   684 	 * List terminates at an entry with size equal to zero.
       
   685 	 *
       
   686 	 * First pass, count entries.
       
   687 	 */
       
   688 	p = inb->ptr;
       
   689 	while (1) {
       
   690 		flat_read_chunk(inb, &re, sizeof(re));
       
   691 		re.address  = fdt64_to_cpu(re.address);
       
   692 		re.size = fdt64_to_cpu(re.size);
       
   693 		if (re.size == 0)
       
   694 			break;
       
   695 
       
   696 		new = build_reserve_entry(re.address, re.size, NULL);
       
   697 		reservelist = add_reserve_entry(reservelist, new);
       
   698 	}
       
   699 
       
   700 	return reservelist;
       
   701 }
       
   702 
       
   703 
       
   704 static char *nodename_from_path(const char *ppath, const char *cpath)
       
   705 {
       
   706 	int plen;
       
   707 
       
   708 	plen = strlen(ppath);
       
   709 
       
   710 	if (!strneq(ppath, cpath, plen))
       
   711 		die("Path \"%s\" is not valid as a child of \"%s\"\n",
       
   712 		    cpath, ppath);
       
   713 
       
   714 	/* root node is a special case */
       
   715 	if (!streq(ppath, "/"))
       
   716 		plen++;
       
   717 
       
   718 	return strdup(cpath + plen);
       
   719 }
       
   720 
       
   721 static struct node *unflatten_tree(struct inbuf *dtbuf,
       
   722 				   struct inbuf *strbuf,
       
   723 				   const char *parent_flatname, int flags)
       
   724 {
       
   725 	struct node *node;
       
   726 	char *flatname;
       
   727 	uint32_t val;
       
   728 
       
   729 	node = build_node(NULL, NULL);
       
   730 
       
   731 	flatname = flat_read_string(dtbuf);
       
   732 
       
   733 	if (flags & FTF_FULLPATH)
       
   734 		node->name = nodename_from_path(parent_flatname, flatname);
       
   735 	else
       
   736 		node->name = flatname;
       
   737 
       
   738 	do {
       
   739 		struct property *prop;
       
   740 		struct node *child;
       
   741 
       
   742 		val = flat_read_word(dtbuf);
       
   743 		switch (val) {
       
   744 		case FDT_PROP:
       
   745 			if (node->children)
       
   746 				fprintf(stderr, "Warning: Flat tree input has "
       
   747 					"subnodes preceding a property.\n");
       
   748 			prop = flat_read_property(dtbuf, strbuf, flags);
       
   749 			add_property(node, prop);
       
   750 			break;
       
   751 
       
   752 		case FDT_BEGIN_NODE:
       
   753 			child = unflatten_tree(dtbuf,strbuf, flatname, flags);
       
   754 			add_child(node, child);
       
   755 			break;
       
   756 
       
   757 		case FDT_END_NODE:
       
   758 			break;
       
   759 
       
   760 		case FDT_END:
       
   761 			die("Premature FDT_END in device tree blob\n");
       
   762 			break;
       
   763 
       
   764 		case FDT_NOP:
       
   765 			if (!(flags & FTF_NOPS))
       
   766 				fprintf(stderr, "Warning: NOP tag found in flat tree"
       
   767 					" version <16\n");
       
   768 
       
   769 			/* Ignore */
       
   770 			break;
       
   771 
       
   772 		default:
       
   773 			die("Invalid opcode word %08x in device tree blob\n",
       
   774 			    val);
       
   775 		}
       
   776 	} while (val != FDT_END_NODE);
       
   777 
       
   778 	return node;
       
   779 }
       
   780 
       
   781 
       
   782 struct boot_info *dt_from_blob(const char *fname)
       
   783 {
       
   784 	struct dtc_file *dtcf;
       
   785 	uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
       
   786 	uint32_t off_dt, off_str, off_mem_rsvmap;
       
   787 	int rc;
       
   788 	char *blob;
       
   789 	struct fdt_header *fdt;
       
   790 	char *p;
       
   791 	struct inbuf dtbuf, strbuf;
       
   792 	struct inbuf memresvbuf;
       
   793 	int sizeleft;
       
   794 	struct reserve_info *reservelist;
       
   795 	struct node *tree;
       
   796 	uint32_t val;
       
   797 	int flags = 0;
       
   798 
       
   799 	dtcf = dtc_open_file(fname, NULL);
       
   800 #ifdef _WIN32
       
   801 	_setmode(_fileno(dtcf->file), _O_BINARY);
       
   802 #endif
       
   803 
       
   804 	rc = fread(&magic, sizeof(magic), 1, dtcf->file);
       
   805 	if (ferror(dtcf->file))
       
   806 		die("Error reading DT blob magic number: %s\n",
       
   807 		    strerror(errno));
       
   808 	if (rc < 1) {
       
   809 		if (feof(dtcf->file))
       
   810 			die("EOF reading DT blob magic number\n");
       
   811 		else
       
   812 			die("Mysterious short read reading magic number\n");
       
   813 	}
       
   814 
       
   815 	magic = fdt32_to_cpu(magic);
       
   816 	if (magic != FDT_MAGIC)
       
   817 		die("Blob has incorrect magic number\n");
       
   818 
       
   819 	rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file);
       
   820 	if (ferror(dtcf->file))
       
   821 		die("Error reading DT blob size: %s\n", strerror(errno));
       
   822 	if (rc < 1) {
       
   823 		if (feof(dtcf->file))
       
   824 			die("EOF reading DT blob size\n");
       
   825 		else
       
   826 			die("Mysterious short read reading blob size\n");
       
   827 	}
       
   828 
       
   829 	totalsize = fdt32_to_cpu(totalsize);
       
   830 	if (totalsize < FDT_V1_SIZE)
       
   831 		die("DT blob size (%d) is too small\n", totalsize);
       
   832 
       
   833 	blob = xmalloc(totalsize);
       
   834 
       
   835 	fdt = (struct fdt_header *)blob;
       
   836 	fdt->magic = cpu_to_fdt32(magic);
       
   837 	fdt->totalsize = cpu_to_fdt32(totalsize);
       
   838 
       
   839 	sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
       
   840 	p = blob + sizeof(magic)  + sizeof(totalsize);
       
   841 
       
   842 	while (sizeleft) {
       
   843 		if (feof(dtcf->file))
       
   844 			die("EOF before reading %d bytes of DT blob\n",
       
   845 			    totalsize);
       
   846 
       
   847 		rc = fread(p, 1, sizeleft, dtcf->file);
       
   848 		if (ferror(dtcf->file))
       
   849 			die("Error reading DT blob: %s\n",
       
   850 			    strerror(errno));
       
   851 
       
   852 		sizeleft -= rc;
       
   853 		p += rc;
       
   854 	}
       
   855 
       
   856 	off_dt = fdt32_to_cpu(fdt->off_dt_struct);
       
   857 	off_str = fdt32_to_cpu(fdt->off_dt_strings);
       
   858 	off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap);
       
   859 	version = fdt32_to_cpu(fdt->version);
       
   860 	boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys);
       
   861 
       
   862 	if (off_mem_rsvmap >= totalsize)
       
   863 		die("Mem Reserve structure offset exceeds total size\n");
       
   864 
       
   865 	if (off_dt >= totalsize)
       
   866 		die("DT structure offset exceeds total size\n");
       
   867 
       
   868 	if (off_str > totalsize)
       
   869 		die("String table offset exceeds total size\n");
       
   870 
       
   871 	if (version >= 3) {
       
   872 		uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
       
   873 		if (off_str+size_str > totalsize)
       
   874 			die("String table extends past total size\n");
       
   875 		inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
       
   876 	} else {
       
   877 		inbuf_init(&strbuf, blob + off_str, blob + totalsize);
       
   878 	}
       
   879 
       
   880 	if (version >= 17) {
       
   881 		size_dt = fdt32_to_cpu(fdt->size_dt_struct);
       
   882 		if (off_dt+size_dt > totalsize)
       
   883 			die("Structure block extends past total size\n");
       
   884 	}
       
   885 
       
   886 	if (version < 16) {
       
   887 		flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
       
   888 	} else {
       
   889 		flags |= FTF_NOPS;
       
   890 	}
       
   891 
       
   892 	inbuf_init(&memresvbuf,
       
   893 		   blob + off_mem_rsvmap, blob + totalsize);
       
   894 	inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
       
   895 
       
   896 	reservelist = flat_read_mem_reserve(&memresvbuf);
       
   897 
       
   898 	val = flat_read_word(&dtbuf);
       
   899 
       
   900 	if (val != FDT_BEGIN_NODE)
       
   901 		die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
       
   902 
       
   903 	tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
       
   904 
       
   905 	val = flat_read_word(&dtbuf);
       
   906 	if (val != FDT_END)
       
   907 		die("Device tree blob doesn't end with FDT_END\n");
       
   908 
       
   909 	free(blob);
       
   910 
       
   911 	dtc_close_file(dtcf);
       
   912 
       
   913 	return build_boot_info(reservelist, tree, boot_cpuid_phys);
       
   914 }