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