|
13 | 13 | import sys
|
14 | 14 |
|
15 | 15 | from elftools.elf.elffile import ELFFile
|
16 |
| - |
17 | 16 | from west import manifest
|
18 | 17 | from west.commands import Verbosity
|
19 | 18 | from west.util import quote_sh_list
|
|
23 | 22 | from runners.core import BuildConfiguration
|
24 | 23 | from zcmake import CMakeCache
|
25 | 24 | from zephyr_ext_common import Forceable, ZEPHYR_SCRIPTS
|
| 25 | +from zephyr_ext_common import ZEPHYR_BASE |
26 | 26 |
|
27 | 27 | # This is needed to load edt.pickle files.
|
28 | 28 | sys.path.insert(0, str(ZEPHYR_SCRIPTS / 'dts' / 'python-devicetree' / 'src'))
|
|
79 | 79 | [rimage] sections in your west config file(s); this is especially useful
|
80 | 80 | when invoking west sign _indirectly_ through CMake/ninja. See how at
|
81 | 81 | https://docs.zephyrproject.org/latest/develop/west/sign.html
|
| 82 | +
|
| 83 | +silabs_commander |
| 84 | +----- |
| 85 | +
|
| 86 | +To create a signed binary with the silabs_commander tool, run this from your build directory: |
| 87 | +
|
| 88 | + west sign -t silabs_commander -- --mic YOUR_OTA_KEY --encrypt YOUR_OTA_KEY --sign YOUR_PRIVATE_KEY.pem |
| 89 | + or west sign -t silabs_commander |
| 90 | +
|
| 91 | +For this to work, Silabs Commander tool must be installed in your PATH. |
| 92 | +
|
| 93 | +The input binary (zephyr.bin.rps) is signed using the specified OTA key and private key, |
| 94 | +producing zephyr.bin.rps by default. If CONFIG_M4_OTA_KEY and CONFIG_M4_PRIVATE_KEY are set |
| 95 | +in your build configuration, they will be used unless overridden by command-line arguments. |
| 96 | +Additional arguments after '--' are passed to silabs_commander directly. |
82 | 97 | '''
|
83 | 98 |
|
84 | 99 | class ToggleAction(argparse.Action):
|
@@ -112,7 +127,7 @@ def do_add_parser(self, parser_adder):
|
112 | 127 |
|
113 | 128 | # general options
|
114 | 129 | group = parser.add_argument_group('tool control options')
|
115 |
| - group.add_argument('-t', '--tool', choices=['imgtool', 'rimage'], |
| 130 | + group.add_argument('-t', '--tool', choices=['imgtool', 'rimage', 'silabs_commander'], |
116 | 131 | help='''image signing tool name; imgtool and rimage
|
117 | 132 | are currently supported (imgtool is deprecated)''')
|
118 | 133 | group.add_argument('-p', '--tool-path', default=None,
|
@@ -195,6 +210,8 @@ def do_run(self, args, ignored):
|
195 | 210 | signer = ImgtoolSigner()
|
196 | 211 | elif args.tool == 'rimage':
|
197 | 212 | signer = RimageSigner()
|
| 213 | + elif args.tool == 'silabs_commander': |
| 214 | + signer = SilabsRPSSigner() |
198 | 215 | # (Add support for other signers here in elif blocks)
|
199 | 216 | else:
|
200 | 217 | if args.tool is None:
|
@@ -633,3 +650,99 @@ def sign(self, command, build_dir, build_conf, formats):
|
633 | 650 |
|
634 | 651 | os.remove(out_bin)
|
635 | 652 | os.rename(out_tmp, out_bin)
|
| 653 | + |
| 654 | +class SilabsRPSSigner(Signer): |
| 655 | + # Signer class for Silicon Labs Commander tool via west sign -t silabs_commander. |
| 656 | + def find_commandertool(self, cmd, args): |
| 657 | + if args.tool_path: |
| 658 | + commandertool = args.tool_path |
| 659 | + if not os.path.isfile(commandertool): |
| 660 | + cmd.die(f'--tool-path {commandertool}: no such file') |
| 661 | + else: |
| 662 | + commandertool = shutil.which('commander') |
| 663 | + if not commandertool: |
| 664 | + cmd.die('commander not found') |
| 665 | + return commandertool |
| 666 | + |
| 667 | + def get_security_configs(self, build_conf, args, command): |
| 668 | + # Retrieve configurations, prioritizing command-line args, then build_conf |
| 669 | + m4_ota_key = getattr(args, 'm4-ota-key', build_conf.get('CONFIG_M4_OTA_KEY')) |
| 670 | + m4_private_key = getattr(args, 'm4-private-key', build_conf.get('CONFIG_M4_PRIVATE_KEY')) |
| 671 | + |
| 672 | + # Use west sign's --tool-path option to find Commander |
| 673 | + commander_path = self.find_commandertool(command, args) |
| 674 | + |
| 675 | + # Validate required settings |
| 676 | + if not m4_ota_key: |
| 677 | + command.die("M4_OTA_KEY not provided via --m4-ota-key or set in prj.conf. Please specify --m4-ota-key=your_key or add CONFIG_M4_OTA_KEY in prj.conf.") |
| 678 | + if not m4_private_key: |
| 679 | + command.die("M4_PRIVATE_KEY not provided via --m4-private-key or set in prj.conf. Please specify --m4-private-key=/path/to/key or add CONFIG_M4_PRIVATE_KEY in prj.conf.") |
| 680 | + |
| 681 | + return m4_ota_key, m4_private_key, commander_path |
| 682 | + |
| 683 | + def sign(self, command, build_dir, build_conf, formats): |
| 684 | + """Sign the Zephyr binary using Silicon Labs Commander. |
| 685 | +
|
| 686 | + :param command: The Sign instance (provides args and utility methods) |
| 687 | + :param build_dir: The build directory path |
| 688 | + :param build_conf: BuildConfiguration object for the build directory |
| 689 | + :param formats: List of formats to generate (e.g., ['bin', 'rps']) |
| 690 | + """ |
| 691 | + self.command = command |
| 692 | + args = command.args |
| 693 | + b = pathlib.Path(build_dir) |
| 694 | + |
| 695 | + # Check if signing is needed |
| 696 | + if not formats: |
| 697 | + if not args.quiet: |
| 698 | + command.inf("No output formats specified, skipping signing.") |
| 699 | + return |
| 700 | + |
| 701 | + zephyr_base = ZEPHYR_BASE |
| 702 | + if not zephyr_base: |
| 703 | + command.die("ZEPHYR_BASE could not be retrieved. Ensure you are running within a Zephyr build environment.") |
| 704 | + workspace_base = pathlib.Path(zephyr_base) |
| 705 | + if not workspace_base.is_dir(): |
| 706 | + command.die(f"Invalid ZEPHYR_BASE directory: {ZEPHYR_BASE}. Please check your Zephyr setup.") |
| 707 | + |
| 708 | + # Get kernel binary name (default to 'zephyr') |
| 709 | + kernel_name = build_conf.get('CONFIG_KERNEL_BIN_NAME', 'zephyr') |
| 710 | + |
| 711 | + # Setting the input and output file directories |
| 712 | + in_rps = b / 'zephyr' / f"{kernel_name}.bin.rps" |
| 713 | + out_rps = args.sbin or (b / 'zephyr' / f"{kernel_name}bin.rps") |
| 714 | + |
| 715 | + # Check if input binary exists |
| 716 | + if not in_rps.is_file(): |
| 717 | + command.die(f"No .rps found at {in_rps}. Ensure the build generated {kernel_name}.bin.rps in {b / 'zephyr'}") |
| 718 | + |
| 719 | + # Load configuration |
| 720 | + m4_ota_key, m4_private_key, commander_path = self.get_security_configs(build_conf, args, command) |
| 721 | + |
| 722 | + # Resolve paths |
| 723 | + tool_path = pathlib.Path(commander_path) |
| 724 | + if not tool_path.is_file(): |
| 725 | + command.die(f"Silicon Labs Commander not found at {tool_path}. Please ensure it is installed or provide --tool-path.") |
| 726 | + |
| 727 | + private_key_path = pathlib.Path(m4_private_key) |
| 728 | + if not private_key_path.is_file(): |
| 729 | + command.die(f"Private key not found at {private_key_path}. Please ensure the path is correct.") |
| 730 | + |
| 731 | + # Build the Silicon Labs Commander signing command |
| 732 | + sign_base = [ |
| 733 | + str(tool_path), |
| 734 | + "rps", |
| 735 | + "convert", |
| 736 | + str(out_rps), |
| 737 | + "--app", str(in_rps), |
| 738 | + "--mic", m4_ota_key, |
| 739 | + "--encrypt", m4_ota_key, |
| 740 | + "--sign", str(private_key_path) |
| 741 | + ] |
| 742 | + |
| 743 | + sign_base.extend(args.tool_args) |
| 744 | + |
| 745 | + try: |
| 746 | + subprocess.check_call(sign_base, stdout=subprocess.PIPE if args.quiet else None, stderr=subprocess.PIPE if args.quiet else None) |
| 747 | + except subprocess.CalledProcessError as e: |
| 748 | + command.die(f"Silicon Labs Commander signing failed with exit code {e.returncode}") |
0 commit comments