edtlib: add "hash" attribute to nodes
Add a new "hash" attribute to all Devicetree EDT nodes. The hash is calculated on the full path of the node; this means that its value remains stable across rebuilds. The hash is checked for uniqueness among nodes in the same EDT. This computed token is then added to `devicetree_generated.h` and made accessible to Zephyr code via a new DT_NODE_HASH(node_id) macro. Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This commit is contained in:
parent
d1d85fa40b
commit
16d71d0598
4 changed files with 45 additions and 0 deletions
|
|
@ -242,6 +242,16 @@
|
||||||
*/
|
*/
|
||||||
#define DT_HAS_ALIAS(alias_name) DT_NODE_EXISTS(DT_ALIAS(alias_name))
|
#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
|
* @brief Get a node identifier for an instance of a compatible
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -720,6 +720,9 @@ def write_dep_info(node: edtlib.Node) -> None:
|
||||||
else:
|
else:
|
||||||
return "/* nothing */"
|
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_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", node.dep_ordinal)
|
||||||
out_dt_define(f"{node.z_path_id}_ORD_STR_SORTABLE", f"{node.dep_ordinal:0>5}")
|
out_dt_define(f"{node.z_path_id}_ORD_STR_SORTABLE", f"{node.dep_ordinal:0>5}")
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ from copy import deepcopy
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import (Any, Callable, Iterable, NoReturn,
|
from typing import (Any, Callable, Iterable, NoReturn,
|
||||||
Optional, TYPE_CHECKING, Union)
|
Optional, TYPE_CHECKING, Union)
|
||||||
|
import base64
|
||||||
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
@ -90,6 +92,12 @@ from devicetree.dtlib import Property as dtlib_Property
|
||||||
from devicetree.grutils import Graph
|
from devicetree.grutils import Graph
|
||||||
from devicetree._private import _slice_helper
|
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
|
# Public classes
|
||||||
#
|
#
|
||||||
|
|
@ -912,6 +920,11 @@ class Node:
|
||||||
The ordinal is defined for all Nodes, and is unique among nodes in its
|
The ordinal is defined for all Nodes, and is unique among nodes in its
|
||||||
EDT 'nodes' list.
|
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:
|
required_by:
|
||||||
A list with the nodes that directly depend on the node
|
A list with the nodes that directly depend on the node
|
||||||
|
|
||||||
|
|
@ -1027,6 +1040,7 @@ class Node:
|
||||||
self.interrupts: list[ControllerAndData] = []
|
self.interrupts: list[ControllerAndData] = []
|
||||||
self.pinctrls: list[PinCtrl] = []
|
self.pinctrls: list[PinCtrl] = []
|
||||||
self.bus_node = self._bus_node(support_fixed_partitions_on_any_bus)
|
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_binding()
|
||||||
self._init_regs()
|
self._init_regs()
|
||||||
|
|
@ -2268,10 +2282,18 @@ class EDT:
|
||||||
# Creates a list of edtlib.Node objects from the dtlib.Node objects, in
|
# Creates a list of edtlib.Node objects from the dtlib.Node objects, in
|
||||||
# self.nodes
|
# self.nodes
|
||||||
|
|
||||||
|
hash2node: dict[str, Node] = {}
|
||||||
|
|
||||||
for dt_node in self._dt.node_iter():
|
for dt_node in self._dt.node_iter():
|
||||||
# Warning: We depend on parent Nodes being created before their
|
# Warning: We depend on parent Nodes being created before their
|
||||||
# children. This is guaranteed by node_iter().
|
# children. This is guaranteed by node_iter().
|
||||||
node = Node(dt_node, self, self._fixed_partitions_no_bus)
|
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.nodes.append(node)
|
||||||
self._node2enode[dt_node] = node
|
self._node2enode[dt_node] = node
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -338,6 +338,16 @@ ZTEST(devicetree_api, test_has_alias)
|
||||||
zassert_equal(DT_NODE_HAS_STATUS(DT_ALIAS(test_undef), okay), 0, "");
|
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)
|
ZTEST(devicetree_api, test_inst_checks)
|
||||||
{
|
{
|
||||||
zassert_equal(DT_NODE_EXISTS(DT_INST(0, vnd_gpio_device)), 1, "");
|
zassert_equal(DT_NODE_EXISTS(DT_INST(0, vnd_gpio_device)), 1, "");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue