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