7
7
8
8
import argparse
9
9
import ctypes as c
10
- import math
11
- import pickle
12
- import re
13
10
import sys
14
- from collections import defaultdict
15
11
from itertools import groupby
16
12
17
13
from elftools .elf .elffile import ELFFile
25
21
# Must match the name used in the linker script.
26
22
PERIPHCONF_SECTION = "uicr_periphconf_entry"
27
23
28
- # Expected nodelabel of the UICR devicetree node, used to extract its location from the devicetree.
29
- UICR_NODELABEL = "uicr"
30
- # Nodelabel of the PERIPHCONF devicetree node, used to extract its location from the devicetree.
31
- PERIPHCONF_NODELABEL = "periphconf_partition"
32
-
33
24
# Common values for representing enabled/disabled in the UICR format.
34
25
ENABLED_VALUE = 0xFFFF_FFFF
35
26
DISABLED_VALUE = 0xBD23_28A8
@@ -141,18 +132,6 @@ def main() -> None:
141
132
"peripherals, and to protect the device in various ways."
142
133
),
143
134
)
144
- parser .add_argument (
145
- "--in-config" ,
146
- required = True ,
147
- type = argparse .FileType ("r" ),
148
- help = "Path to the .config file from the application build" ,
149
- )
150
- parser .add_argument (
151
- "--in-edt-pickle" ,
152
- required = True ,
153
- type = argparse .FileType ("rb" ),
154
- help = "Path to the edt.pickle file from the application build" ,
155
- )
156
135
parser .add_argument (
157
136
"--in-periphconf-elf" ,
158
137
dest = "in_periphconf_elfs" ,
@@ -165,71 +144,103 @@ def main() -> None:
165
144
"by ascending address and cleared of duplicate entries."
166
145
),
167
146
)
147
+ parser .add_argument (
148
+ "--out-merged-hex" ,
149
+ required = True ,
150
+ type = argparse .FileType ("w" , encoding = "utf-8" ),
151
+ help = "Path to write the merged UICR+PERIPHCONF HEX file to" ,
152
+ )
168
153
parser .add_argument (
169
154
"--out-uicr-hex" ,
170
155
required = True ,
171
156
type = argparse .FileType ("w" , encoding = "utf-8" ),
172
- help = "Path to write the generated UICR HEX file to" ,
157
+ help = "Path to write the UICR-only HEX file to" ,
173
158
)
174
159
parser .add_argument (
175
160
"--out-periphconf-hex" ,
176
- default = None ,
177
161
type = argparse .FileType ("w" , encoding = "utf-8" ),
178
- help = "Path to write the generated PERIPHCONF HEX file to" ,
162
+ help = "Path to write the PERIPHCONF-only HEX file to" ,
163
+ )
164
+ parser .add_argument (
165
+ "--periphconf-address" ,
166
+ default = None ,
167
+ type = lambda s : int (s , 0 ),
168
+ help = "Absolute flash address of the PERIPHCONF partition (decimal or 0x-prefixed hex)" ,
169
+ )
170
+ parser .add_argument (
171
+ "--periphconf-size" ,
172
+ default = None ,
173
+ type = lambda s : int (s , 0 ),
174
+ help = "Size in bytes of the PERIPHCONF partition (decimal or 0x-prefixed hex)" ,
175
+ )
176
+ parser .add_argument (
177
+ "--uicr-address" ,
178
+ required = True ,
179
+ type = lambda s : int (s , 0 ),
180
+ help = "Absolute flash address of the UICR region (decimal or 0x-prefixed hex)" ,
179
181
)
180
182
args = parser .parse_args ()
181
183
182
184
try :
185
+ # Validate argument dependencies
186
+ if args .out_periphconf_hex :
187
+ if args .periphconf_address is None :
188
+ raise ScriptError (
189
+ "--periphconf-address is required when --out-periphconf-hex is used"
190
+ )
191
+ if args .periphconf_size is None :
192
+ raise ScriptError ("--periphconf-size is required when --out-periphconf-hex is used" )
193
+
183
194
init_values = DISABLED_VALUE .to_bytes (4 , "little" ) * (c .sizeof (Uicr ) // 4 )
184
195
uicr = Uicr .from_buffer_copy (init_values )
185
196
186
197
uicr .VERSION .MAJOR = UICR_FORMAT_VERSION_MAJOR
187
198
uicr .VERSION .MINOR = UICR_FORMAT_VERSION_MINOR
188
199
189
- kconfig_str = args . in_config . read ()
190
- kconfig = parse_kconfig ( kconfig_str )
200
+ # Process periphconf data first and configure UICR completely before creating hex objects
201
+ periphconf_hex = IntelHex ( )
191
202
192
- edt = pickle .load (args .in_edt_pickle )
203
+ if args .out_periphconf_hex :
204
+ periphconf_combined = extract_and_combine_periphconfs (args .in_periphconf_elfs )
193
205
194
- try :
195
- periphconf_partition = edt .label2node [PERIPHCONF_NODELABEL ]
196
- except LookupError as e :
197
- raise ScriptError (
198
- "Failed to find a PERIPHCONF partition in the devicetree. "
199
- f"Expected a DT node with label '{ PERIPHCONF_NODELABEL } '."
200
- ) from e
206
+ padding_len = args .periphconf_size - len (periphconf_combined )
207
+ periphconf_final = periphconf_combined + bytes ([0xFF for _ in range (padding_len )])
201
208
202
- flash_base_address = periphconf_partition .flash_controller .regs [0 ].addr
203
- periphconf_address = flash_base_address + periphconf_partition .regs [0 ].addr
204
- periphconf_size = periphconf_partition .regs [0 ].size
209
+ # Add periphconf data to periphconf hex object
210
+ periphconf_hex .frombytes (periphconf_final , offset = args .periphconf_address )
205
211
206
- periphconf_combined = extract_and_combine_periphconfs (args .in_periphconf_elfs )
207
- padding_len = periphconf_size - len (periphconf_combined )
208
- periphconf_final = periphconf_combined + bytes ([0xFF for _ in range (padding_len )])
209
-
210
- if kconfig .get ("CONFIG_NRF_HALTIUM_UICR_PERIPHCONF" ) == "y" :
212
+ # Configure UICR with periphconf settings
211
213
uicr .PERIPHCONF .ENABLE = ENABLED_VALUE
212
- uicr .PERIPHCONF .ADDRESS = periphconf_address
213
- uicr .PERIPHCONF .MAXCOUNT = math .floor (periphconf_size / 8 )
214
+ uicr .PERIPHCONF .ADDRESS = args .periphconf_address
215
+
216
+ # MAXCOUNT is given in number of 8-byte peripheral
217
+ # configuration entries and periphconf_size is given in
218
+ # bytes. When setting MAXCOUNT based on the
219
+ # periphconf_size we must first assert that
220
+ # periphconf_size has not been misconfigured.
221
+ if args .periphconf_size % 8 != 0 :
222
+ raise ScriptError (
223
+ f"args.periphconf_size was { args .periphconf_size } , but must be divisible by 8"
224
+ )
214
225
215
- try :
216
- uicr_node = edt .label2node [UICR_NODELABEL ]
217
- except LookupError as e :
218
- raise ScriptError (
219
- "Failed to find UICR node in the devicetree. "
220
- f"Expected a DT node with label '{ UICR_NODELABEL } '."
221
- ) from e
226
+ uicr .PERIPHCONF .MAXCOUNT = args .periphconf_size // 8
222
227
228
+ # Create UICR hex object with final UICR data
223
229
uicr_hex = IntelHex ()
224
- uicr_hex .frombytes (bytes (uicr ), offset = uicr_node . regs [ 0 ]. addr )
230
+ uicr_hex .frombytes (bytes (uicr ), offset = args . uicr_address )
225
231
226
- uicr_hex .write_hex_file (args .out_uicr_hex )
232
+ # Create merged hex by combining UICR and periphconf hex objects
233
+ merged_hex = IntelHex ()
234
+ merged_hex .fromdict (uicr_hex .todict ())
227
235
228
- if args .out_periphconf_hex is not None :
229
- periphconf_hex = IntelHex ()
230
- periphconf_hex .frombytes (periphconf_final , offset = periphconf_address )
236
+ if args .out_periphconf_hex :
231
237
periphconf_hex .write_hex_file (args .out_periphconf_hex )
232
238
239
+ merged_hex .fromdict (periphconf_hex .todict ())
240
+
241
+ merged_hex .write_hex_file (args .out_merged_hex )
242
+ uicr_hex .write_hex_file (args .out_uicr_hex )
243
+
233
244
except ScriptError as e :
234
245
print (f"Error: { e !s} " )
235
246
sys .exit (1 )
@@ -270,16 +281,5 @@ def extract_and_combine_periphconfs(elf_files: list[argparse.FileType]) -> bytes
270
281
return bytes (final_periphconf )
271
282
272
283
273
- def parse_kconfig (content : str ) -> dict [str , str | None ]:
274
- result = defaultdict (None )
275
- match_iter = re .finditer (
276
- r"^(?P<config>(SB_)?CONFIG_[^=\s]+)=(?P<value>[^\s#])+$" , content , re .MULTILINE
277
- )
278
- for match in match_iter :
279
- result [match ["config" ]] = match ["value" ]
280
-
281
- return result
282
-
283
-
284
284
if __name__ == "__main__" :
285
285
main ()
0 commit comments