]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.bin/dtc/checking.cc
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.bin / dtc / checking.cc
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