flattree.c revision 204431
1204431Sraj/* 2204431Sraj * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. 3204431Sraj * 4204431Sraj * 5204431Sraj * This program is free software; you can redistribute it and/or 6204431Sraj * modify it under the terms of the GNU General Public License as 7204431Sraj * published by the Free Software Foundation; either version 2 of the 8204431Sraj * License, or (at your option) any later version. 9204431Sraj * 10204431Sraj * This program is distributed in the hope that it will be useful, 11204431Sraj * but WITHOUT ANY WARRANTY; without even the implied warranty of 12204431Sraj * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13204431Sraj * General Public License for more details. 14204431Sraj * 15204431Sraj * You should have received a copy of the GNU General Public License 16204431Sraj * along with this program; if not, write to the Free Software 17204431Sraj * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18204431Sraj * USA 19204431Sraj */ 20204431Sraj 21204431Sraj#include "dtc.h" 22204431Sraj#include "srcpos.h" 23204431Sraj 24204431Sraj#define FTF_FULLPATH 0x1 25204431Sraj#define FTF_VARALIGN 0x2 26204431Sraj#define FTF_NAMEPROPS 0x4 27204431Sraj#define FTF_BOOTCPUID 0x8 28204431Sraj#define FTF_STRTABSIZE 0x10 29204431Sraj#define FTF_STRUCTSIZE 0x20 30204431Sraj#define FTF_NOPS 0x40 31204431Sraj 32204431Srajstatic struct version_info { 33204431Sraj int version; 34204431Sraj int last_comp_version; 35204431Sraj int hdr_size; 36204431Sraj int flags; 37204431Sraj} version_table[] = { 38204431Sraj {1, 1, FDT_V1_SIZE, 39204431Sraj FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS}, 40204431Sraj {2, 1, FDT_V2_SIZE, 41204431Sraj FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID}, 42204431Sraj {3, 1, FDT_V3_SIZE, 43204431Sraj FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE}, 44204431Sraj {16, 16, FDT_V3_SIZE, 45204431Sraj FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS}, 46204431Sraj {17, 16, FDT_V17_SIZE, 47204431Sraj FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS}, 48204431Sraj}; 49204431Sraj 50204431Srajstruct emitter { 51204431Sraj void (*cell)(void *, cell_t); 52204431Sraj void (*string)(void *, char *, int); 53204431Sraj void (*align)(void *, int); 54204431Sraj void (*data)(void *, struct data); 55204431Sraj void (*beginnode)(void *, const char *); 56204431Sraj void (*endnode)(void *, const char *); 57204431Sraj void (*property)(void *, const char *); 58204431Sraj}; 59204431Sraj 60204431Srajstatic void bin_emit_cell(void *e, cell_t val) 61204431Sraj{ 62204431Sraj struct data *dtbuf = e; 63204431Sraj 64204431Sraj *dtbuf = data_append_cell(*dtbuf, val); 65204431Sraj} 66204431Sraj 67204431Srajstatic void bin_emit_string(void *e, char *str, int len) 68204431Sraj{ 69204431Sraj struct data *dtbuf = e; 70204431Sraj 71204431Sraj if (len == 0) 72204431Sraj len = strlen(str); 73204431Sraj 74204431Sraj *dtbuf = data_append_data(*dtbuf, str, len); 75204431Sraj *dtbuf = data_append_byte(*dtbuf, '\0'); 76204431Sraj} 77204431Sraj 78204431Srajstatic void bin_emit_align(void *e, int a) 79204431Sraj{ 80204431Sraj struct data *dtbuf = e; 81204431Sraj 82204431Sraj *dtbuf = data_append_align(*dtbuf, a); 83204431Sraj} 84204431Sraj 85204431Srajstatic void bin_emit_data(void *e, struct data d) 86204431Sraj{ 87204431Sraj struct data *dtbuf = e; 88204431Sraj 89204431Sraj *dtbuf = data_append_data(*dtbuf, d.val, d.len); 90204431Sraj} 91204431Sraj 92204431Srajstatic void bin_emit_beginnode(void *e, const char *label) 93204431Sraj{ 94204431Sraj bin_emit_cell(e, FDT_BEGIN_NODE); 95204431Sraj} 96204431Sraj 97204431Srajstatic void bin_emit_endnode(void *e, const char *label) 98204431Sraj{ 99204431Sraj bin_emit_cell(e, FDT_END_NODE); 100204431Sraj} 101204431Sraj 102204431Srajstatic void bin_emit_property(void *e, const char *label) 103204431Sraj{ 104204431Sraj bin_emit_cell(e, FDT_PROP); 105204431Sraj} 106204431Sraj 107204431Srajstatic struct emitter bin_emitter = { 108204431Sraj .cell = bin_emit_cell, 109204431Sraj .string = bin_emit_string, 110204431Sraj .align = bin_emit_align, 111204431Sraj .data = bin_emit_data, 112204431Sraj .beginnode = bin_emit_beginnode, 113204431Sraj .endnode = bin_emit_endnode, 114204431Sraj .property = bin_emit_property, 115204431Sraj}; 116204431Sraj 117204431Srajstatic void emit_label(FILE *f, const char *prefix, const char *label) 118204431Sraj{ 119204431Sraj fprintf(f, "\t.globl\t%s_%s\n", prefix, label); 120204431Sraj fprintf(f, "%s_%s:\n", prefix, label); 121204431Sraj fprintf(f, "_%s_%s:\n", prefix, label); 122204431Sraj} 123204431Sraj 124204431Srajstatic void emit_offset_label(FILE *f, const char *label, int offset) 125204431Sraj{ 126204431Sraj fprintf(f, "\t.globl\t%s\n", label); 127204431Sraj fprintf(f, "%s\t= . + %d\n", label, offset); 128204431Sraj} 129204431Sraj 130204431Srajstatic void asm_emit_cell(void *e, cell_t val) 131204431Sraj{ 132204431Sraj FILE *f = e; 133204431Sraj 134204431Sraj fprintf(f, "\t.long\t0x%x\n", val); 135204431Sraj} 136204431Sraj 137204431Srajstatic void asm_emit_string(void *e, char *str, int len) 138204431Sraj{ 139204431Sraj FILE *f = e; 140204431Sraj char c = 0; 141204431Sraj 142204431Sraj if (len != 0) { 143204431Sraj /* XXX: ewww */ 144204431Sraj c = str[len]; 145204431Sraj str[len] = '\0'; 146204431Sraj } 147204431Sraj 148204431Sraj fprintf(f, "\t.string\t\"%s\"\n", str); 149204431Sraj 150204431Sraj if (len != 0) { 151204431Sraj str[len] = c; 152204431Sraj } 153204431Sraj} 154204431Sraj 155204431Srajstatic void asm_emit_align(void *e, int a) 156204431Sraj{ 157204431Sraj FILE *f = e; 158204431Sraj 159204431Sraj fprintf(f, "\t.balign\t%d\n", a); 160204431Sraj} 161204431Sraj 162204431Srajstatic void asm_emit_data(void *e, struct data d) 163204431Sraj{ 164204431Sraj FILE *f = e; 165204431Sraj int off = 0; 166204431Sraj struct marker *m = d.markers; 167204431Sraj 168204431Sraj for_each_marker_of_type(m, LABEL) 169204431Sraj emit_offset_label(f, m->ref, m->offset); 170204431Sraj 171204431Sraj while ((d.len - off) >= sizeof(uint32_t)) { 172204431Sraj fprintf(f, "\t.long\t0x%x\n", 173204431Sraj fdt32_to_cpu(*((uint32_t *)(d.val+off)))); 174204431Sraj off += sizeof(uint32_t); 175204431Sraj } 176204431Sraj 177204431Sraj while ((d.len - off) >= 1) { 178204431Sraj fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]); 179204431Sraj off += 1; 180204431Sraj } 181204431Sraj 182204431Sraj assert(off == d.len); 183204431Sraj} 184204431Sraj 185204431Srajstatic void asm_emit_beginnode(void *e, const char *label) 186204431Sraj{ 187204431Sraj FILE *f = e; 188204431Sraj 189204431Sraj if (label) { 190204431Sraj fprintf(f, "\t.globl\t%s\n", label); 191204431Sraj fprintf(f, "%s:\n", label); 192204431Sraj } 193204431Sraj fprintf(f, "\t.long\tFDT_BEGIN_NODE\n"); 194204431Sraj} 195204431Sraj 196204431Srajstatic void asm_emit_endnode(void *e, const char *label) 197204431Sraj{ 198204431Sraj FILE *f = e; 199204431Sraj 200204431Sraj fprintf(f, "\t.long\tFDT_END_NODE\n"); 201204431Sraj if (label) { 202204431Sraj fprintf(f, "\t.globl\t%s_end\n", label); 203204431Sraj fprintf(f, "%s_end:\n", label); 204204431Sraj } 205204431Sraj} 206204431Sraj 207204431Srajstatic void asm_emit_property(void *e, const char *label) 208204431Sraj{ 209204431Sraj FILE *f = e; 210204431Sraj 211204431Sraj if (label) { 212204431Sraj fprintf(f, "\t.globl\t%s\n", label); 213204431Sraj fprintf(f, "%s:\n", label); 214204431Sraj } 215204431Sraj fprintf(f, "\t.long\tFDT_PROP\n"); 216204431Sraj} 217204431Sraj 218204431Srajstatic struct emitter asm_emitter = { 219204431Sraj .cell = asm_emit_cell, 220204431Sraj .string = asm_emit_string, 221204431Sraj .align = asm_emit_align, 222204431Sraj .data = asm_emit_data, 223204431Sraj .beginnode = asm_emit_beginnode, 224204431Sraj .endnode = asm_emit_endnode, 225204431Sraj .property = asm_emit_property, 226204431Sraj}; 227204431Sraj 228204431Srajstatic int stringtable_insert(struct data *d, const char *str) 229204431Sraj{ 230204431Sraj int i; 231204431Sraj 232204431Sraj /* FIXME: do this more efficiently? */ 233204431Sraj 234204431Sraj for (i = 0; i < d->len; i++) { 235204431Sraj if (streq(str, d->val + i)) 236204431Sraj return i; 237204431Sraj } 238204431Sraj 239204431Sraj *d = data_append_data(*d, str, strlen(str)+1); 240204431Sraj return i; 241204431Sraj} 242204431Sraj 243204431Srajstatic void flatten_tree(struct node *tree, struct emitter *emit, 244204431Sraj void *etarget, struct data *strbuf, 245204431Sraj struct version_info *vi) 246204431Sraj{ 247204431Sraj struct property *prop; 248204431Sraj struct node *child; 249204431Sraj int seen_name_prop = 0; 250204431Sraj 251204431Sraj emit->beginnode(etarget, tree->label); 252204431Sraj 253204431Sraj if (vi->flags & FTF_FULLPATH) 254204431Sraj emit->string(etarget, tree->fullpath, 0); 255204431Sraj else 256204431Sraj emit->string(etarget, tree->name, 0); 257204431Sraj 258204431Sraj emit->align(etarget, sizeof(cell_t)); 259204431Sraj 260204431Sraj for_each_property(tree, prop) { 261204431Sraj int nameoff; 262204431Sraj 263204431Sraj if (streq(prop->name, "name")) 264204431Sraj seen_name_prop = 1; 265204431Sraj 266204431Sraj nameoff = stringtable_insert(strbuf, prop->name); 267204431Sraj 268204431Sraj emit->property(etarget, prop->label); 269204431Sraj emit->cell(etarget, prop->val.len); 270204431Sraj emit->cell(etarget, nameoff); 271204431Sraj 272204431Sraj if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8)) 273204431Sraj emit->align(etarget, 8); 274204431Sraj 275204431Sraj emit->data(etarget, prop->val); 276204431Sraj emit->align(etarget, sizeof(cell_t)); 277204431Sraj } 278204431Sraj 279204431Sraj if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) { 280204431Sraj emit->property(etarget, NULL); 281204431Sraj emit->cell(etarget, tree->basenamelen+1); 282204431Sraj emit->cell(etarget, stringtable_insert(strbuf, "name")); 283204431Sraj 284204431Sraj if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8)) 285204431Sraj emit->align(etarget, 8); 286204431Sraj 287204431Sraj emit->string(etarget, tree->name, tree->basenamelen); 288204431Sraj emit->align(etarget, sizeof(cell_t)); 289204431Sraj } 290204431Sraj 291204431Sraj for_each_child(tree, child) { 292204431Sraj flatten_tree(child, emit, etarget, strbuf, vi); 293204431Sraj } 294204431Sraj 295204431Sraj emit->endnode(etarget, tree->label); 296204431Sraj} 297204431Sraj 298204431Srajstatic struct data flatten_reserve_list(struct reserve_info *reservelist, 299204431Sraj struct version_info *vi) 300204431Sraj{ 301204431Sraj struct reserve_info *re; 302204431Sraj struct data d = empty_data; 303204431Sraj static struct fdt_reserve_entry null_re = {0,0}; 304204431Sraj int j; 305204431Sraj 306204431Sraj for (re = reservelist; re; re = re->next) { 307204431Sraj d = data_append_re(d, &re->re); 308204431Sraj } 309204431Sraj /* 310204431Sraj * Add additional reserved slots if the user asked for them. 311204431Sraj */ 312204431Sraj for (j = 0; j < reservenum; j++) { 313204431Sraj d = data_append_re(d, &null_re); 314204431Sraj } 315204431Sraj 316204431Sraj return d; 317204431Sraj} 318204431Sraj 319204431Srajstatic void make_fdt_header(struct fdt_header *fdt, 320204431Sraj struct version_info *vi, 321204431Sraj int reservesize, int dtsize, int strsize, 322204431Sraj int boot_cpuid_phys) 323204431Sraj{ 324204431Sraj int reserve_off; 325204431Sraj 326204431Sraj reservesize += sizeof(struct fdt_reserve_entry); 327204431Sraj 328204431Sraj memset(fdt, 0xff, sizeof(*fdt)); 329204431Sraj 330204431Sraj fdt->magic = cpu_to_fdt32(FDT_MAGIC); 331204431Sraj fdt->version = cpu_to_fdt32(vi->version); 332204431Sraj fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version); 333204431Sraj 334204431Sraj /* Reserve map should be doubleword aligned */ 335204431Sraj reserve_off = ALIGN(vi->hdr_size, 8); 336204431Sraj 337204431Sraj fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off); 338204431Sraj fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize); 339204431Sraj fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize 340204431Sraj + dtsize); 341204431Sraj fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize); 342204431Sraj 343204431Sraj if (vi->flags & FTF_BOOTCPUID) 344204431Sraj fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys); 345204431Sraj if (vi->flags & FTF_STRTABSIZE) 346204431Sraj fdt->size_dt_strings = cpu_to_fdt32(strsize); 347204431Sraj if (vi->flags & FTF_STRUCTSIZE) 348204431Sraj fdt->size_dt_struct = cpu_to_fdt32(dtsize); 349204431Sraj} 350204431Sraj 351204431Srajvoid dt_to_blob(FILE *f, struct boot_info *bi, int version) 352204431Sraj{ 353204431Sraj struct version_info *vi = NULL; 354204431Sraj int i; 355204431Sraj struct data blob = empty_data; 356204431Sraj struct data reservebuf = empty_data; 357204431Sraj struct data dtbuf = empty_data; 358204431Sraj struct data strbuf = empty_data; 359204431Sraj struct fdt_header fdt; 360204431Sraj int padlen = 0; 361204431Sraj 362204431Sraj for (i = 0; i < ARRAY_SIZE(version_table); i++) { 363204431Sraj if (version_table[i].version == version) 364204431Sraj vi = &version_table[i]; 365204431Sraj } 366204431Sraj if (!vi) 367204431Sraj die("Unknown device tree blob version %d\n", version); 368204431Sraj 369204431Sraj flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi); 370204431Sraj bin_emit_cell(&dtbuf, FDT_END); 371204431Sraj 372204431Sraj reservebuf = flatten_reserve_list(bi->reservelist, vi); 373204431Sraj 374204431Sraj /* Make header */ 375204431Sraj make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len, 376204431Sraj bi->boot_cpuid_phys); 377204431Sraj 378204431Sraj /* 379204431Sraj * If the user asked for more space than is used, adjust the totalsize. 380204431Sraj */ 381204431Sraj if (minsize > 0) { 382204431Sraj padlen = minsize - fdt32_to_cpu(fdt.totalsize); 383204431Sraj if ((padlen < 0) && (quiet < 1)) 384204431Sraj fprintf(stderr, 385204431Sraj "Warning: blob size %d >= minimum size %d\n", 386204431Sraj fdt32_to_cpu(fdt.totalsize), minsize); 387204431Sraj } 388204431Sraj 389204431Sraj if (padsize > 0) 390204431Sraj padlen = padsize; 391204431Sraj 392204431Sraj if (padlen > 0) { 393204431Sraj int tsize = fdt32_to_cpu(fdt.totalsize); 394204431Sraj tsize += padlen; 395204431Sraj fdt.totalsize = cpu_to_fdt32(tsize); 396204431Sraj } 397204431Sraj 398204431Sraj /* 399204431Sraj * Assemble the blob: start with the header, add with alignment 400204431Sraj * the reserve buffer, add the reserve map terminating zeroes, 401204431Sraj * the device tree itself, and finally the strings. 402204431Sraj */ 403204431Sraj blob = data_append_data(blob, &fdt, vi->hdr_size); 404204431Sraj blob = data_append_align(blob, 8); 405204431Sraj blob = data_merge(blob, reservebuf); 406204431Sraj blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry)); 407204431Sraj blob = data_merge(blob, dtbuf); 408204431Sraj blob = data_merge(blob, strbuf); 409204431Sraj 410204431Sraj /* 411204431Sraj * If the user asked for more space than is used, pad out the blob. 412204431Sraj */ 413204431Sraj if (padlen > 0) 414204431Sraj blob = data_append_zeroes(blob, padlen); 415204431Sraj 416204431Sraj fwrite(blob.val, blob.len, 1, f); 417204431Sraj 418204431Sraj if (ferror(f)) 419204431Sraj die("Error writing device tree blob: %s\n", strerror(errno)); 420204431Sraj 421204431Sraj /* 422204431Sraj * data_merge() frees the right-hand element so only the blob 423204431Sraj * remains to be freed. 424204431Sraj */ 425204431Sraj data_free(blob); 426204431Sraj} 427204431Sraj 428204431Srajstatic void dump_stringtable_asm(FILE *f, struct data strbuf) 429204431Sraj{ 430204431Sraj const char *p; 431204431Sraj int len; 432204431Sraj 433204431Sraj p = strbuf.val; 434204431Sraj 435204431Sraj while (p < (strbuf.val + strbuf.len)) { 436204431Sraj len = strlen(p); 437204431Sraj fprintf(f, "\t.string \"%s\"\n", p); 438204431Sraj p += len+1; 439204431Sraj } 440204431Sraj} 441204431Sraj 442204431Srajvoid dt_to_asm(FILE *f, struct boot_info *bi, int version) 443204431Sraj{ 444204431Sraj struct version_info *vi = NULL; 445204431Sraj int i; 446204431Sraj struct data strbuf = empty_data; 447204431Sraj struct reserve_info *re; 448204431Sraj const char *symprefix = "dt"; 449204431Sraj 450204431Sraj for (i = 0; i < ARRAY_SIZE(version_table); i++) { 451204431Sraj if (version_table[i].version == version) 452204431Sraj vi = &version_table[i]; 453204431Sraj } 454204431Sraj if (!vi) 455204431Sraj die("Unknown device tree blob version %d\n", version); 456204431Sraj 457204431Sraj fprintf(f, "/* autogenerated by dtc, do not edit */\n\n"); 458204431Sraj fprintf(f, "#define FDT_MAGIC 0x%x\n", FDT_MAGIC); 459204431Sraj fprintf(f, "#define FDT_BEGIN_NODE 0x%x\n", FDT_BEGIN_NODE); 460204431Sraj fprintf(f, "#define FDT_END_NODE 0x%x\n", FDT_END_NODE); 461204431Sraj fprintf(f, "#define FDT_PROP 0x%x\n", FDT_PROP); 462204431Sraj fprintf(f, "#define FDT_END 0x%x\n", FDT_END); 463204431Sraj fprintf(f, "\n"); 464204431Sraj 465204431Sraj emit_label(f, symprefix, "blob_start"); 466204431Sraj emit_label(f, symprefix, "header"); 467204431Sraj fprintf(f, "\t.long\tFDT_MAGIC\t\t\t\t/* magic */\n"); 468204431Sraj fprintf(f, "\t.long\t_%s_blob_abs_end - _%s_blob_start\t/* totalsize */\n", 469204431Sraj symprefix, symprefix); 470204431Sraj fprintf(f, "\t.long\t_%s_struct_start - _%s_blob_start\t/* off_dt_struct */\n", 471204431Sraj symprefix, symprefix); 472204431Sraj fprintf(f, "\t.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n", 473204431Sraj symprefix, symprefix); 474204431Sraj fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n", 475204431Sraj symprefix, symprefix); 476204431Sraj fprintf(f, "\t.long\t%d\t\t\t\t\t/* version */\n", vi->version); 477204431Sraj fprintf(f, "\t.long\t%d\t\t\t\t\t/* last_comp_version */\n", 478204431Sraj vi->last_comp_version); 479204431Sraj 480204431Sraj if (vi->flags & FTF_BOOTCPUID) 481204431Sraj fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n", 482204431Sraj bi->boot_cpuid_phys); 483204431Sraj 484204431Sraj if (vi->flags & FTF_STRTABSIZE) 485204431Sraj fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n", 486204431Sraj symprefix, symprefix); 487204431Sraj 488204431Sraj if (vi->flags & FTF_STRUCTSIZE) 489204431Sraj fprintf(f, "\t.long\t_%s_struct_end - _%s_struct_start\t/* size_dt_struct */\n", 490204431Sraj symprefix, symprefix); 491204431Sraj 492204431Sraj /* 493204431Sraj * Reserve map entries. 494204431Sraj * Align the reserve map to a doubleword boundary. 495204431Sraj * Each entry is an (address, size) pair of u64 values. 496204431Sraj * Always supply a zero-sized temination entry. 497204431Sraj */ 498204431Sraj asm_emit_align(f, 8); 499204431Sraj emit_label(f, symprefix, "reserve_map"); 500204431Sraj 501204431Sraj fprintf(f, "/* Memory reserve map from source file */\n"); 502204431Sraj 503204431Sraj /* 504204431Sraj * Use .long on high and low halfs of u64s to avoid .quad 505204431Sraj * as it appears .quad isn't available in some assemblers. 506204431Sraj */ 507204431Sraj for (re = bi->reservelist; re; re = re->next) { 508204431Sraj if (re->label) { 509204431Sraj fprintf(f, "\t.globl\t%s\n", re->label); 510204431Sraj fprintf(f, "%s:\n", re->label); 511204431Sraj } 512204431Sraj fprintf(f, "\t.long\t0x%08x, 0x%08x\n", 513204431Sraj (unsigned int)(re->re.address >> 32), 514204431Sraj (unsigned int)(re->re.address & 0xffffffff)); 515204431Sraj fprintf(f, "\t.long\t0x%08x, 0x%08x\n", 516204431Sraj (unsigned int)(re->re.size >> 32), 517204431Sraj (unsigned int)(re->re.size & 0xffffffff)); 518204431Sraj } 519204431Sraj for (i = 0; i < reservenum; i++) { 520204431Sraj fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n"); 521204431Sraj } 522204431Sraj 523204431Sraj fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n"); 524204431Sraj 525204431Sraj emit_label(f, symprefix, "struct_start"); 526204431Sraj flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi); 527204431Sraj fprintf(f, "\t.long\tFDT_END\n"); 528204431Sraj emit_label(f, symprefix, "struct_end"); 529204431Sraj 530204431Sraj emit_label(f, symprefix, "strings_start"); 531204431Sraj dump_stringtable_asm(f, strbuf); 532204431Sraj emit_label(f, symprefix, "strings_end"); 533204431Sraj 534204431Sraj emit_label(f, symprefix, "blob_end"); 535204431Sraj 536204431Sraj /* 537204431Sraj * If the user asked for more space than is used, pad it out. 538204431Sraj */ 539204431Sraj if (minsize > 0) { 540204431Sraj fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n", 541204431Sraj minsize, symprefix, symprefix); 542204431Sraj } 543204431Sraj if (padsize > 0) { 544204431Sraj fprintf(f, "\t.space\t%d, 0\n", padsize); 545204431Sraj } 546204431Sraj emit_label(f, symprefix, "blob_abs_end"); 547204431Sraj 548204431Sraj data_free(strbuf); 549204431Sraj} 550204431Sraj 551204431Srajstruct inbuf { 552204431Sraj char *base, *limit, *ptr; 553204431Sraj}; 554204431Sraj 555204431Srajstatic void inbuf_init(struct inbuf *inb, void *base, void *limit) 556204431Sraj{ 557204431Sraj inb->base = base; 558204431Sraj inb->limit = limit; 559204431Sraj inb->ptr = inb->base; 560204431Sraj} 561204431Sraj 562204431Srajstatic void flat_read_chunk(struct inbuf *inb, void *p, int len) 563204431Sraj{ 564204431Sraj if ((inb->ptr + len) > inb->limit) 565204431Sraj die("Premature end of data parsing flat device tree\n"); 566204431Sraj 567204431Sraj memcpy(p, inb->ptr, len); 568204431Sraj 569204431Sraj inb->ptr += len; 570204431Sraj} 571204431Sraj 572204431Srajstatic uint32_t flat_read_word(struct inbuf *inb) 573204431Sraj{ 574204431Sraj uint32_t val; 575204431Sraj 576204431Sraj assert(((inb->ptr - inb->base) % sizeof(val)) == 0); 577204431Sraj 578204431Sraj flat_read_chunk(inb, &val, sizeof(val)); 579204431Sraj 580204431Sraj return fdt32_to_cpu(val); 581204431Sraj} 582204431Sraj 583204431Srajstatic void flat_realign(struct inbuf *inb, int align) 584204431Sraj{ 585204431Sraj int off = inb->ptr - inb->base; 586204431Sraj 587204431Sraj inb->ptr = inb->base + ALIGN(off, align); 588204431Sraj if (inb->ptr > inb->limit) 589204431Sraj die("Premature end of data parsing flat device tree\n"); 590204431Sraj} 591204431Sraj 592204431Srajstatic char *flat_read_string(struct inbuf *inb) 593204431Sraj{ 594204431Sraj int len = 0; 595204431Sraj const char *p = inb->ptr; 596204431Sraj char *str; 597204431Sraj 598204431Sraj do { 599204431Sraj if (p >= inb->limit) 600204431Sraj die("Premature end of data parsing flat device tree\n"); 601204431Sraj len++; 602204431Sraj } while ((*p++) != '\0'); 603204431Sraj 604204431Sraj str = strdup(inb->ptr); 605204431Sraj 606204431Sraj inb->ptr += len; 607204431Sraj 608204431Sraj flat_realign(inb, sizeof(uint32_t)); 609204431Sraj 610204431Sraj return str; 611204431Sraj} 612204431Sraj 613204431Srajstatic struct data flat_read_data(struct inbuf *inb, int len) 614204431Sraj{ 615204431Sraj struct data d = empty_data; 616204431Sraj 617204431Sraj if (len == 0) 618204431Sraj return empty_data; 619204431Sraj 620204431Sraj d = data_grow_for(d, len); 621204431Sraj d.len = len; 622204431Sraj 623204431Sraj flat_read_chunk(inb, d.val, len); 624204431Sraj 625204431Sraj flat_realign(inb, sizeof(uint32_t)); 626204431Sraj 627204431Sraj return d; 628204431Sraj} 629204431Sraj 630204431Srajstatic char *flat_read_stringtable(struct inbuf *inb, int offset) 631204431Sraj{ 632204431Sraj const char *p; 633204431Sraj 634204431Sraj p = inb->base + offset; 635204431Sraj while (1) { 636204431Sraj if (p >= inb->limit || p < inb->base) 637204431Sraj die("String offset %d overruns string table\n", 638204431Sraj offset); 639204431Sraj 640204431Sraj if (*p == '\0') 641204431Sraj break; 642204431Sraj 643204431Sraj p++; 644204431Sraj } 645204431Sraj 646204431Sraj return strdup(inb->base + offset); 647204431Sraj} 648204431Sraj 649204431Srajstatic struct property *flat_read_property(struct inbuf *dtbuf, 650204431Sraj struct inbuf *strbuf, int flags) 651204431Sraj{ 652204431Sraj uint32_t proplen, stroff; 653204431Sraj char *name; 654204431Sraj struct data val; 655204431Sraj 656204431Sraj proplen = flat_read_word(dtbuf); 657204431Sraj stroff = flat_read_word(dtbuf); 658204431Sraj 659204431Sraj name = flat_read_stringtable(strbuf, stroff); 660204431Sraj 661204431Sraj if ((flags & FTF_VARALIGN) && (proplen >= 8)) 662204431Sraj flat_realign(dtbuf, 8); 663204431Sraj 664204431Sraj val = flat_read_data(dtbuf, proplen); 665204431Sraj 666204431Sraj return build_property(name, val, NULL); 667204431Sraj} 668204431Sraj 669204431Sraj 670204431Srajstatic struct reserve_info *flat_read_mem_reserve(struct inbuf *inb) 671204431Sraj{ 672204431Sraj struct reserve_info *reservelist = NULL; 673204431Sraj struct reserve_info *new; 674204431Sraj const char *p; 675204431Sraj struct fdt_reserve_entry re; 676204431Sraj 677204431Sraj /* 678204431Sraj * Each entry is a pair of u64 (addr, size) values for 4 cell_t's. 679204431Sraj * List terminates at an entry with size equal to zero. 680204431Sraj * 681204431Sraj * First pass, count entries. 682204431Sraj */ 683204431Sraj p = inb->ptr; 684204431Sraj while (1) { 685204431Sraj flat_read_chunk(inb, &re, sizeof(re)); 686204431Sraj re.address = fdt64_to_cpu(re.address); 687204431Sraj re.size = fdt64_to_cpu(re.size); 688204431Sraj if (re.size == 0) 689204431Sraj break; 690204431Sraj 691204431Sraj new = build_reserve_entry(re.address, re.size, NULL); 692204431Sraj reservelist = add_reserve_entry(reservelist, new); 693204431Sraj } 694204431Sraj 695204431Sraj return reservelist; 696204431Sraj} 697204431Sraj 698204431Sraj 699204431Srajstatic char *nodename_from_path(const char *ppath, const char *cpath) 700204431Sraj{ 701204431Sraj int plen; 702204431Sraj 703204431Sraj plen = strlen(ppath); 704204431Sraj 705204431Sraj if (!strneq(ppath, cpath, plen)) 706204431Sraj die("Path \"%s\" is not valid as a child of \"%s\"\n", 707204431Sraj cpath, ppath); 708204431Sraj 709204431Sraj /* root node is a special case */ 710204431Sraj if (!streq(ppath, "/")) 711204431Sraj plen++; 712204431Sraj 713204431Sraj return strdup(cpath + plen); 714204431Sraj} 715204431Sraj 716204431Srajstatic struct node *unflatten_tree(struct inbuf *dtbuf, 717204431Sraj struct inbuf *strbuf, 718204431Sraj const char *parent_flatname, int flags) 719204431Sraj{ 720204431Sraj struct node *node; 721204431Sraj char *flatname; 722204431Sraj uint32_t val; 723204431Sraj 724204431Sraj node = build_node(NULL, NULL); 725204431Sraj 726204431Sraj flatname = flat_read_string(dtbuf); 727204431Sraj 728204431Sraj if (flags & FTF_FULLPATH) 729204431Sraj node->name = nodename_from_path(parent_flatname, flatname); 730204431Sraj else 731204431Sraj node->name = flatname; 732204431Sraj 733204431Sraj do { 734204431Sraj struct property *prop; 735204431Sraj struct node *child; 736204431Sraj 737204431Sraj val = flat_read_word(dtbuf); 738204431Sraj switch (val) { 739204431Sraj case FDT_PROP: 740204431Sraj if (node->children) 741204431Sraj fprintf(stderr, "Warning: Flat tree input has " 742204431Sraj "subnodes preceding a property.\n"); 743204431Sraj prop = flat_read_property(dtbuf, strbuf, flags); 744204431Sraj add_property(node, prop); 745204431Sraj break; 746204431Sraj 747204431Sraj case FDT_BEGIN_NODE: 748204431Sraj child = unflatten_tree(dtbuf,strbuf, flatname, flags); 749204431Sraj add_child(node, child); 750204431Sraj break; 751204431Sraj 752204431Sraj case FDT_END_NODE: 753204431Sraj break; 754204431Sraj 755204431Sraj case FDT_END: 756204431Sraj die("Premature FDT_END in device tree blob\n"); 757204431Sraj break; 758204431Sraj 759204431Sraj case FDT_NOP: 760204431Sraj if (!(flags & FTF_NOPS)) 761204431Sraj fprintf(stderr, "Warning: NOP tag found in flat tree" 762204431Sraj " version <16\n"); 763204431Sraj 764204431Sraj /* Ignore */ 765204431Sraj break; 766204431Sraj 767204431Sraj default: 768204431Sraj die("Invalid opcode word %08x in device tree blob\n", 769204431Sraj val); 770204431Sraj } 771204431Sraj } while (val != FDT_END_NODE); 772204431Sraj 773204431Sraj return node; 774204431Sraj} 775204431Sraj 776204431Sraj 777204431Srajstruct boot_info *dt_from_blob(const char *fname) 778204431Sraj{ 779204431Sraj struct dtc_file *dtcf; 780204431Sraj uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys; 781204431Sraj uint32_t off_dt, off_str, off_mem_rsvmap; 782204431Sraj int rc; 783204431Sraj char *blob; 784204431Sraj struct fdt_header *fdt; 785204431Sraj char *p; 786204431Sraj struct inbuf dtbuf, strbuf; 787204431Sraj struct inbuf memresvbuf; 788204431Sraj int sizeleft; 789204431Sraj struct reserve_info *reservelist; 790204431Sraj struct node *tree; 791204431Sraj uint32_t val; 792204431Sraj int flags = 0; 793204431Sraj 794204431Sraj dtcf = dtc_open_file(fname, NULL); 795204431Sraj 796204431Sraj rc = fread(&magic, sizeof(magic), 1, dtcf->file); 797204431Sraj if (ferror(dtcf->file)) 798204431Sraj die("Error reading DT blob magic number: %s\n", 799204431Sraj strerror(errno)); 800204431Sraj if (rc < 1) { 801204431Sraj if (feof(dtcf->file)) 802204431Sraj die("EOF reading DT blob magic number\n"); 803204431Sraj else 804204431Sraj die("Mysterious short read reading magic number\n"); 805204431Sraj } 806204431Sraj 807204431Sraj magic = fdt32_to_cpu(magic); 808204431Sraj if (magic != FDT_MAGIC) 809204431Sraj die("Blob has incorrect magic number\n"); 810204431Sraj 811204431Sraj rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file); 812204431Sraj if (ferror(dtcf->file)) 813204431Sraj die("Error reading DT blob size: %s\n", strerror(errno)); 814204431Sraj if (rc < 1) { 815204431Sraj if (feof(dtcf->file)) 816204431Sraj die("EOF reading DT blob size\n"); 817204431Sraj else 818204431Sraj die("Mysterious short read reading blob size\n"); 819204431Sraj } 820204431Sraj 821204431Sraj totalsize = fdt32_to_cpu(totalsize); 822204431Sraj if (totalsize < FDT_V1_SIZE) 823204431Sraj die("DT blob size (%d) is too small\n", totalsize); 824204431Sraj 825204431Sraj blob = xmalloc(totalsize); 826204431Sraj 827204431Sraj fdt = (struct fdt_header *)blob; 828204431Sraj fdt->magic = cpu_to_fdt32(magic); 829204431Sraj fdt->totalsize = cpu_to_fdt32(totalsize); 830204431Sraj 831204431Sraj sizeleft = totalsize - sizeof(magic) - sizeof(totalsize); 832204431Sraj p = blob + sizeof(magic) + sizeof(totalsize); 833204431Sraj 834204431Sraj while (sizeleft) { 835204431Sraj if (feof(dtcf->file)) 836204431Sraj die("EOF before reading %d bytes of DT blob\n", 837204431Sraj totalsize); 838204431Sraj 839204431Sraj rc = fread(p, 1, sizeleft, dtcf->file); 840204431Sraj if (ferror(dtcf->file)) 841204431Sraj die("Error reading DT blob: %s\n", 842204431Sraj strerror(errno)); 843204431Sraj 844204431Sraj sizeleft -= rc; 845204431Sraj p += rc; 846204431Sraj } 847204431Sraj 848204431Sraj off_dt = fdt32_to_cpu(fdt->off_dt_struct); 849204431Sraj off_str = fdt32_to_cpu(fdt->off_dt_strings); 850204431Sraj off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap); 851204431Sraj version = fdt32_to_cpu(fdt->version); 852204431Sraj boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys); 853204431Sraj 854204431Sraj if (off_mem_rsvmap >= totalsize) 855204431Sraj die("Mem Reserve structure offset exceeds total size\n"); 856204431Sraj 857204431Sraj if (off_dt >= totalsize) 858204431Sraj die("DT structure offset exceeds total size\n"); 859204431Sraj 860204431Sraj if (off_str > totalsize) 861204431Sraj die("String table offset exceeds total size\n"); 862204431Sraj 863204431Sraj if (version >= 3) { 864204431Sraj uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings); 865204431Sraj if (off_str+size_str > totalsize) 866204431Sraj die("String table extends past total size\n"); 867204431Sraj inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str); 868204431Sraj } else { 869204431Sraj inbuf_init(&strbuf, blob + off_str, blob + totalsize); 870204431Sraj } 871204431Sraj 872204431Sraj if (version >= 17) { 873204431Sraj size_dt = fdt32_to_cpu(fdt->size_dt_struct); 874204431Sraj if (off_dt+size_dt > totalsize) 875204431Sraj die("Structure block extends past total size\n"); 876204431Sraj } 877204431Sraj 878204431Sraj if (version < 16) { 879204431Sraj flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN; 880204431Sraj } else { 881204431Sraj flags |= FTF_NOPS; 882204431Sraj } 883204431Sraj 884204431Sraj inbuf_init(&memresvbuf, 885204431Sraj blob + off_mem_rsvmap, blob + totalsize); 886204431Sraj inbuf_init(&dtbuf, blob + off_dt, blob + totalsize); 887204431Sraj 888204431Sraj reservelist = flat_read_mem_reserve(&memresvbuf); 889204431Sraj 890204431Sraj val = flat_read_word(&dtbuf); 891204431Sraj 892204431Sraj if (val != FDT_BEGIN_NODE) 893204431Sraj die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val); 894204431Sraj 895204431Sraj tree = unflatten_tree(&dtbuf, &strbuf, "", flags); 896204431Sraj 897204431Sraj val = flat_read_word(&dtbuf); 898204431Sraj if (val != FDT_END) 899204431Sraj die("Device tree blob doesn't end with FDT_END\n"); 900204431Sraj 901204431Sraj free(blob); 902204431Sraj 903204431Sraj dtc_close_file(dtcf); 904204431Sraj 905204431Sraj return build_boot_info(reservelist, tree, boot_cpuid_phys); 906204431Sraj} 907