blob: c8a099e8c05b70e8177f8395023a35ec4ef52bd1 [file] [log] [blame]
David Gibson2f1ccc32007-11-01 16:49:26 +11001/*
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
David Gibsonb16a2bd2007-11-22 14:38:07 +110023#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
34enum checklevel {
35 IGNORE = 0,
36 WARN = 1,
37 ERROR = 2,
38};
39
40enum checkstatus {
41 UNCHECKED = 0,
42 PREREQ,
43 PASSED,
44 FAILED,
45};
46
47struct check;
48
49typedef void (*tree_check_fn)(struct check *c, struct node *dt);
50typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node);
51typedef void (*prop_check_fn)(struct check *c, struct node *dt,
52 struct node *node, struct property *prop);
53
54struct check {
55 const char *name;
56 tree_check_fn tree_fn;
57 node_check_fn node_fn;
58 prop_check_fn prop_fn;
59 void *data;
60 enum checklevel level;
61 enum checkstatus status;
62 int inprogress;
63 int num_prereqs;
64 struct check **prereq;
65};
66
67#define CHECK(nm, tfn, nfn, pfn, d, lvl, ...) \
68 static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
69 static struct check nm = { \
70 .name = #nm, \
71 .tree_fn = (tfn), \
72 .node_fn = (nfn), \
73 .prop_fn = (pfn), \
74 .data = (d), \
75 .level = (lvl), \
76 .status = UNCHECKED, \
77 .num_prereqs = ARRAY_SIZE(nm##_prereqs), \
78 .prereq = nm##_prereqs, \
79 };
80
81#define TREE_CHECK(nm, d, lvl, ...) \
82 CHECK(nm, check_##nm, NULL, NULL, d, lvl, __VA_ARGS__)
83#define NODE_CHECK(nm, d, lvl, ...) \
84 CHECK(nm, NULL, check_##nm, NULL, d, lvl, __VA_ARGS__)
85#define PROP_CHECK(nm, d, lvl, ...) \
86 CHECK(nm, NULL, NULL, check_##nm, d, lvl, __VA_ARGS__)
87#define BATCH_CHECK(nm, lvl, ...) \
88 CHECK(nm, NULL, NULL, NULL, NULL, lvl, __VA_ARGS__)
89
90static inline void check_msg(struct check *c, const char *fmt, ...)
91{
92 va_list ap;
93 va_start(ap, fmt);
94
95 if ((c->level < WARN) || (c->level <= quiet))
96 return; /* Suppress message */
97
98 fprintf(stderr, "%s (%s): ",
99 (c->level == ERROR) ? "ERROR" : "Warning", c->name);
100 vfprintf(stderr, fmt, ap);
101 fprintf(stderr, "\n");
102}
103
104#define FAIL(c, fmt, ...) \
105 do { \
106 TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
107 (c)->status = FAILED; \
108 check_msg((c), fmt, __VA_ARGS__); \
109 } while (0)
110
111static void check_nodes_props(struct check *c, struct node *dt, struct node *node)
112{
113 struct node *child;
114 struct property *prop;
115
116 TRACE(c, "%s", node->fullpath);
117 if (c->node_fn)
118 c->node_fn(c, dt, node);
119
120 if (c->prop_fn)
121 for_each_property(node, prop) {
122 TRACE(c, "%s\t'%s'", node->fullpath, prop->name);
123 c->prop_fn(c, dt, node, prop);
124 }
125
126 for_each_child(node, child)
127 check_nodes_props(c, dt, child);
128}
129
130static int run_check(struct check *c, struct node *dt)
131{
132 int error = 0;
133 int i;
134
135 assert(!c->inprogress);
136
137 if (c->status != UNCHECKED)
138 goto out;
139
140 c->inprogress = 1;
141
142 for (i = 0; i < c->num_prereqs; i++) {
143 struct check *prq = c->prereq[i];
144 error |= run_check(prq, dt);
145 if (prq->status != PASSED) {
146 c->status = PREREQ;
147 check_msg(c, "Failed prerequisite '%s'",
148 c->prereq[i]->name);
149 }
150 }
151
152 if (c->status != UNCHECKED)
153 goto out;
154
155 if (c->node_fn || c->prop_fn)
156 check_nodes_props(c, dt, dt);
157
158 if (c->tree_fn)
159 c->tree_fn(c, dt);
160 if (c->status == UNCHECKED)
161 c->status = PASSED;
162
163 TRACE(c, "\tCompleted, status %d", c->status);
164
165out:
166 c->inprogress = 0;
167 if ((c->status != PASSED) && (c->level == ERROR))
168 error = 1;
169 return error;
170}
171
David Gibson2f1ccc32007-11-01 16:49:26 +1100172/*
173 * Structural check functions
174 */
175
David Gibsonb16a2bd2007-11-22 14:38:07 +1100176static void check_duplicate_node_names(struct check *c, struct node *dt,
177 struct node *node)
178{
179 struct node *child, *child2;
180
181 for_each_child(node, child)
182 for (child2 = child->next_sibling;
183 child2;
184 child2 = child2->next_sibling)
185 if (streq(child->name, child2->name))
186 FAIL(c, "Duplicate node name %s",
187 child->fullpath);
188}
189NODE_CHECK(duplicate_node_names, NULL, ERROR);
190
191static void check_duplicate_property_names(struct check *c, struct node *dt,
192 struct node *node)
193{
194 struct property *prop, *prop2;
195
196 for_each_property(node, prop)
197 for (prop2 = prop->next; prop2; prop2 = prop2->next)
198 if (streq(prop->name, prop2->name))
199 FAIL(c, "Duplicate property name %s in %s",
200 prop->name, node->fullpath);
201}
202NODE_CHECK(duplicate_property_names, NULL, ERROR);
203
204static void check_explicit_phandles(struct check *c, struct node *root,
205 struct node *node)
206{
207 struct property *prop;
208 struct node *other;
209 cell_t phandle;
210
211 prop = get_property(node, "linux,phandle");
212 if (! prop)
213 return; /* No phandle, that's fine */
214
215 if (prop->val.len != sizeof(cell_t)) {
216 FAIL(c, "%s has bad length (%d) linux,phandle property",
217 node->fullpath, prop->val.len);
218 return;
219 }
220
221 phandle = propval_cell(prop);
222 if ((phandle == 0) || (phandle == -1)) {
223 FAIL(c, "%s has invalid linux,phandle value 0x%x",
224 node->fullpath, phandle);
225 return;
226 }
227
228 other = get_node_by_phandle(root, phandle);
229 if (other) {
230 FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
231 node->fullpath, phandle, other->fullpath);
232 return;
233 }
234
235 node->phandle = phandle;
236}
237NODE_CHECK(explicit_phandles, NULL, ERROR);
238
239/*
240 * Reference fixup functions
241 */
242
243static void fixup_phandle_references(struct check *c, struct node *dt,
244 struct node *node, struct property *prop)
245{
246 struct fixup *f = prop->val.refs;
247 struct node *refnode;
248 cell_t phandle;
249
250 while (f) {
251 assert(f->offset + sizeof(cell_t) <= prop->val.len);
252
253 refnode = get_node_by_ref(dt, f->ref);
254 if (! refnode) {
255 FAIL(c, "Reference to non-existent node or label \"%s\"\n",
256 f->ref);
257 } else {
258 phandle = get_node_phandle(dt, refnode);
259
260 *((cell_t *)(prop->val.val + f->offset)) = cpu_to_be32(phandle);
261 }
262
263 prop->val.refs = f->next;
264 fixup_free(f);
265 f = prop->val.refs;
266 }
267}
268CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
269 &duplicate_node_names, &explicit_phandles);
270
271static struct check *check_table[] = {
272 &duplicate_node_names, &duplicate_property_names,
273 &explicit_phandles,
274 &phandle_references,
275};
276
277void process_checks(int force, struct node *dt)
278{
279 int i;
280 int error = 0;
281
282 for (i = 0; i < ARRAY_SIZE(check_table); i++) {
283 struct check *c = check_table[i];
284
285 if (c->level != IGNORE)
286 error = error || run_check(c, dt);
287 }
288
289 if (error) {
290 if (!force) {
291 fprintf(stderr, "ERROR: Input tree has errors, aborting "
292 "(use -f to force output)\n");
293 exit(2);
294 } else if (quiet < 3) {
295 fprintf(stderr, "Warning: Input tree has errors, "
296 "output forced\n");
297 }
298 }
299}
300
301/*
302 * Semantic check functions
303 */
304
David Gibson2f1ccc32007-11-01 16:49:26 +1100305#define ERRMSG(...) if (quiet < 2) fprintf(stderr, "ERROR: " __VA_ARGS__)
306#define WARNMSG(...) if (quiet < 1) fprintf(stderr, "Warning: " __VA_ARGS__)
307
308#define DO_ERR(...) do {ERRMSG(__VA_ARGS__); ok = 0; } while (0)
309
David Gibson2f1ccc32007-11-01 16:49:26 +1100310static int must_be_one_cell(struct property *prop, struct node *node)
311{
312 if (prop->val.len != sizeof(cell_t)) {
313 ERRMSG("\"%s\" property in %s has the wrong length (should be 1 cell)\n",
314 prop->name, node->fullpath);
315 return 0;
316 }
317
318 return 1;
319}
320
321static int must_be_cells(struct property *prop, struct node *node)
322{
323 if ((prop->val.len % sizeof(cell_t)) != 0) {
324 ERRMSG("\"%s\" property in %s is not a multiple of cell size\n",
325 prop->name, node->fullpath);
326 return 0;
327 }
328
329 return 1;
330}
331
332static int must_be_string(struct property *prop, struct node *node)
333{
334 if (! data_is_one_string(prop->val)) {
335 ERRMSG("\"%s\" property in %s is not a string\n",
336 prop->name, node->fullpath);
337 return 0;
338 }
339
340 return 1;
341}
342
343static int name_prop_check(struct property *prop, struct node *node)
344{
345 if ((prop->val.len != node->basenamelen+1)
346 || !strneq(prop->val.val, node->name, node->basenamelen)) {
347 ERRMSG("name property \"%s\" does not match node basename in %s\n",
348 prop->val.val,
349 node->fullpath);
350 return 0;
351 }
352
353 return 1;
354}
355
356static struct {
357 char *propname;
358 int (*check_fn)(struct property *prop, struct node *node);
359} prop_checker_table[] = {
360 {"name", must_be_string},
361 {"name", name_prop_check},
362 {"linux,phandle", must_be_one_cell},
363 {"#address-cells", must_be_one_cell},
364 {"#size-cells", must_be_one_cell},
365 {"reg", must_be_cells},
366 {"model", must_be_string},
367 {"device_type", must_be_string},
368};
369
370static int check_properties(struct node *node)
371{
372 struct property *prop;
373 struct node *child;
374 int i;
375 int ok = 1;
376
377 for_each_property(node, prop)
378 for (i = 0; i < ARRAY_SIZE(prop_checker_table); i++)
379 if (streq(prop->name, prop_checker_table[i].propname))
380 if (! prop_checker_table[i].check_fn(prop, node)) {
381 ok = 0;
382 break;
383 }
384
385 for_each_child(node, child)
386 if (! check_properties(child))
387 ok = 0;
388
389 return ok;
390}
391
392#define CHECK_HAVE(node, propname) \
393 do { \
394 if (! (prop = get_property((node), (propname)))) \
395 DO_ERR("Missing \"%s\" property in %s\n", (propname), \
396 (node)->fullpath); \
397 } while (0);
398
399#define CHECK_HAVE_WARN(node, propname) \
400 do { \
401 if (! (prop = get_property((node), (propname)))) \
402 WARNMSG("%s has no \"%s\" property\n", \
403 (node)->fullpath, (propname)); \
404 } while (0)
405
406#define CHECK_HAVE_STRING(node, propname) \
407 do { \
408 CHECK_HAVE((node), (propname)); \
409 if (prop && !data_is_one_string(prop->val)) \
410 DO_ERR("\"%s\" property in %s is not a string\n", \
411 (propname), (node)->fullpath); \
412 } while (0)
413
414#define CHECK_HAVE_STREQ(node, propname, value) \
415 do { \
416 CHECK_HAVE_STRING((node), (propname)); \
417 if (prop && !streq(prop->val.val, (value))) \
418 DO_ERR("%s has wrong %s, %s (should be %s\n", \
419 (node)->fullpath, (propname), \
420 prop->val.val, (value)); \
421 } while (0)
422
423#define CHECK_HAVE_ONECELL(node, propname) \
424 do { \
425 CHECK_HAVE((node), (propname)); \
426 if (prop && (prop->val.len != sizeof(cell_t))) \
427 DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \
428 } while (0)
429
430#define CHECK_HAVE_WARN_ONECELL(node, propname) \
431 do { \
432 CHECK_HAVE_WARN((node), (propname)); \
433 if (prop && (prop->val.len != sizeof(cell_t))) \
434 DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \
435 } while (0)
436
437#define CHECK_HAVE_WARN_PHANDLE(xnode, propname, root) \
438 do { \
439 struct node *ref; \
440 CHECK_HAVE_WARN_ONECELL((xnode), (propname)); \
441 if (prop) {\
442 cell_t phandle = propval_cell(prop); \
443 if ((phandle == 0) || (phandle == -1)) { \
444 DO_ERR("\"%s\" property in %s contains an invalid phandle %x\n", (propname), (xnode)->fullpath, phandle); \
445 } else { \
446 ref = get_node_by_phandle((root), propval_cell(prop)); \
447 if (! ref) \
448 DO_ERR("\"%s\" property in %s refers to non-existant phandle %x\n", (propname), (xnode)->fullpath, propval_cell(prop)); \
449 } \
450 } \
451 } while (0)
452
453#define CHECK_HAVE_WARN_STRING(node, propname) \
454 do { \
455 CHECK_HAVE_WARN((node), (propname)); \
456 if (prop && !data_is_one_string(prop->val)) \
457 DO_ERR("\"%s\" property in %s is not a string\n", \
458 (propname), (node)->fullpath); \
459 } while (0)
460
461static int check_root(struct node *root)
462{
463 struct property *prop;
464 int ok = 1;
465
466 CHECK_HAVE_STRING(root, "model");
467
468 CHECK_HAVE(root, "#address-cells");
469 CHECK_HAVE(root, "#size-cells");
470
471 CHECK_HAVE_WARN(root, "compatible");
472
473 return ok;
474}
475
476static int check_cpus(struct node *root, int outversion, int boot_cpuid_phys)
477{
478 struct node *cpus, *cpu;
479 struct property *prop;
480 struct node *bootcpu = NULL;
481 int ok = 1;
482
483 cpus = get_subnode(root, "cpus");
484 if (! cpus) {
485 ERRMSG("Missing /cpus node\n");
486 return 0;
487 }
488
489 CHECK_HAVE_WARN(cpus, "#address-cells");
490 CHECK_HAVE_WARN(cpus, "#size-cells");
491
492 for_each_child(cpus, cpu) {
493 CHECK_HAVE_STREQ(cpu, "device_type", "cpu");
494
495 if (cpu->addr_cells != 1)
496 DO_ERR("%s has bad #address-cells value %d (should be 1)\n",
497 cpu->fullpath, cpu->addr_cells);
498 if (cpu->size_cells != 0)
499 DO_ERR("%s has bad #size-cells value %d (should be 0)\n",
500 cpu->fullpath, cpu->size_cells);
501
502 CHECK_HAVE_ONECELL(cpu, "reg");
503 if (prop) {
504 cell_t unitnum;
505 char *eptr;
506
507 unitnum = strtol(get_unitname(cpu), &eptr, 16);
508 if (*eptr) {
509 WARNMSG("%s has bad format unit name %s (should be CPU number\n",
510 cpu->fullpath, get_unitname(cpu));
511 } else if (unitnum != propval_cell(prop)) {
512 WARNMSG("%s unit name \"%s\" does not match \"reg\" property <%x>\n",
513 cpu->fullpath, get_unitname(cpu),
514 propval_cell(prop));
515 }
516 }
517
518/* CHECK_HAVE_ONECELL(cpu, "d-cache-line-size"); */
519/* CHECK_HAVE_ONECELL(cpu, "i-cache-line-size"); */
520 CHECK_HAVE_ONECELL(cpu, "d-cache-size");
521 CHECK_HAVE_ONECELL(cpu, "i-cache-size");
522
523 CHECK_HAVE_WARN_ONECELL(cpu, "clock-frequency");
524 CHECK_HAVE_WARN_ONECELL(cpu, "timebase-frequency");
525
526 prop = get_property(cpu, "linux,boot-cpu");
527 if (prop) {
528 if (prop->val.len)
529 WARNMSG("\"linux,boot-cpu\" property in %s is non-empty\n",
530 cpu->fullpath);
531 if (bootcpu)
532 DO_ERR("Multiple boot cpus (%s and %s)\n",
533 bootcpu->fullpath, cpu->fullpath);
534 else
535 bootcpu = cpu;
536 }
537 }
538
539 if (outversion < 2) {
540 if (! bootcpu)
541 WARNMSG("No cpu has \"linux,boot-cpu\" property\n");
542 } else {
543 if (bootcpu)
544 WARNMSG("\"linux,boot-cpu\" property is deprecated in blob version 2 or higher\n");
545 if (boot_cpuid_phys == 0xfeedbeef)
546 WARNMSG("physical boot CPU not set. Use -b option to set\n");
547 }
548
549 return ok;
550}
551
552static int check_memory(struct node *root)
553{
554 struct node *mem;
555 struct property *prop;
556 int nnodes = 0;
557 int ok = 1;
558
559 for_each_child(root, mem) {
560 if (! strneq(mem->name, "memory", mem->basenamelen))
561 continue;
562
563 nnodes++;
564
565 CHECK_HAVE_STREQ(mem, "device_type", "memory");
566 CHECK_HAVE(mem, "reg");
567 }
568
569 if (nnodes == 0) {
570 ERRMSG("No memory nodes\n");
571 return 0;
572 }
573
574 return ok;
575}
576
577static int check_chosen(struct node *root)
578{
579 struct node *chosen;
580 struct property *prop;
581 int ok = 1;
582
583 chosen = get_subnode(root, "chosen");
584 if (!chosen)
585 return ok;
586
587 /* give warning for obsolete interrupt-controller property */
588 do {
589 if ((prop = get_property(chosen, "interrupt-controller")) != NULL) {
590 WARNMSG("%s has obsolete \"%s\" property\n",
591 chosen->fullpath, "interrupt-controller");
592 }
593 } while (0);
594
595 return ok;
596}
597
598static int check_addr_size_reg(struct node *node,
599 int p_addr_cells, int p_size_cells)
600{
601 int addr_cells = p_addr_cells;
602 int size_cells = p_size_cells;
603 struct property *prop;
604 struct node *child;
605 int ok = 1;
606
607 node->addr_cells = addr_cells;
608 node->size_cells = size_cells;
609
610 prop = get_property(node, "reg");
611 if (prop) {
612 int len = prop->val.len / 4;
613
614 if ((len % (addr_cells+size_cells)) != 0)
615 DO_ERR("\"reg\" property in %s has invalid length (%d) for given #address-cells (%d) and #size-cells (%d)\n",
616 node->fullpath, prop->val.len,
617 addr_cells, size_cells);
618 }
619
620 prop = get_property(node, "#address-cells");
621 if (prop)
622 addr_cells = propval_cell(prop);
623
624 prop = get_property(node, "#size-cells");
625 if (prop)
626 size_cells = propval_cell(prop);
627
628 for_each_child(node, child) {
629 ok = ok && check_addr_size_reg(child, addr_cells, size_cells);
630 }
631
632 return ok;
633}
634
635int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys)
636{
637 int ok = 1;
638
639 ok = ok && check_properties(dt);
640 ok = ok && check_addr_size_reg(dt, -1, -1);
641 ok = ok && check_root(dt);
642 ok = ok && check_cpus(dt, outversion, boot_cpuid_phys);
643 ok = ok && check_memory(dt);
644 ok = ok && check_chosen(dt);
645 if (! ok)
646 return 0;
647
648 return 1;
649}