blob: 4bc428c0fd1875d123a8d0c9a4798e4728197979 [file] [log] [blame]
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001"""
2Copyright 2023 Cypress Semiconductor Corporation (an Infineon company)
3or 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
18
19import sys
20import json
21import click
22
23def load_json(file_path):
24 """
25 Loads JSON from file.
26 """
27
28 data_json = None
29
30 try:
31 with open(file_path, encoding="utf-8") as file:
32 data_json = json.load(file)
33
34 except FileNotFoundError:
35 print(f'\nERROR: Cannot find {file_path}')
36 sys.exit(-1)
37
38 return data_json
39
40
41class FieldsValidator:
42 """
43 Validation of required fields and their cross-dependencies.
44 """
45
46 @staticmethod
47 def validate(feature_json, properties_json):
48 """
49 Check 'target' and properties of a platform.
50 """
51 p_target = properties_json.get('target')
52 if p_target is None:
53 raise AttributeError('Field "target" must be present in platform_properties.json')
54
55 f_target = feature_json.get('target')
56 if f_target is None:
57 raise AttributeError('Field "target" must be present in a feature_config.json')
58
59 if f_target not in p_target:
60 raise AttributeError('Target in feature config is not correct.'
61 ' It must be among the target list of platform_properties.json')
62
63 f_security_setup = feature_json.get('security_setup')
64 p_security_setup = properties_json.get('security_setup')
65
66 if f_security_setup:
67
68 if p_security_setup is None:
69 raise AttributeError("This platform doesn't have any 'secure_setup' features")
70
71 if f_security_setup.get('hw_rollback_prot'):
72 if p_security_setup.get('hw_rollback_prot') is None:
73 raise AttributeError("This platform doesn't have HW anti roll-back counter")
74
75 if f_security_setup.get('hw_crypto_acceleration'):
76 if p_security_setup.get('hw_crypto_acceleration') is None:
77 raise AttributeError("The platform doesn't support HW crypto acceleration")
78
79 if f_security_setup.get('validate_upgrade').get('value') is False:
80 raise AttributeError("Deactivation of image validation during the upgrade \
81 process isn't implemented yet")
82
83
84class FeatureProcessor:
85
86 """
87 The general handler of all needed fields and filling the new mk-file.
88 """
89
90 settings_dict = {
91 'validate_boot' : 'MCUBOOT_SKIP_IMAGE_VALIDATION',
92 'validate_upgrade' : 'MCUBOOT_SKIP_UPGRADE_VALIDATION',
93 'dependency_check' : 'MCUBOOT_DEPENDENCY_CHECK',
94 'serial_logging' : 'MCUBOOT_LOG_LEVEL',
95 'hw_rollback_prot' : 'USE_HW_ROLLBACK_PROT',
96 'hw_crypto_acceleration' : "USE_CRYPTO_HW",
97 'sw_downgrade_prev' : 'USE_SW_DOWNGRADE_PREV',
98 'ram_app_staging' : 'USE_STAGE_RAM_APPS',
99 'xip' : 'USE_XIP',
100 'image_encryption' : 'ENC_IMG',
101 'fault_injection_hardening' : 'FIH_PROFILE_LEVEL',
102 'combine_hex' : 'COMBINE_HEX',
103 'hw_key' : 'USE_HW_KEY'
104 }
105
106 debug_level_dict = {
107 'off' : '_OFF',
108 'error' : '_ERROR',
109 'warning' : '_WARNING',
110 'info' : '_INFO',
111 'debug' : '_DEBUG'
112 }
113
114 fih_level_dict = {
115 'off' : 'OFF',
116 'low' : 'LOW',
117 'medium' : 'MEDIUM',
118 'high' : 'HIGH'
119 }
120
121 def __init__(self, output_name):
122 self.out_f = output_name
123
124 @staticmethod
125 def generate_header_guard():
126 """
127 Print header line at the begining of a mk-file
128 """
129 guard_lines = ('# AUTO-GENERATED FILE, DO NOT EDIT.'
130 ' ALL CHANGES WILL BE LOST! #\n\n')
131
132 return guard_lines
133
134 @staticmethod
135 def insert_res(val_to_check) -> str:
136 """
137 Simlpe check result and return the string with value.
138 """
139 return f' := {1 if val_to_check else 0}\n'
140
141 @staticmethod
142 def insert_inverted_res(val_to_check) -> str:
143 """
144 Simlpe check result and return the string with inverted value.
145 """
146 return f' := {0 if val_to_check else 1}\n'
147
148 def __prnt_dict_primitive_key(self, dict_feature_config, settings_dict_key, f_out):
149 """
150 Print kyes of 'feature_config' with bool type of 'value'
151 """
152 val = dict_feature_config.get(settings_dict_key).get('value')
153
154 if isinstance(val, bool):
155
156 # invert because variable use 'skip' command
157 need_invertion = set(("validate_boot", "validate_upgrade"))
158
159 f_out.write(self.settings_dict[settings_dict_key])
160
161 if settings_dict_key not in need_invertion:
162 f_out.write(FeatureProcessor.insert_res(val))
163 else:
164 f_out.write(FeatureProcessor.insert_inverted_res(val))
165
166
167 def __gen_fih_level(self, fih_value):
168 """
169 Print only FIH_
170 """
171 res = f"{self.settings_dict['fault_injection_hardening']} ?= "\
172 f"{self.fih_level_dict[fih_value]}\n"
173
174 return res
175
176 def __gen_debug_level(self, logging_value):
177 """
178 Print only MCUBOOT_LOG_LEVEL
179 """
180 param_txt = self.settings_dict['serial_logging']
181 res_str = f"{param_txt} ?= {param_txt}{self.debug_level_dict[logging_value]}\n"
182
183 return res_str
184
185
186 def __handle_dictionary(self, f_dict, f_out):
187 """
188 Handle any dictionary of 'feature_config'
189 """
190 dont_print_list = set(("validation_key", "version", "description", "target"))
191
192 for k in f_dict:
193
194 if k not in dont_print_list:
195 self.__prnt_dict_primitive_key(f_dict, k, f_out)
196
197 if k == 'fault_injection_hardening':
198 f_out.write(self.__gen_fih_level(f_dict.get(k).get("value")))
199
200 if k == 'serial_logging':
201 f_out.write(self.__gen_debug_level(f_dict.get(k).get("value")))
202
203
204 def make_file_generate(self, feature_json):
205 """
206 Processing all keys and creation of a mk-file
207 """
208
209 with open(self.out_f, "w", encoding='UTF-8') as f_out:
210 f_out.write(FeatureProcessor.generate_header_guard())
211
212 f_security_setup_dict = feature_json.get('security_setup')
213
214 # handling of 'security_setup' section
215 if f_security_setup_dict:
216 self.__handle_dictionary(f_security_setup_dict, f_out)
217
218 self.__handle_dictionary(feature_json, f_out)
219
220
221@click.group()
222def cli():
223 """
224 Feature config parser to run from CLI
225 """
226
227@cli.command()
228@click.option('-f', '--feature_config', required=True,
229 help='feature configuration file path')
230@click.option('-p', '--platform_properties', required=True,
231 help='platform properties file path')
232@click.option('-n', '--output_name', required=True,
233 help='the name of the make file that will be generated')
234
235
236def run(feature_config, platform_properties, output_name):
237 """
238 The main CLI command to run mk-file generation
239 """
240
241 feature_config_json = load_json(feature_config)
242 platform_properties_json = load_json(platform_properties)
243
244 FieldsValidator.validate(feature_config_json, platform_properties_json)
245
246 fprocessor = FeatureProcessor(output_name)
247 fprocessor.make_file_generate(feature_config_json)
248
249
250if __name__ == '__main__':
251 cli()