mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-08-07 13:45:20 +00:00
This got broken in the patches which added the build.dir-fmt config option when BUiLD_DIR_DESCRIPTION was renamed. Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
232 lines
8.4 KiB
Python
232 lines
8.4 KiB
Python
# Copyright (c) 2018 Foundries.io
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
import abc
|
|
import argparse
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
|
|
from west import cmake
|
|
from west import log
|
|
from west.build import is_zephyr_build
|
|
from west.util import quote_sh_list
|
|
|
|
from runners.core import BuildConfiguration
|
|
|
|
from build_helpers import find_build_dir, \
|
|
FIND_BUILD_DIR_DESCRIPTION
|
|
|
|
from zephyr_ext_common import Forceable, \
|
|
cached_runner_config
|
|
|
|
SIGN_DESCRIPTION = '''\
|
|
This command automates some of the drudgery of creating signed Zephyr
|
|
binaries for chain-loading by a bootloader.
|
|
|
|
In the simplest usage, run this from your build directory:
|
|
|
|
west sign -t your_tool -- ARGS_FOR_YOUR_TOOL
|
|
|
|
Assuming your binary was properly built for processing and handling by
|
|
tool "your_tool", this creates zephyr.signed.bin and zephyr.signed.hex
|
|
files (if supported by "your_tool") which are ready for use by your
|
|
bootloader. The "ARGS_FOR_YOUR_TOOL" value can be any additional
|
|
arguments you want to pass to the tool, such as the location of a
|
|
signing key, a version identifier, etc.
|
|
|
|
See tool-specific help below for details.'''
|
|
|
|
SIGN_EPILOG = '''\
|
|
imgtool
|
|
-------
|
|
|
|
Currently, MCUboot's 'imgtool' tool is supported. To build a signed
|
|
binary you can load with MCUboot using imgtool, run this from your
|
|
build directory:
|
|
|
|
west sign -t imgtool -- --key YOUR_SIGNING_KEY.pem
|
|
|
|
For this to work, either imgtool must be installed (e.g. using pip3),
|
|
or you must pass the path to imgtool.py using the -p option.
|
|
|
|
The image header size, alignment, and slot sizes are determined from
|
|
the build directory using .config and the device tree. A default
|
|
version number of 0.0.0+0 is used (which can be overridden by passing
|
|
"--version x.y.z+w" after "--key"). As shown above, extra arguments
|
|
after a '--' are passed to imgtool directly.'''
|
|
|
|
|
|
class ToggleAction(argparse.Action):
|
|
|
|
def __call__(self, parser, args, ignored, option):
|
|
setattr(args, self.dest, not option.startswith('--no-'))
|
|
|
|
|
|
class Sign(Forceable):
|
|
def __init__(self):
|
|
super(Sign, self).__init__(
|
|
'sign',
|
|
# Keep this in sync with the string in west-commands.yml.
|
|
'sign a Zephyr binary for bootloader chain-loading',
|
|
SIGN_DESCRIPTION,
|
|
accepts_unknown_args=False)
|
|
|
|
def do_add_parser(self, parser_adder):
|
|
parser = parser_adder.add_parser(
|
|
self.name,
|
|
epilog=SIGN_EPILOG,
|
|
help=self.help,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
description=self.description)
|
|
|
|
parser.add_argument('-d', '--build-dir',
|
|
help=FIND_BUILD_DIR_DESCRIPTION)
|
|
self.add_force_arg(parser)
|
|
|
|
# general options
|
|
group = parser.add_argument_group('tool control options')
|
|
group.add_argument('-t', '--tool', choices=['imgtool'], required=True,
|
|
help='''image signing tool name; only imgtool is
|
|
currently supported''')
|
|
group.add_argument('-p', '--tool-path', default=None,
|
|
help='''path to the tool itself, if needed''')
|
|
group.add_argument('tool_args', nargs='*', metavar='tool_opt',
|
|
help='extra option(s) to pass to the signing tool')
|
|
|
|
# bin file options
|
|
group = parser.add_argument_group('binary (.bin) file options')
|
|
group.add_argument('--bin', '--no-bin', dest='gen_bin', nargs=0,
|
|
action=ToggleAction,
|
|
help='''produce a signed .bin file?
|
|
(default: yes, if supported)''')
|
|
group.add_argument('-B', '--sbin', metavar='BIN',
|
|
default='zephyr.signed.bin',
|
|
help='''signed .bin file name
|
|
(default: zephyr.signed.bin)''')
|
|
|
|
# hex file options
|
|
group = parser.add_argument_group('Intel HEX (.hex) file options')
|
|
group.add_argument('--hex', '--no-hex', dest='gen_hex', nargs=0,
|
|
action=ToggleAction,
|
|
help='''produce a signed .hex file?
|
|
(default: yes, if supported)''')
|
|
group.add_argument('-H', '--shex', metavar='HEX',
|
|
default='zephyr.signed.hex',
|
|
help='''signed .hex file name
|
|
(default: zephyr.signed.hex)''')
|
|
|
|
# defaults for hex/bin generation
|
|
parser.set_defaults(gen_bin=True, gen_hex=True)
|
|
|
|
return parser
|
|
|
|
def do_run(self, args, ignored):
|
|
if not (args.gen_bin or args.gen_hex):
|
|
return
|
|
|
|
# Provide the build directory if not given, and defer to the signer.
|
|
args.build_dir = find_build_dir(args.build_dir)
|
|
|
|
self.args = args # for check_force
|
|
|
|
self.check_force(os.path.isdir(args.build_dir),
|
|
'no such build directory {}'.format(args.build_dir))
|
|
self.check_force(is_zephyr_build(args.build_dir),
|
|
"build directory {} doesn't look like a Zephyr build "
|
|
'directory'.format(args.build_dir))
|
|
|
|
if args.tool == 'imgtool':
|
|
signer = ImgtoolSigner()
|
|
# (Add support for other signers here in elif blocks)
|
|
else:
|
|
raise RuntimeError("can't happen")
|
|
|
|
signer.sign(self)
|
|
|
|
|
|
class Signer(abc.ABC):
|
|
'''Common abstract superclass for signers.
|
|
|
|
To add support for a new tool, subclass this and add support for
|
|
it in the Sign.do_run() method.'''
|
|
|
|
@abc.abstractmethod
|
|
def sign(self, command):
|
|
'''Abstract method to perform a signature; subclasses must implement.
|
|
|
|
:param command: the Sign instance
|
|
'''
|
|
|
|
|
|
class ImgtoolSigner(Signer):
|
|
|
|
def sign(self, command):
|
|
args = command.args
|
|
|
|
cache = cmake.CMakeCache.from_build_dir(args.build_dir)
|
|
runner_config = cached_runner_config(args.build_dir, cache)
|
|
bcfg = BuildConfiguration(args.build_dir)
|
|
|
|
# Build a signed .bin
|
|
if args.gen_bin and runner_config.bin_file:
|
|
sign_bin = self.sign_cmd(command, bcfg, runner_config.bin_file,
|
|
args.sbin)
|
|
log.dbg(quote_sh_list(sign_bin))
|
|
subprocess.check_call(sign_bin)
|
|
|
|
# Build a signed .hex
|
|
if args.gen_hex and runner_config.hex_file:
|
|
sign_hex = self.sign_cmd(command, bcfg, runner_config.hex_file,
|
|
args.shex)
|
|
log.dbg(quote_sh_list(sign_hex))
|
|
subprocess.check_call(sign_hex)
|
|
|
|
def sign_cmd(self, command, bcfg, infile, outfile):
|
|
align, vtoff, slot_size = [self.get_cfg_str(command, bcfg, x) for x in
|
|
('DT_FLASH_WRITE_BLOCK_SIZE',
|
|
'CONFIG_TEXT_SECTION_OFFSET',
|
|
'DT_FLASH_AREA_IMAGE_0_SIZE')]
|
|
align_arg = ['--align', align] if align else []
|
|
header_arg = ['--header-size', vtoff] if vtoff else []
|
|
slot_arg = ['--slot-size', slot_size] if slot_size else []
|
|
|
|
args = command.args
|
|
if args.tool_path:
|
|
tool_path = args.tool_path
|
|
else:
|
|
tool_path = shutil.which('imgtool')
|
|
if not tool_path:
|
|
log.die('imgtool not found; either install it',
|
|
'(e.g. "pip3 install imgtool") or provide --tool-path')
|
|
|
|
sign_command = ([tool_path,
|
|
'sign'] +
|
|
align_arg +
|
|
header_arg +
|
|
slot_arg +
|
|
# We provide a default --version in case the
|
|
# user is just messing around and doesn't want
|
|
# to set one. It will be overridden if there is
|
|
# a --version in args.tool_args.
|
|
['--version', '0.0.0+0',
|
|
infile,
|
|
outfile])
|
|
|
|
sign_command.extend(args.tool_args)
|
|
|
|
return sign_command
|
|
|
|
def get_cfg_str(self, command, bcfg, item):
|
|
try:
|
|
return str(bcfg[item])
|
|
except KeyError:
|
|
command.check_force(
|
|
False,
|
|
"imgtool parameter unknown, build directory has no {} {}".
|
|
format('device tree define' if item.startswith('DT_') else
|
|
'Kconfig option',
|
|
item))
|
|
return None
|