diff options
Diffstat (limited to 'arch/powerpc/boot/dtc-src/checks.c')
-rw-r--r-- | arch/powerpc/boot/dtc-src/checks.c | 305 |
1 files changed, 71 insertions, 234 deletions
diff --git a/arch/powerpc/boot/dtc-src/checks.c b/arch/powerpc/boot/dtc-src/checks.c index 2ce961cd414d..95485796f253 100644 --- a/arch/powerpc/boot/dtc-src/checks.c +++ b/arch/powerpc/boot/dtc-src/checks.c | |||
@@ -242,6 +242,42 @@ static void check_duplicate_property_names(struct check *c, struct node *dt, | |||
242 | } | 242 | } |
243 | NODE_CHECK(duplicate_property_names, NULL, ERROR); | 243 | NODE_CHECK(duplicate_property_names, NULL, ERROR); |
244 | 244 | ||
245 | #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" | ||
246 | #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | ||
247 | #define DIGITS "0123456789" | ||
248 | #define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" | ||
249 | |||
250 | static void check_node_name_chars(struct check *c, struct node *dt, | ||
251 | struct node *node) | ||
252 | { | ||
253 | int n = strspn(node->name, c->data); | ||
254 | |||
255 | if (n < strlen(node->name)) | ||
256 | FAIL(c, "Bad character '%c' in node %s", | ||
257 | node->name[n], node->fullpath); | ||
258 | } | ||
259 | NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR); | ||
260 | |||
261 | static void check_node_name_format(struct check *c, struct node *dt, | ||
262 | struct node *node) | ||
263 | { | ||
264 | if (strchr(get_unitname(node), '@')) | ||
265 | FAIL(c, "Node %s has multiple '@' characters in name", | ||
266 | node->fullpath); | ||
267 | } | ||
268 | NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars); | ||
269 | |||
270 | static void check_property_name_chars(struct check *c, struct node *dt, | ||
271 | struct node *node, struct property *prop) | ||
272 | { | ||
273 | int n = strspn(prop->name, c->data); | ||
274 | |||
275 | if (n < strlen(prop->name)) | ||
276 | FAIL(c, "Bad character '%c' in property name \"%s\", node %s", | ||
277 | prop->name[n], prop->name, node->fullpath); | ||
278 | } | ||
279 | PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR); | ||
280 | |||
245 | static void check_explicit_phandles(struct check *c, struct node *root, | 281 | static void check_explicit_phandles(struct check *c, struct node *root, |
246 | struct node *node) | 282 | struct node *node) |
247 | { | 283 | { |
@@ -280,16 +316,29 @@ NODE_CHECK(explicit_phandles, NULL, ERROR); | |||
280 | static void check_name_properties(struct check *c, struct node *root, | 316 | static void check_name_properties(struct check *c, struct node *root, |
281 | struct node *node) | 317 | struct node *node) |
282 | { | 318 | { |
283 | struct property *prop; | 319 | struct property **pp, *prop = NULL; |
320 | |||
321 | for (pp = &node->proplist; *pp; pp = &((*pp)->next)) | ||
322 | if (streq((*pp)->name, "name")) { | ||
323 | prop = *pp; | ||
324 | break; | ||
325 | } | ||
284 | 326 | ||
285 | prop = get_property(node, "name"); | ||
286 | if (!prop) | 327 | if (!prop) |
287 | return; /* No name property, that's fine */ | 328 | return; /* No name property, that's fine */ |
288 | 329 | ||
289 | if ((prop->val.len != node->basenamelen+1) | 330 | if ((prop->val.len != node->basenamelen+1) |
290 | || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) | 331 | || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { |
291 | FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead" | 332 | FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead" |
292 | " of base node name)", node->fullpath, prop->val.val); | 333 | " of base node name)", node->fullpath, prop->val.val); |
334 | } else { | ||
335 | /* The name property is correct, and therefore redundant. | ||
336 | * Delete it */ | ||
337 | *pp = prop->next; | ||
338 | free(prop->name); | ||
339 | data_free(prop->val); | ||
340 | free(prop); | ||
341 | } | ||
293 | } | 342 | } |
294 | CHECK_IS_STRING(name_is_string, "name", ERROR); | 343 | CHECK_IS_STRING(name_is_string, "name", ERROR); |
295 | NODE_CHECK(name_properties, NULL, ERROR, &name_is_string); | 344 | NODE_CHECK(name_properties, NULL, ERROR, &name_is_string); |
@@ -301,23 +350,23 @@ NODE_CHECK(name_properties, NULL, ERROR, &name_is_string); | |||
301 | static void fixup_phandle_references(struct check *c, struct node *dt, | 350 | static void fixup_phandle_references(struct check *c, struct node *dt, |
302 | struct node *node, struct property *prop) | 351 | struct node *node, struct property *prop) |
303 | { | 352 | { |
304 | struct marker *m = prop->val.markers; | 353 | struct marker *m = prop->val.markers; |
305 | struct node *refnode; | 354 | struct node *refnode; |
306 | cell_t phandle; | 355 | cell_t phandle; |
307 | 356 | ||
308 | for_each_marker_of_type(m, REF_PHANDLE) { | 357 | for_each_marker_of_type(m, REF_PHANDLE) { |
309 | assert(m->offset + sizeof(cell_t) <= prop->val.len); | 358 | assert(m->offset + sizeof(cell_t) <= prop->val.len); |
310 | 359 | ||
311 | refnode = get_node_by_ref(dt, m->ref); | 360 | refnode = get_node_by_ref(dt, m->ref); |
312 | if (! refnode) { | 361 | if (! refnode) { |
313 | FAIL(c, "Reference to non-existent node or label \"%s\"\n", | 362 | FAIL(c, "Reference to non-existent node or label \"%s\"\n", |
314 | m->ref); | 363 | m->ref); |
315 | continue; | 364 | continue; |
316 | } | 365 | } |
317 | 366 | ||
318 | phandle = get_node_phandle(dt, refnode); | 367 | phandle = get_node_phandle(dt, refnode); |
319 | *((cell_t *)(prop->val.val + m->offset)) = cpu_to_be32(phandle); | 368 | *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); |
320 | } | 369 | } |
321 | } | 370 | } |
322 | CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR, | 371 | CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR, |
323 | &duplicate_node_names, &explicit_phandles); | 372 | &duplicate_node_names, &explicit_phandles); |
@@ -498,6 +547,7 @@ TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN); | |||
498 | 547 | ||
499 | static struct check *check_table[] = { | 548 | static struct check *check_table[] = { |
500 | &duplicate_node_names, &duplicate_property_names, | 549 | &duplicate_node_names, &duplicate_property_names, |
550 | &node_name_chars, &node_name_format, &property_name_chars, | ||
501 | &name_is_string, &name_properties, | 551 | &name_is_string, &name_properties, |
502 | &explicit_phandles, | 552 | &explicit_phandles, |
503 | &phandle_references, &path_references, | 553 | &phandle_references, &path_references, |
@@ -511,10 +561,7 @@ static struct check *check_table[] = { | |||
511 | &obsolete_chosen_interrupt_controller, | 561 | &obsolete_chosen_interrupt_controller, |
512 | }; | 562 | }; |
513 | 563 | ||
514 | int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys); | 564 | void process_checks(int force, struct boot_info *bi) |
515 | |||
516 | void process_checks(int force, struct boot_info *bi, | ||
517 | int checkflag, int outversion, int boot_cpuid_phys) | ||
518 | { | 565 | { |
519 | struct node *dt = bi->dt; | 566 | struct node *dt = bi->dt; |
520 | int i; | 567 | int i; |
@@ -537,214 +584,4 @@ void process_checks(int force, struct boot_info *bi, | |||
537 | "output forced\n"); | 584 | "output forced\n"); |
538 | } | 585 | } |
539 | } | 586 | } |
540 | |||
541 | if (checkflag) { | ||
542 | if (error) { | ||
543 | fprintf(stderr, "Warning: Skipping semantic checks due to structural errors\n"); | ||
544 | } else { | ||
545 | if (!check_semantics(bi->dt, outversion, | ||
546 | boot_cpuid_phys)) | ||
547 | fprintf(stderr, "Warning: Input tree has semantic errors\n"); | ||
548 | } | ||
549 | } | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * Semantic check functions | ||
554 | */ | ||
555 | |||
556 | #define ERRMSG(...) if (quiet < 2) fprintf(stderr, "ERROR: " __VA_ARGS__) | ||
557 | #define WARNMSG(...) if (quiet < 1) fprintf(stderr, "Warning: " __VA_ARGS__) | ||
558 | |||
559 | #define DO_ERR(...) do {ERRMSG(__VA_ARGS__); ok = 0; } while (0) | ||
560 | |||
561 | #define CHECK_HAVE(node, propname) \ | ||
562 | do { \ | ||
563 | if (! (prop = get_property((node), (propname)))) \ | ||
564 | DO_ERR("Missing \"%s\" property in %s\n", (propname), \ | ||
565 | (node)->fullpath); \ | ||
566 | } while (0); | ||
567 | |||
568 | #define CHECK_HAVE_WARN(node, propname) \ | ||
569 | do { \ | ||
570 | if (! (prop = get_property((node), (propname)))) \ | ||
571 | WARNMSG("%s has no \"%s\" property\n", \ | ||
572 | (node)->fullpath, (propname)); \ | ||
573 | } while (0) | ||
574 | |||
575 | #define CHECK_HAVE_STRING(node, propname) \ | ||
576 | do { \ | ||
577 | CHECK_HAVE((node), (propname)); \ | ||
578 | if (prop && !data_is_one_string(prop->val)) \ | ||
579 | DO_ERR("\"%s\" property in %s is not a string\n", \ | ||
580 | (propname), (node)->fullpath); \ | ||
581 | } while (0) | ||
582 | |||
583 | #define CHECK_HAVE_STREQ(node, propname, value) \ | ||
584 | do { \ | ||
585 | CHECK_HAVE_STRING((node), (propname)); \ | ||
586 | if (prop && !streq(prop->val.val, (value))) \ | ||
587 | DO_ERR("%s has wrong %s, %s (should be %s\n", \ | ||
588 | (node)->fullpath, (propname), \ | ||
589 | prop->val.val, (value)); \ | ||
590 | } while (0) | ||
591 | |||
592 | #define CHECK_HAVE_ONECELL(node, propname) \ | ||
593 | do { \ | ||
594 | CHECK_HAVE((node), (propname)); \ | ||
595 | if (prop && (prop->val.len != sizeof(cell_t))) \ | ||
596 | DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \ | ||
597 | } while (0) | ||
598 | |||
599 | #define CHECK_HAVE_WARN_ONECELL(node, propname) \ | ||
600 | do { \ | ||
601 | CHECK_HAVE_WARN((node), (propname)); \ | ||
602 | if (prop && (prop->val.len != sizeof(cell_t))) \ | ||
603 | DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \ | ||
604 | } while (0) | ||
605 | |||
606 | #define CHECK_HAVE_WARN_PHANDLE(xnode, propname, root) \ | ||
607 | do { \ | ||
608 | struct node *ref; \ | ||
609 | CHECK_HAVE_WARN_ONECELL((xnode), (propname)); \ | ||
610 | if (prop) {\ | ||
611 | cell_t phandle = propval_cell(prop); \ | ||
612 | if ((phandle == 0) || (phandle == -1)) { \ | ||
613 | DO_ERR("\"%s\" property in %s contains an invalid phandle %x\n", (propname), (xnode)->fullpath, phandle); \ | ||
614 | } else { \ | ||
615 | ref = get_node_by_phandle((root), propval_cell(prop)); \ | ||
616 | if (! ref) \ | ||
617 | DO_ERR("\"%s\" property in %s refers to non-existant phandle %x\n", (propname), (xnode)->fullpath, propval_cell(prop)); \ | ||
618 | } \ | ||
619 | } \ | ||
620 | } while (0) | ||
621 | |||
622 | #define CHECK_HAVE_WARN_STRING(node, propname) \ | ||
623 | do { \ | ||
624 | CHECK_HAVE_WARN((node), (propname)); \ | ||
625 | if (prop && !data_is_one_string(prop->val)) \ | ||
626 | DO_ERR("\"%s\" property in %s is not a string\n", \ | ||
627 | (propname), (node)->fullpath); \ | ||
628 | } while (0) | ||
629 | |||
630 | static int check_root(struct node *root) | ||
631 | { | ||
632 | struct property *prop; | ||
633 | int ok = 1; | ||
634 | |||
635 | CHECK_HAVE_STRING(root, "model"); | ||
636 | CHECK_HAVE_WARN(root, "compatible"); | ||
637 | |||
638 | return ok; | ||
639 | } | ||
640 | |||
641 | static int check_cpus(struct node *root, int outversion, int boot_cpuid_phys) | ||
642 | { | ||
643 | struct node *cpus, *cpu; | ||
644 | struct property *prop; | ||
645 | struct node *bootcpu = NULL; | ||
646 | int ok = 1; | ||
647 | |||
648 | cpus = get_subnode(root, "cpus"); | ||
649 | if (! cpus) { | ||
650 | ERRMSG("Missing /cpus node\n"); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | if (cpus->addr_cells != 1) | ||
655 | DO_ERR("%s has bad #address-cells value %d (should be 1)\n", | ||
656 | cpus->fullpath, cpus->addr_cells); | ||
657 | if (cpus->size_cells != 0) | ||
658 | DO_ERR("%s has bad #size-cells value %d (should be 0)\n", | ||
659 | cpus->fullpath, cpus->size_cells); | ||
660 | |||
661 | for_each_child(cpus, cpu) { | ||
662 | CHECK_HAVE_STREQ(cpu, "device_type", "cpu"); | ||
663 | |||
664 | CHECK_HAVE_ONECELL(cpu, "reg"); | ||
665 | if (prop) { | ||
666 | cell_t unitnum; | ||
667 | char *eptr; | ||
668 | |||
669 | unitnum = strtol(get_unitname(cpu), &eptr, 16); | ||
670 | if (*eptr) { | ||
671 | WARNMSG("%s has bad format unit name %s (should be CPU number\n", | ||
672 | cpu->fullpath, get_unitname(cpu)); | ||
673 | } else if (unitnum != propval_cell(prop)) { | ||
674 | WARNMSG("%s unit name \"%s\" does not match \"reg\" property <%x>\n", | ||
675 | cpu->fullpath, get_unitname(cpu), | ||
676 | propval_cell(prop)); | ||
677 | } | ||
678 | } | ||
679 | |||
680 | /* CHECK_HAVE_ONECELL(cpu, "d-cache-line-size"); */ | ||
681 | /* CHECK_HAVE_ONECELL(cpu, "i-cache-line-size"); */ | ||
682 | CHECK_HAVE_ONECELL(cpu, "d-cache-size"); | ||
683 | CHECK_HAVE_ONECELL(cpu, "i-cache-size"); | ||
684 | |||
685 | CHECK_HAVE_WARN_ONECELL(cpu, "clock-frequency"); | ||
686 | CHECK_HAVE_WARN_ONECELL(cpu, "timebase-frequency"); | ||
687 | |||
688 | prop = get_property(cpu, "linux,boot-cpu"); | ||
689 | if (prop) { | ||
690 | if (prop->val.len) | ||
691 | WARNMSG("\"linux,boot-cpu\" property in %s is non-empty\n", | ||
692 | cpu->fullpath); | ||
693 | if (bootcpu) | ||
694 | DO_ERR("Multiple boot cpus (%s and %s)\n", | ||
695 | bootcpu->fullpath, cpu->fullpath); | ||
696 | else | ||
697 | bootcpu = cpu; | ||
698 | } | ||
699 | } | ||
700 | |||
701 | if (outversion < 2) { | ||
702 | if (! bootcpu) | ||
703 | WARNMSG("No cpu has \"linux,boot-cpu\" property\n"); | ||
704 | } else { | ||
705 | if (bootcpu) | ||
706 | WARNMSG("\"linux,boot-cpu\" property is deprecated in blob version 2 or higher\n"); | ||
707 | if (boot_cpuid_phys == 0xfeedbeef) | ||
708 | WARNMSG("physical boot CPU not set. Use -b option to set\n"); | ||
709 | } | ||
710 | |||
711 | return ok; | ||
712 | } | ||
713 | |||
714 | static int check_memory(struct node *root) | ||
715 | { | ||
716 | struct node *mem; | ||
717 | struct property *prop; | ||
718 | int nnodes = 0; | ||
719 | int ok = 1; | ||
720 | |||
721 | for_each_child(root, mem) { | ||
722 | if (! strneq(mem->name, "memory", mem->basenamelen)) | ||
723 | continue; | ||
724 | |||
725 | nnodes++; | ||
726 | |||
727 | CHECK_HAVE_STREQ(mem, "device_type", "memory"); | ||
728 | CHECK_HAVE(mem, "reg"); | ||
729 | } | ||
730 | |||
731 | if (nnodes == 0) { | ||
732 | ERRMSG("No memory nodes\n"); | ||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | return ok; | ||
737 | } | ||
738 | |||
739 | int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys) | ||
740 | { | ||
741 | int ok = 1; | ||
742 | |||
743 | ok = ok && check_root(dt); | ||
744 | ok = ok && check_cpus(dt, outversion, boot_cpuid_phys); | ||
745 | ok = ok && check_memory(dt); | ||
746 | if (! ok) | ||
747 | return 0; | ||
748 | |||
749 | return 1; | ||
750 | } | 587 | } |