77
88import argparse
99import ctypes as c
10- import math
11- import pickle
12- import re
1310import sys
14- from collections import defaultdict
1511from itertools import groupby
1612
1713from elftools .elf .elffile import ELFFile
2521# Must match the name used in the linker script.
2622PERIPHCONF_SECTION = "uicr_periphconf_entry"
2723
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-
3324# Common values for representing enabled/disabled in the UICR format.
3425ENABLED_VALUE = 0xFFFF_FFFF
3526DISABLED_VALUE = 0xBD23_28A8
@@ -141,18 +132,6 @@ def main() -> None:
141132 "peripherals, and to protect the device in various ways."
142133 ),
143134 )
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- )
156135 parser .add_argument (
157136 "--in-periphconf-elf" ,
158137 dest = "in_periphconf_elfs" ,
@@ -165,71 +144,103 @@ def main() -> None:
165144 "by ascending address and cleared of duplicate entries."
166145 ),
167146 )
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+ )
168153 parser .add_argument (
169154 "--out-uicr-hex" ,
170155 required = True ,
171156 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" ,
173158 )
174159 parser .add_argument (
175160 "--out-periphconf-hex" ,
176- default = None ,
177161 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)" ,
179181 )
180182 args = parser .parse_args ()
181183
182184 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+
183194 init_values = DISABLED_VALUE .to_bytes (4 , "little" ) * (c .sizeof (Uicr ) // 4 )
184195 uicr = Uicr .from_buffer_copy (init_values )
185196
186197 uicr .VERSION .MAJOR = UICR_FORMAT_VERSION_MAJOR
187198 uicr .VERSION .MINOR = UICR_FORMAT_VERSION_MINOR
188199
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 ( )
191202
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 )
193205
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 )])
201208
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 )
205211
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
211213 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+ )
214225
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
222227
228+ # Create UICR hex object with final UICR data
223229 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 )
225231
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 ())
227235
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 :
231237 periphconf_hex .write_hex_file (args .out_periphconf_hex )
232238
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+
233244 except ScriptError as e :
234245 print (f"Error: { e !s} " )
235246 sys .exit (1 )
@@ -270,16 +281,5 @@ def extract_and_combine_periphconfs(elf_files: list[argparse.FileType]) -> bytes
270281 return bytes (final_periphconf )
271282
272283
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-
284284if __name__ == "__main__" :
285285 main ()
0 commit comments