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