blob: 06fa520dd2509356097bb6cf596aca4d0627ca80 [file] [log] [blame]
Manish Pandey3f90ad72020-01-14 11:52:05 +00001#!/usr/bin/python3
J-Alvesa890d062024-01-11 13:35:52 +00002# Copyright (c) 2020-2024, Arm Limited. All rights reserved.
Manish Pandey3f90ad72020-01-14 11:52:05 +00003#
4# SPDX-License-Identifier: BSD-3-Clause
5
6"""
7This script is invoked by Make system and generates secure partition makefile.
8It expects platform provided secure partition layout file which contains list
9of Secure Partition Images and Partition manifests(PM).
10Layout file can exist outside of TF-A tree and the paths of Image and PM files
11must be relative to it.
12
13This script parses the layout file and generates a make file which updates
Manish Pandeyaaaeb312020-05-26 23:59:36 +010014FDT_SOURCES, FIP_ARGS, CRT_ARGS and SPTOOL_ARGS which are used in later build
15steps.
Imre Kis3f370fd2022-02-08 18:06:18 +010016If the SP entry in the layout file has a "uuid" field the scripts gets the UUID
17from there, otherwise it parses the associated partition manifest and extracts
18the UUID from there.
Manish Pandey3f90ad72020-01-14 11:52:05 +000019
20param1: Generated mk file "sp_gen.mk"
21param2: "SP_LAYOUT_FILE", json file containing platform provided information
22param3: plat out directory
Ruari Phipps571ed6b2020-07-24 16:20:57 +010023param4: CoT parameter
Karl Meakinaba46182023-02-14 11:56:02 +000024param5: Generated dts file "sp_list_fragment.dts"
Manish Pandey3f90ad72020-01-14 11:52:05 +000025
26Generated "sp_gen.mk" file contains triplet of following information for each
27Secure Partition entry
28 FDT_SOURCES += sp1.dts
29 SPTOOL_ARGS += -i sp1.bin:sp1.dtb -o sp1.pkg
30 FIP_ARGS += --blob uuid=XXXXX-XXX...,file=sp1.pkg
Manish Pandeyaaaeb312020-05-26 23:59:36 +010031 CRT_ARGS += --sp-pkg1 sp1.pkg
Manish Pandey3f90ad72020-01-14 11:52:05 +000032
33A typical SP_LAYOUT_FILE file will look like
34{
35 "SP1" : {
36 "image": "sp1.bin",
37 "pm": "test/sp1.dts"
38 },
39
40 "SP2" : {
41 "image": "sp2.bin",
Imre Kis3f370fd2022-02-08 18:06:18 +010042 "pm": "test/sp2.dts",
43 "uuid": "1b1820fe-48f7-4175-8999-d51da00b7c9f"
Manish Pandey3f90ad72020-01-14 11:52:05 +000044 }
45
46 ...
47}
48
49"""
Manish Pandey3f90ad72020-01-14 11:52:05 +000050import json
51import os
52import re
53import sys
54import uuid
J-Alvesd10fb032022-03-21 14:11:43 +000055from spactions import SpSetupActions
Manish Pandey3f90ad72020-01-14 11:52:05 +000056
Ruari Phipps571ed6b2020-07-24 16:20:57 +010057MAX_SP = 8
J-Alvesd10fb032022-03-21 14:11:43 +000058UUID_LEN = 4
Manish Pandey3f90ad72020-01-14 11:52:05 +000059
J-Alvesd10fb032022-03-21 14:11:43 +000060# Some helper functions to access args propagated to the action functions in
61# SpSetupActions framework.
J-Alvesd10fb032022-03-21 14:11:43 +000062def check_sp_mk_gen(args :dict):
63 if "sp_gen_mk" not in args.keys():
64 raise Exception(f"Path to file sp_gen.mk needs to be in 'args'.")
Ruari Phipps571ed6b2020-07-24 16:20:57 +010065
J-Alvesd10fb032022-03-21 14:11:43 +000066def check_out_dir(args :dict):
67 if "out_dir" not in args.keys() or not os.path.isdir(args["out_dir"]):
68 raise Exception("Define output folder with \'out_dir\' key.")
Ruari Phipps571ed6b2020-07-24 16:20:57 +010069
J-Alvesd10fb032022-03-21 14:11:43 +000070def check_sp_layout_dir(args :dict):
71 if "sp_layout_dir" not in args.keys() or not os.path.isdir(args["sp_layout_dir"]):
72 raise Exception("Define output folder with \'sp_layout_dir\' key.")
Ruari Phipps571ed6b2020-07-24 16:20:57 +010073
J-Alvesd10fb032022-03-21 14:11:43 +000074def write_to_sp_mk_gen(content, args :dict):
75 check_sp_mk_gen(args)
76 with open(args["sp_gen_mk"], "a") as f:
77 f.write(f"{content}\n")
Manish Pandey3f90ad72020-01-14 11:52:05 +000078
J-Alvesd10fb032022-03-21 14:11:43 +000079def get_sp_manifest_full_path(sp_node, args :dict):
80 check_sp_layout_dir(args)
81 return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["pm"]))
Manish Pandey3f90ad72020-01-14 11:52:05 +000082
J-Alvesd10fb032022-03-21 14:11:43 +000083def get_sp_img_full_path(sp_node, args :dict):
84 check_sp_layout_dir(args)
85 return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["image"]))
86
87def get_sp_pkg(sp, args :dict):
88 check_out_dir(args)
89 return os.path.join(args["out_dir"], f"{sp}.pkg")
90
91def is_line_in_sp_gen(line, args :dict):
92 with open(args["sp_gen_mk"], "r") as f:
93 sppkg_rule = [l for l in f if line in l]
J-Alves5b97ec32022-10-07 10:02:33 +010094 return len(sppkg_rule) != 0
Olivier Deprez18909842021-05-11 09:43:37 +020095
J-Alvesd10fb032022-03-21 14:11:43 +000096def get_file_from_layout(node):
97 ''' Helper to fetch a file path from sp_layout.json. '''
98 if type(node) is dict and "file" in node.keys():
99 return node["file"]
100 return node
Manish Pandey3f90ad72020-01-14 11:52:05 +0000101
J-Alvesd10fb032022-03-21 14:11:43 +0000102def get_offset_from_layout(node):
103 ''' Helper to fetch an offset from sp_layout.json. '''
104 if type(node) is dict and "offset" in node.keys():
105 return int(node["offset"], 0)
106 return None
107
108def get_image_offset(node):
109 ''' Helper to fetch image offset from sp_layout.json '''
110 return get_offset_from_layout(node["image"])
111
112def get_pm_offset(node):
113 ''' Helper to fetch pm offset from sp_layout.json '''
114 return get_offset_from_layout(node["pm"])
115
Karl Meakinaba46182023-02-14 11:56:02 +0000116def get_uuid(sp_layout, sp, args :dict):
117 ''' Helper to fetch uuid from pm file listed in sp_layout.json'''
118 if "uuid" in sp_layout[sp]:
119 # Extract the UUID from the JSON file if the SP entry has a 'uuid' field
120 uuid_std = uuid.UUID(sp_layout[sp]['uuid'])
121 else:
122 with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
123 uuid_lines = [l for l in pm_f if 'uuid' in l]
124 assert(len(uuid_lines) == 1)
125 # The uuid field in SP manifest is the little endian representation
126 # mapped to arguments as described in SMCCC section 5.3.
127 # Convert each unsigned integer value to a big endian representation
128 # required by fiptool.
129 uuid_parsed = re.findall("0x([0-9a-f]+)", uuid_lines[0])
130 y = list(map(bytearray.fromhex, uuid_parsed))
131 z = [int.from_bytes(i, byteorder='little', signed=False) for i in y]
132 uuid_std = uuid.UUID(f'{z[0]:08x}{z[1]:08x}{z[2]:08x}{z[3]:08x}')
133 return uuid_std
134
135def get_load_address(sp_layout, sp, args :dict):
136 ''' Helper to fetch load-address from pm file listed in sp_layout.json'''
137 with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
138 load_address_lines = [l for l in pm_f if 'load-address' in l]
J-Alvesa890d062024-01-11 13:35:52 +0000139
140 if len(load_address_lines) is not 1:
141 return None
142
Karl Meakinaba46182023-02-14 11:56:02 +0000143 load_address_parsed = re.search("(0x[0-9a-f]+)", load_address_lines[0])
144 return load_address_parsed.group(0)
145
146
J-Alvesd10fb032022-03-21 14:11:43 +0000147@SpSetupActions.sp_action(global_action=True)
148def check_max_sps(sp_layout, _, args :dict):
149 ''' Check validate the maximum number of SPs is respected. '''
150 if len(sp_layout.keys()) > MAX_SP:
151 raise Exception(f"Too many SPs in SP layout file. Max: {MAX_SP}")
152 return args
Manish Pandey3f90ad72020-01-14 11:52:05 +0000153
J-Alvesd10fb032022-03-21 14:11:43 +0000154@SpSetupActions.sp_action
155def gen_fdt_sources(sp_layout, sp, args :dict):
156 ''' Generate FDT_SOURCES values for a given SP. '''
157 manifest_path = get_sp_manifest_full_path(sp_layout[sp], args)
158 write_to_sp_mk_gen(f"FDT_SOURCES += {manifest_path}", args)
159 return args
Manish Pandeyaaaeb312020-05-26 23:59:36 +0100160
J-Alvesd10fb032022-03-21 14:11:43 +0000161@SpSetupActions.sp_action
J-Alvesef8e0982022-03-22 16:28:51 +0000162def gen_sptool_args(sp_layout, sp, args :dict):
163 ''' Generate Sp Pkgs rules. '''
J-Alvesd10fb032022-03-21 14:11:43 +0000164 sp_pkg = get_sp_pkg(sp, args)
J-Alvesef8e0982022-03-22 16:28:51 +0000165 sp_dtb_name = os.path.basename(get_file_from_layout(sp_layout[sp]["pm"]))[:-1] + "b"
J-Alvesd10fb032022-03-21 14:11:43 +0000166 sp_dtb = os.path.join(args["out_dir"], f"fdts/{sp_dtb_name}")
Jens Wiklander6b533252022-10-31 09:17:50 +0100167 sp_img = get_sp_img_full_path(sp_layout[sp], args)
J-Alvesef8e0982022-03-22 16:28:51 +0000168
169 # Do not generate rule if already there.
170 if is_line_in_sp_gen(f'{sp_pkg}:', args):
171 return args
172 write_to_sp_mk_gen(f"SP_PKGS += {sp_pkg}\n", args)
173
Jens Wiklander6b533252022-10-31 09:17:50 +0100174 sptool_args = f" -i {sp_img}:{sp_dtb}"
J-Alvesef8e0982022-03-22 16:28:51 +0000175 pm_offset = get_pm_offset(sp_layout[sp])
176 sptool_args += f" --pm-offset {pm_offset}" if pm_offset is not None else ""
177 image_offset = get_image_offset(sp_layout[sp])
178 sptool_args += f" --img-offset {image_offset}" if image_offset is not None else ""
179 sptool_args += f" -o {sp_pkg}"
180 sppkg_rule = f'''
Jens Wiklander6b533252022-10-31 09:17:50 +0100181{sp_pkg}: {sp_dtb} {sp_img}
J-Alvesef8e0982022-03-22 16:28:51 +0000182\t$(Q)echo Generating {sp_pkg}
183\t$(Q)$(PYTHON) $(SPTOOL) {sptool_args}
184'''
185 write_to_sp_mk_gen(sppkg_rule, args)
J-Alvesd10fb032022-03-21 14:11:43 +0000186 return args
187
188@SpSetupActions.sp_action(global_action=True, exec_order=1)
189def check_dualroot(sp_layout, _, args :dict):
190 ''' Validate the amount of SPs from SiP and Platform owners. '''
191 if not args.get("dualroot"):
192 return args
193 args["split"] = int(MAX_SP / 2)
194 owners = [sp_layout[sp].get("owner") for sp in sp_layout]
195 args["plat_max_count"] = owners.count("Plat")
196 # If it is owned by the platform owner, it is assigned to the SiP.
197 args["sip_max_count"] = len(sp_layout.keys()) - args["plat_max_count"]
198 if args["sip_max_count"] > args["split"] or args["sip_max_count"] > args["split"]:
199 print(f"WARN: SiP Secure Partitions should not be more than {args['split']}")
200 # Counters for gen_crt_args.
201 args["sip_count"] = 1
202 args["plat_count"] = 1
203 return args
204
205@SpSetupActions.sp_action
206def gen_crt_args(sp_layout, sp, args :dict):
207 ''' Append CRT_ARGS. '''
208 # If "dualroot" is configured, 'sp_pkg_idx' depends on whether the SP is owned
209 # by the "SiP" or the "Plat".
210 if args.get("dualroot"):
211 # If the owner is not specified as "Plat", default to "SiP".
212 if sp_layout[sp].get("owner") == "Plat":
213 if args["plat_count"] > args["plat_max_count"]:
214 raise ValueError("plat_count can't surpass plat_max_count in args.")
215 sp_pkg_idx = args["plat_count"] + args["split"]
216 args["plat_count"] += 1
217 else:
218 if args["sip_count"] > args["sip_max_count"]:
219 raise ValueError("sip_count can't surpass sip_max_count in args.")
220 sp_pkg_idx = args["sip_count"]
221 args["sip_count"] += 1
222 else:
223 sp_pkg_idx = [k for k in sp_layout.keys()].index(sp) + 1
224 write_to_sp_mk_gen(f"CRT_ARGS += --sp-pkg{sp_pkg_idx} {get_sp_pkg(sp, args)}\n", args)
225 return args
226
227@SpSetupActions.sp_action
228def gen_fiptool_args(sp_layout, sp, args :dict):
229 ''' Generate arguments for the FIP Tool. '''
Karl Meakinaba46182023-02-14 11:56:02 +0000230 uuid_std = get_uuid(sp_layout, sp, args)
J-Alvesd10fb032022-03-21 14:11:43 +0000231 write_to_sp_mk_gen(f"FIP_ARGS += --blob uuid={str(uuid_std)},file={get_sp_pkg(sp, args)}\n", args)
232 return args
233
Karl Meakinaba46182023-02-14 11:56:02 +0000234@SpSetupActions.sp_action
235def gen_fconf_fragment(sp_layout, sp, args: dict):
236 ''' Generate the fconf fragment file'''
237 with open(args["fconf_fragment"], "a") as f:
238 uuid = get_uuid(sp_layout, sp, args)
239 owner = "Plat" if sp_layout[sp].get("owner") == "Plat" else "SiP"
240
241 if "physical-load-address" in sp_layout[sp].keys():
242 load_address = sp_layout[sp]["physical-load-address"]
243 else:
244 load_address = get_load_address(sp_layout, sp, args)
245
J-Alvesa890d062024-01-11 13:35:52 +0000246 if load_address is not None:
247 f.write(
Karl Meakinaba46182023-02-14 11:56:02 +0000248f'''\
249{sp} {{
250 uuid = "{uuid}";
251 load-address = <{load_address}>;
252 owner = "{owner}";
253}};
254
255''')
J-Alvesa890d062024-01-11 13:35:52 +0000256 else:
257 print("Warning: No load-address was found in the SP manifest.")
258
Karl Meakinaba46182023-02-14 11:56:02 +0000259 return args
260
J-Alvesd10fb032022-03-21 14:11:43 +0000261def init_sp_actions(sys):
J-Alvesd10fb032022-03-21 14:11:43 +0000262 # Initialize arguments for the SP actions framework
263 args = {}
264 args["sp_gen_mk"] = os.path.abspath(sys.argv[1])
Karl Meakinaba46182023-02-14 11:56:02 +0000265 sp_layout_file = os.path.abspath(sys.argv[2])
J-Alvesd10fb032022-03-21 14:11:43 +0000266 args["sp_layout_dir"] = os.path.dirname(sp_layout_file)
267 args["out_dir"] = os.path.abspath(sys.argv[3])
268 args["dualroot"] = sys.argv[4] == "dualroot"
Karl Meakinaba46182023-02-14 11:56:02 +0000269 args["fconf_fragment"] = os.path.abspath(sys.argv[5])
270
271
272 with open(sp_layout_file) as json_file:
273 sp_layout = json.load(json_file)
J-Alvesd10fb032022-03-21 14:11:43 +0000274 #Clear content of file "sp_gen.mk".
275 with open(args["sp_gen_mk"], "w"):
276 None
Karl Meakinaba46182023-02-14 11:56:02 +0000277 #Clear content of file "fconf_fragment".
278 with open(args["fconf_fragment"], "w"):
279 None
280
J-Alvesd10fb032022-03-21 14:11:43 +0000281 return args, sp_layout
Ruari Phipps571ed6b2020-07-24 16:20:57 +0100282
J-Alvesd10fb032022-03-21 14:11:43 +0000283if __name__ == "__main__":
284 args, sp_layout = init_sp_actions(sys)
285 SpSetupActions.run_actions(sp_layout, args)