1 /* 2 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2007. 3 * 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18 * USA 19 */ 20 21 #include "dtc.h" 22 23 #ifdef TRACE_CHECKS 24 #define TRACE(c, ...) \ 25 do { \ 26 fprintf(stderr, "=== %s: ", (c)->name); \ 27 fprintf(stderr, __VA_ARGS__); \ 28 fprintf(stderr, "\n"); \ 29 } while (0) 30 #else 31 #define TRACE(c, fmt, ...) do { } while (0) 32 #endif 33 34 enum checkstatus { 35 UNCHECKED = 0, 36 PREREQ, 37 PASSED, 38 FAILED, 39 }; 40 41 struct check; 42 43 typedef void (*tree_check_fn)(struct check *c, struct node *dt); 44 typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node); 45 typedef void (*prop_check_fn)(struct check *c, struct node *dt, 46 struct node *node, struct property *prop); 47 48 struct check { 49 const char *name; 50 tree_check_fn tree_fn; 51 node_check_fn node_fn; 52 prop_check_fn prop_fn; 53 void *data; 54 bool warn, error; 55 enum checkstatus status; 56 bool inprogress; 57 int num_prereqs; 58 struct check **prereq; 59 }; 60 61 #define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \ 62 static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ 63 static struct check nm = { \ 64 .name = #nm, \ 65 .tree_fn = (tfn), \ 66 .node_fn = (nfn), \ 67 .prop_fn = (pfn), \ 68 .data = (d), \ 69 .warn = (w), \ 70 .error = (e), \ 71 .status = UNCHECKED, \ 72 .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ 73 .prereq = nm##_prereqs, \ 74 }; 75 #define WARNING(nm, tfn, nfn, pfn, d, ...) \ 76 CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__) 77 #define ERROR(nm, tfn, nfn, pfn, d, ...) \ 78 CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__) 79 #define CHECK(nm, tfn, nfn, pfn, d, ...) \ 80 CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__) 81 82 #define TREE_WARNING(nm, d, ...) \ 83 WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) 84 #define TREE_ERROR(nm, d, ...) \ 85 ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) 86 #define TREE_CHECK(nm, d, ...) \ 87 CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) 88 #define NODE_WARNING(nm, d, ...) \ 89 WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) 90 #define NODE_ERROR(nm, d, ...) \ 91 ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) 92 #define NODE_CHECK(nm, d, ...) \ 93 CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) 94 #define PROP_WARNING(nm, d, ...) \ 95 WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) 96 #define PROP_ERROR(nm, d, ...) \ 97 ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) 98 #define PROP_CHECK(nm, d, ...) \ 99 CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) 100 101 #ifdef __GNUC__ 102 static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); 103 #endif 104 static inline void check_msg(struct check *c, const char *fmt, ...) 105 { 106 va_list ap; 107 va_start(ap, fmt); 108 109 if ((c->warn && (quiet < 1)) 110 || (c->error && (quiet < 2))) { 111 fprintf(stderr, "%s (%s): ", 112 (c->error) ? "ERROR" : "Warning", c->name); 113 vfprintf(stderr, fmt, ap); 114 fprintf(stderr, "\n"); 115 } 116 va_end(ap); 117 } 118 119 #define FAIL(c, ...) \ 120 do { \ 121 TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \ 122 (c)->status = FAILED; \ 123 check_msg((c), __VA_ARGS__); \ 124 } while (0) 125 126 static void check_nodes_props(struct check *c, struct node *dt, struct node *node) 127 { 128 struct node *child; 129 struct property *prop; 130 131 TRACE(c, "%s", node->fullpath); 132 if (c->node_fn) 133 c->node_fn(c, dt, node); 134 135 if (c->prop_fn) 136 for_each_property(node, prop) { 137 TRACE(c, "%s\t'%s'", node->fullpath, prop->name); 138 c->prop_fn(c, dt, node, prop); 139 } 140 141 for_each_child(node, child) 142 check_nodes_props(c, dt, child); 143 } 144 145 static bool run_check(struct check *c, struct node *dt) 146 { 147 bool error = false; 148 int i; 149 150 assert(!c->inprogress); 151 152 if (c->status != UNCHECKED) 153 goto out; 154 155 c->inprogress = true; 156 157 for (i = 0; i < c->num_prereqs; i++) { 158 struct check *prq = c->prereq[i]; 159 error = error || run_check(prq, dt); 160 if (prq->status != PASSED) { 161 c->status = PREREQ; 162 check_msg(c, "Failed prerequisite '%s'", 163 c->prereq[i]->name); 164 } 165 } 166 167 if (c->status != UNCHECKED) 168 goto out; 169 170 if (c->node_fn || c->prop_fn) 171 check_nodes_props(c, dt, dt); 172 173 if (c->tree_fn) 174 c->tree_fn(c, dt); 175 if (c->status == UNCHECKED) 176 c->status = PASSED; 177 178 TRACE(c, "\tCompleted, status %d", c->status); 179 180 out: 181 c->inprogress = false; 182 if ((c->status != PASSED) && (c->error)) 183 error = true; 184 return error; 185 } 186 187 /* 188 * Utility check functions 189 */ 190 191 /* A check which always fails, for testing purposes only */ 192 static inline void check_always_fail(struct check *c, struct node *dt) 193 { 194 FAIL(c, "always_fail check"); 195 } 196 TREE_CHECK(always_fail, NULL); 197 198 static void check_is_string(struct check *c, struct node *root, 199 struct node *node) 200 { 201 struct property *prop; 202 char *propname = c->data; 203 204 prop = get_property(node, propname); 205 if (!prop) 206 return; /* Not present, assumed ok */ 207 208 if (!data_is_one_string(prop->val)) 209 FAIL(c, "\"%s\" property in %s is not a string", 210 propname, node->fullpath); 211 } 212 #define WARNING_IF_NOT_STRING(nm, propname) \ 213 WARNING(nm, NULL, check_is_string, NULL, (propname)) 214 #define ERROR_IF_NOT_STRING(nm, propname) \ 215 ERROR(nm, NULL, check_is_string, NULL, (propname)) 216 217 static void check_is_cell(struct check *c, struct node *root, 218 struct node *node) 219 { 220 struct property *prop; 221 char *propname = c->data; 222 223 prop = get_property(node, propname); 224 if (!prop) 225 return; /* Not present, assumed ok */ 226 227 if (prop->val.len != sizeof(cell_t)) 228 FAIL(c, "\"%s\" property in %s is not a single cell", 229 propname, node->fullpath); 230 } 231 #define WARNING_IF_NOT_CELL(nm, propname) \ 232 WARNING(nm, NULL, check_is_cell, NULL, (propname)) 233 #define ERROR_IF_NOT_CELL(nm, propname) \ 234 ERROR(nm, NULL, check_is_cell, NULL, (propname)) 235 236 /* 237 * Structural check functions 238 */ 239 240 static void check_duplicate_node_names(struct check *c, struct node *dt, 241 struct node *node) 242 { 243 struct node *child, *child2; 244 245 for_each_child(node, child) 246 for (child2 = child->next_sibling; 247 child2; 248 child2 = child2->next_sibling) 249 if (streq(child->name, child2->name)) 250 FAIL(c, "Duplicate node name %s", 251 child->fullpath); 252 } 253 NODE_ERROR(duplicate_node_names, NULL); 254 255 static void check_duplicate_property_names(struct check *c, struct node *dt, 256 struct node *node) 257 { 258 struct property *prop, *prop2; 259 260 for_each_property(node, prop) { 261 for (prop2 = prop->next; prop2; prop2 = prop2->next) { 262 if (prop2->deleted) 263 continue; 264 if (streq(prop->name, prop2->name)) 265 FAIL(c, "Duplicate property name %s in %s", 266 prop->name, node->fullpath); 267 } 268 } 269 } 270 NODE_ERROR(duplicate_property_names, NULL); 271 272 #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" 273 #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 274 #define DIGITS "0123456789" 275 #define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" 276 277 static void check_node_name_chars(struct check *c, struct node *dt, 278 struct node *node) 279 { 280 int n = strspn(node->name, c->data); 281 282 if (n < strlen(node->name)) 283 FAIL(c, "Bad character '%c' in node %s", 284 node->name[n], node->fullpath); 285 } 286 NODE_ERROR(node_name_chars, PROPNODECHARS "@"); 287 288 static void check_node_name_format(struct check *c, struct node *dt, 289 struct node *node) 290 { 291 if (strchr(get_unitname(node), '@')) 292 FAIL(c, "Node %s has multiple '@' characters in name", 293 node->fullpath); 294 } 295 NODE_ERROR(node_name_format, NULL, &node_name_chars); 296 297 static void check_unit_address_vs_reg(struct check *c, struct node *dt, 298 struct node *node) 299 { 300 const char *unitname = get_unitname(node); 301 struct property *prop = get_property(node, "reg"); 302 303 if (!prop) { 304 prop = get_property(node, "ranges"); 305 if (prop && !prop->val.len) 306 prop = NULL; 307 } 308 309 if (prop) { 310 if (!unitname[0]) 311 FAIL(c, "Node %s has a reg or ranges property, but no unit name", 312 node->fullpath); 313 } else { 314 if (unitname[0]) 315 FAIL(c, "Node %s has a unit name, but no reg property", 316 node->fullpath); 317 } 318 } 319 NODE_WARNING(unit_address_vs_reg, NULL); 320 321 static void check_property_name_chars(struct check *c, struct node *dt, 322 struct node *node, struct property *prop) 323 { 324 int n = strspn(prop->name, c->data); 325 326 if (n < strlen(prop->name)) 327 FAIL(c, "Bad character '%c' in property name \"%s\", node %s", 328 prop->name[n], prop->name, node->fullpath); 329 } 330 PROP_ERROR(property_name_chars, PROPNODECHARS); 331 332 #define DESCLABEL_FMT "%s%s%s%s%s" 333 #define DESCLABEL_ARGS(node,prop,mark) \ 334 ((mark) ? "value of " : ""), \ 335 ((prop) ? "'" : ""), \ 336 ((prop) ? (prop)->name : ""), \ 337 ((prop) ? "' in " : ""), (node)->fullpath 338 339 static void check_duplicate_label(struct check *c, struct node *dt, 340 const char *label, struct node *node, 341 struct property *prop, struct marker *mark) 342 { 343 struct node *othernode = NULL; 344 struct property *otherprop = NULL; 345 struct marker *othermark = NULL; 346 347 othernode = get_node_by_label(dt, label); 348 349 if (!othernode) 350 otherprop = get_property_by_label(dt, label, &othernode); 351 if (!othernode) 352 othermark = get_marker_label(dt, label, &othernode, 353 &otherprop); 354 355 if (!othernode) 356 return; 357 358 if ((othernode != node) || (otherprop != prop) || (othermark != mark)) 359 FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT 360 " and " DESCLABEL_FMT, 361 label, DESCLABEL_ARGS(node, prop, mark), 362 DESCLABEL_ARGS(othernode, otherprop, othermark)); 363 } 364 365 static void check_duplicate_label_node(struct check *c, struct node *dt, 366 struct node *node) 367 { 368 struct label *l; 369 370 for_each_label(node->labels, l) 371 check_duplicate_label(c, dt, l->label, node, NULL, NULL); 372 } 373 static void check_duplicate_label_prop(struct check *c, struct node *dt, 374 struct node *node, struct property *prop) 375 { 376 struct marker *m = prop->val.markers; 377 struct label *l; 378 379 for_each_label(prop->labels, l) 380 check_duplicate_label(c, dt, l->label, node, prop, NULL); 381 382 for_each_marker_of_type(m, LABEL) 383 check_duplicate_label(c, dt, m->ref, node, prop, m); 384 } 385 ERROR(duplicate_label, NULL, check_duplicate_label_node, 386 check_duplicate_label_prop, NULL); 387 388 static void check_explicit_phandles(struct check *c, struct node *root, 389 struct node *node, struct property *prop) 390 { 391 struct marker *m; 392 struct node *other; 393 cell_t phandle; 394 395 if (!streq(prop->name, "phandle") 396 && !streq(prop->name, "linux,phandle")) 397 return; 398 399 if (prop->val.len != sizeof(cell_t)) { 400 FAIL(c, "%s has bad length (%d) %s property", 401 node->fullpath, prop->val.len, prop->name); 402 return; 403 } 404 405 m = prop->val.markers; 406 for_each_marker_of_type(m, REF_PHANDLE) { 407 assert(m->offset == 0); 408 if (node != get_node_by_ref(root, m->ref)) 409 /* "Set this node's phandle equal to some 410 * other node's phandle". That's nonsensical 411 * by construction. */ { 412 FAIL(c, "%s in %s is a reference to another node", 413 prop->name, node->fullpath); 414 return; 415 } 416 /* But setting this node's phandle equal to its own 417 * phandle is allowed - that means allocate a unique 418 * phandle for this node, even if it's not otherwise 419 * referenced. The value will be filled in later, so 420 * no further checking for now. */ 421 return; 422 } 423 424 phandle = propval_cell(prop); 425 426 if ((phandle == 0) || (phandle == -1)) { 427 FAIL(c, "%s has bad value (0x%x) in %s property", 428 node->fullpath, phandle, prop->name); 429 return; 430 } 431 432 if (node->phandle && (node->phandle != phandle)) 433 FAIL(c, "%s has %s property which replaces existing phandle information", 434 node->fullpath, prop->name); 435 436 other = get_node_by_phandle(root, phandle); 437 if (other && (other != node)) { 438 FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)", 439 node->fullpath, phandle, other->fullpath); 440 return; 441 } 442 443 node->phandle = phandle; 444 } 445 PROP_ERROR(explicit_phandles, NULL); 446 447 static void check_name_properties(struct check *c, struct node *root, 448 struct node *node) 449 { 450 struct property **pp, *prop = NULL; 451 452 for (pp = &node->proplist; *pp; pp = &((*pp)->next)) 453 if (streq((*pp)->name, "name")) { 454 prop = *pp; 455 break; 456 } 457 458 if (!prop) 459 return; /* No name property, that's fine */ 460 461 if ((prop->val.len != node->basenamelen+1) 462 || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { 463 FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead" 464 " of base node name)", node->fullpath, prop->val.val); 465 } else { 466 /* The name property is correct, and therefore redundant. 467 * Delete it */ 468 *pp = prop->next; 469 free(prop->name); 470 data_free(prop->val); 471 free(prop); 472 } 473 } 474 ERROR_IF_NOT_STRING(name_is_string, "name"); 475 NODE_ERROR(name_properties, NULL, &name_is_string); 476 477 /* 478 * Reference fixup functions 479 */ 480 481 static void fixup_phandle_references(struct check *c, struct node *dt, 482 struct node *node, struct property *prop) 483 { 484 struct marker *m = prop->val.markers; 485 struct node *refnode; 486 cell_t phandle; 487 488 for_each_marker_of_type(m, REF_PHANDLE) { 489 assert(m->offset + sizeof(cell_t) <= prop->val.len); 490 491 refnode = get_node_by_ref(dt, m->ref); 492 if (! refnode) { 493 FAIL(c, "Reference to non-existent node or label \"%s\"\n", 494 m->ref); 495 continue; 496 } 497 498 phandle = get_node_phandle(dt, refnode); 499 *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); 500 } 501 } 502 ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL, 503 &duplicate_node_names, &explicit_phandles); 504 505 static void fixup_path_references(struct check *c, struct node *dt, 506 struct node *node, struct property *prop) 507 { 508 struct marker *m = prop->val.markers; 509 struct node *refnode; 510 char *path; 511 512 for_each_marker_of_type(m, REF_PATH) { 513 assert(m->offset <= prop->val.len); 514 515 refnode = get_node_by_ref(dt, m->ref); 516 if (!refnode) { 517 FAIL(c, "Reference to non-existent node or label \"%s\"\n", 518 m->ref); 519 continue; 520 } 521 522 path = refnode->fullpath; 523 prop->val = data_insert_at_marker(prop->val, m, path, 524 strlen(path) + 1); 525 } 526 } 527 ERROR(path_references, NULL, NULL, fixup_path_references, NULL, 528 &duplicate_node_names); 529 530 /* 531 * Semantic checks 532 */ 533 WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); 534 WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); 535 WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); 536 537 WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); 538 WARNING_IF_NOT_STRING(model_is_string, "model"); 539 WARNING_IF_NOT_STRING(status_is_string, "status"); 540 541 static void fixup_addr_size_cells(struct check *c, struct node *dt, 542 struct node *node) 543 { 544 struct property *prop; 545 546 node->addr_cells = -1; 547 node->size_cells = -1; 548 549 prop = get_property(node, "#address-cells"); 550 if (prop) 551 node->addr_cells = propval_cell(prop); 552 553 prop = get_property(node, "#size-cells"); 554 if (prop) 555 node->size_cells = propval_cell(prop); 556 } 557 WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, 558 &address_cells_is_cell, &size_cells_is_cell); 559 560 #define node_addr_cells(n) \ 561 (((n)->addr_cells == -1) ? 2 : (n)->addr_cells) 562 #define node_size_cells(n) \ 563 (((n)->size_cells == -1) ? 1 : (n)->size_cells) 564 565 static void check_reg_format(struct check *c, struct node *dt, 566 struct node *node) 567 { 568 struct property *prop; 569 int addr_cells, size_cells, entrylen; 570 571 prop = get_property(node, "reg"); 572 if (!prop) 573 return; /* No "reg", that's fine */ 574 575 if (!node->parent) { 576 FAIL(c, "Root node has a \"reg\" property"); 577 return; 578 } 579 580 if (prop->val.len == 0) 581 FAIL(c, "\"reg\" property in %s is empty", node->fullpath); 582 583 addr_cells = node_addr_cells(node->parent); 584 size_cells = node_size_cells(node->parent); 585 entrylen = (addr_cells + size_cells) * sizeof(cell_t); 586 587 if (!entrylen || (prop->val.len % entrylen) != 0) 588 FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) " 589 "(#address-cells == %d, #size-cells == %d)", 590 node->fullpath, prop->val.len, addr_cells, size_cells); 591 } 592 NODE_WARNING(reg_format, NULL, &addr_size_cells); 593 594 static void check_ranges_format(struct check *c, struct node *dt, 595 struct node *node) 596 { 597 struct property *prop; 598 int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen; 599 600 prop = get_property(node, "ranges"); 601 if (!prop) 602 return; 603 604 if (!node->parent) { 605 FAIL(c, "Root node has a \"ranges\" property"); 606 return; 607 } 608 609 p_addr_cells = node_addr_cells(node->parent); 610 p_size_cells = node_size_cells(node->parent); 611 c_addr_cells = node_addr_cells(node); 612 c_size_cells = node_size_cells(node); 613 entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t); 614 615 if (prop->val.len == 0) { 616 if (p_addr_cells != c_addr_cells) 617 FAIL(c, "%s has empty \"ranges\" property but its " 618 "#address-cells (%d) differs from %s (%d)", 619 node->fullpath, c_addr_cells, node->parent->fullpath, 620 p_addr_cells); 621 if (p_size_cells != c_size_cells) 622 FAIL(c, "%s has empty \"ranges\" property but its " 623 "#size-cells (%d) differs from %s (%d)", 624 node->fullpath, c_size_cells, node->parent->fullpath, 625 p_size_cells); 626 } else if ((prop->val.len % entrylen) != 0) { 627 FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) " 628 "(parent #address-cells == %d, child #address-cells == %d, " 629 "#size-cells == %d)", node->fullpath, prop->val.len, 630 p_addr_cells, c_addr_cells, c_size_cells); 631 } 632 } 633 NODE_WARNING(ranges_format, NULL, &addr_size_cells); 634 635 /* 636 * Style checks 637 */ 638 static void check_avoid_default_addr_size(struct check *c, struct node *dt, 639 struct node *node) 640 { 641 struct property *reg, *ranges; 642 643 if (!node->parent) 644 return; /* Ignore root node */ 645 646 reg = get_property(node, "reg"); 647 ranges = get_property(node, "ranges"); 648 649 if (!reg && !ranges) 650 return; 651 652 if (node->parent->addr_cells == -1) 653 FAIL(c, "Relying on default #address-cells value for %s", 654 node->fullpath); 655 656 if (node->parent->size_cells == -1) 657 FAIL(c, "Relying on default #size-cells value for %s", 658 node->fullpath); 659 } 660 NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells); 661 662 static void check_obsolete_chosen_interrupt_controller(struct check *c, 663 struct node *dt) 664 { 665 struct node *chosen; 666 struct property *prop; 667 668 chosen = get_node_by_path(dt, "/chosen"); 669 if (!chosen) 670 return; 671 672 prop = get_property(chosen, "interrupt-controller"); 673 if (prop) 674 FAIL(c, "/chosen has obsolete \"interrupt-controller\" " 675 "property"); 676 } 677 TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); 678 679 static struct check *check_table[] = { 680 &duplicate_node_names, &duplicate_property_names, 681 &node_name_chars, &node_name_format, &property_name_chars, 682 &name_is_string, &name_properties, 683 684 &duplicate_label, 685 686 &explicit_phandles, 687 &phandle_references, &path_references, 688 689 &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, 690 &device_type_is_string, &model_is_string, &status_is_string, 691 692 &addr_size_cells, ®_format, &ranges_format, 693 694 &unit_address_vs_reg, 695 696 &avoid_default_addr_size, 697 &obsolete_chosen_interrupt_controller, 698 699 &always_fail, 700 }; 701 702 static void enable_warning_error(struct check *c, bool warn, bool error) 703 { 704 int i; 705 706 /* Raising level, also raise it for prereqs */ 707 if ((warn && !c->warn) || (error && !c->error)) 708 for (i = 0; i < c->num_prereqs; i++) 709 enable_warning_error(c->prereq[i], warn, error); 710 711 c->warn = c->warn || warn; 712 c->error = c->error || error; 713 } 714 715 static void disable_warning_error(struct check *c, bool warn, bool error) 716 { 717 int i; 718 719 /* Lowering level, also lower it for things this is the prereq 720 * for */ 721 if ((warn && c->warn) || (error && c->error)) { 722 for (i = 0; i < ARRAY_SIZE(check_table); i++) { 723 struct check *cc = check_table[i]; 724 int j; 725 726 for (j = 0; j < cc->num_prereqs; j++) 727 if (cc->prereq[j] == c) 728 disable_warning_error(cc, warn, error); 729 } 730 } 731 732 c->warn = c->warn && !warn; 733 c->error = c->error && !error; 734 } 735 736 void parse_checks_option(bool warn, bool error, const char *arg) 737 { 738 int i; 739 const char *name = arg; 740 bool enable = true; 741 742 if ((strncmp(arg, "no-", 3) == 0) 743 || (strncmp(arg, "no_", 3) == 0)) { 744 name = arg + 3; 745 enable = false; 746 } 747 748 for (i = 0; i < ARRAY_SIZE(check_table); i++) { 749 struct check *c = check_table[i]; 750 751 if (streq(c->name, name)) { 752 if (enable) 753 enable_warning_error(c, warn, error); 754 else 755 disable_warning_error(c, warn, error); 756 return; 757 } 758 } 759 760 die("Unrecognized check name \"%s\"\n", name); 761 } 762 763 void process_checks(bool force, struct boot_info *bi) 764 { 765 struct node *dt = bi->dt; 766 int i; 767 int error = 0; 768 769 for (i = 0; i < ARRAY_SIZE(check_table); i++) { 770 struct check *c = check_table[i]; 771 772 if (c->warn || c->error) 773 error = error || run_check(c, dt); 774 } 775 776 if (error) { 777 if (!force) { 778 fprintf(stderr, "ERROR: Input tree has errors, aborting " 779 "(use -f to force output)\n"); 780 exit(2); 781 } else if (quiet < 3) { 782 fprintf(stderr, "Warning: Input tree has errors, " 783 "output forced\n"); 784 } 785 } 786 } 787