1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2013 David Chisnall
5 * All rights reserved.
6 *
7 * This software was developed by SRI International and the University of
8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9 * ("CTSRD"), as part of the DARPA CRASH research programme.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef _CHECKING_HH_
34#define _CHECKING_HH_
35#include <string>
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, const node_ptr &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 *, const node_ptr &)
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 *, const node_ptr &, property_ptr )
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	std::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, const node_ptr &n, property_ptr 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, const std::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, const node_ptr &n, property_ptr 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, const std::string &property_name) :
151		property_checker(name, property_name) {}
152	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr 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, const std::string &property_name) :
162		property_checker(name, property_name) {}
163	virtual bool check(device_tree *, const node_ptr &, property_ptr 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, const std::string &property_name) :
177		property_checker(name, property_name) {}
178	virtual bool check(device_tree *, const node_ptr &, property_ptr 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, const std::string &property_name) :
192		property_checker(name, property_name) {}
193	virtual bool check(device_tree *, const node_ptr &, property_ptr 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, const std::string &property_name) :
215		property_checker(name, property_name) {}
216	virtual bool check(device_tree *tree, const node_ptr &, property_ptr 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,
238	                      const std::string &property_name,
239	                      uint32_t bytes)
240		: property_checker(name, property_name), size(bytes) {}
241	/**
242	 * Check, validates that the property has the correct size.
243	 */
244	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p);
245};
246
247
248/**
249 * The check manager is the interface to running the checks.  This allows
250 * default checks to be enabled, non-default checks to be enabled, and so on.
251 */
252class check_manager
253{
254	/**
255	 * The enabled checkers, indexed by their names.  The name is used when
256	 * disabling checkers from the command line.  When this manager runs,
257	 * it will only run the checkers from this map.
258	 */
259	std::unordered_map<std::string, checker*> checkers;
260	/**
261	 * The disabled checkers.  Moving checkers to this list disables them,
262	 * but allows them to be easily moved back.
263	 */
264	std::unordered_map<std::string, checker*> disabled_checkers;
265	/**
266	 * Helper function for adding a property value checker.
267	 */
268	template<property_value::value_type T>
269	void add_property_type_checker(const char *name, const std::string &prop);
270	/**
271	 * Helper function for adding a simple type checker.
272	 */
273	void add_property_type_checker(const char *name, const std::string &prop);
274	/**
275	 * Helper function for adding a property value checker.
276	 */
277	void add_property_size_checker(const char *name,
278	                               const std::string &prop,
279	                               uint32_t size);
280	public:
281	/**
282	 * Delete all of the checkers that are part of this checker manager.
283	 */
284	~check_manager();
285	/**
286	 * Default constructor, creates check manager containing all of the
287	 * default checks.
288	 */
289	check_manager();
290	/**
291	 * Run all of the checks on the specified tree.
292	 */
293	bool run_checks(device_tree *tree, bool keep_going);
294	/**
295	 * Disables the named checker.
296	 */
297	bool disable_checker(const std::string &name);
298	/**
299	 * Enables the named checker.
300	 */
301	bool enable_checker(const std::string &name);
302};
303
304} // namespace checking
305
306} // namespace fdt
307
308} // namespace dtc
309
310#endif // !_CHECKING_HH_
311