175dc0fdtheraven/*-
27551d83pfg * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
37551d83pfg *
475dc0fdtheraven * Copyright (c) 2013 David Chisnall
575dc0fdtheraven * All rights reserved.
675dc0fdtheraven *
775dc0fdtheraven * This software was developed by SRI International and the University of
875dc0fdtheraven * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
975dc0fdtheraven * ("CTSRD"), as part of the DARPA CRASH research programme.
1075dc0fdtheraven *
1175dc0fdtheraven * Redistribution and use in source and binary forms, with or without
1275dc0fdtheraven * modification, are permitted provided that the following conditions
1375dc0fdtheraven * are met:
1475dc0fdtheraven * 1. Redistributions of source code must retain the above copyright
1575dc0fdtheraven *    notice, this list of conditions and the following disclaimer.
1675dc0fdtheraven * 2. Redistributions in binary form must reproduce the above copyright
1775dc0fdtheraven *    notice, this list of conditions and the following disclaimer in the
1875dc0fdtheraven *    documentation and/or other materials provided with the distribution.
1975dc0fdtheraven *
2075dc0fdtheraven * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2175dc0fdtheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2275dc0fdtheraven * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2375dc0fdtheraven * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2475dc0fdtheraven * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2575dc0fdtheraven * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2675dc0fdtheraven * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2775dc0fdtheraven * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2875dc0fdtheraven * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2975dc0fdtheraven * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3075dc0fdtheraven * SUCH DAMAGE.
3175dc0fdtheraven *
3275dc0fdtheraven * $FreeBSD$
3375dc0fdtheraven */
3475dc0fdtheraven
3575dc0fdtheraven#ifndef _CHECKING_HH_
3675dc0fdtheraven#define _CHECKING_HH_
376b647a7emaste#include <string>
3875dc0fdtheraven#include "fdt.hh"
3975dc0fdtheraven
4075dc0fdtheravennamespace dtc
4175dc0fdtheraven{
4275dc0fdtheravennamespace fdt
4375dc0fdtheraven{
4475dc0fdtheravennamespace checking
4575dc0fdtheraven{
4675dc0fdtheraven/**
4775dc0fdtheraven * Base class for all checkers.  This will visit the entire tree and perform
4875dc0fdtheraven * semantic checks defined in subclasses.  Note that device trees are generally
4975dc0fdtheraven * small (a few dozen nodes at most) and so we optimise for flexibility and
5075dc0fdtheraven * extensibility here, not for performance.  Each checker will visit the entire
5175dc0fdtheraven * tree.
5275dc0fdtheraven */
5375dc0fdtheravenclass checker
5475dc0fdtheraven{
5575dc0fdtheraven	/**
5675dc0fdtheraven	 * The path to the current node being checked.  This is used for
5775dc0fdtheraven	 * printing error messages.
5875dc0fdtheraven	 */
5975dc0fdtheraven	device_tree::node_path path;
6075dc0fdtheraven	/**
6175dc0fdtheraven	 * The name of the checker.  This is used for printing error messages
6275dc0fdtheraven	 * and for enabling / disabling specific checkers from the command
636b647a7emaste	 * line.
6475dc0fdtheraven	 */
6575dc0fdtheraven	const char *checker_name;
6675dc0fdtheraven	/**
6775dc0fdtheraven	 * Visits each node, calling the checker functions on properties and
6875dc0fdtheraven	 * nodes.
6975dc0fdtheraven	 */
70f89934etheraven	bool visit_node(device_tree *tree, const node_ptr &n);
7175dc0fdtheraven	protected:
7275dc0fdtheraven	/**
7375dc0fdtheraven	 * Prints the error message, along with the path to the node that
7475dc0fdtheraven	 * caused the error and the name of the checker.
7575dc0fdtheraven	 */
7675dc0fdtheraven	void report_error(const char *errmsg);
7775dc0fdtheraven	public:
7875dc0fdtheraven	/**
7975dc0fdtheraven	 * Constructor.  Takes the name of this checker, which is which is used
8075dc0fdtheraven	 * when reporting errors.
8175dc0fdtheraven	 */
8275dc0fdtheraven	checker(const char *name) : checker_name(name) {}
8375dc0fdtheraven	/**
8475dc0fdtheraven	 * Virtual destructor in case any subclasses need to do cleanup.
8575dc0fdtheraven	 */
8675dc0fdtheraven	virtual ~checker() {}
8775dc0fdtheraven	/**
8875dc0fdtheraven	 * Method for checking that a node is valid.  The root class version
8975dc0fdtheraven	 * does nothing, subclasses should override this.
9075dc0fdtheraven	 */
9113531e8theraven	virtual bool check_node(device_tree *, const node_ptr &)
9275dc0fdtheraven	{
9375dc0fdtheraven		return true;
9475dc0fdtheraven	}
9575dc0fdtheraven	/**
9675dc0fdtheraven	 * Method for checking that a property is valid.  The root class
9775dc0fdtheraven	 * version does nothing, subclasses should override this.
9875dc0fdtheraven	 */
9913531e8theraven	virtual bool check_property(device_tree *, const node_ptr &, property_ptr )
10075dc0fdtheraven	{
10175dc0fdtheraven		return true;
10275dc0fdtheraven	}
10375dc0fdtheraven	/**
10475dc0fdtheraven	 * Runs the checker on the specified device tree.
10575dc0fdtheraven	 */
10675dc0fdtheraven	bool check_tree(fdt::device_tree *tree)
10775dc0fdtheraven	{
10875dc0fdtheraven		return visit_node(tree, tree->get_root());
10975dc0fdtheraven	}
11075dc0fdtheraven};
11175dc0fdtheraven
11275dc0fdtheraven/**
11375dc0fdtheraven * Abstract base class for simple property checks.  This class defines a check
11475dc0fdtheraven * method for subclasses, which is invoked only when it finds a property with
11575dc0fdtheraven * the matching name.  To define simple property checkers, just subclass this
11675dc0fdtheraven * and override the check() method.
11775dc0fdtheraven */
11875dc0fdtheravenclass property_checker : public checker
11975dc0fdtheraven{
12075dc0fdtheraven	/**
12175dc0fdtheraven	 * The name of the property that this checker is looking for.
12275dc0fdtheraven	 */
1236b647a7emaste	std::string key;
12475dc0fdtheraven	public:
12575dc0fdtheraven	/**
12675dc0fdtheraven	 * Implementation of the generic property-checking method that checks
1276b647a7emaste	 * for a property with the name specified in the constructor.
12875dc0fdtheraven	 */
129f89934etheraven	virtual bool check_property(device_tree *tree, const node_ptr &n, property_ptr p);
13075dc0fdtheraven	/**
13175dc0fdtheraven	 * Constructor.  Takes the name of the checker and the name of the
13275dc0fdtheraven	 * property to check.
13375dc0fdtheraven	 */
1346b647a7emaste	property_checker(const char* name, const std::string &property_name)
13575dc0fdtheraven		: checker(name), key(property_name) {}
13675dc0fdtheraven	/**
13775dc0fdtheraven	 * The check method, which subclasses should implement.
13875dc0fdtheraven	 */
139f89934etheraven	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0;
14075dc0fdtheraven};
14175dc0fdtheraven
14275dc0fdtheraven/**
14375dc0fdtheraven * Property type checker.
14475dc0fdtheraven */
14575dc0fdtheraventemplate<property_value::value_type T>
14675dc0fdtheravenstruct property_type_checker : public property_checker
14775dc0fdtheraven{
14875dc0fdtheraven	/**
14975dc0fdtheraven	 * Constructor, takes the name of the checker and the name of the
15075dc0fdtheraven	 * property to check as arguments.
15175dc0fdtheraven	 */
1526b647a7emaste	property_type_checker(const char* name, const std::string &property_name) :
15375dc0fdtheraven		property_checker(name, property_name) {}
154f89934etheraven	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0;
15575dc0fdtheraven};
15675dc0fdtheraven
15775dc0fdtheraven/**
15875dc0fdtheraven * Empty property checker.  This checks that the property has no value.
15975dc0fdtheraven */
16075dc0fdtheraventemplate<>
16175dc0fdtheravenstruct property_type_checker <property_value::EMPTY> : public property_checker
16275dc0fdtheraven{
1636b647a7emaste	property_type_checker(const char* name, const std::string &property_name) :
16475dc0fdtheraven		property_checker(name, property_name) {}
16513531e8theraven	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
16675dc0fdtheraven	{
16775dc0fdtheraven		return p->begin() == p->end();
16875dc0fdtheraven	}
16975dc0fdtheraven};
17075dc0fdtheraven
17175dc0fdtheraven/**
17275dc0fdtheraven * String property checker.  This checks that the property has exactly one
17375dc0fdtheraven * value, which is a string.
17475dc0fdtheraven */
17575dc0fdtheraventemplate<>
17675dc0fdtheravenstruct property_type_checker <property_value::STRING> : public property_checker
17775dc0fdtheraven{
1786b647a7emaste	property_type_checker(const char* name, const std::string &property_name) :
17975dc0fdtheraven		property_checker(name, property_name) {}
18013531e8theraven	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
18175dc0fdtheraven	{
18275dc0fdtheraven		return (p->begin() + 1 == p->end()) && p->begin()->is_string();
18375dc0fdtheraven	}
18475dc0fdtheraven};
18575dc0fdtheraven/**
18675dc0fdtheraven * String list property checker.  This checks that the property has at least
18775dc0fdtheraven * one value, all of which are strings.
18875dc0fdtheraven */
18975dc0fdtheraventemplate<>
19075dc0fdtheravenstruct property_type_checker <property_value::STRING_LIST> :
19175dc0fdtheraven	public property_checker
19275dc0fdtheraven{
1936b647a7emaste	property_type_checker(const char* name, const std::string &property_name) :
19475dc0fdtheraven		property_checker(name, property_name) {}
19513531e8theraven	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
19675dc0fdtheraven	{
19775dc0fdtheraven		for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ;
19875dc0fdtheraven		     ++i)
19975dc0fdtheraven		{
20075dc0fdtheraven			if (!(i->is_string() || i->is_string_list()))
20175dc0fdtheraven			{
20275dc0fdtheraven				return false;
20375dc0fdtheraven			}
20475dc0fdtheraven		}
20575dc0fdtheraven		return p->begin() != p->end();
20675dc0fdtheraven	}
20775dc0fdtheraven};
20875dc0fdtheraven
20975dc0fdtheraven/**
21075dc0fdtheraven * Phandle property checker.  This checks that the property has exactly one
21175dc0fdtheraven * value, which is a valid phandle.
21275dc0fdtheraven */
21375dc0fdtheraventemplate<>
21475dc0fdtheravenstruct property_type_checker <property_value::PHANDLE> : public property_checker
21575dc0fdtheraven{
2166b647a7emaste	property_type_checker(const char* name, const std::string &property_name) :
21775dc0fdtheraven		property_checker(name, property_name) {}
21813531e8theraven	virtual bool check(device_tree *tree, const node_ptr &, property_ptr p)
21975dc0fdtheraven	{
2206b647a7emaste		return (p->begin() + 1 == p->end()) &&
22175dc0fdtheraven			(tree->referenced_node(*p->begin()) != 0);
22275dc0fdtheraven	}
22375dc0fdtheraven};
22475dc0fdtheraven
22575dc0fdtheraven/**
22675dc0fdtheraven * Check that a property has the correct size.
22775dc0fdtheraven */
22875dc0fdtheravenstruct property_size_checker : public property_checker
22975dc0fdtheraven{
23075dc0fdtheraven	/**
23175dc0fdtheraven	 * The expected size of the property.
23275dc0fdtheraven	 */
23375dc0fdtheraven	uint32_t size;
23475dc0fdtheraven	public:
23575dc0fdtheraven	/**
23675dc0fdtheraven	 * Constructor, takes the name of the checker, the name of the property
23775dc0fdtheraven	 * to check, and its expected size as arguments.
23875dc0fdtheraven	 */
2396b647a7emaste	property_size_checker(const char* name,
2406b647a7emaste	                      const std::string &property_name,
2416b647a7emaste	                      uint32_t bytes)
24275dc0fdtheraven		: property_checker(name, property_name), size(bytes) {}
24375dc0fdtheraven	/**
24475dc0fdtheraven	 * Check, validates that the property has the correct size.
24575dc0fdtheraven	 */
246f89934etheraven	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p);
24775dc0fdtheraven};
24875dc0fdtheraven
24975dc0fdtheraven
25075dc0fdtheraven/**
25175dc0fdtheraven * The check manager is the interface to running the checks.  This allows
25275dc0fdtheraven * default checks to be enabled, non-default checks to be enabled, and so on.
25375dc0fdtheraven */
25475dc0fdtheravenclass check_manager
25575dc0fdtheraven{
25675dc0fdtheraven	/**
25775dc0fdtheraven	 * The enabled checkers, indexed by their names.  The name is used when
25875dc0fdtheraven	 * disabling checkers from the command line.  When this manager runs,
25975dc0fdtheraven	 * it will only run the checkers from this map.
26075dc0fdtheraven	 */
2616b647a7emaste	std::unordered_map<std::string, checker*> checkers;
26275dc0fdtheraven	/**
26375dc0fdtheraven	 * The disabled checkers.  Moving checkers to this list disables them,
26475dc0fdtheraven	 * but allows them to be easily moved back.
26575dc0fdtheraven	 */
2666b647a7emaste	std::unordered_map<std::string, checker*> disabled_checkers;
26775dc0fdtheraven	/**
26875dc0fdtheraven	 * Helper function for adding a property value checker.
26975dc0fdtheraven	 */
27075dc0fdtheraven	template<property_value::value_type T>
2716b647a7emaste	void add_property_type_checker(const char *name, const std::string &prop);
27275dc0fdtheraven	/**
27375dc0fdtheraven	 * Helper function for adding a simple type checker.
27475dc0fdtheraven	 */
2756b647a7emaste	void add_property_type_checker(const char *name, const std::string &prop);
27675dc0fdtheraven	/**
27775dc0fdtheraven	 * Helper function for adding a property value checker.
27875dc0fdtheraven	 */
27975dc0fdtheraven	void add_property_size_checker(const char *name,
2806b647a7emaste	                               const std::string &prop,
28175dc0fdtheraven	                               uint32_t size);
28275dc0fdtheraven	public:
28375dc0fdtheraven	/**
28475dc0fdtheraven	 * Delete all of the checkers that are part of this checker manager.
28575dc0fdtheraven	 */
28675dc0fdtheraven	~check_manager();
28775dc0fdtheraven	/**
28875dc0fdtheraven	 * Default constructor, creates check manager containing all of the
28975dc0fdtheraven	 * default checks.
29075dc0fdtheraven	 */
29175dc0fdtheraven	check_manager();
29275dc0fdtheraven	/**
29375dc0fdtheraven	 * Run all of the checks on the specified tree.
29475dc0fdtheraven	 */
29575dc0fdtheraven	bool run_checks(device_tree *tree, bool keep_going);
29675dc0fdtheraven	/**
29775dc0fdtheraven	 * Disables the named checker.
29875dc0fdtheraven	 */
2996b647a7emaste	bool disable_checker(const std::string &name);
30075dc0fdtheraven	/**
3016b647a7emaste	 * Enables the named checker.
30275dc0fdtheraven	 */
3036b647a7emaste	bool enable_checker(const std::string &name);
30475dc0fdtheraven};
30575dc0fdtheraven
30675dc0fdtheraven} // namespace checking
30775dc0fdtheraven
30875dc0fdtheraven} // namespace fdt
30975dc0fdtheraven
31075dc0fdtheraven} // namespace dtc
31175dc0fdtheraven
31275dc0fdtheraven#endif // !_CHECKING_HH_
313