blob: de8995947a4de6082dfe909c3017e1bde2bf91e2 [file] [log] [blame]
Archana1f1a34a2021-11-17 08:44:07 +05301#!/usr/bin/env python3
Xiaokang Qian54a4fdf2023-09-11 02:39:27 +00002"""Generate library/psa_crypto_driver_wrappers.h
3 library/psa_crypto_driver_wrappers_no_static.c
Archanae03960e2021-12-19 09:17:04 +05304
Andrzej Kurek5c65c572022-04-13 14:28:52 -04005 This module is invoked by the build scripts to auto generate the
Xiaokang Qian54a4fdf2023-09-11 02:39:27 +00006 psa_crypto_driver_wrappers.h and psa_crypto_driver_wrappers_no_static
7 based on template files in script/data_files/driver_templates/.
Archanae03960e2021-12-19 09:17:04 +05308"""
9# Copyright The Mbed TLS Contributors
Thomas Daubneyc1750bb2023-11-14 15:16:38 +000010# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Archana1f1a34a2021-11-17 08:44:07 +053011
12import sys
Archana1f1a34a2021-11-17 08:44:07 +053013import os
Archanae829cd62021-12-24 12:50:36 +053014import json
Asfandyar Orakzai5c9569a2022-09-17 23:13:52 +020015from typing import NewType, Dict, Any
16from traceback import format_tb
Archanae03960e2021-12-19 09:17:04 +053017import argparse
Archana31438052022-01-09 15:01:20 +053018import jsonschema
Archana1f1a34a2021-11-17 08:44:07 +053019import jinja2
Archanae03960e2021-12-19 09:17:04 +053020from mbedtls_dev import build_tree
Archana1f1a34a2021-11-17 08:44:07 +053021
Archanafdbbcba2022-02-27 05:38:55 +053022JSONSchema = NewType('JSONSchema', object)
Archanaa78dc702022-03-13 17:57:45 +053023# The Driver is an Object, but practically it's indexable and can called a dictionary to
24# keep MyPy happy till MyPy comes with a more composite type for JsonObjects.
25Driver = NewType('Driver', dict)
Archanafdbbcba2022-02-27 05:38:55 +053026
Asfandyar Orakzai08f397a2022-09-15 14:25:37 +020027
28class JsonValidationException(Exception):
29 def __init__(self, message="Json Validation Failed"):
30 self.message = message
31 super().__init__(self.message)
32
33
Asfandyar Orakzaide088032022-09-17 22:07:58 +020034class DriverReaderException(Exception):
35 def __init__(self, message="Driver Reader Failed"):
36 self.message = message
37 super().__init__(self.message)
38
39
Archanae829cd62021-12-24 12:50:36 +053040def render(template_path: str, driver_jsoncontext: list) -> str:
Archanae03960e2021-12-19 09:17:04 +053041 """
Archanae829cd62021-12-24 12:50:36 +053042 Render template from the input file and driver JSON.
Archanae03960e2021-12-19 09:17:04 +053043 """
Archana6f21e452021-11-23 14:46:51 +053044 environment = jinja2.Environment(
45 loader=jinja2.FileSystemLoader(os.path.dirname(template_path)),
46 keep_trailing_newline=True)
47 template = environment.get_template(os.path.basename(template_path))
Archanae03960e2021-12-19 09:17:04 +053048
Archana31438052022-01-09 15:01:20 +053049 return template.render(drivers=driver_jsoncontext)
Archana1f1a34a2021-11-17 08:44:07 +053050
Asfandyar Orakzai9e6170d2022-09-17 23:37:16 +020051def generate_driver_wrapper_file(template_dir: str,
52 output_dir: str,
Xiaokang Qian54a4fdf2023-09-11 02:39:27 +000053 template_file_name: str,
Asfandyar Orakzai9e6170d2022-09-17 23:37:16 +020054 driver_jsoncontext: list) -> None:
Archanae03960e2021-12-19 09:17:04 +053055 """
56 Generate the file psa_crypto_driver_wrapper.c.
57 """
58 driver_wrapper_template_filename = \
Xiaokang Qian54a4fdf2023-09-11 02:39:27 +000059 os.path.join(template_dir, template_file_name)
Archana1f1a34a2021-11-17 08:44:07 +053060
Archanae829cd62021-12-24 12:50:36 +053061 result = render(driver_wrapper_template_filename, driver_jsoncontext)
Archana1f1a34a2021-11-17 08:44:07 +053062
Xiaokang Qian7d546c72023-09-12 10:45:55 +000063 with open(file=os.path.join(output_dir, os.path.splitext(template_file_name)[0]),
Asfandyar Orakzai5c9569a2022-09-17 23:13:52 +020064 mode='w',
65 encoding='UTF-8') as out_file:
Archanae03960e2021-12-19 09:17:04 +053066 out_file.write(result)
Archana6f21e452021-11-23 14:46:51 +053067
Archanae829cd62021-12-24 12:50:36 +053068
Asfandyar Orakzaide088032022-09-17 22:07:58 +020069def validate_json(driverjson_data: Driver, driverschema_list: dict) -> None:
Archanae829cd62021-12-24 12:50:36 +053070 """
Archanafdbbcba2022-02-27 05:38:55 +053071 Validate the Driver JSON against an appropriate schema
72 the schema passed could be that matching an opaque/ transparent driver.
Archana04cfe342022-01-09 13:28:28 +053073 """
Archanafdbbcba2022-02-27 05:38:55 +053074 driver_type = driverjson_data["type"]
75 driver_prefix = driverjson_data["prefix"]
Archana04cfe342022-01-09 13:28:28 +053076 try:
Archanafdbbcba2022-02-27 05:38:55 +053077 _schema = driverschema_list[driver_type]
78 jsonschema.validate(instance=driverjson_data, schema=_schema)
Archanafdbbcba2022-02-27 05:38:55 +053079 except KeyError as err:
Asfandyar Orakzaide088032022-09-17 22:07:58 +020080 # This could happen if the driverjson_data.type does not exist in the provided schema list
Archanafdbbcba2022-02-27 05:38:55 +053081 # schemas = {'transparent': transparent_driver_schema, 'opaque': opaque_driver_schema}
82 # Print onto stdout and stderr.
83 print("Unknown Driver type " + driver_type +
84 " for driver " + driver_prefix, str(err))
85 print("Unknown Driver type " + driver_type +
86 " for driver " + driver_prefix, str(err), file=sys.stderr)
Asfandyar Orakzaide088032022-09-17 22:07:58 +020087 raise JsonValidationException() from err
Archanafdbbcba2022-02-27 05:38:55 +053088
Archana04cfe342022-01-09 13:28:28 +053089 except jsonschema.exceptions.ValidationError as err:
Archanafdbbcba2022-02-27 05:38:55 +053090 # Print onto stdout and stderr.
91 print("Error: Failed to validate data file: {} using schema: {}."
92 "\n Exception Message: \"{}\""
93 " ".format(driverjson_data, _schema, str(err)))
94 print("Error: Failed to validate data file: {} using schema: {}."
95 "\n Exception Message: \"{}\""
96 " ".format(driverjson_data, _schema, str(err)), file=sys.stderr)
Asfandyar Orakzaide088032022-09-17 22:07:58 +020097 raise JsonValidationException() from err
Archana04cfe342022-01-09 13:28:28 +053098
Asfandyar Orakzai08f397a2022-09-15 14:25:37 +020099
100def load_driver(schemas: Dict[str, Any], driver_file: str) -> Any:
Asfandyar Orakzai9e6170d2022-09-17 23:37:16 +0200101 """loads validated json driver"""
Asfandyar Orakzai5c9569a2022-09-17 23:13:52 +0200102 with open(file=driver_file, mode='r', encoding='UTF-8') as f:
Asfandyar Orakzai08f397a2022-09-15 14:25:37 +0200103 json_data = json.load(f)
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200104 try:
105 validate_json(json_data, schemas)
106 except JsonValidationException as e:
107 raise DriverReaderException from e
Asfandyar Orakzai08f397a2022-09-15 14:25:37 +0200108 return json_data
109
110
Thomas Daubney5556f902023-11-15 16:43:02 +0000111def load_schemas(repo_root: str) -> Dict[str, Any]:
Asfandyar Orakzaiac6f6502022-09-19 10:03:05 +0200112 """
113 Load schemas map
114 """
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200115 schema_file_paths = {
Thomas Daubney5556f902023-11-15 16:43:02 +0000116 'transparent': os.path.join(repo_root,
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200117 'scripts',
118 'data_files',
119 'driver_jsons',
120 'driver_transparent_schema.json'),
Thomas Daubney5556f902023-11-15 16:43:02 +0000121 'opaque': os.path.join(repo_root,
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200122 'scripts',
123 'data_files',
124 'driver_jsons',
Asfandyar Orakzai4ca4a932022-09-18 12:37:53 +0200125 'driver_opaque_schema.json')
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200126 }
127 driver_schema = {}
128 for key, file_path in schema_file_paths.items():
Asfandyar Orakzai5c9569a2022-09-17 23:13:52 +0200129 with open(file=file_path, mode='r', encoding='UTF-8') as file:
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200130 driver_schema[key] = json.load(file)
131 return driver_schema
132
133
Thomas Daubney5556f902023-11-15 16:43:02 +0000134def read_driver_descriptions(repo_root: str,
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200135 json_directory: str,
136 jsondriver_list: str) -> list:
Archana04cfe342022-01-09 13:28:28 +0530137 """
138 Merge driver JSON files into a single ordered JSON after validation.
Archanae829cd62021-12-24 12:50:36 +0530139 """
Thomas Daubney5556f902023-11-15 16:43:02 +0000140 driver_schema = load_schemas(repo_root)
Archana04cfe342022-01-09 13:28:28 +0530141
Asfandyar Orakzai5c9569a2022-09-17 23:13:52 +0200142 with open(file=os.path.join(json_directory, jsondriver_list),
143 mode='r',
144 encoding='UTF-8') as driver_list_file:
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200145 driver_list = json.load(driver_list_file)
Asfandyar Orakzai08f397a2022-09-15 14:25:37 +0200146
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200147 return [load_driver(schemas=driver_schema,
148 driver_file=os.path.join(json_directory, driver_file_name))
149 for driver_file_name in driver_list]
Asfandyar Orakzai08f397a2022-09-15 14:25:37 +0200150
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200151
Asfandyar Orakzai9e6170d2022-09-17 23:37:16 +0200152def trace_exception(e: Exception, file=sys.stderr) -> None:
153 """Prints exception trace to the given TextIO handle"""
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200154 print("Exception: type: %s, message: %s, trace: %s" % (
155 e.__class__, str(e), format_tb(e.__traceback__)
156 ), file)
Archanae829cd62021-12-24 12:50:36 +0530157
158
Xiaokang Qianfe9666b2023-09-11 10:36:20 +0000159TEMPLATE_FILENAMES = ["psa_crypto_driver_wrappers.h.jinja",
Xiaokang Qian54a4fdf2023-09-11 02:39:27 +0000160 "psa_crypto_driver_wrappers_no_static.c.jinja"]
161
Archanae03960e2021-12-19 09:17:04 +0530162def main() -> int:
163 """
164 Main with command line arguments.
165 """
Thomas Daubney5556f902023-11-15 16:43:02 +0000166 def_arg_repo_root = build_tree.guess_mbedtls_root()
Archana4a9e0262021-12-19 13:34:30 +0530167
Archanae03960e2021-12-19 09:17:04 +0530168 parser = argparse.ArgumentParser()
Thomas Daubney5556f902023-11-15 16:43:02 +0000169 parser.add_argument('--repo-root', default=def_arg_repo_root,
170 help='root directory of repo source code')
Archana22c78272022-04-11 10:12:08 +0530171 parser.add_argument('--template-dir',
172 help='directory holding the driver templates')
173 parser.add_argument('--json-dir',
174 help='directory holding the driver JSONs')
Archana01aa39e2022-03-14 15:29:00 +0530175 parser.add_argument('output_directory', nargs='?',
176 help='output file\'s location')
Archanae03960e2021-12-19 09:17:04 +0530177 args = parser.parse_args()
Archana4a9e0262021-12-19 13:34:30 +0530178
Thomas Daubney5556f902023-11-15 16:43:02 +0000179 repo_root = os.path.abspath(args.repo_root)
Archana01aa39e2022-03-14 15:29:00 +0530180
Thomas Daubney5556f902023-11-15 16:43:02 +0000181 if build_tree.looks_like_mbedtls_root(repo_root):
Thomas Daubneyb10cc7a2023-11-14 11:56:02 +0000182 library_dir = 'library'
Thomas Daubney5556f902023-11-15 16:43:02 +0000183 elif build_tree.looks_like_tf_psa_crypto_root(repo_root):
Thomas Daubneyb10cc7a2023-11-14 11:56:02 +0000184 library_dir = 'core'
Thomas Daubney4291bc22023-11-14 18:05:19 +0000185
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200186 output_directory = args.output_directory if args.output_directory is not None else \
Thomas Daubney5556f902023-11-15 16:43:02 +0000187 os.path.join(repo_root, library_dir)
Thomas Daubney4291bc22023-11-14 18:05:19 +0000188
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200189 template_directory = args.template_dir if args.template_dir is not None else \
Thomas Daubney5556f902023-11-15 16:43:02 +0000190 os.path.join(repo_root,
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200191 'scripts',
192 'data_files',
193 'driver_templates')
194 json_directory = args.json_dir if args.json_dir is not None else \
Thomas Daubney5556f902023-11-15 16:43:02 +0000195 os.path.join(repo_root,
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200196 'scripts',
197 'data_files',
198 'driver_jsons')
Archanae03960e2021-12-19 09:17:04 +0530199
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200200 try:
201 # Read and validate list of driver jsons from driverlist.json
Thomas Daubney5556f902023-11-15 16:43:02 +0000202 merged_driver_json = read_driver_descriptions(repo_root,
Asfandyar Orakzaide088032022-09-17 22:07:58 +0200203 json_directory,
204 'driverlist.json')
205 except DriverReaderException as e:
206 trace_exception(e)
Archanae829cd62021-12-24 12:50:36 +0530207 return 1
Xiaokang Qian54a4fdf2023-09-11 02:39:27 +0000208 for template_filename in TEMPLATE_FILENAMES:
209 generate_driver_wrapper_file(template_directory, output_directory,
210 template_filename, merged_driver_json)
Archanae03960e2021-12-19 09:17:04 +0530211 return 0
212
Asfandyar Orakzai08f397a2022-09-15 14:25:37 +0200213
Archanae03960e2021-12-19 09:17:04 +0530214if __name__ == '__main__':
215 sys.exit(main())