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
@ -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
|
||||
*
|
||||
|
||||
@ -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}")
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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, "");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user