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,142 @@ 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 environment or current directory
676
+ zephyr_workspace_root = os .environ .get ('ZEPHYR_WORKSPACE_ROOT' )
677
+ if zephyr_workspace_root :
678
+ workspace_base = pathlib .Path (zephyr_workspace_root )
679
+ if not workspace_base .is_dir ():
680
+ command .die (f"Invalid ZEPHYR_WORKSPACE_ROOT directory: { workspace_base } . Please check the environment variable." )
681
+ else :
682
+ workspace_base = pathlib .Path (os .getcwd ())
683
+ if not args .quiet :
684
+ command .inf (f"ZEPHYR_WORKSPACE_ROOT not set, using current directory: { workspace_base } " )
685
+
686
+ soc_dir = 'Give_Soc_Directory_path from the working directory' # Modify the Relative path to SoC dir
687
+ soc_kconfig_base = workspace_base / soc_dir
688
+
689
+ # Get kernel binary name (default to 'zephyr')
690
+ kernel_name = build_conf .get ('CONFIG_KERNEL_BIN_NAME' , 'zephyr' )
691
+
692
+ # Input and output files (using BUILD_DIR)
693
+ in_bin = b / 'zephyr' / f"{ kernel_name } .bin.rps" # Raw binary input
694
+ out_rps = args .sbin or (b / 'zephyr' / f"{ kernel_name } .bin.rps" ) # Signed output
695
+
696
+ # Check if input binary exists
697
+ if not in_bin .is_file ():
698
+ command .die (f"No unsigned .bin found at { in_bin } " )
699
+
700
+ # Load configuration from Kconfig.soc
701
+ soc_kconfig = soc_kconfig_base / 'Kconfig.soc' # Name of Kconfig file to be given here.Like Kconfig.soc or something.
702
+ m4_ota_key = None
703
+ m4_private_key = None
704
+ commander_path = None
705
+
706
+ if soc_kconfig .is_file ():
707
+ if not args .quiet :
708
+ command .inf (f"Parsing Kconfig.soc at { soc_kconfig } " )
709
+ # Read the Kconfig.soc file and extract relevant values
710
+ with open (soc_kconfig ) as f :
711
+ current_config = None
712
+ for line in f :
713
+ line = line .strip ()
714
+ if line .startswith ('config ' ):
715
+ current_config = line .split ('config ' )[1 ].split ()[0 ] # Extract config name
716
+ elif line .startswith ('default ' ) and current_config :
717
+ value = line .split ('default ' )[1 ].strip ().strip ('"' )
718
+ if current_config == 'M4_OTA_KEY' :
719
+ m4_ota_key = value
720
+ elif current_config == 'M4_PRIVATE_KEY' :
721
+ m4_private_key = value
722
+ elif current_config == 'COMMANDER_PATH' :
723
+ commander_path = value
724
+ else :
725
+ if not args .quiet :
726
+ command .inf (f"No Kconfig.soc found at { soc_kconfig } . Using default values." )
727
+
728
+ # Apply default values only if not set from Kconfig.soc
729
+ m4_ota_key = m4_ota_key or "Give_default_OTA_KEY_VALUE" # Default OTA key
730
+ m4_private_key = m4_private_key or "/default/path/to/m4_private_key.pem" # Default private key path
731
+ commander_path = commander_path or "/default/path/to/SimplicityCommander-Linux/commander/commander" # Default Commander path
732
+
733
+ # Override with command-line arguments if provided
734
+ m4_ota_key = getattr (args , 'm4-ota-key' , m4_ota_key )
735
+ m4_private_key = getattr (args , 'm4-private-key' , m4_private_key )
736
+ commander_path = getattr (args , 'commander-path' , commander_path )
737
+
738
+ # Validate required settings
739
+ if not m4_ota_key :
740
+ command .die ("M4_OTA_KEY not set in Kconfig.soc and no --m4-ota-key provided." )
741
+ if not m4_private_key :
742
+ command .die ("M4_PRIVATE_KEY not set in Kconfig.soc and no --m4-private-key provided." )
743
+ if not commander_path :
744
+ command .die ("COMMANDER_PATH not set in Kconfig.soc and no --commander-path provided." )
745
+
746
+ # Resolve paths
747
+ tool_path = pathlib .Path (commander_path )
748
+ if not tool_path .is_file ():
749
+ command .die (f"Commander not found at { tool_path } . Please ensure the path is correct." )
750
+
751
+ private_key_path = pathlib .Path (m4_private_key )
752
+ if not private_key_path .is_file ():
753
+ command .die (f"Private key not found at { private_key_path } . Please ensure the path is correct." )
754
+
755
+ # Build the commander signing command
756
+ sign_base = [
757
+ str (tool_path ),
758
+ "rps" ,
759
+ "convert" ,
760
+ str (out_rps ),
761
+ "--app" , str (in_bin ),
762
+ "--mic" , m4_ota_key ,
763
+ "--encrypt" , m4_ota_key ,
764
+ "--sign" , str (private_key_path )
765
+ ]
766
+
767
+ sign_base .extend (args .tool_args )
768
+
769
+ if not args .quiet :
770
+ command .inf (f"Signing with tool { tool_path } " )
771
+ command .inf (f"Unsigned binary: { in_bin } " )
772
+ command .inf (f"Signed output: { out_rps } " )
773
+
774
+ try :
775
+ subprocess .check_call (sign_base , stdout = subprocess .PIPE if args .quiet else None , stderr = subprocess .PIPE if args .quiet else None )
776
+ except subprocess .CalledProcessError as e :
777
+ command .die (f"Commander signing failed with exit code { e .returncode } " )
778
+
779
+ if not args .quiet :
780
+ command .inf (f"Successfully generated signed file: { out_rps } " )
781
+
782
+ # Register the signer and add command-line arguments
783
+ west_signers = {'silabs_rps' : Silabs_rpsSigner }
784
+
785
+ def add_parser (subparsers ):
786
+ """Add custom arguments for the silabs_rps signer."""
787
+ parser = subparsers .add_parser ('silabs_rps' , help = 'Sign with Silicon Labs Commander' )
788
+ parser .add_argument ('--m4-ota-key' , help = 'OTA key for signing (overrides Kconfig.soc default)' )
789
+ parser .add_argument ('--m4-private-key' , help = 'Absolute path to private key file (overrides Kconfig.soc default)' )
790
+ parser .add_argument ('--commander-path' , help = 'Absolute path to Commander executable (overrides Kconfig.soc default)' )
791
+ return parser
0 commit comments