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