blob: a0a61c46e6d91a713af2493c4d8459e92b66bc59 [file] [log] [blame]
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001"""
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002Copyright 2024 Cypress Semiconductor Corporation (an Infineon company)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16"""
17
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +020018import argparse
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030019import json
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +020020import sys
21import os
22
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030023
24def load_json(file_path):
25 """
26 Loads JSON from file.
27 """
28
29 data_json = None
30
31 try:
32 with open(file_path, encoding="utf-8") as file:
33 data_json = json.load(file)
34
35 except FileNotFoundError:
36 print(f'\nERROR: Cannot find {file_path}')
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +020037 sys.exit(1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030038
39 return data_json
40
41
42class FieldsValidator:
43 """
44 Validation of required fields and their cross-dependencies.
45 """
46
47 @staticmethod
48 def validate(feature_json, properties_json):
49 """
50 Check 'target' and properties of a platform.
51 """
52 p_target = properties_json.get('target')
53 if p_target is None:
54 raise AttributeError('Field "target" must be present in platform_properties.json')
55
56 f_target = feature_json.get('target')
57 if f_target is None:
58 raise AttributeError('Field "target" must be present in a feature_config.json')
59
60 if f_target not in p_target:
61 raise AttributeError('Target in feature config is not correct.'
62 ' It must be among the target list of platform_properties.json')
63
64 f_security_setup = feature_json.get('security_setup')
65 p_security_setup = properties_json.get('security_setup')
66
67 if f_security_setup:
68
69 if p_security_setup is None:
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +020070 print("\nThis platform doesn't have any 'secure_setup' features")
71 sys.exit(1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030072
73 if f_security_setup.get('hw_rollback_prot'):
74 if p_security_setup.get('hw_rollback_prot') is None:
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +020075 print("\nThis platform doesn't have HW anti roll-back counter")
76 sys.exit(1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030077
78 if f_security_setup.get('hw_crypto_acceleration'):
79 if p_security_setup.get('hw_crypto_acceleration') is None:
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +020080 print("\nThe platform doesn't support HW crypto acceleration")
81 sys.exit(1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030082
83 if f_security_setup.get('validate_upgrade').get('value') is False:
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +020084 if f_security_setup.get('validate_boot').get('value'):
85 print("\nERROR: Boot slot validation cannot be enabled if upgrade "\
86 "slot validation is disabled")
87 sys.exit(1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030088
89
90class FeatureProcessor:
91
92 """
93 The general handler of all needed fields and filling the new mk-file.
94 """
95
96 settings_dict = {
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +020097 'validate_boot' : 'MCUBOOT_SKIP_BOOT_VALIDATION',
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030098 'validate_upgrade' : 'MCUBOOT_SKIP_UPGRADE_VALIDATION',
99 'dependency_check' : 'MCUBOOT_DEPENDENCY_CHECK',
100 'serial_logging' : 'MCUBOOT_LOG_LEVEL',
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200101 'watch_dog_timer' : 'USE_WDT',
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300102 'hw_rollback_prot' : 'USE_HW_ROLLBACK_PROT',
103 'hw_crypto_acceleration' : "USE_CRYPTO_HW",
104 'sw_downgrade_prev' : 'USE_SW_DOWNGRADE_PREV',
105 'ram_app_staging' : 'USE_STAGE_RAM_APPS',
106 'xip' : 'USE_XIP',
107 'image_encryption' : 'ENC_IMG',
108 'fault_injection_hardening' : 'FIH_PROFILE_LEVEL',
109 'combine_hex' : 'COMBINE_HEX',
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200110 'hw_key' : 'USE_HW_KEY',
111 'built_in_keys' : 'USE_BUILT_IN_KEYS'
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300112 }
113
114 debug_level_dict = {
115 'off' : '_OFF',
116 'error' : '_ERROR',
117 'warning' : '_WARNING',
118 'info' : '_INFO',
119 'debug' : '_DEBUG'
120 }
121
122 fih_level_dict = {
123 'off' : 'OFF',
124 'low' : 'LOW',
125 'medium' : 'MEDIUM',
126 'high' : 'HIGH'
127 }
128
129 def __init__(self, output_name):
130 self.out_f = output_name
131
132 @staticmethod
133 def generate_header_guard():
134 """
135 Print header line at the begining of a mk-file
136 """
137 guard_lines = ('# AUTO-GENERATED FILE, DO NOT EDIT.'
138 ' ALL CHANGES WILL BE LOST! #\n\n')
139
140 return guard_lines
141
142 @staticmethod
143 def insert_res(val_to_check) -> str:
144 """
145 Simlpe check result and return the string with value.
146 """
147 return f' := {1 if val_to_check else 0}\n'
148
149 @staticmethod
150 def insert_inverted_res(val_to_check) -> str:
151 """
152 Simlpe check result and return the string with inverted value.
153 """
154 return f' := {0 if val_to_check else 1}\n'
155
156 def __prnt_dict_primitive_key(self, dict_feature_config, settings_dict_key, f_out):
157 """
158 Print kyes of 'feature_config' with bool type of 'value'
159 """
160 val = dict_feature_config.get(settings_dict_key).get('value')
161
162 if isinstance(val, bool):
163
164 # invert because variable use 'skip' command
165 need_invertion = set(("validate_boot", "validate_upgrade"))
166
167 f_out.write(self.settings_dict[settings_dict_key])
168
169 if settings_dict_key not in need_invertion:
170 f_out.write(FeatureProcessor.insert_res(val))
171 else:
172 f_out.write(FeatureProcessor.insert_inverted_res(val))
173
174
175 def __gen_fih_level(self, fih_value):
176 """
177 Print only FIH_
178 """
179 res = f"{self.settings_dict['fault_injection_hardening']} ?= "\
180 f"{self.fih_level_dict[fih_value]}\n"
181
182 return res
183
184 def __gen_debug_level(self, logging_value):
185 """
186 Print only MCUBOOT_LOG_LEVEL
187 """
188 param_txt = self.settings_dict['serial_logging']
189 res_str = f"{param_txt} ?= {param_txt}{self.debug_level_dict[logging_value]}\n"
190
191 return res_str
192
193
194 def __handle_dictionary(self, f_dict, f_out):
195 """
196 Handle any dictionary of 'feature_config'
197 """
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200198 dont_print_list = set(("validation_key", "encryption_key", "version", "description", "target"))
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300199
200 for k in f_dict:
201
202 if k not in dont_print_list:
203 self.__prnt_dict_primitive_key(f_dict, k, f_out)
204
205 if k == 'fault_injection_hardening':
206 f_out.write(self.__gen_fih_level(f_dict.get(k).get("value")))
207
208 if k == 'serial_logging':
209 f_out.write(self.__gen_debug_level(f_dict.get(k).get("value")))
210
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200211 if k == "validation_key":
212 value = f_dict.get(k).get("value")
213 if value != '':
214 f_out.write(f'ECDSA_PUBLIC_KEY={value}\n')
215
216 if k == "encryption_key":
217 value = f_dict.get(k).get("value")
218 if value != '':
219 f_out.write(f'ENC_PRIVATE_KEY={value}\n')
220
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300221
222 def make_file_generate(self, feature_json):
223 """
224 Processing all keys and creation of a mk-file
225 """
226
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200227 out_dir = os.path.dirname(self.out_f)
228
229 if not os.path.exists(out_dir):
230 os.mkdir(out_dir)
231
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300232 with open(self.out_f, "w", encoding='UTF-8') as f_out:
233 f_out.write(FeatureProcessor.generate_header_guard())
234
235 f_security_setup_dict = feature_json.get('security_setup')
236
237 # handling of 'security_setup' section
238 if f_security_setup_dict:
239 self.__handle_dictionary(f_security_setup_dict, f_out)
240
241 self.__handle_dictionary(feature_json, f_out)
242
243
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300244def cli():
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200245 parser = argparse.ArgumentParser(description='Feature config parser to run from CLI')
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300246
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200247 parser.add_argument('-f', '--feature_config', required=True,
248 help='Feature configuration file path')
249 parser.add_argument('-p', '--platform_properties', required=True,
250 help='Platform properties file path')
251 parser.add_argument('-n', '--output_name', required=True,
252 help='The name of the make file that will be generated')
253 parser.add_argument('other_args', nargs='?',
254 help='Ignore all other arguments, such as: run')
255
256 args = parser.parse_args()
257
258 run(args.feature_config, args.platform_properties, args.output_name)
259
260 # run('C:/Work/mcuboot/mtb-example-bootloader-solution/platforms/PSC3/feature_config.json',
261 # 'C:/Work/mcuboot/mtb-example-bootloader-solution/mtb_shared/mcuboot/1.9.3-ifx-boy2-es10/boot/cypress/platforms/memory/PSC3/flashmap/platform_properties.json',
262 # 'C:/Work/mcuboot/mtb-example-bootloader-solution/platforms/PSC3/feature_config.mk')
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300263
264
265def run(feature_config, platform_properties, output_name):
266 """
267 The main CLI command to run mk-file generation
268 """
269
270 feature_config_json = load_json(feature_config)
271 platform_properties_json = load_json(platform_properties)
272
273 FieldsValidator.validate(feature_config_json, platform_properties_json)
274
275 fprocessor = FeatureProcessor(output_name)
276 fprocessor.make_file_generate(feature_config_json)
277
278
279if __name__ == '__main__':
280 cli()