1ce2b1ec6SManish Pandey#!/usr/bin/python3 2b06344a3SAnders Dellien# Copyright (c) 2020-2022, Arm Limited. All rights reserved. 3ce2b1ec6SManish Pandey# 4ce2b1ec6SManish Pandey# SPDX-License-Identifier: BSD-3-Clause 5ce2b1ec6SManish Pandey 6ce2b1ec6SManish Pandey""" 7ce2b1ec6SManish PandeyThis script is invoked by Make system and generates secure partition makefile. 8ce2b1ec6SManish PandeyIt expects platform provided secure partition layout file which contains list 9ce2b1ec6SManish Pandeyof Secure Partition Images and Partition manifests(PM). 10ce2b1ec6SManish PandeyLayout file can exist outside of TF-A tree and the paths of Image and PM files 11ce2b1ec6SManish Pandeymust be relative to it. 12ce2b1ec6SManish Pandey 13ce2b1ec6SManish PandeyThis script parses the layout file and generates a make file which updates 1407c44475SManish PandeyFDT_SOURCES, FIP_ARGS, CRT_ARGS and SPTOOL_ARGS which are used in later build 1507c44475SManish Pandeysteps. 165ac60ea1SImre KisIf the SP entry in the layout file has a "uuid" field the scripts gets the UUID 175ac60ea1SImre Kisfrom there, otherwise it parses the associated partition manifest and extracts 185ac60ea1SImre Kisthe UUID from there. 19ce2b1ec6SManish Pandey 20ce2b1ec6SManish Pandeyparam1: Generated mk file "sp_gen.mk" 21ce2b1ec6SManish Pandeyparam2: "SP_LAYOUT_FILE", json file containing platform provided information 22ce2b1ec6SManish Pandeyparam3: plat out directory 231e7528ecSRuari Phippsparam4: CoT parameter 24ce2b1ec6SManish Pandey 25ce2b1ec6SManish PandeyGenerated "sp_gen.mk" file contains triplet of following information for each 26ce2b1ec6SManish PandeySecure Partition entry 27ce2b1ec6SManish Pandey FDT_SOURCES += sp1.dts 28ce2b1ec6SManish Pandey SPTOOL_ARGS += -i sp1.bin:sp1.dtb -o sp1.pkg 29ce2b1ec6SManish Pandey FIP_ARGS += --blob uuid=XXXXX-XXX...,file=sp1.pkg 3007c44475SManish Pandey CRT_ARGS += --sp-pkg1 sp1.pkg 31ce2b1ec6SManish Pandey 32ce2b1ec6SManish PandeyA typical SP_LAYOUT_FILE file will look like 33ce2b1ec6SManish Pandey{ 34ce2b1ec6SManish Pandey "SP1" : { 35ce2b1ec6SManish Pandey "image": "sp1.bin", 36ce2b1ec6SManish Pandey "pm": "test/sp1.dts" 37ce2b1ec6SManish Pandey }, 38ce2b1ec6SManish Pandey 39ce2b1ec6SManish Pandey "SP2" : { 40ce2b1ec6SManish Pandey "image": "sp2.bin", 415ac60ea1SImre Kis "pm": "test/sp2.dts", 425ac60ea1SImre Kis "uuid": "1b1820fe-48f7-4175-8999-d51da00b7c9f" 43ce2b1ec6SManish Pandey } 44ce2b1ec6SManish Pandey 45ce2b1ec6SManish Pandey ... 46ce2b1ec6SManish Pandey} 47ce2b1ec6SManish Pandey 48ce2b1ec6SManish Pandey""" 49ce2b1ec6SManish Pandey 50ce2b1ec6SManish Pandeyimport json 51ce2b1ec6SManish Pandeyimport os 52ce2b1ec6SManish Pandeyimport re 53ce2b1ec6SManish Pandeyimport sys 54ce2b1ec6SManish Pandeyimport uuid 55*a96a07bfSJ-Alvesfrom spactions import SpSetupActions 56ce2b1ec6SManish Pandey 571e7528ecSRuari PhippsMAX_SP = 8 58*a96a07bfSJ-AlvesUUID_LEN = 4 59ce2b1ec6SManish Pandey 60*a96a07bfSJ-Alves# Some helper functions to access args propagated to the action functions in 61*a96a07bfSJ-Alves# SpSetupActions framework. 62ce2b1ec6SManish Pandey 63*a96a07bfSJ-Alvesdef check_sp_mk_gen(args :dict): 64*a96a07bfSJ-Alves if "sp_gen_mk" not in args.keys(): 65*a96a07bfSJ-Alves raise Exception(f"Path to file sp_gen.mk needs to be in 'args'.") 661e7528ecSRuari Phipps 67*a96a07bfSJ-Alvesdef check_out_dir(args :dict): 68*a96a07bfSJ-Alves if "out_dir" not in args.keys() or not os.path.isdir(args["out_dir"]): 69*a96a07bfSJ-Alves raise Exception("Define output folder with \'out_dir\' key.") 701e7528ecSRuari Phipps 71*a96a07bfSJ-Alvesdef check_sp_layout_dir(args :dict): 72*a96a07bfSJ-Alves if "sp_layout_dir" not in args.keys() or not os.path.isdir(args["sp_layout_dir"]): 73*a96a07bfSJ-Alves raise Exception("Define output folder with \'sp_layout_dir\' key.") 74*a96a07bfSJ-Alves 75*a96a07bfSJ-Alvesdef write_to_sp_mk_gen(content, args :dict): 76*a96a07bfSJ-Alves check_sp_mk_gen(args) 77*a96a07bfSJ-Alves with open(args["sp_gen_mk"], "a") as f: 78*a96a07bfSJ-Alves f.write(f"{content}\n") 79*a96a07bfSJ-Alves 80*a96a07bfSJ-Alvesdef get_sp_manifest_full_path(sp_node, args :dict): 81*a96a07bfSJ-Alves check_sp_layout_dir(args) 82*a96a07bfSJ-Alves return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["pm"])) 83*a96a07bfSJ-Alves 84*a96a07bfSJ-Alvesdef get_sp_img_full_path(sp_node, args :dict): 85*a96a07bfSJ-Alves check_sp_layout_dir(args) 86*a96a07bfSJ-Alves return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["image"])) 87*a96a07bfSJ-Alves 88*a96a07bfSJ-Alvesdef get_sp_pkg(sp, args :dict): 89*a96a07bfSJ-Alves check_out_dir(args) 90*a96a07bfSJ-Alves return os.path.join(args["out_dir"], f"{sp}.pkg") 91*a96a07bfSJ-Alves 92*a96a07bfSJ-Alvesdef is_line_in_sp_gen(line, args :dict): 93*a96a07bfSJ-Alves with open(args["sp_gen_mk"], "r") as f: 94*a96a07bfSJ-Alves sppkg_rule = [l for l in f if line in l] 95*a96a07bfSJ-Alves return len(sppkg_rule) is not 0 96*a96a07bfSJ-Alves 97*a96a07bfSJ-Alvesdef get_file_from_layout(node): 98*a96a07bfSJ-Alves ''' Helper to fetch a file path from sp_layout.json. ''' 99*a96a07bfSJ-Alves if type(node) is dict and "file" in node.keys(): 100*a96a07bfSJ-Alves return node["file"] 101*a96a07bfSJ-Alves return node 102*a96a07bfSJ-Alves 103*a96a07bfSJ-Alvesdef get_offset_from_layout(node): 104*a96a07bfSJ-Alves ''' Helper to fetch an offset from sp_layout.json. ''' 105*a96a07bfSJ-Alves if type(node) is dict and "offset" in node.keys(): 106*a96a07bfSJ-Alves return int(node["offset"], 0) 107*a96a07bfSJ-Alves return None 108*a96a07bfSJ-Alves 109*a96a07bfSJ-Alvesdef get_image_offset(node): 110*a96a07bfSJ-Alves ''' Helper to fetch image offset from sp_layout.json ''' 111*a96a07bfSJ-Alves return get_offset_from_layout(node["image"]) 112*a96a07bfSJ-Alves 113*a96a07bfSJ-Alvesdef get_pm_offset(node): 114*a96a07bfSJ-Alves ''' Helper to fetch pm offset from sp_layout.json ''' 115*a96a07bfSJ-Alves return get_offset_from_layout(node["pm"]) 116*a96a07bfSJ-Alves 117*a96a07bfSJ-Alves@SpSetupActions.sp_action(global_action=True) 118*a96a07bfSJ-Alvesdef check_max_sps(sp_layout, _, args :dict): 119*a96a07bfSJ-Alves ''' Check validate the maximum number of SPs is respected. ''' 120*a96a07bfSJ-Alves if len(sp_layout.keys()) > MAX_SP: 121*a96a07bfSJ-Alves raise Exception(f"Too many SPs in SP layout file. Max: {MAX_SP}") 122*a96a07bfSJ-Alves return args 123*a96a07bfSJ-Alves 124*a96a07bfSJ-Alves@SpSetupActions.sp_action 125*a96a07bfSJ-Alvesdef gen_fdt_sources(sp_layout, sp, args :dict): 126*a96a07bfSJ-Alves ''' Generate FDT_SOURCES values for a given SP. ''' 127*a96a07bfSJ-Alves manifest_path = get_sp_manifest_full_path(sp_layout[sp], args) 128*a96a07bfSJ-Alves write_to_sp_mk_gen(f"FDT_SOURCES += {manifest_path}", args) 129*a96a07bfSJ-Alves return args 130*a96a07bfSJ-Alves 131*a96a07bfSJ-Alves@SpSetupActions.sp_action 132*a96a07bfSJ-Alvesdef gen_sptool_args(sp_layout, sp, args): 133*a96a07bfSJ-Alves ''' Generate sptool arguments to generate SP Pkg for a given SP. ''' 134*a96a07bfSJ-Alves check_out_dir(args) 135*a96a07bfSJ-Alves check_sp_layout_dir(args) 136*a96a07bfSJ-Alves sp_pkg = get_sp_pkg(sp, args) 137*a96a07bfSJ-Alves sp_dtb_name = os.path.basename(sp_layout[sp]["pm"])[:-1] + "b" 138*a96a07bfSJ-Alves sp_dtb = os.path.join(args["out_dir"], f"fdts/{sp_dtb_name}") 139*a96a07bfSJ-Alves sp_bin = os.path.join(args["sp_layout_dir"], sp_layout[sp]["image"]) 140*a96a07bfSJ-Alves write_to_sp_mk_gen(f"SPTOOL_ARGS += -i {sp_bin}:{sp_dtb} -o {sp_pkg}\n", args) 141*a96a07bfSJ-Alves return args 142*a96a07bfSJ-Alves 143*a96a07bfSJ-Alves@SpSetupActions.sp_action(global_action=True, exec_order=1) 144*a96a07bfSJ-Alvesdef check_dualroot(sp_layout, _, args :dict): 145*a96a07bfSJ-Alves ''' Validate the amount of SPs from SiP and Platform owners. ''' 146*a96a07bfSJ-Alves if not args.get("dualroot"): 147*a96a07bfSJ-Alves return args 148*a96a07bfSJ-Alves args["split"] = int(MAX_SP / 2) 149*a96a07bfSJ-Alves owners = [sp_layout[sp].get("owner") for sp in sp_layout] 150*a96a07bfSJ-Alves args["plat_max_count"] = owners.count("Plat") 151*a96a07bfSJ-Alves # If it is owned by the platform owner, it is assigned to the SiP. 152*a96a07bfSJ-Alves args["sip_max_count"] = len(sp_layout.keys()) - args["plat_max_count"] 153*a96a07bfSJ-Alves if args["sip_max_count"] > args["split"] or args["sip_max_count"] > args["split"]: 154*a96a07bfSJ-Alves print(f"WARN: SiP Secure Partitions should not be more than {args['split']}") 155*a96a07bfSJ-Alves # Counters for gen_crt_args. 156*a96a07bfSJ-Alves args["sip_count"] = 1 157*a96a07bfSJ-Alves args["plat_count"] = 1 158*a96a07bfSJ-Alves return args 159*a96a07bfSJ-Alves 160*a96a07bfSJ-Alves@SpSetupActions.sp_action 161*a96a07bfSJ-Alvesdef gen_crt_args(sp_layout, sp, args :dict): 162*a96a07bfSJ-Alves ''' Append CRT_ARGS. ''' 163*a96a07bfSJ-Alves # If "dualroot" is configured, 'sp_pkg_idx' depends on whether the SP is owned 164*a96a07bfSJ-Alves # by the "SiP" or the "Plat". 165*a96a07bfSJ-Alves if args.get("dualroot"): 166*a96a07bfSJ-Alves # If the owner is not specified as "Plat", default to "SiP". 167*a96a07bfSJ-Alves if sp_layout[sp].get("owner") == "Plat": 168*a96a07bfSJ-Alves if args["plat_count"] > args["plat_max_count"]: 169*a96a07bfSJ-Alves raise ValueError("plat_count can't surpass plat_max_count in args.") 170*a96a07bfSJ-Alves sp_pkg_idx = args["plat_count"] + args["split"] 171*a96a07bfSJ-Alves args["plat_count"] += 1 1721e7528ecSRuari Phipps else: 173*a96a07bfSJ-Alves if args["sip_count"] > args["sip_max_count"]: 174*a96a07bfSJ-Alves raise ValueError("sip_count can't surpass sip_max_count in args.") 175*a96a07bfSJ-Alves sp_pkg_idx = args["sip_count"] 176*a96a07bfSJ-Alves args["sip_count"] += 1 177*a96a07bfSJ-Alves else: 178*a96a07bfSJ-Alves sp_pkg_idx = [k for k in sp_layout.keys()].index(sp) + 1 179*a96a07bfSJ-Alves write_to_sp_mk_gen(f"CRT_ARGS += --sp-pkg{sp_pkg_idx} {get_sp_pkg(sp, args)}\n", args) 180*a96a07bfSJ-Alves return args 1811e7528ecSRuari Phipps 182*a96a07bfSJ-Alves@SpSetupActions.sp_action 183*a96a07bfSJ-Alvesdef gen_fiptool_args(sp_layout, sp, args :dict): 184*a96a07bfSJ-Alves ''' Generate arguments for the FIP Tool. ''' 185*a96a07bfSJ-Alves if "uuid" in sp_layout[sp]: 186*a96a07bfSJ-Alves # Extract the UUID from the JSON file if the SP entry has a 'uuid' field 1875ac60ea1SImre Kis uuid_std = uuid.UUID(data[key]['uuid']) 1885ac60ea1SImre Kis else: 189*a96a07bfSJ-Alves with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f: 190*a96a07bfSJ-Alves uuid_lines = [l for l in pm_f if 'uuid' in l] 191*a96a07bfSJ-Alves assert(len(uuid_lines) is 1) 192dcdbcddeSOlivier Deprez # The uuid field in SP manifest is the little endian representation 193dcdbcddeSOlivier Deprez # mapped to arguments as described in SMCCC section 5.3. 194dcdbcddeSOlivier Deprez # Convert each unsigned integer value to a big endian representation 195dcdbcddeSOlivier Deprez # required by fiptool. 196*a96a07bfSJ-Alves uuid_parsed = re.findall("0x([0-9a-f]+)", uuid_lines[0]) 197*a96a07bfSJ-Alves y = list(map(bytearray.fromhex, uuid_parsed)) 198*a96a07bfSJ-Alves z = [int.from_bytes(i, byteorder='little', signed=False) for i in y] 199b06344a3SAnders Dellien uuid_std = uuid.UUID(f'{z[0]:08x}{z[1]:08x}{z[2]:08x}{z[3]:08x}') 200*a96a07bfSJ-Alves write_to_sp_mk_gen(f"FIP_ARGS += --blob uuid={str(uuid_std)},file={get_sp_pkg(sp, args)}\n", args) 201*a96a07bfSJ-Alves return args 202ce2b1ec6SManish Pandey 203*a96a07bfSJ-Alvesdef init_sp_actions(sys): 204*a96a07bfSJ-Alves sp_layout_file = os.path.abspath(sys.argv[2]) 205*a96a07bfSJ-Alves with open(sp_layout_file) as json_file: 206*a96a07bfSJ-Alves sp_layout = json.load(json_file) 207*a96a07bfSJ-Alves # Initialize arguments for the SP actions framework 208*a96a07bfSJ-Alves args = {} 209*a96a07bfSJ-Alves args["sp_gen_mk"] = os.path.abspath(sys.argv[1]) 210*a96a07bfSJ-Alves args["sp_layout_dir"] = os.path.dirname(sp_layout_file) 211*a96a07bfSJ-Alves args["out_dir"] = os.path.abspath(sys.argv[3]) 212*a96a07bfSJ-Alves args["dualroot"] = sys.argv[4] == "dualroot" 213*a96a07bfSJ-Alves #Clear content of file "sp_gen.mk". 214*a96a07bfSJ-Alves with open(args["sp_gen_mk"], "w"): 215*a96a07bfSJ-Alves None 216*a96a07bfSJ-Alves return args, sp_layout 21707c44475SManish Pandey 218*a96a07bfSJ-Alvesif __name__ == "__main__": 219*a96a07bfSJ-Alves args, sp_layout = init_sp_actions(sys) 220*a96a07bfSJ-Alves SpSetupActions.run_actions(sp_layout, args) 221