checks.c revision 204488
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
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
90#ifdef __GNUC__
91static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
92#endif
93static 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
114static 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
133static 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
168out:
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
179static 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
196static 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
217static 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}
230NODE_CHECK(duplicate_node_names, NULL, ERROR);
231
232static 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}
243NODE_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
250static 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}
259NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR);
260
261static 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}
268NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars);
269
270static 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}
279PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
280
281static void check_explicit_phandles(struct check *c, struct node *root,
282				    struct node *node, struct property *prop)
283{
284	struct marker *m;
285	struct node *other;
286	cell_t phandle;
287
288	if (!streq(prop->name, "phandle")
289	    && !streq(prop->name, "linux,phandle"))
290		return;
291
292	if (prop->val.len != sizeof(cell_t)) {
293		FAIL(c, "%s has bad length (%d) %s property",
294		     node->fullpath, prop->val.len, prop->name);
295		return;
296	}
297
298	m = prop->val.markers;
299	for_each_marker_of_type(m, REF_PHANDLE) {
300		assert(m->offset == 0);
301		if (node != get_node_by_ref(root, m->ref))
302			/* "Set this node's phandle equal to some
303			 * other node's phandle".  That's nonsensical
304			 * by construction. */ {
305			FAIL(c, "%s in %s is a reference to another node",
306			     prop->name, node->fullpath);
307			return;
308		}
309		/* But setting this node's phandle equal to its own
310		 * phandle is allowed - that means allocate a unique
311		 * phandle for this node, even if it's not otherwise
312		 * referenced.  The value will be filled in later, so
313		 * no further checking for now. */
314		return;
315	}
316
317	phandle = propval_cell(prop);
318
319	if ((phandle == 0) || (phandle == -1)) {
320		FAIL(c, "%s has bad value (0x%x) in %s property",
321		     node->fullpath, phandle, prop->name);
322		return;
323	}
324
325	if (node->phandle && (node->phandle != phandle))
326		FAIL(c, "%s has %s property which replaces existing phandle information",
327		     node->fullpath, prop->name);
328
329	other = get_node_by_phandle(root, phandle);
330	if (other && (other != node)) {
331		FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
332		     node->fullpath, phandle, other->fullpath);
333		return;
334	}
335
336	node->phandle = phandle;
337}
338PROP_CHECK(explicit_phandles, NULL, ERROR);
339
340static void check_name_properties(struct check *c, struct node *root,
341				  struct node *node)
342{
343	struct property **pp, *prop = NULL;
344
345	for (pp = &node->proplist; *pp; pp = &((*pp)->next))
346		if (streq((*pp)->name, "name")) {
347			prop = *pp;
348			break;
349		}
350
351	if (!prop)
352		return; /* No name property, that's fine */
353
354	if ((prop->val.len != node->basenamelen+1)
355	    || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
356		FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
357		     " of base node name)", node->fullpath, prop->val.val);
358	} else {
359		/* The name property is correct, and therefore redundant.
360		 * Delete it */
361		*pp = prop->next;
362		free(prop->name);
363		data_free(prop->val);
364		free(prop);
365	}
366}
367CHECK_IS_STRING(name_is_string, "name", ERROR);
368NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
369
370/*
371 * Reference fixup functions
372 */
373
374static void fixup_phandle_references(struct check *c, struct node *dt,
375				     struct node *node, struct property *prop)
376{
377	struct marker *m = prop->val.markers;
378	struct node *refnode;
379	cell_t phandle;
380
381	for_each_marker_of_type(m, REF_PHANDLE) {
382		assert(m->offset + sizeof(cell_t) <= prop->val.len);
383
384		refnode = get_node_by_ref(dt, m->ref);
385		if (! refnode) {
386			FAIL(c, "Reference to non-existent node or label \"%s\"\n",
387			     m->ref);
388			continue;
389		}
390
391		phandle = get_node_phandle(dt, refnode);
392		*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
393	}
394}
395CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
396      &duplicate_node_names, &explicit_phandles);
397
398static void fixup_path_references(struct check *c, struct node *dt,
399				  struct node *node, struct property *prop)
400{
401	struct marker *m = prop->val.markers;
402	struct node *refnode;
403	char *path;
404
405	for_each_marker_of_type(m, REF_PATH) {
406		assert(m->offset <= prop->val.len);
407
408		refnode = get_node_by_ref(dt, m->ref);
409		if (!refnode) {
410			FAIL(c, "Reference to non-existent node or label \"%s\"\n",
411			     m->ref);
412			continue;
413		}
414
415		path = refnode->fullpath;
416		prop->val = data_insert_at_marker(prop->val, m, path,
417						  strlen(path) + 1);
418	}
419}
420CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR,
421      &duplicate_node_names);
422
423/*
424 * Semantic checks
425 */
426CHECK_IS_CELL(address_cells_is_cell, "#address-cells", WARN);
427CHECK_IS_CELL(size_cells_is_cell, "#size-cells", WARN);
428CHECK_IS_CELL(interrupt_cells_is_cell, "#interrupt-cells", WARN);
429
430CHECK_IS_STRING(device_type_is_string, "device_type", WARN);
431CHECK_IS_STRING(model_is_string, "model", WARN);
432CHECK_IS_STRING(status_is_string, "status", WARN);
433
434static void fixup_addr_size_cells(struct check *c, struct node *dt,
435				  struct node *node)
436{
437	struct property *prop;
438
439	node->addr_cells = -1;
440	node->size_cells = -1;
441
442	prop = get_property(node, "#address-cells");
443	if (prop)
444		node->addr_cells = propval_cell(prop);
445
446	prop = get_property(node, "#size-cells");
447	if (prop)
448		node->size_cells = propval_cell(prop);
449}
450CHECK(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, WARN,
451      &address_cells_is_cell, &size_cells_is_cell);
452
453#define node_addr_cells(n) \
454	(((n)->addr_cells == -1) ? 2 : (n)->addr_cells)
455#define node_size_cells(n) \
456	(((n)->size_cells == -1) ? 1 : (n)->size_cells)
457
458static void check_reg_format(struct check *c, struct node *dt,
459			     struct node *node)
460{
461	struct property *prop;
462	int addr_cells, size_cells, entrylen;
463
464	prop = get_property(node, "reg");
465	if (!prop)
466		return; /* No "reg", that's fine */
467
468	if (!node->parent) {
469		FAIL(c, "Root node has a \"reg\" property");
470		return;
471	}
472
473	if (prop->val.len == 0)
474		FAIL(c, "\"reg\" property in %s is empty", node->fullpath);
475
476	addr_cells = node_addr_cells(node->parent);
477	size_cells = node_size_cells(node->parent);
478	entrylen = (addr_cells + size_cells) * sizeof(cell_t);
479
480	if ((prop->val.len % entrylen) != 0)
481		FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
482		     "(#address-cells == %d, #size-cells == %d)",
483		     node->fullpath, prop->val.len, addr_cells, size_cells);
484}
485NODE_CHECK(reg_format, NULL, WARN, &addr_size_cells);
486
487static void check_ranges_format(struct check *c, struct node *dt,
488				struct node *node)
489{
490	struct property *prop;
491	int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
492
493	prop = get_property(node, "ranges");
494	if (!prop)
495		return;
496
497	if (!node->parent) {
498		FAIL(c, "Root node has a \"ranges\" property");
499		return;
500	}
501
502	p_addr_cells = node_addr_cells(node->parent);
503	p_size_cells = node_size_cells(node->parent);
504	c_addr_cells = node_addr_cells(node);
505	c_size_cells = node_size_cells(node);
506	entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t);
507
508	if (prop->val.len == 0) {
509		if (p_addr_cells != c_addr_cells)
510			FAIL(c, "%s has empty \"ranges\" property but its "
511			     "#address-cells (%d) differs from %s (%d)",
512			     node->fullpath, c_addr_cells, node->parent->fullpath,
513			     p_addr_cells);
514		if (p_size_cells != c_size_cells)
515			FAIL(c, "%s has empty \"ranges\" property but its "
516			     "#size-cells (%d) differs from %s (%d)",
517			     node->fullpath, c_size_cells, node->parent->fullpath,
518			     p_size_cells);
519	} else if ((prop->val.len % entrylen) != 0) {
520		FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) "
521		     "(parent #address-cells == %d, child #address-cells == %d, "
522		     "#size-cells == %d)", node->fullpath, prop->val.len,
523		     p_addr_cells, c_addr_cells, c_size_cells);
524	}
525}
526NODE_CHECK(ranges_format, NULL, WARN, &addr_size_cells);
527
528/*
529 * Style checks
530 */
531static void check_avoid_default_addr_size(struct check *c, struct node *dt,
532					  struct node *node)
533{
534	struct property *reg, *ranges;
535
536	if (!node->parent)
537		return; /* Ignore root node */
538
539	reg = get_property(node, "reg");
540	ranges = get_property(node, "ranges");
541
542	if (!reg && !ranges)
543		return;
544
545	if ((node->parent->addr_cells == -1))
546		FAIL(c, "Relying on default #address-cells value for %s",
547		     node->fullpath);
548
549	if ((node->parent->size_cells == -1))
550		FAIL(c, "Relying on default #size-cells value for %s",
551		     node->fullpath);
552}
553NODE_CHECK(avoid_default_addr_size, NULL, WARN, &addr_size_cells);
554
555static void check_obsolete_chosen_interrupt_controller(struct check *c,
556						       struct node *dt)
557{
558	struct node *chosen;
559	struct property *prop;
560
561	chosen = get_node_by_path(dt, "/chosen");
562	if (!chosen)
563		return;
564
565	prop = get_property(chosen, "interrupt-controller");
566	if (prop)
567		FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
568		     "property");
569}
570TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN);
571
572static struct check *check_table[] = {
573	&duplicate_node_names, &duplicate_property_names,
574	&node_name_chars, &node_name_format, &property_name_chars,
575	&name_is_string, &name_properties,
576	&explicit_phandles,
577	&phandle_references, &path_references,
578
579	&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
580	&device_type_is_string, &model_is_string, &status_is_string,
581
582	&addr_size_cells, &reg_format, &ranges_format,
583
584	&avoid_default_addr_size,
585	&obsolete_chosen_interrupt_controller,
586};
587
588void process_checks(int force, struct boot_info *bi)
589{
590	struct node *dt = bi->dt;
591	int i;
592	int error = 0;
593
594	for (i = 0; i < ARRAY_SIZE(check_table); i++) {
595		struct check *c = check_table[i];
596
597		if (c->level != IGNORE)
598			error = error || run_check(c, dt);
599	}
600
601	if (error) {
602		if (!force) {
603			fprintf(stderr, "ERROR: Input tree has errors, aborting "
604				"(use -f to force output)\n");
605			exit(2);
606		} else if (quiet < 3) {
607			fprintf(stderr, "Warning: Input tree has errors, "
608				"output forced\n");
609		}
610	}
611}
612