blob: 40673312fd8131746f7aed529105478401daa26f [file] [log] [blame]
Manish Pandey3f90ad72020-01-14 11:52:05 +00001#!/usr/bin/python3
Anders Dellien836c64f2022-01-07 13:26:29 +00002# Copyright (c) 2020-2022, 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
Manish Pandey3f90ad72020-01-14 11:52:05 +000024
25Generated "sp_gen.mk" file contains triplet of following information for each
26Secure Partition entry
27 FDT_SOURCES += sp1.dts
28 SPTOOL_ARGS += -i sp1.bin:sp1.dtb -o sp1.pkg
29 FIP_ARGS += --blob uuid=XXXXX-XXX...,file=sp1.pkg
Manish Pandeyaaaeb312020-05-26 23:59:36 +010030 CRT_ARGS += --sp-pkg1 sp1.pkg
Manish Pandey3f90ad72020-01-14 11:52:05 +000031
32A typical SP_LAYOUT_FILE file will look like
33{
34 "SP1" : {
35 "image": "sp1.bin",
36 "pm": "test/sp1.dts"
37 },
38
39 "SP2" : {
40 "image": "sp2.bin",
Imre Kis3f370fd2022-02-08 18:06:18 +010041 "pm": "test/sp2.dts",
42 "uuid": "1b1820fe-48f7-4175-8999-d51da00b7c9f"
Manish Pandey3f90ad72020-01-14 11:52:05 +000043 }
44
45 ...
46}
47
48"""
Manish Pandey3f90ad72020-01-14 11:52:05 +000049import json
50import os
51import re
52import sys
53import uuid
J-Alvesd10fb032022-03-21 14:11:43 +000054from spactions import SpSetupActions
Manish Pandey3f90ad72020-01-14 11:52:05 +000055
Ruari Phipps571ed6b2020-07-24 16:20:57 +010056MAX_SP = 8
J-Alvesd10fb032022-03-21 14:11:43 +000057UUID_LEN = 4
Manish Pandey3f90ad72020-01-14 11:52:05 +000058
J-Alvesd10fb032022-03-21 14:11:43 +000059# Some helper functions to access args propagated to the action functions in
60# SpSetupActions framework.
J-Alvesd10fb032022-03-21 14:11:43 +000061def check_sp_mk_gen(args :dict):
62 if "sp_gen_mk" not in args.keys():
63 raise Exception(f"Path to file sp_gen.mk needs to be in 'args'.")
Ruari Phipps571ed6b2020-07-24 16:20:57 +010064
J-Alvesd10fb032022-03-21 14:11:43 +000065def check_out_dir(args :dict):
66 if "out_dir" not in args.keys() or not os.path.isdir(args["out_dir"]):
67 raise Exception("Define output folder with \'out_dir\' key.")
Ruari Phipps571ed6b2020-07-24 16:20:57 +010068
J-Alvesd10fb032022-03-21 14:11:43 +000069def check_sp_layout_dir(args :dict):
70 if "sp_layout_dir" not in args.keys() or not os.path.isdir(args["sp_layout_dir"]):
71 raise Exception("Define output folder with \'sp_layout_dir\' key.")
Ruari Phipps571ed6b2020-07-24 16:20:57 +010072
J-Alvesd10fb032022-03-21 14:11:43 +000073def write_to_sp_mk_gen(content, args :dict):
74 check_sp_mk_gen(args)
75 with open(args["sp_gen_mk"], "a") as f:
76 f.write(f"{content}\n")
Manish Pandey3f90ad72020-01-14 11:52:05 +000077
J-Alvesd10fb032022-03-21 14:11:43 +000078def get_sp_manifest_full_path(sp_node, args :dict):
79 check_sp_layout_dir(args)
80 return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["pm"]))
Manish Pandey3f90ad72020-01-14 11:52:05 +000081
J-Alvesd10fb032022-03-21 14:11:43 +000082def get_sp_img_full_path(sp_node, args :dict):
83 check_sp_layout_dir(args)
84 return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["image"]))
85
86def get_sp_pkg(sp, args :dict):
87 check_out_dir(args)
88 return os.path.join(args["out_dir"], f"{sp}.pkg")
89
90def is_line_in_sp_gen(line, args :dict):
91 with open(args["sp_gen_mk"], "r") as f:
92 sppkg_rule = [l for l in f if line in l]
J-Alves5b97ec32022-10-07 10:02:33 +010093 return len(sppkg_rule) != 0
Olivier Deprez18909842021-05-11 09:43:37 +020094
J-Alvesd10fb032022-03-21 14:11:43 +000095def get_file_from_layout(node):
96 ''' Helper to fetch a file path from sp_layout.json. '''
97 if type(node) is dict and "file" in node.keys():
98 return node["file"]
99 return node
Manish Pandey3f90ad72020-01-14 11:52:05 +0000100
J-Alvesd10fb032022-03-21 14:11:43 +0000101def get_offset_from_layout(node):
102 ''' Helper to fetch an offset from sp_layout.json. '''
103 if type(node) is dict and "offset" in node.keys():
104 return int(node["offset"], 0)
105 return None
106
107def get_image_offset(node):
108 ''' Helper to fetch image offset from sp_layout.json '''
109 return get_offset_from_layout(node["image"])
110
111def get_pm_offset(node):
112 ''' Helper to fetch pm offset from sp_layout.json '''
113 return get_offset_from_layout(node["pm"])
114
115@SpSetupActions.sp_action(global_action=True)
116def check_max_sps(sp_layout, _, args :dict):
117 ''' Check validate the maximum number of SPs is respected. '''
118 if len(sp_layout.keys()) > MAX_SP:
119 raise Exception(f"Too many SPs in SP layout file. Max: {MAX_SP}")
120 return args
Manish Pandey3f90ad72020-01-14 11:52:05 +0000121
J-Alvesd10fb032022-03-21 14:11:43 +0000122@SpSetupActions.sp_action
123def gen_fdt_sources(sp_layout, sp, args :dict):
124 ''' Generate FDT_SOURCES values for a given SP. '''
125 manifest_path = get_sp_manifest_full_path(sp_layout[sp], args)
126 write_to_sp_mk_gen(f"FDT_SOURCES += {manifest_path}", args)
127 return args
Manish Pandeyaaaeb312020-05-26 23:59:36 +0100128
J-Alvesd10fb032022-03-21 14:11:43 +0000129@SpSetupActions.sp_action
J-Alvesef8e0982022-03-22 16:28:51 +0000130def gen_sptool_args(sp_layout, sp, args :dict):
131 ''' Generate Sp Pkgs rules. '''
J-Alvesd10fb032022-03-21 14:11:43 +0000132 sp_pkg = get_sp_pkg(sp, args)
J-Alvesef8e0982022-03-22 16:28:51 +0000133 sp_dtb_name = os.path.basename(get_file_from_layout(sp_layout[sp]["pm"]))[:-1] + "b"
J-Alvesd10fb032022-03-21 14:11:43 +0000134 sp_dtb = os.path.join(args["out_dir"], f"fdts/{sp_dtb_name}")
Jens Wiklander6b533252022-10-31 09:17:50 +0100135 sp_img = get_sp_img_full_path(sp_layout[sp], args)
J-Alvesef8e0982022-03-22 16:28:51 +0000136
137 # Do not generate rule if already there.
138 if is_line_in_sp_gen(f'{sp_pkg}:', args):
139 return args
140 write_to_sp_mk_gen(f"SP_PKGS += {sp_pkg}\n", args)
141
Jens Wiklander6b533252022-10-31 09:17:50 +0100142 sptool_args = f" -i {sp_img}:{sp_dtb}"
J-Alvesef8e0982022-03-22 16:28:51 +0000143 pm_offset = get_pm_offset(sp_layout[sp])
144 sptool_args += f" --pm-offset {pm_offset}" if pm_offset is not None else ""
145 image_offset = get_image_offset(sp_layout[sp])
146 sptool_args += f" --img-offset {image_offset}" if image_offset is not None else ""
147 sptool_args += f" -o {sp_pkg}"
148 sppkg_rule = f'''
Jens Wiklander6b533252022-10-31 09:17:50 +0100149{sp_pkg}: {sp_dtb} {sp_img}
J-Alvesef8e0982022-03-22 16:28:51 +0000150\t$(Q)echo Generating {sp_pkg}
151\t$(Q)$(PYTHON) $(SPTOOL) {sptool_args}
152'''
153 write_to_sp_mk_gen(sppkg_rule, args)
J-Alvesd10fb032022-03-21 14:11:43 +0000154 return args
155
156@SpSetupActions.sp_action(global_action=True, exec_order=1)
157def check_dualroot(sp_layout, _, args :dict):
158 ''' Validate the amount of SPs from SiP and Platform owners. '''
159 if not args.get("dualroot"):
160 return args
161 args["split"] = int(MAX_SP / 2)
162 owners = [sp_layout[sp].get("owner") for sp in sp_layout]
163 args["plat_max_count"] = owners.count("Plat")
164 # If it is owned by the platform owner, it is assigned to the SiP.
165 args["sip_max_count"] = len(sp_layout.keys()) - args["plat_max_count"]
166 if args["sip_max_count"] > args["split"] or args["sip_max_count"] > args["split"]:
167 print(f"WARN: SiP Secure Partitions should not be more than {args['split']}")
168 # Counters for gen_crt_args.
169 args["sip_count"] = 1
170 args["plat_count"] = 1
171 return args
172
173@SpSetupActions.sp_action
174def gen_crt_args(sp_layout, sp, args :dict):
175 ''' Append CRT_ARGS. '''
176 # If "dualroot" is configured, 'sp_pkg_idx' depends on whether the SP is owned
177 # by the "SiP" or the "Plat".
178 if args.get("dualroot"):
179 # If the owner is not specified as "Plat", default to "SiP".
180 if sp_layout[sp].get("owner") == "Plat":
181 if args["plat_count"] > args["plat_max_count"]:
182 raise ValueError("plat_count can't surpass plat_max_count in args.")
183 sp_pkg_idx = args["plat_count"] + args["split"]
184 args["plat_count"] += 1
185 else:
186 if args["sip_count"] > args["sip_max_count"]:
187 raise ValueError("sip_count can't surpass sip_max_count in args.")
188 sp_pkg_idx = args["sip_count"]
189 args["sip_count"] += 1
190 else:
191 sp_pkg_idx = [k for k in sp_layout.keys()].index(sp) + 1
192 write_to_sp_mk_gen(f"CRT_ARGS += --sp-pkg{sp_pkg_idx} {get_sp_pkg(sp, args)}\n", args)
193 return args
194
195@SpSetupActions.sp_action
196def gen_fiptool_args(sp_layout, sp, args :dict):
197 ''' Generate arguments for the FIP Tool. '''
198 if "uuid" in sp_layout[sp]:
199 # Extract the UUID from the JSON file if the SP entry has a 'uuid' field
J-Alvesc23b1b22022-09-14 15:31:17 +0100200 uuid_std = uuid.UUID(sp_layout[sp]['uuid'])
J-Alvesd10fb032022-03-21 14:11:43 +0000201 else:
202 with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
203 uuid_lines = [l for l in pm_f if 'uuid' in l]
J-Alves5b97ec32022-10-07 10:02:33 +0100204 assert(len(uuid_lines) == 1)
J-Alvesd10fb032022-03-21 14:11:43 +0000205 # The uuid field in SP manifest is the little endian representation
206 # mapped to arguments as described in SMCCC section 5.3.
207 # Convert each unsigned integer value to a big endian representation
208 # required by fiptool.
209 uuid_parsed = re.findall("0x([0-9a-f]+)", uuid_lines[0])
210 y = list(map(bytearray.fromhex, uuid_parsed))
211 z = [int.from_bytes(i, byteorder='little', signed=False) for i in y]
212 uuid_std = uuid.UUID(f'{z[0]:08x}{z[1]:08x}{z[2]:08x}{z[3]:08x}')
213 write_to_sp_mk_gen(f"FIP_ARGS += --blob uuid={str(uuid_std)},file={get_sp_pkg(sp, args)}\n", args)
214 return args
215
216def init_sp_actions(sys):
217 sp_layout_file = os.path.abspath(sys.argv[2])
218 with open(sp_layout_file) as json_file:
219 sp_layout = json.load(json_file)
220 # Initialize arguments for the SP actions framework
221 args = {}
222 args["sp_gen_mk"] = os.path.abspath(sys.argv[1])
223 args["sp_layout_dir"] = os.path.dirname(sp_layout_file)
224 args["out_dir"] = os.path.abspath(sys.argv[3])
225 args["dualroot"] = sys.argv[4] == "dualroot"
226 #Clear content of file "sp_gen.mk".
227 with open(args["sp_gen_mk"], "w"):
228 None
229 return args, sp_layout
Ruari Phipps571ed6b2020-07-24 16:20:57 +0100230
J-Alvesd10fb032022-03-21 14:11:43 +0000231if __name__ == "__main__":
232 args, sp_layout = init_sp_actions(sys)
233 SpSetupActions.run_actions(sp_layout, args)