1245803Stheraven/*- 2245803Stheraven * Copyright (c) 2013 David Chisnall 3245803Stheraven * All rights reserved. 4245803Stheraven * 5245803Stheraven * This software was developed by SRI International and the University of 6245803Stheraven * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7245803Stheraven * ("CTSRD"), as part of the DARPA CRASH research programme. 8245803Stheraven * 9245803Stheraven * Redistribution and use in source and binary forms, with or without 10245803Stheraven * modification, are permitted provided that the following conditions 11245803Stheraven * are met: 12245803Stheraven * 1. Redistributions of source code must retain the above copyright 13245803Stheraven * notice, this list of conditions and the following disclaimer. 14245803Stheraven * 2. Redistributions in binary form must reproduce the above copyright 15245803Stheraven * notice, this list of conditions and the following disclaimer in the 16245803Stheraven * documentation and/or other materials provided with the distribution. 17245803Stheraven * 18245803Stheraven * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19245803Stheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20245803Stheraven * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21245803Stheraven * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22245803Stheraven * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23245803Stheraven * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24245803Stheraven * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25245803Stheraven * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26245803Stheraven * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27245803Stheraven * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28245803Stheraven * SUCH DAMAGE. 29245803Stheraven * 30245803Stheraven * $FreeBSD: releng/10.3/usr.bin/dtc/checking.cc 251934 2013-06-18 10:26:22Z theraven $ 31245803Stheraven */ 32245803Stheraven 33245803Stheraven#include "checking.hh" 34245839Stheraven#include <stdio.h> 35245803Stheraven 36251856Stheraven 37251856Stheraven 38245803Stheravennamespace dtc 39245803Stheraven{ 40245803Stheravennamespace fdt 41245803Stheraven{ 42245803Stheravennamespace checking 43245803Stheraven{ 44245803Stheraven 45251856Stheravennamespace 46251856Stheraven{ 47251856Stheraven /** 48251856Stheraven * Checker that verifies that every node that has children has 49251856Stheraven * #address-cells and #size-cells properties. 50251856Stheraven */ 51251856Stheraven struct address_cells_checker : public checker 52251856Stheraven { 53251856Stheraven address_cells_checker(const char *name) : checker(name) {} 54251856Stheraven virtual bool check_node(device_tree *tree, node *n) 55251856Stheraven { 56251856Stheraven // If this has no children, it trivially meets the 57251856Stheraven // conditions. 58251856Stheraven if (n->child_begin() == n->child_end()) 59251856Stheraven { 60251856Stheraven return true; 61251856Stheraven } 62251856Stheraven bool found_address = false; 63251856Stheraven bool found_size = false; 64251856Stheraven for (node::property_iterator i=n->property_begin(), 65251856Stheraven e=n->property_end() ; i!=e ; ++i) 66251856Stheraven { 67251856Stheraven if (!found_address) 68251856Stheraven { 69251856Stheraven found_address = ((*i)->get_key() == "#address-cells"); 70251856Stheraven } 71251856Stheraven if (!found_size) 72251856Stheraven { 73251856Stheraven found_size = ((*i)->get_key() == "#size-cells"); 74251856Stheraven } 75251856Stheraven if (found_size && found_address) 76251856Stheraven { 77251856Stheraven break; 78251856Stheraven } 79251856Stheraven } 80251856Stheraven if (!found_address) 81251856Stheraven { 82251856Stheraven report_error("Missing #address-cells property"); 83251856Stheraven } 84251856Stheraven if (!found_size) 85251856Stheraven { 86251856Stheraven report_error("Missing #size-cells property"); 87251856Stheraven } 88251856Stheraven return found_address && found_size; 89251856Stheraven } 90251856Stheraven }; 91251856Stheraven} // anonymous namespace 92251856Stheraven 93245803Stheravenbool 94245803Stheravenchecker::visit_node(device_tree *tree, node *n) 95245803Stheraven{ 96245803Stheraven path.push_back(std::make_pair(n->name, n->unit_address)); 97245803Stheraven // Check this node 98245803Stheraven if (!check_node(tree, n)) 99245803Stheraven { 100245803Stheraven return false; 101245803Stheraven } 102245803Stheraven // Now check its properties 103245803Stheraven for (node::property_iterator i=n->property_begin(), e=n->property_end() 104245803Stheraven ; i!=e ; ++i) 105245803Stheraven { 106245803Stheraven if (!check_property(tree, n, *i)) 107245803Stheraven { 108245803Stheraven return false; 109245803Stheraven } 110245803Stheraven } 111245803Stheraven // And then recursively check the children 112245803Stheraven for (node::child_iterator i=n->child_begin(), e=n->child_end() ; i!=e ; 113245803Stheraven ++i) 114245803Stheraven { 115245803Stheraven if (!visit_node(tree, *i)) 116245803Stheraven { 117245803Stheraven return false; 118245803Stheraven } 119245803Stheraven } 120245803Stheraven path.pop_back(); 121245803Stheraven return true; 122245803Stheraven} 123245803Stheraven 124245803Stheravenvoid 125245803Stheravenchecker::report_error(const char *errmsg) 126245803Stheraven{ 127245803Stheraven fprintf(stderr, "Error: %s, while checking node: ", errmsg); 128245803Stheraven for (device_tree::node_path::iterator p=path.begin()+1, pe=path.end() ; 129245803Stheraven p!=pe ; ++p) 130245803Stheraven { 131245803Stheraven putc('/', stderr); 132245803Stheraven p->first.dump(); 133245803Stheraven if (!(p->second.empty())) 134245803Stheraven { 135245803Stheraven putc('@', stderr); 136245803Stheraven p->second.dump(); 137245803Stheraven } 138245803Stheraven } 139245803Stheraven fprintf(stderr, " [-W%s]\n", checker_name); 140245803Stheraven} 141245803Stheraven 142245803Stheravenbool 143245803Stheravenproperty_checker::check_property(device_tree *tree, node *n, property *p) 144245803Stheraven{ 145245803Stheraven if (p->get_key() == key) 146245803Stheraven { 147245803Stheraven if (!check(tree, n, p)) 148245803Stheraven { 149245803Stheraven report_error("property check failed"); 150245803Stheraven return false; 151245803Stheraven } 152245803Stheraven } 153245803Stheraven return true; 154245803Stheraven} 155245803Stheraven 156245803Stheravenbool 157245803Stheravenproperty_size_checker::check(device_tree *tree, node *n, property *p) 158245803Stheraven{ 159245803Stheraven uint32_t psize = 0; 160245803Stheraven for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ; ++i) 161245803Stheraven { 162245803Stheraven if (!i->is_binary()) 163245803Stheraven { 164245803Stheraven return false; 165245803Stheraven } 166245803Stheraven psize += i->byte_data.size(); 167245803Stheraven } 168245803Stheraven return psize == size; 169245803Stheraven} 170245803Stheraven 171245803Stheraventemplate<property_value::value_type T> 172245803Stheravenvoid 173245803Stheravencheck_manager::add_property_type_checker(const char *name, string prop) 174245803Stheraven{ 175245803Stheraven checkers.insert(std::make_pair(string(name), 176245803Stheraven new property_type_checker<T>(name, prop))); 177245803Stheraven} 178245803Stheraven 179245803Stheravenvoid 180245803Stheravencheck_manager::add_property_size_checker(const char *name, 181245803Stheraven string prop, 182245803Stheraven uint32_t size) 183245803Stheraven{ 184245803Stheraven checkers.insert(std::make_pair(string(name), 185245803Stheraven new property_size_checker(name, prop, size))); 186245803Stheraven} 187245803Stheraven 188245803Stheravencheck_manager::~check_manager() 189245803Stheraven{ 190245803Stheraven while (checkers.begin() != checkers.end()) 191245803Stheraven { 192245803Stheraven delete checkers.begin()->second; 193245803Stheraven checkers.erase(checkers.begin()); 194245803Stheraven } 195245803Stheraven while (disabled_checkers.begin() != disabled_checkers.end()) 196245803Stheraven { 197245803Stheraven delete disabled_checkers.begin()->second; 198251934Stheraven disabled_checkers.erase(disabled_checkers.begin()); 199245803Stheraven } 200245803Stheraven} 201245803Stheraven 202245803Stheravencheck_manager::check_manager() 203245803Stheraven{ 204245803Stheraven // NOTE: All checks listed here MUST have a corresponding line 205245803Stheraven // in the man page! 206245803Stheraven add_property_type_checker<property_value::STRING_LIST>( 207245803Stheraven "type-compatible", string("compatible")); 208245803Stheraven add_property_type_checker<property_value::STRING>( 209245803Stheraven "type-model", string("model")); 210245803Stheraven add_property_size_checker("type-phandle", string("phandle"), 4); 211251856Stheraven disabled_checkers.insert(std::make_pair(string("cells-attributes"), 212251856Stheraven new address_cells_checker("cells-attributes"))); 213245803Stheraven} 214245803Stheraven 215245803Stheravenbool 216245803Stheravencheck_manager::run_checks(device_tree *tree, bool keep_going) 217245803Stheraven{ 218245803Stheraven bool success = true; 219245803Stheraven for (std::map<string, checker*>::iterator i=checkers.begin(), 220245803Stheraven e=checkers.end() ; i!=e ; ++i) 221245803Stheraven { 222245803Stheraven success &= i->second->check_tree(tree); 223245803Stheraven if (!(success || keep_going)) 224245803Stheraven { 225245803Stheraven break; 226245803Stheraven } 227245803Stheraven } 228245803Stheraven return success; 229245803Stheraven} 230245803Stheraven 231245803Stheravenbool 232245803Stheravencheck_manager::disable_checker(string name) 233245803Stheraven{ 234245803Stheraven std::map<string, checker*>::iterator checker = checkers.find(name); 235245803Stheraven if (checker != checkers.end()) 236245803Stheraven { 237245803Stheraven disabled_checkers.insert(std::make_pair(name, 238245803Stheraven checker->second)); 239245803Stheraven checkers.erase(checker); 240245803Stheraven return true; 241245803Stheraven } 242245803Stheraven return false; 243245803Stheraven} 244245803Stheraven 245245803Stheravenbool 246245803Stheravencheck_manager::enable_checker(string name) 247245803Stheraven{ 248245803Stheraven std::map<string, checker*>::iterator checker = 249245803Stheraven disabled_checkers.find(name); 250245803Stheraven if (checker != disabled_checkers.end()) 251245803Stheraven { 252245803Stheraven checkers.insert(std::make_pair(name, checker->second)); 253245803Stheraven disabled_checkers.erase(checker); 254245803Stheraven return true; 255245803Stheraven } 256245803Stheraven return false; 257245803Stheraven} 258245803Stheraven 259245803Stheraven} // namespace checking 260245803Stheraven 261245803Stheraven} // namespace fdt 262245803Stheraven 263245803Stheraven} // namespace dtc 264245803Stheraven 265