scripts: check_init_priorities: handle init and device decoupling
Fix check_init_priorities.py to handle the decoupling between SYS_INIT
and devices.
Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
diff --git a/scripts/build/check_init_priorities.py b/scripts/build/check_init_priorities.py
index 582d7dd..288090b 100755
--- a/scripts/build/check_init_priorities.py
+++ b/scripts/build/check_init_priorities.py
@@ -105,8 +105,14 @@
def __init__(self, file_path):
self.file_path = file_path
self._elf = ELFFile(open(file_path, "rb"))
+
+ self.initlevels = {}
+ for level in _DEVICE_INIT_LEVELS:
+ self.initlevels[level] = []
+
self._load_objects()
self._load_level_addr()
+ self._process_devices()
self._process_initlevels()
def _load_objects(self):
@@ -124,27 +130,37 @@
self._objects[sym.entry.st_value] = (
sym.name, sym.entry.st_size, sym.entry.st_shndx)
- def _load_level_addr(self):
+ def _find_level_addr(self, prefix, levels):
"""Find the address associated with known init levels."""
- self._init_level_addr = {}
+ addrs = {}
+ end = None
for section in self._elf.iter_sections():
if not isinstance(section, SymbolTableSection):
continue
for sym in section.iter_symbols():
- for level in _DEVICE_INIT_LEVELS:
- name = f"__init_{level}_start"
+ for level in levels:
+ name = f"{prefix}_{level}_start"
if sym.name == name:
- self._init_level_addr[level] = sym.entry.st_value
- elif sym.name == "__init_end":
- self._init_level_end = sym.entry.st_value
+ addrs[level] = sym.entry.st_value
+ elif sym.name == f"{prefix}_end":
+ end = sym.entry.st_value
- if len(self._init_level_addr) != len(_DEVICE_INIT_LEVELS):
- raise ValueError(f"Missing init symbols, found: {self._init_level_addr}")
+ if len(addrs) != len(levels):
+ raise ValueError(f"Missing level symbols, found: {addrs}")
- if not self._init_level_end:
- raise ValueError(f"Missing init section end symbol")
+ if not end:
+ raise ValueError(f"Missing level section end symbol")
+
+ return addrs, end
+
+ def _load_level_addr(self):
+ """Load the address level for both init and device sections."""
+ self._init_level_addr, self._init_level_end = self._find_level_addr(
+ "__init", _DEVICE_INIT_LEVELS)
+ self._device_level_addr, self._device_level_end = self._find_level_addr(
+ "_device_list", _DEVICE_INIT_LEVELS)
def _device_ord_from_name(self, sym_name):
"""Find a device ordinal from a symbol name."""
@@ -185,19 +201,16 @@
return int.from_bytes(data[start:stop], byteorder="little")
- def _process_initlevels(self):
- """Process the init level and find the init functions and devices."""
+ def _process_devices(self):
+ """Process the init level and find the devices."""
self.devices = {}
- self.initlevels = {}
for i, level in enumerate(_DEVICE_INIT_LEVELS):
- start = self._init_level_addr[level]
+ start = self._device_level_addr[level]
if i + 1 == len(_DEVICE_INIT_LEVELS):
- stop = self._init_level_end
+ stop = self._device_level_end
else:
- stop = self._init_level_addr[_DEVICE_INIT_LEVELS[i + 1]]
-
- self.initlevels[level] = []
+ stop = self._device_level_addr[_DEVICE_INIT_LEVELS[i + 1]]
priority = 0
addr = start
@@ -206,12 +219,11 @@
raise ValueError(f"no symbol at addr {addr:08x}")
obj, size, shidx = self._objects[addr]
- arg0_name = self._object_name(self._initlevel_pointer(addr, 0, shidx))
- arg1_name = self._object_name(self._initlevel_pointer(addr, 1, shidx))
+ init_name = self._object_name(self._initlevel_pointer(addr, 5, shidx))
- self.initlevels[level].append(f"{obj}: {arg0_name}({arg1_name})")
+ self.initlevels[level].append(f"DEVICE {init_name}({obj})")
- ordinal = self._device_ord_from_name(arg1_name)
+ ordinal = self._device_ord_from_name(obj)
if ordinal:
prio = Priority(level, priority)
self.devices[ordinal] = prio
@@ -219,6 +231,27 @@
addr += size
priority += 1
+ def _process_initlevels(self):
+ """Process the init level and find the init functions."""
+ for i, level in enumerate(_DEVICE_INIT_LEVELS):
+ start = self._init_level_addr[level]
+ if i + 1 == len(_DEVICE_INIT_LEVELS):
+ stop = self._init_level_end
+ else:
+ stop = self._init_level_addr[_DEVICE_INIT_LEVELS[i + 1]]
+
+ addr = start
+ while addr < stop:
+ if addr not in self._objects:
+ raise ValueError(f"no symbol at addr {addr:08x}")
+ _, size, shidx = self._objects[addr]
+
+ init_name = self._object_name(self._initlevel_pointer(addr, 0, shidx))
+
+ self.initlevels[level].append(f"SYS_INIT {init_name}()")
+
+ addr += size
+
class Validator():
"""Validates the initialization priorities.
diff --git a/scripts/build/check_init_priorities_test.py b/scripts/build/check_init_priorities_test.py
index 6e40422..c48d6c1 100755
--- a/scripts/build/check_init_priorities_test.py
+++ b/scripts/build/check_init_priorities_test.py
@@ -89,7 +89,7 @@
self.assertDictEqual(obj._objects, {0xaa: ("a", 4, 1), 0xbb: ("b", 8, 2)})
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
- def test_load_level_addr(self, mock_zilinit):
+ def test_find_level_addr(self, mock_zilinit):
mock_elf = mock.Mock()
sts = mock.Mock(spec=SymbolTableSection)
@@ -97,40 +97,40 @@
mock_elf.iter_sections.return_value = [sts, rel]
s0 = mock.Mock()
- s0.name = "__init_EARLY_start"
+ s0.name = "prefix_EARLY_start"
s0.entry.st_value = 0x00
s1 = mock.Mock()
- s1.name = "__init_PRE_KERNEL_1_start"
+ s1.name = "prefix_PRE_KERNEL_1_start"
s1.entry.st_value = 0x11
s2 = mock.Mock()
- s2.name = "__init_PRE_KERNEL_2_start"
+ s2.name = "prefix_PRE_KERNEL_2_start"
s2.entry.st_value = 0x22
s3 = mock.Mock()
- s3.name = "__init_POST_KERNEL_start"
+ s3.name = "prefix_POST_KERNEL_start"
s3.entry.st_value = 0x33
s4 = mock.Mock()
- s4.name = "__init_APPLICATION_start"
+ s4.name = "prefix_APPLICATION_start"
s4.entry.st_value = 0x44
s5 = mock.Mock()
- s5.name = "__init_SMP_start"
+ s5.name = "prefix_SMP_start"
s5.entry.st_value = 0x55
s6 = mock.Mock()
- s6.name = "__init_end"
+ s6.name = "prefix_end"
s6.entry.st_value = 0x66
sts.iter_symbols.return_value = [s0, s1, s2, s3, s4, s5, s6]
obj = check_init_priorities.ZephyrInitLevels("")
obj._elf = mock_elf
- obj._load_level_addr()
+ addrs, end = obj._find_level_addr("prefix", check_init_priorities._DEVICE_INIT_LEVELS)
- self.assertDictEqual(obj._init_level_addr, {
+ self.assertDictEqual(addrs, {
"EARLY": 0x00,
"PRE_KERNEL_1": 0x11,
"PRE_KERNEL_2": 0x22,
@@ -138,7 +138,7 @@
"APPLICATION": 0x44,
"SMP": 0x55,
})
- self.assertEqual(obj._init_level_end, 0x66)
+ self.assertEqual(end, 0x66)
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
def test_device_ord_from_name(self, mock_zilinit):
@@ -194,8 +194,56 @@
@mock.patch("check_init_priorities.ZephyrInitLevels._object_name")
@mock.patch("check_init_priorities.ZephyrInitLevels._initlevel_pointer")
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
+ def test_process_devices(self, mock_zilinit, mock_ip, mock_on):
+ obj = check_init_priorities.ZephyrInitLevels("")
+ obj.initlevels = {
+ "PRE_KERNEL_2": [],
+ "POST_KERNEL": [],
+ }
+ obj._device_level_addr = {
+ "EARLY": 0x00,
+ "PRE_KERNEL_1": 0x00,
+ "PRE_KERNEL_2": 0x00,
+ "POST_KERNEL": 0x08,
+ "APPLICATION": 0x0c,
+ "SMP": 0x0c,
+ }
+ obj._device_level_end = 0x0c
+ obj._objects = {
+ 0x00: ("__device_dts_ord_11", 4, 0),
+ 0x04: ("__device_dts_ord_22", 4, 0),
+ 0x08: ("__device_dts_ord_33", 4, 0),
+ }
+
+ mock_ip.side_effect = lambda *args: args
+ mock_on.side_effect = lambda *args: f"dev_init_fn_{args[0][0]}"
+
+ obj._process_devices()
+
+ self.assertDictEqual(obj.initlevels, {
+ "PRE_KERNEL_2": [
+ "DEVICE dev_init_fn_0(__device_dts_ord_11)",
+ "DEVICE dev_init_fn_4(__device_dts_ord_22)",
+ ],
+ "POST_KERNEL": [
+ "DEVICE dev_init_fn_8(__device_dts_ord_33)",
+ ],
+ })
+ self.assertDictEqual(obj.devices, {
+ 11: check_init_priorities.Priority("PRE_KERNEL_2", 0),
+ 22: check_init_priorities.Priority("PRE_KERNEL_2", 1),
+ 33: check_init_priorities.Priority("POST_KERNEL", 0),
+ })
+
+ @mock.patch("check_init_priorities.ZephyrInitLevels._object_name")
+ @mock.patch("check_init_priorities.ZephyrInitLevels._initlevel_pointer")
+ @mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
def test_process_initlevels(self, mock_zilinit, mock_ip, mock_on):
obj = check_init_priorities.ZephyrInitLevels("")
+ obj.initlevels = {
+ "PRE_KERNEL_2": [],
+ "POST_KERNEL": [],
+ }
obj._init_level_addr = {
"EARLY": 0x00,
"PRE_KERNEL_1": 0x00,
@@ -212,32 +260,18 @@
}
mock_ip.side_effect = lambda *args: args
-
- def mock_obj_name(*args):
- if args[0] == (0, 0, 0):
- return "i0"
- elif args[0] == (0, 1, 0):
- return "__device_dts_ord_11"
- elif args[0] == (4, 0, 0):
- return "i1"
- elif args[0] == (4, 1, 0):
- return "__device_dts_ord_22"
- return f"name_{args[0][0]}_{args[0][1]}"
- mock_on.side_effect = mock_obj_name
+ mock_on.side_effect = lambda *args: f"init_fn_{args[0][0]}"
obj._process_initlevels()
self.assertDictEqual(obj.initlevels, {
- "EARLY": [],
- "PRE_KERNEL_1": [],
- "PRE_KERNEL_2": ["a: i0(__device_dts_ord_11)", "b: i1(__device_dts_ord_22)"],
- "POST_KERNEL": ["c: name_8_0(name_8_1)"],
- "APPLICATION": [],
- "SMP": [],
- })
- self.assertDictEqual(obj.devices, {
- 11: check_init_priorities.Priority("PRE_KERNEL_2", 0),
- 22: check_init_priorities.Priority("PRE_KERNEL_2", 1),
+ "PRE_KERNEL_2": [
+ "SYS_INIT init_fn_0()",
+ "SYS_INIT init_fn_4()",
+ ],
+ "POST_KERNEL": [
+ "SYS_INIT init_fn_8()",
+ ],
})
class testValidator(unittest.TestCase):