13
13
import sys
14
14
15
15
from elftools .elf .elffile import ELFFile
16
-
16
+ # custom tool signer
17
+ from west .configuration import config
17
18
from west import manifest
18
19
from west .commands import Verbosity
19
20
from west .util import quote_sh_list
79
80
[rimage] sections in your west config file(s); this is especially useful
80
81
when invoking west sign _indirectly_ through CMake/ninja. See how at
81
82
https://docs.zephyrproject.org/latest/develop/west/sign.html
83
+
84
+ silabs_rps
85
+ -----
86
+
87
+ To create a signed binary with the silabs_rps tool, run this from your build directory:
88
+
89
+ west sign -t silabs_rps -- --mic YOUR_OTA_KEY --encrypt YOUR_OTA_KEY --sign YOUR_PRIVATE_KEY.pem
90
+
91
+ For this to work, either silabs_rps commander 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_rps 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_rps' ],
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_rps' :
214
+ signer = Silabs_rpsSigner ()
198
215
# (Add support for other signers here in elif blocks)
199
216
else :
200
217
if args .tool is None :
@@ -633,3 +650,144 @@ 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 Silabs_rpsSigner (Signer ):
655
+ """Signer class for Silicon Labs Commander tool via west sign -t silabs_rps."""
656
+
657
+ def sign (self , command , build_dir , build_conf , formats ):
658
+ """Sign the Zephyr binary using Silicon Labs Commander.
659
+
660
+ :param command: The Sign instance (provides args and utility methods)
661
+ :param build_dir: The build directory path
662
+ :param build_conf: BuildConfiguration object for the build directory
663
+ :param formats: List of formats to generate (e.g., ['bin', 'rps'])
664
+ """
665
+ self .command = command
666
+ args = command .args
667
+ b = pathlib .Path (build_dir ) # BUILD_DIR from -d option
668
+
669
+ # Check if signing is needed
670
+ if not formats :
671
+ if not args .quiet :
672
+ command .inf ("No output formats specified, skipping signing." )
673
+ return
674
+
675
+ # Determine workspace base based on context (automation vs. manual)
676
+ zephyr_workspace_root = os .environ .get ('ZEPHYR_WORKSPACE_ROOT' )
677
+ if zephyr_workspace_root :
678
+ # Automation context: Use ZEPHYR_WORKSPACE_ROOT as the workspace root
679
+ workspace_base = pathlib .Path (zephyr_workspace_root )
680
+ if not workspace_base .is_dir ():
681
+ command .die (f"Invalid ZEPHYR_WORKSPACE_ROOT directory: { workspace_base } . Please check the environment variable." )
682
+ soc_dir = 'GIVE PATH FOR KCONFIG.SOC AFTER WORKSPACE' # Relative path from workspace root
683
+ else :
684
+ # Manual context: Assume current directory is workspace root
685
+ workspace_base = pathlib .Path (os .getcwd ())
686
+ if not args .quiet :
687
+ command .inf (f"ZEPHYR_WORKSPACE_ROOT not set, using current directory: { workspace_base } " )
688
+ soc_dir = 'GIVE PATH FOR KCONFIG.SOC AFTER WORKSPACE' # Same relative path
689
+
690
+ soc_kconfig_base = workspace_base / soc_dir
691
+
692
+ # Get kernel binary name (default to 'zephyr')
693
+ kernel_name = build_conf .get ('CONFIG_KERNEL_BIN_NAME' , 'zephyr' )
694
+
695
+ # Input and output files (using BUILD_DIR)
696
+ in_bin = b / 'zephyr' / f"{ kernel_name } .bin.rps" # Raw binary input (corrected)
697
+ out_rps = args .sbin or (b / 'zephyr' / f"{ kernel_name } .bin.rps" ) # Signed output
698
+
699
+ # Check if input binary exists
700
+ if not in_bin .is_file ():
701
+ command .die (f"No unsigned .bin found at { in_bin } " )
702
+
703
+ # Load configuration from Kconfig.soc
704
+ soc_kconfig = soc_kconfig_base / 'Kconfig.soc'
705
+ m4_ota_key = None
706
+ m4_private_key = None
707
+ commander_path = None
708
+
709
+ if soc_kconfig .is_file ():
710
+ if not args .quiet :
711
+ command .inf (f"Parsing Kconfig.soc at { soc_kconfig } " )
712
+ with open (soc_kconfig ) as f :
713
+ current_config = None
714
+ for line in f :
715
+ line = line .strip ()
716
+ if line .startswith ('config ' ):
717
+ current_config = line .split ('config ' )[1 ].split ()[0 ] # Extract config name
718
+ elif line .startswith ('default ' ) and current_config :
719
+ value = line .split ('default ' )[1 ].strip ().strip ('"' )
720
+ if current_config == 'M4_OTA_KEY' :
721
+ m4_ota_key = value
722
+ elif current_config == 'M4_PRIVATE_KEY' :
723
+ m4_private_key = value
724
+ elif current_config == 'COMMANDER_PATH' :
725
+ commander_path = value
726
+ else :
727
+ if not args .quiet :
728
+ command .inf (f"No Kconfig.soc found at { soc_kconfig } . Using default values." )
729
+
730
+ # Apply default values only if not set from Kconfig.soc
731
+ m4_ota_key = m4_ota_key or "OTA_KEY_IN_HEX" # Default OTA key
732
+ m4_private_key = m4_private_key or "M4_PRIVATE_KEY_PATH" # Updated default private key path
733
+ commander_path = commander_path or "COMMANDER_PATH_HERE" # Updated default Commander path
734
+
735
+ # Override with command-line arguments if provided
736
+ m4_ota_key = getattr (args , 'm4-ota-key' , m4_ota_key )
737
+ m4_private_key = getattr (args , 'm4-private-key' , m4_private_key )
738
+ commander_path = getattr (args , 'commander-path' , commander_path )
739
+
740
+ # Validate required settings
741
+ if not m4_ota_key :
742
+ command .die ("M4_OTA_KEY not set in Kconfig.soc and no --m4-ota-key provided." )
743
+ if not m4_private_key :
744
+ command .die ("M4_PRIVATE_KEY not set in Kconfig.soc and no --m4-private-key provided." )
745
+ if not commander_path :
746
+ command .die ("COMMANDER_PATH not set in Kconfig.soc and no --commander-path provided." )
747
+
748
+ # Resolve paths
749
+ tool_path = pathlib .Path (commander_path )
750
+ if not tool_path .is_file ():
751
+ command .die (f"Commander not found at { tool_path } . Please ensure the path is correct." )
752
+
753
+ private_key_path = pathlib .Path (m4_private_key )
754
+ if not private_key_path .is_file ():
755
+ command .die (f"Private key not found at { private_key_path } . Please ensure the path is correct." )
756
+
757
+ # Build the commander signing command
758
+ sign_base = [
759
+ str (tool_path ),
760
+ "rps" ,
761
+ "convert" ,
762
+ str (out_rps ),
763
+ "--app" , str (in_bin ),
764
+ "--mic" , m4_ota_key ,
765
+ "--encrypt" , m4_ota_key ,
766
+ "--sign" , str (private_key_path )
767
+ ]
768
+
769
+ sign_base .extend (args .tool_args )
770
+
771
+ if not args .quiet :
772
+ command .inf (f"Signing with tool { tool_path } " )
773
+ command .inf (f"Unsigned binary: { in_bin } " )
774
+ command .inf (f"Signed output: { out_rps } " )
775
+
776
+ try :
777
+ subprocess .check_call (sign_base , stdout = subprocess .PIPE if args .quiet else None , stderr = subprocess .PIPE if args .quiet else None )
778
+ except subprocess .CalledProcessError as e :
779
+ command .die (f"Commander signing failed with exit code { e .returncode } " )
780
+
781
+ if not args .quiet :
782
+ command .inf (f"Successfully generated signed file: { out_rps } " )
783
+
784
+ # Register the signer and add command-line arguments
785
+ west_signers = {'silabs_rps' : Silabs_rpsSigner }
786
+
787
+ def add_parser (subparsers ):
788
+ """Add custom arguments for the silabs_rps signer."""
789
+ parser = subparsers .add_parser ('silabs_rps' , help = 'Sign with Silicon Labs Commander' )
790
+ parser .add_argument ('--m4-ota-key' , help = 'OTA key for signing (overrides Kconfig.soc default)' )
791
+ parser .add_argument ('--m4-private-key' , help = 'Absolute path to private key file (overrides Kconfig.soc default)' )
792
+ parser .add_argument ('--commander-path' , help = 'Absolute path to Commander executable (overrides Kconfig.soc default)' )
793
+ return parser
0 commit comments