Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/scripts/dtc/checks.c
10817 views
1
/*
2
* (C) Copyright David Gibson <[email protected]>, 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 checklevel {
35
IGNORE = 0,
36
WARN = 1,
37
ERROR = 2,
38
};
39
40
enum checkstatus {
41
UNCHECKED = 0,
42
PREREQ,
43
PASSED,
44
FAILED,
45
};
46
47
struct check;
48
49
typedef void (*tree_check_fn)(struct check *c, struct node *dt);
50
typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node);
51
typedef void (*prop_check_fn)(struct check *c, struct node *dt,
52
struct node *node, struct property *prop);
53
54
struct 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
90
#ifdef __GNUC__
91
static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
92
#endif
93
static inline void check_msg(struct check *c, const char *fmt, ...)
94
{
95
va_list ap;
96
va_start(ap, fmt);
97
98
if ((c->level < WARN) || (c->level <= quiet))
99
return; /* Suppress message */
100
101
fprintf(stderr, "%s (%s): ",
102
(c->level == ERROR) ? "ERROR" : "Warning", c->name);
103
vfprintf(stderr, fmt, ap);
104
fprintf(stderr, "\n");
105
}
106
107
#define FAIL(c, ...) \
108
do { \
109
TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
110
(c)->status = FAILED; \
111
check_msg((c), __VA_ARGS__); \
112
} while (0)
113
114
static void check_nodes_props(struct check *c, struct node *dt, struct node *node)
115
{
116
struct node *child;
117
struct property *prop;
118
119
TRACE(c, "%s", node->fullpath);
120
if (c->node_fn)
121
c->node_fn(c, dt, node);
122
123
if (c->prop_fn)
124
for_each_property(node, prop) {
125
TRACE(c, "%s\t'%s'", node->fullpath, prop->name);
126
c->prop_fn(c, dt, node, prop);
127
}
128
129
for_each_child(node, child)
130
check_nodes_props(c, dt, child);
131
}
132
133
static int run_check(struct check *c, struct node *dt)
134
{
135
int error = 0;
136
int i;
137
138
assert(!c->inprogress);
139
140
if (c->status != UNCHECKED)
141
goto out;
142
143
c->inprogress = 1;
144
145
for (i = 0; i < c->num_prereqs; i++) {
146
struct check *prq = c->prereq[i];
147
error |= run_check(prq, dt);
148
if (prq->status != PASSED) {
149
c->status = PREREQ;
150
check_msg(c, "Failed prerequisite '%s'",
151
c->prereq[i]->name);
152
}
153
}
154
155
if (c->status != UNCHECKED)
156
goto out;
157
158
if (c->node_fn || c->prop_fn)
159
check_nodes_props(c, dt, dt);
160
161
if (c->tree_fn)
162
c->tree_fn(c, dt);
163
if (c->status == UNCHECKED)
164
c->status = PASSED;
165
166
TRACE(c, "\tCompleted, status %d", c->status);
167
168
out:
169
c->inprogress = 0;
170
if ((c->status != PASSED) && (c->level == ERROR))
171
error = 1;
172
return error;
173
}
174
175
/*
176
* Utility check functions
177
*/
178
179
static void check_is_string(struct check *c, struct node *root,
180
struct node *node)
181
{
182
struct property *prop;
183
char *propname = c->data;
184
185
prop = get_property(node, propname);
186
if (!prop)
187
return; /* Not present, assumed ok */
188
189
if (!data_is_one_string(prop->val))
190
FAIL(c, "\"%s\" property in %s is not a string",
191
propname, node->fullpath);
192
}
193
#define CHECK_IS_STRING(nm, propname, lvl) \
194
CHECK(nm, NULL, check_is_string, NULL, (propname), (lvl))
195
196
static void check_is_cell(struct check *c, struct node *root,
197
struct node *node)
198
{
199
struct property *prop;
200
char *propname = c->data;
201
202
prop = get_property(node, propname);
203
if (!prop)
204
return; /* Not present, assumed ok */
205
206
if (prop->val.len != sizeof(cell_t))
207
FAIL(c, "\"%s\" property in %s is not a single cell",
208
propname, node->fullpath);
209
}
210
#define CHECK_IS_CELL(nm, propname, lvl) \
211
CHECK(nm, NULL, check_is_cell, NULL, (propname), (lvl))
212
213
/*
214
* Structural check functions
215
*/
216
217
static void check_duplicate_node_names(struct check *c, struct node *dt,
218
struct node *node)
219
{
220
struct node *child, *child2;
221
222
for_each_child(node, child)
223
for (child2 = child->next_sibling;
224
child2;
225
child2 = child2->next_sibling)
226
if (streq(child->name, child2->name))
227
FAIL(c, "Duplicate node name %s",
228
child->fullpath);
229
}
230
NODE_CHECK(duplicate_node_names, NULL, ERROR);
231
232
static void check_duplicate_property_names(struct check *c, struct node *dt,
233
struct node *node)
234
{
235
struct property *prop, *prop2;
236
237
for_each_property(node, prop)
238
for (prop2 = prop->next; prop2; prop2 = prop2->next)
239
if (streq(prop->name, prop2->name))
240
FAIL(c, "Duplicate property name %s in %s",
241
prop->name, node->fullpath);
242
}
243
NODE_CHECK(duplicate_property_names, NULL, ERROR);
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
281
#define DESCLABEL_FMT "%s%s%s%s%s"
282
#define DESCLABEL_ARGS(node,prop,mark) \
283
((mark) ? "value of " : ""), \
284
((prop) ? "'" : ""), \
285
((prop) ? (prop)->name : ""), \
286
((prop) ? "' in " : ""), (node)->fullpath
287
288
static void check_duplicate_label(struct check *c, struct node *dt,
289
const char *label, struct node *node,
290
struct property *prop, struct marker *mark)
291
{
292
struct node *othernode = NULL;
293
struct property *otherprop = NULL;
294
struct marker *othermark = NULL;
295
296
othernode = get_node_by_label(dt, label);
297
298
if (!othernode)
299
otherprop = get_property_by_label(dt, label, &othernode);
300
if (!othernode)
301
othermark = get_marker_label(dt, label, &othernode,
302
&otherprop);
303
304
if (!othernode)
305
return;
306
307
if ((othernode != node) || (otherprop != prop) || (othermark != mark))
308
FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT
309
" and " DESCLABEL_FMT,
310
label, DESCLABEL_ARGS(node, prop, mark),
311
DESCLABEL_ARGS(othernode, otherprop, othermark));
312
}
313
314
static void check_duplicate_label_node(struct check *c, struct node *dt,
315
struct node *node)
316
{
317
struct label *l;
318
319
for_each_label(node->labels, l)
320
check_duplicate_label(c, dt, l->label, node, NULL, NULL);
321
}
322
static void check_duplicate_label_prop(struct check *c, struct node *dt,
323
struct node *node, struct property *prop)
324
{
325
struct marker *m = prop->val.markers;
326
struct label *l;
327
328
for_each_label(prop->labels, l)
329
check_duplicate_label(c, dt, l->label, node, prop, NULL);
330
331
for_each_marker_of_type(m, LABEL)
332
check_duplicate_label(c, dt, m->ref, node, prop, m);
333
}
334
CHECK(duplicate_label, NULL, check_duplicate_label_node,
335
check_duplicate_label_prop, NULL, ERROR);
336
337
static void check_explicit_phandles(struct check *c, struct node *root,
338
struct node *node, struct property *prop)
339
{
340
struct marker *m;
341
struct node *other;
342
cell_t phandle;
343
344
if (!streq(prop->name, "phandle")
345
&& !streq(prop->name, "linux,phandle"))
346
return;
347
348
if (prop->val.len != sizeof(cell_t)) {
349
FAIL(c, "%s has bad length (%d) %s property",
350
node->fullpath, prop->val.len, prop->name);
351
return;
352
}
353
354
m = prop->val.markers;
355
for_each_marker_of_type(m, REF_PHANDLE) {
356
assert(m->offset == 0);
357
if (node != get_node_by_ref(root, m->ref))
358
/* "Set this node's phandle equal to some
359
* other node's phandle". That's nonsensical
360
* by construction. */ {
361
FAIL(c, "%s in %s is a reference to another node",
362
prop->name, node->fullpath);
363
return;
364
}
365
/* But setting this node's phandle equal to its own
366
* phandle is allowed - that means allocate a unique
367
* phandle for this node, even if it's not otherwise
368
* referenced. The value will be filled in later, so
369
* no further checking for now. */
370
return;
371
}
372
373
phandle = propval_cell(prop);
374
375
if ((phandle == 0) || (phandle == -1)) {
376
FAIL(c, "%s has bad value (0x%x) in %s property",
377
node->fullpath, phandle, prop->name);
378
return;
379
}
380
381
if (node->phandle && (node->phandle != phandle))
382
FAIL(c, "%s has %s property which replaces existing phandle information",
383
node->fullpath, prop->name);
384
385
other = get_node_by_phandle(root, phandle);
386
if (other && (other != node)) {
387
FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
388
node->fullpath, phandle, other->fullpath);
389
return;
390
}
391
392
node->phandle = phandle;
393
}
394
PROP_CHECK(explicit_phandles, NULL, ERROR);
395
396
static void check_name_properties(struct check *c, struct node *root,
397
struct node *node)
398
{
399
struct property **pp, *prop = NULL;
400
401
for (pp = &node->proplist; *pp; pp = &((*pp)->next))
402
if (streq((*pp)->name, "name")) {
403
prop = *pp;
404
break;
405
}
406
407
if (!prop)
408
return; /* No name property, that's fine */
409
410
if ((prop->val.len != node->basenamelen+1)
411
|| (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
412
FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
413
" of base node name)", node->fullpath, prop->val.val);
414
} else {
415
/* The name property is correct, and therefore redundant.
416
* Delete it */
417
*pp = prop->next;
418
free(prop->name);
419
data_free(prop->val);
420
free(prop);
421
}
422
}
423
CHECK_IS_STRING(name_is_string, "name", ERROR);
424
NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
425
426
/*
427
* Reference fixup functions
428
*/
429
430
static void fixup_phandle_references(struct check *c, struct node *dt,
431
struct node *node, struct property *prop)
432
{
433
struct marker *m = prop->val.markers;
434
struct node *refnode;
435
cell_t phandle;
436
437
for_each_marker_of_type(m, REF_PHANDLE) {
438
assert(m->offset + sizeof(cell_t) <= prop->val.len);
439
440
refnode = get_node_by_ref(dt, m->ref);
441
if (! refnode) {
442
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
443
m->ref);
444
continue;
445
}
446
447
phandle = get_node_phandle(dt, refnode);
448
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
449
}
450
}
451
CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
452
&duplicate_node_names, &explicit_phandles);
453
454
static void fixup_path_references(struct check *c, struct node *dt,
455
struct node *node, struct property *prop)
456
{
457
struct marker *m = prop->val.markers;
458
struct node *refnode;
459
char *path;
460
461
for_each_marker_of_type(m, REF_PATH) {
462
assert(m->offset <= prop->val.len);
463
464
refnode = get_node_by_ref(dt, m->ref);
465
if (!refnode) {
466
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
467
m->ref);
468
continue;
469
}
470
471
path = refnode->fullpath;
472
prop->val = data_insert_at_marker(prop->val, m, path,
473
strlen(path) + 1);
474
}
475
}
476
CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR,
477
&duplicate_node_names);
478
479
/*
480
* Semantic checks
481
*/
482
CHECK_IS_CELL(address_cells_is_cell, "#address-cells", WARN);
483
CHECK_IS_CELL(size_cells_is_cell, "#size-cells", WARN);
484
CHECK_IS_CELL(interrupt_cells_is_cell, "#interrupt-cells", WARN);
485
486
CHECK_IS_STRING(device_type_is_string, "device_type", WARN);
487
CHECK_IS_STRING(model_is_string, "model", WARN);
488
CHECK_IS_STRING(status_is_string, "status", WARN);
489
490
static void fixup_addr_size_cells(struct check *c, struct node *dt,
491
struct node *node)
492
{
493
struct property *prop;
494
495
node->addr_cells = -1;
496
node->size_cells = -1;
497
498
prop = get_property(node, "#address-cells");
499
if (prop)
500
node->addr_cells = propval_cell(prop);
501
502
prop = get_property(node, "#size-cells");
503
if (prop)
504
node->size_cells = propval_cell(prop);
505
}
506
CHECK(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, WARN,
507
&address_cells_is_cell, &size_cells_is_cell);
508
509
#define node_addr_cells(n) \
510
(((n)->addr_cells == -1) ? 2 : (n)->addr_cells)
511
#define node_size_cells(n) \
512
(((n)->size_cells == -1) ? 1 : (n)->size_cells)
513
514
static void check_reg_format(struct check *c, struct node *dt,
515
struct node *node)
516
{
517
struct property *prop;
518
int addr_cells, size_cells, entrylen;
519
520
prop = get_property(node, "reg");
521
if (!prop)
522
return; /* No "reg", that's fine */
523
524
if (!node->parent) {
525
FAIL(c, "Root node has a \"reg\" property");
526
return;
527
}
528
529
if (prop->val.len == 0)
530
FAIL(c, "\"reg\" property in %s is empty", node->fullpath);
531
532
addr_cells = node_addr_cells(node->parent);
533
size_cells = node_size_cells(node->parent);
534
entrylen = (addr_cells + size_cells) * sizeof(cell_t);
535
536
if ((prop->val.len % entrylen) != 0)
537
FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
538
"(#address-cells == %d, #size-cells == %d)",
539
node->fullpath, prop->val.len, addr_cells, size_cells);
540
}
541
NODE_CHECK(reg_format, NULL, WARN, &addr_size_cells);
542
543
static void check_ranges_format(struct check *c, struct node *dt,
544
struct node *node)
545
{
546
struct property *prop;
547
int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
548
549
prop = get_property(node, "ranges");
550
if (!prop)
551
return;
552
553
if (!node->parent) {
554
FAIL(c, "Root node has a \"ranges\" property");
555
return;
556
}
557
558
p_addr_cells = node_addr_cells(node->parent);
559
p_size_cells = node_size_cells(node->parent);
560
c_addr_cells = node_addr_cells(node);
561
c_size_cells = node_size_cells(node);
562
entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t);
563
564
if (prop->val.len == 0) {
565
if (p_addr_cells != c_addr_cells)
566
FAIL(c, "%s has empty \"ranges\" property but its "
567
"#address-cells (%d) differs from %s (%d)",
568
node->fullpath, c_addr_cells, node->parent->fullpath,
569
p_addr_cells);
570
if (p_size_cells != c_size_cells)
571
FAIL(c, "%s has empty \"ranges\" property but its "
572
"#size-cells (%d) differs from %s (%d)",
573
node->fullpath, c_size_cells, node->parent->fullpath,
574
p_size_cells);
575
} else if ((prop->val.len % entrylen) != 0) {
576
FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) "
577
"(parent #address-cells == %d, child #address-cells == %d, "
578
"#size-cells == %d)", node->fullpath, prop->val.len,
579
p_addr_cells, c_addr_cells, c_size_cells);
580
}
581
}
582
NODE_CHECK(ranges_format, NULL, WARN, &addr_size_cells);
583
584
/*
585
* Style checks
586
*/
587
static void check_avoid_default_addr_size(struct check *c, struct node *dt,
588
struct node *node)
589
{
590
struct property *reg, *ranges;
591
592
if (!node->parent)
593
return; /* Ignore root node */
594
595
reg = get_property(node, "reg");
596
ranges = get_property(node, "ranges");
597
598
if (!reg && !ranges)
599
return;
600
601
if ((node->parent->addr_cells == -1))
602
FAIL(c, "Relying on default #address-cells value for %s",
603
node->fullpath);
604
605
if ((node->parent->size_cells == -1))
606
FAIL(c, "Relying on default #size-cells value for %s",
607
node->fullpath);
608
}
609
NODE_CHECK(avoid_default_addr_size, NULL, WARN, &addr_size_cells);
610
611
static void check_obsolete_chosen_interrupt_controller(struct check *c,
612
struct node *dt)
613
{
614
struct node *chosen;
615
struct property *prop;
616
617
chosen = get_node_by_path(dt, "/chosen");
618
if (!chosen)
619
return;
620
621
prop = get_property(chosen, "interrupt-controller");
622
if (prop)
623
FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
624
"property");
625
}
626
TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN);
627
628
static struct check *check_table[] = {
629
&duplicate_node_names, &duplicate_property_names,
630
&node_name_chars, &node_name_format, &property_name_chars,
631
&name_is_string, &name_properties,
632
633
&duplicate_label,
634
635
&explicit_phandles,
636
&phandle_references, &path_references,
637
638
&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
639
&device_type_is_string, &model_is_string, &status_is_string,
640
641
&addr_size_cells, &reg_format, &ranges_format,
642
643
&avoid_default_addr_size,
644
&obsolete_chosen_interrupt_controller,
645
};
646
647
void process_checks(int force, struct boot_info *bi)
648
{
649
struct node *dt = bi->dt;
650
int i;
651
int error = 0;
652
653
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
654
struct check *c = check_table[i];
655
656
if (c->level != IGNORE)
657
error = error || run_check(c, dt);
658
}
659
660
if (error) {
661
if (!force) {
662
fprintf(stderr, "ERROR: Input tree has errors, aborting "
663
"(use -f to force output)\n");
664
exit(2);
665
} else if (quiet < 3) {
666
fprintf(stderr, "Warning: Input tree has errors, "
667
"output forced\n");
668
}
669
}
670
}
671
672