1245803Stheraven/*-
2245803Stheraven * Copyright (c) 2013 David Chisnall
3245803Stheraven * All rights reserved.
4245803Stheraven *
5245803Stheraven * This software was developed by SRI International and the University of
6245803Stheraven * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7245803Stheraven * ("CTSRD"), as part of the DARPA CRASH research programme.
8245803Stheraven *
9245803Stheraven * Redistribution and use in source and binary forms, with or without
10245803Stheraven * modification, are permitted provided that the following conditions
11245803Stheraven * are met:
12245803Stheraven * 1. Redistributions of source code must retain the above copyright
13245803Stheraven *    notice, this list of conditions and the following disclaimer.
14245803Stheraven * 2. Redistributions in binary form must reproduce the above copyright
15245803Stheraven *    notice, this list of conditions and the following disclaimer in the
16245803Stheraven *    documentation and/or other materials provided with the distribution.
17245803Stheraven *
18245803Stheraven * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19245803Stheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20245803Stheraven * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21245803Stheraven * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22245803Stheraven * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23245803Stheraven * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24245803Stheraven * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25245803Stheraven * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26245803Stheraven * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27245803Stheraven * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28245803Stheraven * SUCH DAMAGE.
29245803Stheraven *
30245803Stheraven * $FreeBSD: releng/10.3/usr.bin/dtc/checking.cc 251934 2013-06-18 10:26:22Z theraven $
31245803Stheraven */
32245803Stheraven
33245803Stheraven#include "checking.hh"
34245839Stheraven#include <stdio.h>
35245803Stheraven
36251856Stheraven
37251856Stheraven
38245803Stheravennamespace dtc
39245803Stheraven{
40245803Stheravennamespace fdt
41245803Stheraven{
42245803Stheravennamespace checking
43245803Stheraven{
44245803Stheraven
45251856Stheravennamespace
46251856Stheraven{
47251856Stheraven	/**
48251856Stheraven	 * Checker that verifies that every node that has children has
49251856Stheraven	 * #address-cells and #size-cells properties.
50251856Stheraven	 */
51251856Stheraven	struct address_cells_checker : public checker
52251856Stheraven	{
53251856Stheraven		address_cells_checker(const char *name) : checker(name) {}
54251856Stheraven		virtual bool check_node(device_tree *tree, node *n)
55251856Stheraven		{
56251856Stheraven			// If this has no children, it trivially meets the
57251856Stheraven			// conditions.
58251856Stheraven			if (n->child_begin() == n->child_end())
59251856Stheraven			{
60251856Stheraven				return true;
61251856Stheraven			}
62251856Stheraven			bool found_address = false;
63251856Stheraven			bool found_size = false;
64251856Stheraven			for (node::property_iterator i=n->property_begin(),
65251856Stheraven			     e=n->property_end() ; i!=e ; ++i)
66251856Stheraven			{
67251856Stheraven				if (!found_address)
68251856Stheraven				{
69251856Stheraven					found_address = ((*i)->get_key() == "#address-cells");
70251856Stheraven				}
71251856Stheraven				if (!found_size)
72251856Stheraven				{
73251856Stheraven					found_size = ((*i)->get_key() == "#size-cells");
74251856Stheraven				}
75251856Stheraven				if (found_size && found_address)
76251856Stheraven				{
77251856Stheraven						break;
78251856Stheraven				}
79251856Stheraven			}
80251856Stheraven			if (!found_address)
81251856Stheraven			{
82251856Stheraven					report_error("Missing #address-cells property");
83251856Stheraven			}
84251856Stheraven			if (!found_size)
85251856Stheraven			{
86251856Stheraven					report_error("Missing #size-cells property");
87251856Stheraven			}
88251856Stheraven			return found_address && found_size;
89251856Stheraven		}
90251856Stheraven	};
91251856Stheraven} // anonymous namespace
92251856Stheraven
93245803Stheravenbool
94245803Stheravenchecker::visit_node(device_tree *tree, node *n)
95245803Stheraven{
96245803Stheraven	path.push_back(std::make_pair(n->name, n->unit_address));
97245803Stheraven	// Check this node
98245803Stheraven	if (!check_node(tree, n))
99245803Stheraven	{
100245803Stheraven		return false;
101245803Stheraven	}
102245803Stheraven	// Now check its properties
103245803Stheraven	for (node::property_iterator i=n->property_begin(), e=n->property_end()
104245803Stheraven	     ; i!=e ; ++i)
105245803Stheraven	{
106245803Stheraven		if (!check_property(tree, n, *i))
107245803Stheraven		{
108245803Stheraven			return false;
109245803Stheraven		}
110245803Stheraven	}
111245803Stheraven	// And then recursively check the children
112245803Stheraven	for (node::child_iterator i=n->child_begin(), e=n->child_end() ; i!=e ;
113245803Stheraven	     ++i)
114245803Stheraven	{
115245803Stheraven		if (!visit_node(tree, *i))
116245803Stheraven		{
117245803Stheraven			return false;
118245803Stheraven		}
119245803Stheraven	}
120245803Stheraven	path.pop_back();
121245803Stheraven	return true;
122245803Stheraven}
123245803Stheraven
124245803Stheravenvoid
125245803Stheravenchecker::report_error(const char *errmsg)
126245803Stheraven{
127245803Stheraven	fprintf(stderr, "Error: %s, while checking node: ", errmsg);
128245803Stheraven	for (device_tree::node_path::iterator p=path.begin()+1, pe=path.end() ;
129245803Stheraven	     p!=pe ; ++p)
130245803Stheraven	{
131245803Stheraven		putc('/', stderr);
132245803Stheraven		p->first.dump();
133245803Stheraven		if (!(p->second.empty()))
134245803Stheraven		{
135245803Stheraven			putc('@', stderr);
136245803Stheraven			p->second.dump();
137245803Stheraven		}
138245803Stheraven	}
139245803Stheraven	fprintf(stderr, " [-W%s]\n", checker_name);
140245803Stheraven}
141245803Stheraven
142245803Stheravenbool
143245803Stheravenproperty_checker::check_property(device_tree *tree, node *n, property *p)
144245803Stheraven{
145245803Stheraven	if (p->get_key() == key)
146245803Stheraven	{
147245803Stheraven		if (!check(tree, n, p))
148245803Stheraven		{
149245803Stheraven			report_error("property check failed");
150245803Stheraven			return false;
151245803Stheraven		}
152245803Stheraven	}
153245803Stheraven	return true;
154245803Stheraven}
155245803Stheraven
156245803Stheravenbool
157245803Stheravenproperty_size_checker::check(device_tree *tree, node *n, property *p)
158245803Stheraven{
159245803Stheraven	uint32_t psize = 0;
160245803Stheraven	for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ; ++i)
161245803Stheraven	{
162245803Stheraven		if (!i->is_binary())
163245803Stheraven		{
164245803Stheraven			return false;
165245803Stheraven		}
166245803Stheraven		psize += i->byte_data.size();
167245803Stheraven	}
168245803Stheraven	return psize == size;
169245803Stheraven}
170245803Stheraven
171245803Stheraventemplate<property_value::value_type T>
172245803Stheravenvoid
173245803Stheravencheck_manager::add_property_type_checker(const char *name, string prop)
174245803Stheraven{
175245803Stheraven	checkers.insert(std::make_pair(string(name),
176245803Stheraven		new property_type_checker<T>(name, prop)));
177245803Stheraven}
178245803Stheraven
179245803Stheravenvoid
180245803Stheravencheck_manager::add_property_size_checker(const char *name,
181245803Stheraven                                         string prop,
182245803Stheraven                                         uint32_t size)
183245803Stheraven{
184245803Stheraven	checkers.insert(std::make_pair(string(name),
185245803Stheraven		new property_size_checker(name, prop, size)));
186245803Stheraven}
187245803Stheraven
188245803Stheravencheck_manager::~check_manager()
189245803Stheraven{
190245803Stheraven	while (checkers.begin() != checkers.end())
191245803Stheraven	{
192245803Stheraven		delete checkers.begin()->second;
193245803Stheraven		checkers.erase(checkers.begin());
194245803Stheraven	}
195245803Stheraven	while (disabled_checkers.begin() != disabled_checkers.end())
196245803Stheraven	{
197245803Stheraven		delete disabled_checkers.begin()->second;
198251934Stheraven		disabled_checkers.erase(disabled_checkers.begin());
199245803Stheraven	}
200245803Stheraven}
201245803Stheraven
202245803Stheravencheck_manager::check_manager()
203245803Stheraven{
204245803Stheraven	// NOTE: All checks listed here MUST have a corresponding line
205245803Stheraven	// in the man page!
206245803Stheraven	add_property_type_checker<property_value::STRING_LIST>(
207245803Stheraven			"type-compatible", string("compatible"));
208245803Stheraven	add_property_type_checker<property_value::STRING>(
209245803Stheraven			"type-model", string("model"));
210245803Stheraven	add_property_size_checker("type-phandle", string("phandle"), 4);
211251856Stheraven	disabled_checkers.insert(std::make_pair(string("cells-attributes"),
212251856Stheraven		new address_cells_checker("cells-attributes")));
213245803Stheraven}
214245803Stheraven
215245803Stheravenbool
216245803Stheravencheck_manager::run_checks(device_tree *tree, bool keep_going)
217245803Stheraven{
218245803Stheraven	bool success = true;
219245803Stheraven	for (std::map<string, checker*>::iterator i=checkers.begin(),
220245803Stheraven	     e=checkers.end() ; i!=e ; ++i)
221245803Stheraven	{
222245803Stheraven		success &= i->second->check_tree(tree);
223245803Stheraven		if (!(success || keep_going))
224245803Stheraven		{
225245803Stheraven			break;
226245803Stheraven		}
227245803Stheraven	}
228245803Stheraven	return success;
229245803Stheraven}
230245803Stheraven
231245803Stheravenbool
232245803Stheravencheck_manager::disable_checker(string name)
233245803Stheraven{
234245803Stheraven	std::map<string, checker*>::iterator checker = checkers.find(name);
235245803Stheraven	if (checker != checkers.end())
236245803Stheraven	{
237245803Stheraven		disabled_checkers.insert(std::make_pair(name,
238245803Stheraven		                                        checker->second));
239245803Stheraven		checkers.erase(checker);
240245803Stheraven		return true;
241245803Stheraven	}
242245803Stheraven	return false;
243245803Stheraven}
244245803Stheraven
245245803Stheravenbool
246245803Stheravencheck_manager::enable_checker(string name)
247245803Stheraven{
248245803Stheraven	std::map<string, checker*>::iterator checker =
249245803Stheraven		disabled_checkers.find(name);
250245803Stheraven	if (checker != disabled_checkers.end())
251245803Stheraven	{
252245803Stheraven		checkers.insert(std::make_pair(name, checker->second));
253245803Stheraven		disabled_checkers.erase(checker);
254245803Stheraven		return true;
255245803Stheraven	}
256245803Stheraven	return false;
257245803Stheraven}
258245803Stheraven
259245803Stheraven} // namespace checking
260245803Stheraven
261245803Stheraven} // namespace fdt
262245803Stheraven
263245803Stheraven} // namespace dtc
264245803Stheraven
265