1/*-
2 * Copyright (c) 2013 David Chisnall
3 * All rights reserved.
4 *
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $FreeBSD$
31 */
32
33#ifndef _CHECKING_HH_
34#define _CHECKING_HH_
35#include "string.hh"
36#include "fdt.hh"
37
38namespace dtc
39{
40namespace fdt
41{
42namespace checking
43{
44/**
45 * Base class for all checkers.  This will visit the entire tree and perform
46 * semantic checks defined in subclasses.  Note that device trees are generally
47 * small (a few dozen nodes at most) and so we optimise for flexibility and
48 * extensibility here, not for performance.  Each checker will visit the entire
49 * tree.
50 */
51class checker
52{
53	/**
54	 * The path to the current node being checked.  This is used for
55	 * printing error messages.
56	 */
57	device_tree::node_path path;
58	/**
59	 * The name of the checker.  This is used for printing error messages
60	 * and for enabling / disabling specific checkers from the command
61	 * line.
62	 */
63	const char *checker_name;
64	/**
65	 * Visits each node, calling the checker functions on properties and
66	 * nodes.
67	 */
68	bool visit_node(device_tree *tree, node *n);
69	protected:
70	/**
71	 * Prints the error message, along with the path to the node that
72	 * caused the error and the name of the checker.
73	 */
74	void report_error(const char *errmsg);
75	public:
76	/**
77	 * Constructor.  Takes the name of this checker, which is which is used
78	 * when reporting errors.
79	 */
80	checker(const char *name) : checker_name(name) {}
81	/**
82	 * Virtual destructor in case any subclasses need to do cleanup.
83	 */
84	virtual ~checker() {}
85	/**
86	 * Method for checking that a node is valid.  The root class version
87	 * does nothing, subclasses should override this.
88	 */
89	virtual bool check_node(device_tree *tree, node *n)
90	{
91		return true;
92	}
93	/**
94	 * Method for checking that a property is valid.  The root class
95	 * version does nothing, subclasses should override this.
96	 */
97	virtual bool check_property(device_tree *tree, node *n, property *p)
98	{
99		return true;
100	}
101	/**
102	 * Runs the checker on the specified device tree.
103	 */
104	bool check_tree(fdt::device_tree *tree)
105	{
106		return visit_node(tree, tree->get_root());
107	}
108};
109
110/**
111 * Abstract base class for simple property checks.  This class defines a check
112 * method for subclasses, which is invoked only when it finds a property with
113 * the matching name.  To define simple property checkers, just subclass this
114 * and override the check() method.
115 */
116class property_checker : public checker
117{
118	/**
119	 * The name of the property that this checker is looking for.
120	 */
121	string key;
122	public:
123	/**
124	 * Implementation of the generic property-checking method that checks
125	 * for a property with the name specified in the constructor
126	 */
127	virtual bool check_property(device_tree *tree, node *n, property *p);
128	/**
129	 * Constructor.  Takes the name of the checker and the name of the
130	 * property to check.
131	 */
132	property_checker(const char* name, string property_name)
133		: checker(name), key(property_name) {}
134	/**
135	 * The check method, which subclasses should implement.
136	 */
137	virtual bool check(device_tree *tree, node *n, property *p) = 0;
138};
139
140/**
141 * Property type checker.
142 */
143template<property_value::value_type T>
144struct property_type_checker : public property_checker
145{
146	/**
147	 * Constructor, takes the name of the checker and the name of the
148	 * property to check as arguments.
149	 */
150	property_type_checker(const char* name, string property_name) :
151		property_checker(name, property_name) {}
152	virtual bool check(device_tree *tree, node *n, property *p) = 0;
153};
154
155/**
156 * Empty property checker.  This checks that the property has no value.
157 */
158template<>
159struct property_type_checker <property_value::EMPTY> : public property_checker
160{
161	property_type_checker(const char* name, string property_name) :
162		property_checker(name, property_name) {}
163	virtual bool check(device_tree *tree, node *n, property *p)
164	{
165		return p->begin() == p->end();
166	}
167};
168
169/**
170 * String property checker.  This checks that the property has exactly one
171 * value, which is a string.
172 */
173template<>
174struct property_type_checker <property_value::STRING> : public property_checker
175{
176	property_type_checker(const char* name, string property_name) :
177		property_checker(name, property_name) {}
178	virtual bool check(device_tree *tree, node *n, property *p)
179	{
180		return (p->begin() + 1 == p->end()) && p->begin()->is_string();
181	}
182};
183/**
184 * String list property checker.  This checks that the property has at least
185 * one value, all of which are strings.
186 */
187template<>
188struct property_type_checker <property_value::STRING_LIST> :
189	public property_checker
190{
191	property_type_checker(const char* name, string property_name) :
192		property_checker(name, property_name) {}
193	virtual bool check(device_tree *tree, node *n, property *p)
194	{
195		for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ;
196		     ++i)
197		{
198			if (!(i->is_string() || i->is_string_list()))
199			{
200				return false;
201			}
202		}
203		return p->begin() != p->end();
204	}
205};
206
207/**
208 * Phandle property checker.  This checks that the property has exactly one
209 * value, which is a valid phandle.
210 */
211template<>
212struct property_type_checker <property_value::PHANDLE> : public property_checker
213{
214	property_type_checker(const char* name, string property_name) :
215		property_checker(name, property_name) {}
216	virtual bool check(device_tree *tree, node *n, property *p)
217	{
218		return (p->begin() + 1 == p->end()) &&
219			(tree->referenced_node(*p->begin()) != 0);
220	}
221};
222
223/**
224 * Check that a property has the correct size.
225 */
226struct property_size_checker : public property_checker
227{
228	/**
229	 * The expected size of the property.
230	 */
231	uint32_t size;
232	public:
233	/**
234	 * Constructor, takes the name of the checker, the name of the property
235	 * to check, and its expected size as arguments.
236	 */
237	property_size_checker(const char* name, string property_name, uint32_t bytes)
238		: property_checker(name, property_name), size(bytes) {}
239	/**
240	 * Check, validates that the property has the correct size.
241	 */
242	virtual bool check(device_tree *tree, node *n, property *p);
243};
244
245
246/**
247 * The check manager is the interface to running the checks.  This allows
248 * default checks to be enabled, non-default checks to be enabled, and so on.
249 */
250class check_manager
251{
252	/**
253	 * The enabled checkers, indexed by their names.  The name is used when
254	 * disabling checkers from the command line.  When this manager runs,
255	 * it will only run the checkers from this map.
256	 */
257	std::map<string, checker*> checkers;
258	/**
259	 * The disabled checkers.  Moving checkers to this list disables them,
260	 * but allows them to be easily moved back.
261	 */
262	std::map<string, checker*> disabled_checkers;
263	/**
264	 * Helper function for adding a property value checker.
265	 */
266	template<property_value::value_type T>
267	void add_property_type_checker(const char *name, string prop);
268	/**
269	 * Helper function for adding a simple type checker.
270	 */
271	void add_property_type_checker(const char *name, string prop);
272	/**
273	 * Helper function for adding a property value checker.
274	 */
275	void add_property_size_checker(const char *name,
276	                               string prop,
277	                               uint32_t size);
278	public:
279	/**
280	 * Delete all of the checkers that are part of this checker manager.
281	 */
282	~check_manager();
283	/**
284	 * Default constructor, creates check manager containing all of the
285	 * default checks.
286	 */
287	check_manager();
288	/**
289	 * Run all of the checks on the specified tree.
290	 */
291	bool run_checks(device_tree *tree, bool keep_going);
292	/**
293	 * Disables the named checker.
294	 */
295	bool disable_checker(string name);
296	/**
297	 * Enables the named checker.
298	 */
299	bool enable_checker(string name);
300};
301
302} // namespace checking
303
304} // namespace fdt
305
306} // namespace dtc
307
308#endif // !_CHECKING_HH_
309