blob: 3f563eb466b940900a26fe1fc99b84e9ba36424c [file] [log] [blame]
Peter Bigotd554d342020-06-30 10:05:35 -05001#!/usr/bin/env python3
2#
3# Copyright (c) 2017 Intel Corporation
4# Copyright (c) 2020 Nordic Semiconductor NA
5#
6# SPDX-License-Identifier: Apache-2.0
7"""Translate generic handles into ones optimized for the application.
8
9Immutable device data includes information about dependencies,
10e.g. that a particular sensor is controlled through a specific I2C bus
11and that it signals event on a pin on a specific GPIO controller.
12This information is encoded in the first-pass binary using identifiers
13derived from the devicetree. This script extracts those identifiers
14and replaces them with ones optimized for use with the devices
15actually present.
16
17For example the sensor might have a first-pass handle defined by its
18devicetree ordinal 52, with the I2C driver having ordinal 24 and the
19GPIO controller ordinal 14. The runtime ordinal is the index of the
20corresponding device in the static devicetree array, which might be 6,
215, and 3, respectively.
22
23The output is a C source file that provides alternative definitions
24for the array contents referenced from the immutable device objects.
25In the final link these definitions supersede the ones in the
26driver-specific object file.
27"""
28
29import sys
30import argparse
31import os
Peter Bigotd554d342020-06-30 10:05:35 -050032import pickle
Peter Bigotd554d342020-06-30 10:05:35 -050033
Jordan Yates8d17e852022-07-10 13:43:24 +100034from elf_parser import ZephyrElf
Peter Bigotd554d342020-06-30 10:05:35 -050035
Martí Bolívar53328472021-03-26 16:18:58 -070036# This is needed to load edt.pickle files.
Anas Nashif80f4b5d2022-07-11 10:48:04 -040037sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..',
Jordan Yates8e4107f2022-04-30 21:13:52 +100038 'dts', 'python-devicetree', 'src'))
Martí Bolívar53328472021-03-26 16:18:58 -070039
Peter Bigotd554d342020-06-30 10:05:35 -050040def parse_args():
41 global args
42
43 parser = argparse.ArgumentParser(
44 description=__doc__,
Jamie McCraeec704442023-01-04 16:08:36 +000045 formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False)
Peter Bigotd554d342020-06-30 10:05:35 -050046
47 parser.add_argument("-k", "--kernel", required=True,
48 help="Input zephyr ELF binary")
Gerard Marull-Paretasb6d5d242023-06-14 17:12:55 +020049 parser.add_argument("--dynamic-deps", action="store_true",
50 help="Indicates if device dependencies are dynamic")
Flavio Ceolin0b13b442022-01-05 17:19:53 -080051 parser.add_argument("-d", "--num-dynamic-devices", required=False, default=0,
52 type=int, help="Input number of dynamic devices allowed")
Peter Bigotd554d342020-06-30 10:05:35 -050053 parser.add_argument("-o", "--output-source", required=True,
Jordan Yates8d17e852022-07-10 13:43:24 +100054 help="Output source file")
Jordan Yates29942472022-07-10 13:46:17 +100055 parser.add_argument("-g", "--output-graphviz",
56 help="Output file for graphviz dependency graph")
Torsten Rasmussenb92b5802021-03-12 15:28:54 +010057 parser.add_argument("-z", "--zephyr-base",
58 help="Path to current Zephyr base. If this argument \
59 is not provided the environment will be checked for \
60 the ZEPHYR_BASE environment variable.")
Torsten Rasmussenc9804d22021-05-21 21:34:58 +020061 parser.add_argument("-s", "--start-symbol", required=True,
62 help="Symbol name of the section which contains the \
63 devices. The symbol name must point to the first \
64 device in that section.")
65
Peter Bigotd554d342020-06-30 10:05:35 -050066 args = parser.parse_args()
Peter Bigotd554d342020-06-30 10:05:35 -050067
Torsten Rasmussenb92b5802021-03-12 15:28:54 +010068 ZEPHYR_BASE = args.zephyr_base or os.getenv("ZEPHYR_BASE")
69
70 if ZEPHYR_BASE is None:
71 sys.exit("-z / --zephyr-base not provided. Please provide "
72 "--zephyr-base or set ZEPHYR_BASE in environment")
73
74 sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/dts"))
75
Keith Shortf896fc22022-07-22 15:28:22 -060076def c_handle_comment(dev, handles):
Jordan Yates8d17e852022-07-10 13:43:24 +100077 def dev_path_str(dev):
78 return dev.edt_node and dev.edt_node.path or dev.sym.name
79 lines = [
80 '',
81 '/* {:d} : {:s}:'.format(dev.handle, (dev_path_str(dev))),
82 ]
Keith Shortf896fc22022-07-22 15:28:22 -060083 if len(handles["depends"]) > 0:
Jordan Yates8d17e852022-07-10 13:43:24 +100084 lines.append(' * Direct Dependencies:')
Keith Shortf896fc22022-07-22 15:28:22 -060085 for dep in handles["depends"]:
Jordan Yates8d17e852022-07-10 13:43:24 +100086 lines.append(' * - {:s}'.format(dev_path_str(dep)))
Keith Shortf896fc22022-07-22 15:28:22 -060087 if len(handles["injected"]) > 0:
Jordan Yates8d17e852022-07-10 13:43:24 +100088 lines.append(' * Injected Dependencies:')
Keith Shortf896fc22022-07-22 15:28:22 -060089 for dep in handles["injected"]:
Jordan Yates8d17e852022-07-10 13:43:24 +100090 lines.append(' * - {:s}'.format(dev_path_str(dep)))
Keith Shortf896fc22022-07-22 15:28:22 -060091 if len(handles["supports"]) > 0:
Jordan Yates8d17e852022-07-10 13:43:24 +100092 lines.append(' * Supported:')
Keith Shortf896fc22022-07-22 15:28:22 -060093 for sup in handles["supports"]:
Jordan Yates8d17e852022-07-10 13:43:24 +100094 lines.append(' * - {:s}'.format(dev_path_str(sup)))
95 lines.append(' */')
96 return lines
Peter Bigotd554d342020-06-30 10:05:35 -050097
Gerard Marull-Paretasb6d5d242023-06-14 17:12:55 +020098def c_handle_array(dev, handles, dynamic_deps, extra_support_handles=0):
Jordan Yates8d17e852022-07-10 13:43:24 +100099 handles = [
Keith Shortf896fc22022-07-22 15:28:22 -0600100 *[str(d.handle) for d in handles["depends"]],
Gerard Marull-Paretas4eb406e2023-06-14 12:35:14 +0200101 'Z_DEVICE_DEPS_SEP',
Keith Shortf896fc22022-07-22 15:28:22 -0600102 *[str(d.handle) for d in handles["injected"]],
Gerard Marull-Paretas4eb406e2023-06-14 12:35:14 +0200103 'Z_DEVICE_DEPS_SEP',
Keith Shortf896fc22022-07-22 15:28:22 -0600104 *[str(d.handle) for d in handles["supports"]],
Jordan Yates8d17e852022-07-10 13:43:24 +1000105 *(extra_support_handles * ['DEVICE_HANDLE_NULL']),
Gerard Marull-Paretas4eb406e2023-06-14 12:35:14 +0200106 'Z_DEVICE_DEPS_ENDS',
Jordan Yates8d17e852022-07-10 13:43:24 +1000107 ]
Gerard Marull-Paretase5335f32023-06-14 10:15:12 +0200108 ctype = (
109 '{:s}Z_DECL_ALIGN(device_handle_t) '
Gerard Marull-Paretas8bee39e2023-06-14 12:10:40 +0200110 '__attribute__((__section__(".__device_deps_pass2")))'
Gerard Marull-Paretasb6d5d242023-06-14 17:12:55 +0200111 ).format('const ' if not dynamic_deps else '')
Jordan Yates8d17e852022-07-10 13:43:24 +1000112 return [
Marc Herbert16880cc2023-04-24 18:53:22 +0000113 # The `extern` line pretends this was first declared in some .h
114 # file to silence "should it be static?" warnings in some
115 # compilers and static analyzers.
116 'extern {:s} {:s}[{:d}];'.format(ctype, dev.ordinals.sym.name, len(handles)),
117 ctype,
Jordan Yates8d17e852022-07-10 13:43:24 +1000118 '{:s}[] = {{ {:s} }};'.format(dev.ordinals.sym.name, ', '.join(handles)),
119 ]
Peter Bigotd554d342020-06-30 10:05:35 -0500120
121def main():
122 parse_args()
123
Peter Bigotd554d342020-06-30 10:05:35 -0500124 edtser = os.path.join(os.path.split(args.kernel)[0], "edt.pickle")
125 with open(edtser, 'rb') as f:
126 edt = pickle.load(f)
127
Jordan Yates8d17e852022-07-10 13:43:24 +1000128 parsed_elf = ZephyrElf(args.kernel, edt, args.start_symbol)
Jordan Yates86dd23e2023-05-30 17:48:26 +1000129 if parsed_elf.relocatable:
130 # While relocatable elf files will load cleanly, the pointers pulled from
131 # the symbol table are invalid (as expected, because the structures have not
132 # yet been allocated addresses). Fixing this will require iterating over
133 # the relocation sections to find the symbols those pointers will end up
134 # referring to.
135 sys.exit('Relocatable elf files are not yet supported')
Peter Bigotd554d342020-06-30 10:05:35 -0500136
Jordan Yates29942472022-07-10 13:46:17 +1000137 if args.output_graphviz:
138 # Try and output the dependency tree
139 try:
140 dot = parsed_elf.device_dependency_graph('Device dependency graph', args.kernel)
141 with open(args.output_graphviz, 'w') as f:
142 f.write(dot.source)
143 except ImportError:
144 pass
145
Peter Bigotd554d342020-06-30 10:05:35 -0500146 with open(args.output_source, "w") as fp:
Gerard Marull-Paretas8f091182022-05-09 13:58:12 +0200147 fp.write('#include <zephyr/device.h>\n')
148 fp.write('#include <zephyr/toolchain.h>\n')
Jordan Yates8d17e852022-07-10 13:43:24 +1000149 for dev in parsed_elf.devices:
Keith Shortf896fc22022-07-22 15:28:22 -0600150 # The device handle are collected up in a set, which has no
151 # specified order. Sort each sub-category of device handle types
152 # separately, so that the generated C array is reproducible across
153 # builds.
154 sorted_handles = {
155 "depends": sorted(dev.devs_depends_on, key=lambda d: d.handle),
156 "injected": sorted(dev.devs_depends_on_injected, key=lambda d: d.handle),
157 "supports": sorted(dev.devs_supports, key=lambda d: d.handle),
158 }
Jordan Yates8d17e852022-07-10 13:43:24 +1000159 extra_sups = args.num_dynamic_devices if dev.pm and dev.pm.is_power_domain else 0
Keith Shortf896fc22022-07-22 15:28:22 -0600160 lines = c_handle_comment(dev, sorted_handles)
Gerard Marull-Paretase5335f32023-06-14 10:15:12 +0200161 lines.extend(
Gerard Marull-Paretasb6d5d242023-06-14 17:12:55 +0200162 c_handle_array(dev, sorted_handles, args.dynamic_deps, extra_sups)
Gerard Marull-Paretase5335f32023-06-14 10:15:12 +0200163 )
Jordan Yates8d17e852022-07-10 13:43:24 +1000164 lines.extend([''])
Peter Bigotd554d342020-06-30 10:05:35 -0500165 fp.write('\n'.join(lines))
166
167if __name__ == "__main__":
168 main()