xref: /rk3399_ARM-atf/tools/sptool/sp_mk_generator.py (revision a96a07bfb66b7d38fe3da824e8ba183967659008)
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