xref: /rk3399_ARM-atf/tools/sptool/sp_mk_generator.py (revision 6a3225e2277df18e5c3aceb6173579cccefece51)
1ce2b1ec6SManish Pandey#!/usr/bin/python3
204e7f808SJ-Alves# Copyright (c) 2020-2024, 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
2420629b31SKarl Meakinparam5: Generated dts file "sp_list_fragment.dts"
25ce2b1ec6SManish Pandey
26ce2b1ec6SManish PandeyGenerated "sp_gen.mk" file contains triplet of following information for each
27ce2b1ec6SManish PandeySecure Partition entry
28ce2b1ec6SManish Pandey    FDT_SOURCES +=  sp1.dts
29ce2b1ec6SManish Pandey    SPTOOL_ARGS += -i sp1.bin:sp1.dtb -o sp1.pkg
30ce2b1ec6SManish Pandey    FIP_ARGS += --blob uuid=XXXXX-XXX...,file=sp1.pkg
3107c44475SManish Pandey    CRT_ARGS += --sp-pkg1 sp1.pkg
32ce2b1ec6SManish Pandey
33ce2b1ec6SManish PandeyA typical SP_LAYOUT_FILE file will look like
34ce2b1ec6SManish Pandey{
35ce2b1ec6SManish Pandey        "SP1" : {
36ce2b1ec6SManish Pandey                "image": "sp1.bin",
37ce2b1ec6SManish Pandey                "pm": "test/sp1.dts"
38ce2b1ec6SManish Pandey        },
39ce2b1ec6SManish Pandey
40ce2b1ec6SManish Pandey        "SP2" : {
41ce2b1ec6SManish Pandey                "image": "sp2.bin",
425ac60ea1SImre Kis                "pm": "test/sp2.dts",
435ac60ea1SImre Kis                "uuid": "1b1820fe-48f7-4175-8999-d51da00b7c9f"
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
55a96a07bfSJ-Alvesfrom spactions import SpSetupActions
56ce2b1ec6SManish Pandey
571e7528ecSRuari PhippsMAX_SP = 8
58a96a07bfSJ-AlvesUUID_LEN = 4
59ce2b1ec6SManish Pandey
60a96a07bfSJ-Alves# Some helper functions to access args propagated to the action functions in
61a96a07bfSJ-Alves# SpSetupActions framework.
62a96a07bfSJ-Alvesdef check_sp_mk_gen(args :dict):
63a96a07bfSJ-Alves    if "sp_gen_mk" not in args.keys():
64a96a07bfSJ-Alves        raise Exception(f"Path to file sp_gen.mk needs to be in 'args'.")
651e7528ecSRuari Phipps
66a96a07bfSJ-Alvesdef check_out_dir(args :dict):
67a96a07bfSJ-Alves    if "out_dir" not in args.keys() or not os.path.isdir(args["out_dir"]):
68a96a07bfSJ-Alves        raise Exception("Define output folder with \'out_dir\' key.")
691e7528ecSRuari Phipps
70a96a07bfSJ-Alvesdef check_sp_layout_dir(args :dict):
71a96a07bfSJ-Alves    if "sp_layout_dir" not in args.keys() or not os.path.isdir(args["sp_layout_dir"]):
72a96a07bfSJ-Alves        raise Exception("Define output folder with \'sp_layout_dir\' key.")
73a96a07bfSJ-Alves
74a96a07bfSJ-Alvesdef write_to_sp_mk_gen(content, args :dict):
75a96a07bfSJ-Alves    check_sp_mk_gen(args)
76a96a07bfSJ-Alves    with open(args["sp_gen_mk"], "a") as f:
77a96a07bfSJ-Alves        f.write(f"{content}\n")
78a96a07bfSJ-Alves
79a96a07bfSJ-Alvesdef get_sp_manifest_full_path(sp_node, args :dict):
80a96a07bfSJ-Alves    check_sp_layout_dir(args)
81a96a07bfSJ-Alves    return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["pm"]))
82a96a07bfSJ-Alves
83a96a07bfSJ-Alvesdef get_sp_img_full_path(sp_node, args :dict):
84a96a07bfSJ-Alves    check_sp_layout_dir(args)
85a96a07bfSJ-Alves    return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["image"]))
86a96a07bfSJ-Alves
87a96a07bfSJ-Alvesdef get_sp_pkg(sp, args :dict):
88a96a07bfSJ-Alves    check_out_dir(args)
89a96a07bfSJ-Alves    return os.path.join(args["out_dir"], f"{sp}.pkg")
90a96a07bfSJ-Alves
91a96a07bfSJ-Alvesdef is_line_in_sp_gen(line, args :dict):
92a96a07bfSJ-Alves    with open(args["sp_gen_mk"], "r") as f:
93a96a07bfSJ-Alves        sppkg_rule = [l for l in f if line in l]
941a28f290SJ-Alves    return len(sppkg_rule) != 0
95a96a07bfSJ-Alves
96a96a07bfSJ-Alvesdef get_file_from_layout(node):
97a96a07bfSJ-Alves    ''' Helper to fetch a file path from sp_layout.json. '''
98a96a07bfSJ-Alves    if type(node) is dict and "file" in node.keys():
99a96a07bfSJ-Alves        return node["file"]
100a96a07bfSJ-Alves    return node
101a96a07bfSJ-Alves
102a96a07bfSJ-Alvesdef get_offset_from_layout(node):
103a96a07bfSJ-Alves    ''' Helper to fetch an offset from sp_layout.json. '''
104a96a07bfSJ-Alves    if type(node) is dict and "offset" in node.keys():
105a96a07bfSJ-Alves        return int(node["offset"], 0)
106a96a07bfSJ-Alves    return None
107a96a07bfSJ-Alves
108a96a07bfSJ-Alvesdef get_image_offset(node):
109a96a07bfSJ-Alves    ''' Helper to fetch image offset from sp_layout.json '''
110a96a07bfSJ-Alves    return get_offset_from_layout(node["image"])
111a96a07bfSJ-Alves
112a96a07bfSJ-Alvesdef get_pm_offset(node):
113a96a07bfSJ-Alves    ''' Helper to fetch pm offset from sp_layout.json '''
114a96a07bfSJ-Alves    return get_offset_from_layout(node["pm"])
115a96a07bfSJ-Alves
11620629b31SKarl Meakindef get_uuid(sp_layout, sp, args :dict):
11720629b31SKarl Meakin    ''' Helper to fetch uuid from pm file listed in sp_layout.json'''
11820629b31SKarl Meakin    if "uuid" in sp_layout[sp]:
11920629b31SKarl Meakin        # Extract the UUID from the JSON file if the SP entry has a 'uuid' field
12020629b31SKarl Meakin        uuid_std = uuid.UUID(sp_layout[sp]['uuid'])
12120629b31SKarl Meakin    else:
12220629b31SKarl Meakin        with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
12320629b31SKarl Meakin            uuid_lines = [l for l in pm_f if 'uuid' in l]
12420629b31SKarl Meakin        assert(len(uuid_lines) == 1)
12520629b31SKarl Meakin        # The uuid field in SP manifest is the little endian representation
12620629b31SKarl Meakin        # mapped to arguments as described in SMCCC section 5.3.
12720629b31SKarl Meakin        # Convert each unsigned integer value to a big endian representation
12820629b31SKarl Meakin        # required by fiptool.
12920629b31SKarl Meakin        uuid_parsed = re.findall("0x([0-9a-f]+)", uuid_lines[0])
13020629b31SKarl Meakin        y = list(map(bytearray.fromhex, uuid_parsed))
13120629b31SKarl Meakin        z = [int.from_bytes(i, byteorder='little', signed=False) for i in y]
13220629b31SKarl Meakin        uuid_std = uuid.UUID(f'{z[0]:08x}{z[1]:08x}{z[2]:08x}{z[3]:08x}')
13320629b31SKarl Meakin    return uuid_std
13420629b31SKarl Meakin
13520629b31SKarl Meakindef get_load_address(sp_layout, sp, args :dict):
13620629b31SKarl Meakin    ''' Helper to fetch load-address from pm file listed in sp_layout.json'''
13720629b31SKarl Meakin    with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
13820629b31SKarl Meakin        load_address_lines = [l for l in pm_f if 'load-address' in l]
13904e7f808SJ-Alves
140*6a3225e2SJ-Alves    if len(load_address_lines) != 1:
14104e7f808SJ-Alves        return None
14204e7f808SJ-Alves
14320629b31SKarl Meakin    load_address_parsed = re.search("(0x[0-9a-f]+)", load_address_lines[0])
14420629b31SKarl Meakin    return load_address_parsed.group(0)
14520629b31SKarl Meakin
14620629b31SKarl Meakin
147a96a07bfSJ-Alves@SpSetupActions.sp_action(global_action=True)
148a96a07bfSJ-Alvesdef check_max_sps(sp_layout, _, args :dict):
149a96a07bfSJ-Alves    ''' Check validate the maximum number of SPs is respected. '''
150a96a07bfSJ-Alves    if len(sp_layout.keys()) > MAX_SP:
151a96a07bfSJ-Alves        raise Exception(f"Too many SPs in SP layout file. Max: {MAX_SP}")
152a96a07bfSJ-Alves    return args
153a96a07bfSJ-Alves
154a96a07bfSJ-Alves@SpSetupActions.sp_action
155a96a07bfSJ-Alvesdef gen_fdt_sources(sp_layout, sp, args :dict):
156a96a07bfSJ-Alves    ''' Generate FDT_SOURCES values for a given SP. '''
157a96a07bfSJ-Alves    manifest_path = get_sp_manifest_full_path(sp_layout[sp], args)
158a96a07bfSJ-Alves    write_to_sp_mk_gen(f"FDT_SOURCES += {manifest_path}", args)
159a96a07bfSJ-Alves    return args
160a96a07bfSJ-Alves
161a96a07bfSJ-Alves@SpSetupActions.sp_action
162822c7279SJ-Alvesdef gen_sptool_args(sp_layout, sp, args :dict):
163822c7279SJ-Alves    ''' Generate Sp Pkgs rules. '''
164a96a07bfSJ-Alves    sp_pkg = get_sp_pkg(sp, args)
165822c7279SJ-Alves    sp_dtb_name = os.path.basename(get_file_from_layout(sp_layout[sp]["pm"]))[:-1] + "b"
166a96a07bfSJ-Alves    sp_dtb = os.path.join(args["out_dir"], f"fdts/{sp_dtb_name}")
1674daeaf34SJens Wiklander    sp_img = get_sp_img_full_path(sp_layout[sp], args)
168822c7279SJ-Alves
169822c7279SJ-Alves    # Do not generate rule if already there.
170822c7279SJ-Alves    if is_line_in_sp_gen(f'{sp_pkg}:', args):
171822c7279SJ-Alves        return args
172822c7279SJ-Alves    write_to_sp_mk_gen(f"SP_PKGS += {sp_pkg}\n", args)
173822c7279SJ-Alves
1744daeaf34SJens Wiklander    sptool_args = f" -i {sp_img}:{sp_dtb}"
175822c7279SJ-Alves    pm_offset = get_pm_offset(sp_layout[sp])
176822c7279SJ-Alves    sptool_args += f" --pm-offset {pm_offset}" if pm_offset is not None else ""
177822c7279SJ-Alves    image_offset = get_image_offset(sp_layout[sp])
178822c7279SJ-Alves    sptool_args += f" --img-offset {image_offset}" if image_offset is not None else ""
179822c7279SJ-Alves    sptool_args += f" -o {sp_pkg}"
180822c7279SJ-Alves    sppkg_rule = f'''
1814daeaf34SJens Wiklander{sp_pkg}: {sp_dtb} {sp_img}
182822c7279SJ-Alves\t$(Q)echo Generating {sp_pkg}
183822c7279SJ-Alves\t$(Q)$(PYTHON) $(SPTOOL) {sptool_args}
184822c7279SJ-Alves'''
185822c7279SJ-Alves    write_to_sp_mk_gen(sppkg_rule, args)
186a96a07bfSJ-Alves    return args
187a96a07bfSJ-Alves
188a96a07bfSJ-Alves@SpSetupActions.sp_action(global_action=True, exec_order=1)
189a96a07bfSJ-Alvesdef check_dualroot(sp_layout, _, args :dict):
190a96a07bfSJ-Alves    ''' Validate the amount of SPs from SiP and Platform owners. '''
191a96a07bfSJ-Alves    if not args.get("dualroot"):
192a96a07bfSJ-Alves        return args
193a96a07bfSJ-Alves    args["split"] =  int(MAX_SP / 2)
194a96a07bfSJ-Alves    owners = [sp_layout[sp].get("owner") for sp in sp_layout]
195a96a07bfSJ-Alves    args["plat_max_count"] = owners.count("Plat")
196a96a07bfSJ-Alves    # If it is owned by the platform owner, it is assigned to the SiP.
197a96a07bfSJ-Alves    args["sip_max_count"] = len(sp_layout.keys()) - args["plat_max_count"]
198a96a07bfSJ-Alves    if  args["sip_max_count"] > args["split"] or args["sip_max_count"] > args["split"]:
199a96a07bfSJ-Alves        print(f"WARN: SiP Secure Partitions should not be more than {args['split']}")
200a96a07bfSJ-Alves    # Counters for gen_crt_args.
201a96a07bfSJ-Alves    args["sip_count"] = 1
202a96a07bfSJ-Alves    args["plat_count"] = 1
203a96a07bfSJ-Alves    return args
204a96a07bfSJ-Alves
205a96a07bfSJ-Alves@SpSetupActions.sp_action
206a96a07bfSJ-Alvesdef gen_crt_args(sp_layout, sp, args :dict):
207a96a07bfSJ-Alves    ''' Append CRT_ARGS. '''
208a96a07bfSJ-Alves    # If "dualroot" is configured, 'sp_pkg_idx' depends on whether the SP is owned
209a96a07bfSJ-Alves    # by the "SiP" or the "Plat".
210a96a07bfSJ-Alves    if args.get("dualroot"):
211a96a07bfSJ-Alves        # If the owner is not specified as "Plat", default to "SiP".
212a96a07bfSJ-Alves        if sp_layout[sp].get("owner") == "Plat":
213a96a07bfSJ-Alves            if args["plat_count"] > args["plat_max_count"]:
214a96a07bfSJ-Alves                raise ValueError("plat_count can't surpass plat_max_count in args.")
215a96a07bfSJ-Alves            sp_pkg_idx = args["plat_count"] + args["split"]
216a96a07bfSJ-Alves            args["plat_count"] += 1
2171e7528ecSRuari Phipps        else:
218a96a07bfSJ-Alves            if args["sip_count"] > args["sip_max_count"]:
219a96a07bfSJ-Alves                raise ValueError("sip_count can't surpass sip_max_count in args.")
220a96a07bfSJ-Alves            sp_pkg_idx = args["sip_count"]
221a96a07bfSJ-Alves            args["sip_count"] += 1
222a96a07bfSJ-Alves    else:
223a96a07bfSJ-Alves        sp_pkg_idx = [k for k in sp_layout.keys()].index(sp) + 1
224a96a07bfSJ-Alves    write_to_sp_mk_gen(f"CRT_ARGS += --sp-pkg{sp_pkg_idx} {get_sp_pkg(sp, args)}\n", args)
225a96a07bfSJ-Alves    return args
2261e7528ecSRuari Phipps
227a96a07bfSJ-Alves@SpSetupActions.sp_action
228a96a07bfSJ-Alvesdef gen_fiptool_args(sp_layout, sp, args :dict):
229a96a07bfSJ-Alves    ''' Generate arguments for the FIP Tool. '''
23020629b31SKarl Meakin    uuid_std = get_uuid(sp_layout, sp, args)
231a96a07bfSJ-Alves    write_to_sp_mk_gen(f"FIP_ARGS += --blob uuid={str(uuid_std)},file={get_sp_pkg(sp, args)}\n", args)
232a96a07bfSJ-Alves    return args
233ce2b1ec6SManish Pandey
23420629b31SKarl Meakin@SpSetupActions.sp_action
23520629b31SKarl Meakindef gen_fconf_fragment(sp_layout, sp, args: dict):
23620629b31SKarl Meakin    ''' Generate the fconf fragment file'''
23720629b31SKarl Meakin    with open(args["fconf_fragment"], "a") as f:
23820629b31SKarl Meakin        uuid = get_uuid(sp_layout, sp, args)
23920629b31SKarl Meakin        owner = "Plat" if sp_layout[sp].get("owner") == "Plat" else "SiP"
24020629b31SKarl Meakin
24120629b31SKarl Meakin        if "physical-load-address" in sp_layout[sp].keys():
24220629b31SKarl Meakin            load_address = sp_layout[sp]["physical-load-address"]
24320629b31SKarl Meakin        else:
24420629b31SKarl Meakin            load_address = get_load_address(sp_layout, sp, args)
24520629b31SKarl Meakin
24604e7f808SJ-Alves        if load_address is not None:
24720629b31SKarl Meakin            f.write(
24820629b31SKarl Meakinf'''\
24920629b31SKarl Meakin{sp} {{
25020629b31SKarl Meakin    uuid = "{uuid}";
25120629b31SKarl Meakin    load-address = <{load_address}>;
25220629b31SKarl Meakin    owner = "{owner}";
25320629b31SKarl Meakin}};
25420629b31SKarl Meakin
25520629b31SKarl Meakin''')
25604e7f808SJ-Alves        else:
25704e7f808SJ-Alves            print("Warning: No load-address was found in the SP manifest.")
25804e7f808SJ-Alves
25920629b31SKarl Meakin    return args
26020629b31SKarl Meakin
261a96a07bfSJ-Alvesdef init_sp_actions(sys):
262a96a07bfSJ-Alves    # Initialize arguments for the SP actions framework
263a96a07bfSJ-Alves    args = {}
264a96a07bfSJ-Alves    args["sp_gen_mk"] = os.path.abspath(sys.argv[1])
26520629b31SKarl Meakin    sp_layout_file = os.path.abspath(sys.argv[2])
266a96a07bfSJ-Alves    args["sp_layout_dir"] = os.path.dirname(sp_layout_file)
267a96a07bfSJ-Alves    args["out_dir"] = os.path.abspath(sys.argv[3])
268a96a07bfSJ-Alves    args["dualroot"] = sys.argv[4] == "dualroot"
26920629b31SKarl Meakin    args["fconf_fragment"] = os.path.abspath(sys.argv[5])
27020629b31SKarl Meakin
27120629b31SKarl Meakin
27220629b31SKarl Meakin    with open(sp_layout_file) as json_file:
27320629b31SKarl Meakin        sp_layout = json.load(json_file)
274a96a07bfSJ-Alves    #Clear content of file "sp_gen.mk".
275a96a07bfSJ-Alves    with open(args["sp_gen_mk"], "w"):
276a96a07bfSJ-Alves        None
27720629b31SKarl Meakin    #Clear content of file "fconf_fragment".
27820629b31SKarl Meakin    with open(args["fconf_fragment"], "w"):
27920629b31SKarl Meakin        None
28020629b31SKarl Meakin
281a96a07bfSJ-Alves    return args, sp_layout
28207c44475SManish Pandey
283a96a07bfSJ-Alvesif __name__ == "__main__":
284a96a07bfSJ-Alves    args, sp_layout = init_sp_actions(sys)
285a96a07bfSJ-Alves    SpSetupActions.run_actions(sp_layout, args)
286