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: stable/10/usr.bin/dtc/checking.cc 251934 2013-06-18 10:26:22Z theraven $
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 {
address_cells_checkerdtc::fdt::checking::__anonbe6d8ca10111::address_cells_checker53 address_cells_checker(const char *name) : checker(name) {}
check_nodedtc::fdt::checking::__anonbe6d8ca10111::address_cells_checker54 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
visit_node(device_tree * tree,node * n)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
report_error(const char * errmsg)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
check_property(device_tree * tree,node * n,property * p)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
check(device_tree * tree,node * n,property * p)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
add_property_type_checker(const char * name,string prop)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
add_property_size_checker(const char * name,string prop,uint32_t size)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
~check_manager()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
check_manager()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
run_checks(device_tree * tree,bool keep_going)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
disable_checker(string name)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
enable_checker(string name)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