1#!/usr/bin/python3
2# Copyright (c) 2020-2021, Arm Limited. All rights reserved.
3#
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
14FDT_SOURCES, FIP_ARGS, CRT_ARGS and SPTOOL_ARGS which are used in later build
15steps.
16This script also gets SP "uuid" from parsing its PM and converting it to a
17standard format.
18
19param1: Generated mk file "sp_gen.mk"
20param2: "SP_LAYOUT_FILE", json file containing platform provided information
21param3: plat out directory
22param4: CoT parameter
23
24Generated "sp_gen.mk" file contains triplet of following information for each
25Secure Partition entry
26    FDT_SOURCES +=  sp1.dts
27    SPTOOL_ARGS += -i sp1.bin:sp1.dtb -o sp1.pkg
28    FIP_ARGS += --blob uuid=XXXXX-XXX...,file=sp1.pkg
29    CRT_ARGS += --sp-pkg1 sp1.pkg
30
31A typical SP_LAYOUT_FILE file will look like
32{
33        "SP1" : {
34                "image": "sp1.bin",
35                "pm": "test/sp1.dts"
36        },
37
38        "SP2" : {
39                "image": "sp2.bin",
40                "pm": "test/sp2.dts"
41        }
42
43        ...
44}
45
46"""
47
48import getopt
49import json
50import os
51import re
52import sys
53import uuid
54
55with open(sys.argv[2],'r') as in_file:
56    data = json.load(in_file)
57json_file = os.path.abspath(sys.argv[2])
58json_dir = os.path.dirname(json_file)
59gen_file = os.path.abspath(sys.argv[1])
60out_dir = os.path.abspath(sys.argv[3])
61dtb_dir = out_dir + "/fdts/"
62MAX_SP = 8
63dualroot = sys.argv[4].lower() == "dualroot"
64split = int(MAX_SP / 2)
65print(dtb_dir)
66platform_count = 1
67sip_count = 1
68
69with open(gen_file, 'w') as out_file:
70    for idx, key in enumerate(data.keys()):
71
72        pkg_num = idx + 1
73
74        if (pkg_num > MAX_SP):
75            print("WARNING: Too many secure partitions\n")
76            exit(-1)
77
78        if dualroot:
79            owner = data[key].get('owner')
80            if owner == "Plat":
81                if (platform_count > split):
82                    print("WARNING: Maximum Secure partitions by Plat " +
83                    "have been exceeded (" + str(split) + ")\n")
84                    exit(-1)
85                pkg_num = split + platform_count
86                platform_count += 1
87            elif (sip_count > split):
88                print("WARNING: Maximum Secure partitions by SiP " +
89                "have been exceeded (" + str(split) + ")\n")
90                exit(-1)
91            else:
92                pkg_num = sip_count
93                sip_count += 1
94
95        """
96        Append FDT_SOURCES
97        """
98        dts = os.path.join(json_dir, data[key]['pm'])
99        dtb = dtb_dir + os.path.basename(data[key]['pm'][:-1] + "b")
100        out_file.write("FDT_SOURCES += " + dts + "\n")
101
102        """
103        Update SPTOOL_ARGS
104        """
105        dst = out_dir + "/" + key + ".pkg"
106        src = [ json_dir + "/" + data[key]['image'] , dtb  ]
107        out_file.write("SPTOOL_ARGS += -i " + ":".join(src) + " -o " + dst + "\n")
108
109        """
110        Extract uuid from partition manifest
111        """
112        pm_file = open(dts)
113        for line in pm_file:
114            if "uuid" in line:
115                # re.findall returns a list of string tuples.
116                # uuid_hex is the first item in this list representing the four
117                # uuid hex integers from the manifest uuid field. The heading
118                # '0x' of the hexadecimal representation is stripped out.
119                # e.g. uuid = <0x1e67b5b4 0xe14f904a 0x13fb1fb8 0xcbdae1da>;
120                # uuid_hex = ('1e67b5b4', 'e14f904a', '13fb1fb8', 'cbdae1da')
121                uuid_hex = re.findall(r'0x([0-9a-f]+) 0x([0-9a-f]+) 0x([0-9a-f]+) 0x([0-9a-f]+)', line)[0];
122
123        # uuid_hex is a list of four hex string values
124        if len(uuid_hex) != 4:
125            print("ERROR: malformed UUID")
126            exit(-1)
127
128        # The uuid field in SP manifest is the little endian representation
129        # mapped to arguments as described in SMCCC section 5.3.
130        # Convert each unsigned integer value to a big endian representation
131        # required by fiptool.
132        y=list(map(bytearray.fromhex, uuid_hex))
133        z=(int.from_bytes(y[0], byteorder='little', signed=False),
134        int.from_bytes(y[1], byteorder='little', signed=False),
135        int.from_bytes(y[2], byteorder='little', signed=False),
136        int.from_bytes(y[3], byteorder='little', signed=False))
137        uuid_std = uuid.UUID(f'{z[0]:04x}{z[1]:04x}{z[2]:04x}{z[3]:04x}')
138
139        """
140        Append FIP_ARGS
141        """
142        out_file.write("FIP_ARGS += --blob uuid=" + str(uuid_std) + ",file=" + dst + "\n")
143
144        """
145        Append CRT_ARGS
146        """
147
148        out_file.write("CRT_ARGS += --sp-pkg" + str(pkg_num) + " " + dst + "\n")
149        out_file.write("\n")
150