Commit 0705a630 authored by Carles Cufi's avatar Carles Cufi Committed by David Leach
Browse files

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: default avatarCarles Cufi <carles.cufi@nordicsemi.no>
parent faba6325
Loading
Loading
Loading
Loading
+69 −9
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@

import abc
from collections import deque
import functools
import os
from pathlib import Path
import shlex
@@ -14,6 +15,11 @@ import subprocess
import sys
from re import fullmatch, escape

from zephyr_ext_common import ZEPHYR_BASE

sys.path.append(os.fspath(Path(__file__).parent.parent.parent))
import zephyr_module

from runners.core import ZephyrBinaryRunner, RunnerCaps

try:
@@ -34,6 +40,29 @@ UICR_RANGES = {
    }
}

# Relative to the root of the hal_nordic module
SUIT_STARTER_PATH = Path('zephyr/blobs/suit/bin/suit_manifest_starter.hex')

@functools.cache
def _get_suit_starter():
    path = None
    modules = zephyr_module.parse_modules(ZEPHYR_BASE)
    for m in modules:
        if 'hal_nordic' in m.meta.get('name'):
            path = Path(m.project)
            break

    if not path:
        raise RuntimeError("hal_nordic project missing in the manifest")

    suit_starter = path / SUIT_STARTER_PATH
    if not suit_starter.exists():
        raise RuntimeError("Unable to find suit manifest starter file, "
                           "please make sure to run \'west blobs fetch "
                           "hal_nordic\'")

    return str(suit_starter.resolve())

class NrfBinaryRunner(ZephyrBinaryRunner):
    '''Runner front-end base class for nrf tools.'''

@@ -51,6 +80,9 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
        self.force = force
        self.recover = bool(recover)

        # Only applicable for nrfutil
        self.suit_starter = False

        self.tool_opt = []
        for opts in [shlex.split(opt) for opt in tool_opt]:
            self.tool_opt += opts
@@ -425,14 +457,33 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
    def do_require(self):
        ''' Ensure the tool is installed '''

    def _check_suit_starter(self, op):
        op = op['operation']
        if op['type'] not in ('erase', 'recover', 'program'):
            return None
        elif op['type']  == 'program' and op['chip_erase_mode'] != "ERASE_UICR":
            return None

        file = _get_suit_starter()
        self.logger.debug(f'suit starter: {file}')

        return file

    def op_program(self, hex_file, erase, qspi_erase, defer=False, core=None):
        args = self._op_program(hex_file, erase, qspi_erase)
        self.exec_op('program', defer, core, **args)

    def _op_program(self, hex_file, erase, qspi_erase):
        args = {'firmware': {'file': hex_file},
                'chip_erase_mode': erase, 'verify': 'VERIFY_READ'}
        if qspi_erase:
            args['qspi_erase_mode'] = qspi_erase
        self.exec_op('program', defer, core, **args)

        return args

    def exec_op(self, op, defer=False, core=None, **kwargs):

        def _exec_op(op, defer=False, core=None, **kwargs):
            _op = f'{op}'
            op = {'operation': {'type': _op}}
            if core:
@@ -441,6 +492,15 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
            self.logger.debug(f'defer: {defer} op: {op}')
            if defer or not self.do_exec_op(op, force=False):
                self.ops.append(op)
            return op

        _op = _exec_op(op, defer, core, **kwargs)
        # Check if the suit manifest starter needs programming
        if self.suit_starter and self.family == 'NRF54H_FAMILY':
            file = self._check_suit_starter(_op)
            if file:
                args = self._op_program(file, 'ERASE_NONE', None)
                _exec_op('program', defer, core, **args)

    @abc.abstractmethod
    def do_exec_op(self, op, force=False):
+14 −3
Original line number Diff line number Diff line
@@ -13,15 +13,18 @@ import subprocess
from runners.core import _DRY_RUN
from runners.nrf_common import NrfBinaryRunner


class NrfUtilBinaryRunner(NrfBinaryRunner):
    '''Runner front-end for nrfutil.'''

    def __init__(self, cfg, family, softreset, dev_id, erase=False,
                 reset=True, tool_opt=[], force=False, recover=False):
                 reset=True, tool_opt=[], force=False, recover=False,
                 suit_starter=False):

        super().__init__(cfg, family, softreset, dev_id, erase, reset,
                         tool_opt, force, recover)

        self.suit_starter = suit_starter

        self._ops = []
        self._op_id = 1

@@ -39,7 +42,15 @@ class NrfUtilBinaryRunner(NrfBinaryRunner):
                                   args.dev_id, erase=args.erase,
                                   reset=args.reset,
                                   tool_opt=args.tool_opt, force=args.force,
                                   recover=args.recover)
                                   recover=args.recover,
                                   suit_starter=args.suit_manifest_starter)

    @classmethod
    def do_add_parser(cls, parser):
        super().do_add_parser(parser)
        parser.add_argument('--suit-manifest-starter', required=False,
                            action='store_true',
                            help='Use the SUIT manifest starter file')

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