Skip to content

Commit 0705a63

Browse files
carlescufidleach02
authored andcommitted
west: runners: nrf: Add support for the suit manifest starter
With the recent introduction of the SUIT manifest starter binary blob, it is now possible to use it with the nRF54H20 during the flashing procedure in order to provide a valid SUIT manifest to the system. This PR introduces the code that handles programming the SUIT manifest starter, as well as a new --suit-manifest-starter command-line option. Signed-off-by: Carles Cufi <[email protected]>
1 parent faba632 commit 0705a63

File tree

2 files changed

+83
-12
lines changed

2 files changed

+83
-12
lines changed

scripts/west_commands/runners/nrf_common.py

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,19 @@
77

88
import abc
99
from collections import deque
10+
import functools
1011
import os
1112
from pathlib import Path
1213
import shlex
1314
import subprocess
1415
import sys
1516
from re import fullmatch, escape
1617

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+
1723
from runners.core import ZephyrBinaryRunner, RunnerCaps
1824

1925
try:
@@ -34,6 +40,29 @@
3440
}
3541
}
3642

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+
3766
class NrfBinaryRunner(ZephyrBinaryRunner):
3867
'''Runner front-end base class for nrf tools.'''
3968

@@ -51,6 +80,9 @@ def __init__(self, cfg, family, softreset, dev_id, erase=False,
5180
self.force = force
5281
self.recover = bool(recover)
5382

83+
# Only applicable for nrfutil
84+
self.suit_starter = False
85+
5486
self.tool_opt = []
5587
for opts in [shlex.split(opt) for opt in tool_opt]:
5688
self.tool_opt += opts
@@ -425,22 +457,50 @@ def reset_target(self):
425457
def do_require(self):
426458
''' Ensure the tool is installed '''
427459

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+
428472
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):
429477
args = {'firmware': {'file': hex_file},
430478
'chip_erase_mode': erase, 'verify': 'VERIFY_READ'}
431479
if qspi_erase:
432480
args['qspi_erase_mode'] = qspi_erase
433-
self.exec_op('program', defer, core, **args)
481+
482+
return args
434483

435484
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)
444504

445505
@abc.abstractmethod
446506
def do_exec_op(self, op, force=False):

scripts/west_commands/runners/nrfutil.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,18 @@
1313
from runners.core import _DRY_RUN
1414
from runners.nrf_common import NrfBinaryRunner
1515

16-
1716
class NrfUtilBinaryRunner(NrfBinaryRunner):
1817
'''Runner front-end for nrfutil.'''
1918

2019
def __init__(self, cfg, family, softreset, dev_id, erase=False,
21-
reset=True, tool_opt=[], force=False, recover=False):
20+
reset=True, tool_opt=[], force=False, recover=False,
21+
suit_starter=False):
2222

2323
super().__init__(cfg, family, softreset, dev_id, erase, reset,
2424
tool_opt, force, recover)
25+
26+
self.suit_starter = suit_starter
27+
2528
self._ops = []
2629
self._op_id = 1
2730

@@ -39,7 +42,15 @@ def do_create(cls, cfg, args):
3942
args.dev_id, erase=args.erase,
4043
reset=args.reset,
4144
tool_opt=args.tool_opt, force=args.force,
42-
recover=args.recover)
45+
recover=args.recover,
46+
suit_starter=args.suit_manifest_starter)
47+
48+
@classmethod
49+
def do_add_parser(cls, parser):
50+
super().do_add_parser(parser)
51+
parser.add_argument('--suit-manifest-starter', required=False,
52+
action='store_true',
53+
help='Use the SUIT manifest starter file')
4354

4455
def _exec(self, args):
4556
jout_all = []

0 commit comments

Comments
 (0)