root/scripts/dtc/flattree.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bin_emit_cell
  2. bin_emit_string
  3. bin_emit_align
  4. bin_emit_data
  5. bin_emit_beginnode
  6. bin_emit_endnode
  7. bin_emit_property
  8. emit_label
  9. emit_offset_label
  10. asm_emit_cell
  11. asm_emit_string
  12. asm_emit_align
  13. asm_emit_data
  14. asm_emit_beginnode
  15. asm_emit_endnode
  16. asm_emit_property
  17. stringtable_insert
  18. flatten_tree
  19. flatten_reserve_list
  20. make_fdt_header
  21. dt_to_blob
  22. dump_stringtable_asm
  23. dt_to_asm
  24. inbuf_init
  25. flat_read_chunk
  26. flat_read_word
  27. flat_realign
  28. flat_read_string
  29. flat_read_data
  30. flat_read_stringtable
  31. flat_read_property
  32. flat_read_mem_reserve
  33. nodename_from_path
  34. unflatten_tree
  35. dt_from_blob

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

/* [<][>][^][v][top][bottom][index][help] */