diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index a4ba6daf498..70ee27f6b9e 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -242,6 +242,16 @@ */ #define DT_HAS_ALIAS(alias_name) DT_NODE_EXISTS(DT_ALIAS(alias_name)) +/** + * @brief Get the hash associated with a DT node + * + * Get the hash for the specified node_id. The hash is calculated on the + * full devicetree path of the node. + * @param node_id node identifier + * @return hash value as a preprocessor token + */ +#define DT_NODE_HASH(node_id) DT_CAT(node_id, _HASH) + /** * @brief Get a node identifier for an instance of a compatible * diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index eb9fc5e8ce0..99aac7d720c 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -720,6 +720,9 @@ def write_dep_info(node: edtlib.Node) -> None: else: return "/* nothing */" + out_comment("Node's hash:") + out_dt_define(f"{node.z_path_id}_HASH", node.hash) + out_comment("Node's dependency ordinal:") out_dt_define(f"{node.z_path_id}_ORD", node.dep_ordinal) out_dt_define(f"{node.z_path_id}_ORD_STR_SORTABLE", f"{node.dep_ordinal:0>5}") diff --git a/scripts/dts/python-devicetree/src/devicetree/edtlib.py b/scripts/dts/python-devicetree/src/devicetree/edtlib.py index bb605771c5a..f036bf1f1c5 100644 --- a/scripts/dts/python-devicetree/src/devicetree/edtlib.py +++ b/scripts/dts/python-devicetree/src/devicetree/edtlib.py @@ -72,6 +72,8 @@ from copy import deepcopy from dataclasses import dataclass from typing import (Any, Callable, Iterable, NoReturn, Optional, TYPE_CHECKING, Union) +import base64 +import hashlib import logging import os import re @@ -90,6 +92,12 @@ from devicetree.dtlib import Property as dtlib_Property from devicetree.grutils import Graph from devicetree._private import _slice_helper +def _compute_hash(path: str) -> str: + # Calculates the hash associated with the node's full path. + hasher = hashlib.sha256() + hasher.update(path.encode()) + return base64.b64encode(hasher.digest(), altchars=b'__').decode().rstrip('=') + # # Public classes # @@ -912,6 +920,11 @@ class Node: The ordinal is defined for all Nodes, and is unique among nodes in its EDT 'nodes' list. + hash: + A hashed value of the devicetree path of the node. This is defined for + all Nodes, and is checked for uniqueness among nodes in its EDT 'nodes' + list. + required_by: A list with the nodes that directly depend on the node @@ -1027,6 +1040,7 @@ class Node: self.interrupts: list[ControllerAndData] = [] self.pinctrls: list[PinCtrl] = [] self.bus_node = self._bus_node(support_fixed_partitions_on_any_bus) + self.hash: str = _compute_hash(dt_node.path) self._init_binding() self._init_regs() @@ -2268,10 +2282,18 @@ class EDT: # Creates a list of edtlib.Node objects from the dtlib.Node objects, in # self.nodes + hash2node: dict[str, Node] = {} + for dt_node in self._dt.node_iter(): # Warning: We depend on parent Nodes being created before their # children. This is guaranteed by node_iter(). node = Node(dt_node, self, self._fixed_partitions_no_bus) + + if node.hash in hash2node: + _err(f"hash collision between '{node.path}' and " + f"'{hash2node[node.hash].path}'") + hash2node[node.hash] = node + self.nodes.append(node) self._node2enode[dt_node] = node diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index b23cf116c55..ae87818b4e7 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -338,6 +338,16 @@ ZTEST(devicetree_api, test_has_alias) zassert_equal(DT_NODE_HAS_STATUS(DT_ALIAS(test_undef), okay), 0, ""); } +ZTEST(devicetree_api, test_node_hashes) +{ + zassert_str_equal(TO_STRING(DT_NODE_HASH(DT_ROOT)), + "il7asoJjJEMhngUeSt4tHVu8Zxx4EFG_FDeJfL3_oPE"); + zassert_str_equal(TO_STRING(DT_NODE_HASH(TEST_DEADBEEF)), + "kPPqtBX5DX_QDQMO0_cOls2ebJMevAWHhAPY1JCKTyU"); + zassert_str_equal(TO_STRING(DT_NODE_HASH(TEST_ABCD1234)), + "Bk4fvF6o3Mgslz_xiIZaJcuwo6_IeelozwOaxtUsSos"); +} + ZTEST(devicetree_api, test_inst_checks) { zassert_equal(DT_NODE_EXISTS(DT_INST(0, vnd_gpio_device)), 1, "");