7
7
8
8
import abc
9
9
from collections import deque
10
+ import functools
10
11
import os
11
12
from pathlib import Path
12
13
import shlex
13
14
import subprocess
14
15
import sys
15
16
from re import fullmatch , escape
16
17
18
+ from zephyr_ext_common import ZEPHYR_BASE
19
+
20
+ sys .path .append (os .fspath (Path (__file__ ).parent .parent .parent ))
21
+ import zephyr_module
22
+
17
23
from runners .core import ZephyrBinaryRunner , RunnerCaps
18
24
19
25
try :
34
40
}
35
41
}
36
42
43
+ # Relative to the root of the hal_nordic module
44
+ SUIT_STARTER_PATH = Path ('zephyr/blobs/suit/bin/suit_manifest_starter.hex' )
45
+
46
+ @functools .cache
47
+ def _get_suit_starter ():
48
+ path = None
49
+ modules = zephyr_module .parse_modules (ZEPHYR_BASE )
50
+ for m in modules :
51
+ if 'hal_nordic' in m .meta .get ('name' ):
52
+ path = Path (m .project )
53
+ break
54
+
55
+ if not path :
56
+ raise RuntimeError ("hal_nordic project missing in the manifest" )
57
+
58
+ suit_starter = path / SUIT_STARTER_PATH
59
+ if not suit_starter .exists ():
60
+ raise RuntimeError ("Unable to find suit manifest starter file, "
61
+ "please make sure to run \' west blobs fetch "
62
+ "hal_nordic\' " )
63
+
64
+ return str (suit_starter .resolve ())
65
+
37
66
class NrfBinaryRunner (ZephyrBinaryRunner ):
38
67
'''Runner front-end base class for nrf tools.'''
39
68
@@ -51,6 +80,9 @@ def __init__(self, cfg, family, softreset, dev_id, erase=False,
51
80
self .force = force
52
81
self .recover = bool (recover )
53
82
83
+ # Only applicable for nrfutil
84
+ self .suit_starter = False
85
+
54
86
self .tool_opt = []
55
87
for opts in [shlex .split (opt ) for opt in tool_opt ]:
56
88
self .tool_opt += opts
@@ -425,22 +457,50 @@ def reset_target(self):
425
457
def do_require (self ):
426
458
''' Ensure the tool is installed '''
427
459
460
+ def _check_suit_starter (self , op ):
461
+ op = op ['operation' ]
462
+ if op ['type' ] not in ('erase' , 'recover' , 'program' ):
463
+ return None
464
+ elif op ['type' ] == 'program' and op ['chip_erase_mode' ] != "ERASE_UICR" :
465
+ return None
466
+
467
+ file = _get_suit_starter ()
468
+ self .logger .debug (f'suit starter: { file } ' )
469
+
470
+ return file
471
+
428
472
def op_program (self , hex_file , erase , qspi_erase , defer = False , core = None ):
473
+ args = self ._op_program (hex_file , erase , qspi_erase )
474
+ self .exec_op ('program' , defer , core , ** args )
475
+
476
+ def _op_program (self , hex_file , erase , qspi_erase ):
429
477
args = {'firmware' : {'file' : hex_file },
430
478
'chip_erase_mode' : erase , 'verify' : 'VERIFY_READ' }
431
479
if qspi_erase :
432
480
args ['qspi_erase_mode' ] = qspi_erase
433
- self .exec_op ('program' , defer , core , ** args )
481
+
482
+ return args
434
483
435
484
def exec_op (self , op , defer = False , core = None , ** kwargs ):
436
- _op = f'{ op } '
437
- op = {'operation' : {'type' : _op }}
438
- if core :
439
- op ['core' ] = core
440
- op ['operation' ].update (kwargs )
441
- self .logger .debug (f'defer: { defer } op: { op } ' )
442
- if defer or not self .do_exec_op (op , force = False ):
443
- self .ops .append (op )
485
+
486
+ def _exec_op (op , defer = False , core = None , ** kwargs ):
487
+ _op = f'{ op } '
488
+ op = {'operation' : {'type' : _op }}
489
+ if core :
490
+ op ['core' ] = core
491
+ op ['operation' ].update (kwargs )
492
+ self .logger .debug (f'defer: { defer } op: { op } ' )
493
+ if defer or not self .do_exec_op (op , force = False ):
494
+ self .ops .append (op )
495
+ return op
496
+
497
+ _op = _exec_op (op , defer , core , ** kwargs )
498
+ # Check if the suit manifest starter needs programming
499
+ if self .suit_starter and self .family == 'NRF54H_FAMILY' :
500
+ file = self ._check_suit_starter (_op )
501
+ if file :
502
+ args = self ._op_program (file , 'ERASE_NONE' , None )
503
+ _exec_op ('program' , defer , core , ** args )
444
504
445
505
@abc .abstractmethod
446
506
def do_exec_op (self , op , force = False ):
0 commit comments