xref: /freebsd/usr.bin/dtc/checking.cc (revision a18eacbefdfa1085ca3db829e86ece78cd416493)
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 #include "checking.hh"
34 #include <stdio.h>
35 
36 
37 
38 namespace dtc
39 {
40 namespace fdt
41 {
42 namespace checking
43 {
44 
45 namespace
46 {
47 	/**
48 	 * Checker that verifies that every node that has children has
49 	 * #address-cells and #size-cells properties.
50 	 */
51 	struct address_cells_checker : public checker
52 	{
53 		address_cells_checker(const char *name) : checker(name) {}
54 		virtual bool check_node(device_tree *tree, node *n)
55 		{
56 			// If this has no children, it trivially meets the
57 			// conditions.
58 			if (n->child_begin() == n->child_end())
59 			{
60 				return true;
61 			}
62 			bool found_address = false;
63 			bool found_size = false;
64 			for (node::property_iterator i=n->property_begin(),
65 			     e=n->property_end() ; i!=e ; ++i)
66 			{
67 				if (!found_address)
68 				{
69 					found_address = ((*i)->get_key() == "#address-cells");
70 				}
71 				if (!found_size)
72 				{
73 					found_size = ((*i)->get_key() == "#size-cells");
74 				}
75 				if (found_size && found_address)
76 				{
77 						break;
78 				}
79 			}
80 			if (!found_address)
81 			{
82 					report_error("Missing #address-cells property");
83 			}
84 			if (!found_size)
85 			{
86 					report_error("Missing #size-cells property");
87 			}
88 			return found_address && found_size;
89 		}
90 	};
91 } // anonymous namespace
92 
93 bool
94 checker::visit_node(device_tree *tree, node *n)
95 {
96 	path.push_back(std::make_pair(n->name, n->unit_address));
97 	// Check this node
98 	if (!check_node(tree, n))
99 	{
100 		return false;
101 	}
102 	// Now check its properties
103 	for (node::property_iterator i=n->property_begin(), e=n->property_end()
104 	     ; i!=e ; ++i)
105 	{
106 		if (!check_property(tree, n, *i))
107 		{
108 			return false;
109 		}
110 	}
111 	// And then recursively check the children
112 	for (node::child_iterator i=n->child_begin(), e=n->child_end() ; i!=e ;
113 	     ++i)
114 	{
115 		if (!visit_node(tree, *i))
116 		{
117 			return false;
118 		}
119 	}
120 	path.pop_back();
121 	return true;
122 }
123 
124 void
125 checker::report_error(const char *errmsg)
126 {
127 	fprintf(stderr, "Error: %s, while checking node: ", errmsg);
128 	for (device_tree::node_path::iterator p=path.begin()+1, pe=path.end() ;
129 	     p!=pe ; ++p)
130 	{
131 		putc('/', stderr);
132 		p->first.dump();
133 		if (!(p->second.empty()))
134 		{
135 			putc('@', stderr);
136 			p->second.dump();
137 		}
138 	}
139 	fprintf(stderr, " [-W%s]\n", checker_name);
140 }
141 
142 bool
143 property_checker::check_property(device_tree *tree, node *n, property *p)
144 {
145 	if (p->get_key() == key)
146 	{
147 		if (!check(tree, n, p))
148 		{
149 			report_error("property check failed");
150 			return false;
151 		}
152 	}
153 	return true;
154 }
155 
156 bool
157 property_size_checker::check(device_tree *tree, node *n, property *p)
158 {
159 	uint32_t psize = 0;
160 	for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ; ++i)
161 	{
162 		if (!i->is_binary())
163 		{
164 			return false;
165 		}
166 		psize += i->byte_data.size();
167 	}
168 	return psize == size;
169 }
170 
171 template<property_value::value_type T>
172 void
173 check_manager::add_property_type_checker(const char *name, string prop)
174 {
175 	checkers.insert(std::make_pair(string(name),
176 		new property_type_checker<T>(name, prop)));
177 }
178 
179 void
180 check_manager::add_property_size_checker(const char *name,
181                                          string prop,
182                                          uint32_t size)
183 {
184 	checkers.insert(std::make_pair(string(name),
185 		new property_size_checker(name, prop, size)));
186 }
187 
188 check_manager::~check_manager()
189 {
190 	while (checkers.begin() != checkers.end())
191 	{
192 		delete checkers.begin()->second;
193 		checkers.erase(checkers.begin());
194 	}
195 	while (disabled_checkers.begin() != disabled_checkers.end())
196 	{
197 		delete disabled_checkers.begin()->second;
198 		disabled_checkers.erase(disabled_checkers.begin());
199 	}
200 }
201 
202 check_manager::check_manager()
203 {
204 	// NOTE: All checks listed here MUST have a corresponding line
205 	// in the man page!
206 	add_property_type_checker<property_value::STRING_LIST>(
207 			"type-compatible", string("compatible"));
208 	add_property_type_checker<property_value::STRING>(
209 			"type-model", string("model"));
210 	add_property_size_checker("type-phandle", string("phandle"), 4);
211 	disabled_checkers.insert(std::make_pair(string("cells-attributes"),
212 		new address_cells_checker("cells-attributes")));
213 }
214 
215 bool
216 check_manager::run_checks(device_tree *tree, bool keep_going)
217 {
218 	bool success = true;
219 	for (std::map<string, checker*>::iterator i=checkers.begin(),
220 	     e=checkers.end() ; i!=e ; ++i)
221 	{
222 		success &= i->second->check_tree(tree);
223 		if (!(success || keep_going))
224 		{
225 			break;
226 		}
227 	}
228 	return success;
229 }
230 
231 bool
232 check_manager::disable_checker(string name)
233 {
234 	std::map<string, checker*>::iterator checker = checkers.find(name);
235 	if (checker != checkers.end())
236 	{
237 		disabled_checkers.insert(std::make_pair(name,
238 		                                        checker->second));
239 		checkers.erase(checker);
240 		return true;
241 	}
242 	return false;
243 }
244 
245 bool
246 check_manager::enable_checker(string name)
247 {
248 	std::map<string, checker*>::iterator checker =
249 		disabled_checkers.find(name);
250 	if (checker != disabled_checkers.end())
251 	{
252 		checkers.insert(std::make_pair(name, checker->second));
253 		disabled_checkers.erase(checker);
254 		return true;
255 	}
256 	return false;
257 }
258 
259 } // namespace checking
260 
261 } // namespace fdt
262 
263 } // namespace dtc
264 
265