1#!/usr/bin/env python3
2"""This hacky script generates a partition from a manifest file"""
3
4# Copyright The Mbed TLS Contributors
5# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6
7import json
8import os
9import sys
10from os import listdir
11
12if len(sys.argv) != 2:
13    print("Usage: psa_autogen <manifest_file>")
14    sys.exit(1)
15
16FILENAME = str(sys.argv[1])
17
18SCRIPT_PATH = os.path.dirname(__file__)
19GENERATED_H_PATH = os.path.join(SCRIPT_PATH, "..", "include", "psa_manifest")
20GENERATED_C_PATH = os.path.join(SCRIPT_PATH, "..", "src")
21
22MANIFEST_FILE = os.path.join(GENERATED_H_PATH, "manifest.h")
23PID_FILE = os.path.join(GENERATED_H_PATH, "pid.h")
24SID_FILE = os.path.join(GENERATED_H_PATH, "sid.h")
25
26with open(str(FILENAME), "r") as read_file:
27    data = json.load(read_file)
28    FILENAME = os.path.basename(FILENAME)
29    FILENAME = FILENAME.split('.')[0]
30    print("Base filename is " + str(FILENAME))
31
32    if str(data['psa_framework_version'] == "1.0"):
33        entry_point = str(data['entry_point'])
34        partition_name = str(data['name'])
35        services = data['services']
36        try:
37            irqs = data['irqs']
38        except KeyError:
39            irqs = []
40
41        try:
42            os.mkdir(GENERATED_H_PATH)
43            print("Generating psa_manifest directory")
44        except OSError:
45            print("PSA manifest directory already exists")
46
47        manifest_content = []
48        pids_content = []
49        sids_content = []
50
51        if len(services) > 28:
52           print ("Unsupported number of services")
53
54        count = 4 # For creating SID array
55        nsacl = "const int ns_allowed[32] = { "
56        policy = "const int strict_policy[32] = { "
57        qcode = "const char *psa_queues[] = { "
58        versions = "const uint32_t versions[32] = { "
59        queue_path = "psa_service_"
60        start = False
61
62        for x in range(0, count):
63            qcode = qcode + "\"\", "
64            nsacl = nsacl + "0, "
65            policy = policy + "0, "
66            versions = versions + "0, "
67
68        # Go through all the services to make sid.h and pid.h
69        for svc in services:
70            manifest_content.append("#define {}_SIGNAL    0x{:08x}".format(svc['signal'], 2**count))
71            sids_content.append("#define {}_SID    {}".format(svc['name'], svc['sid']))
72            qcode = qcode + "\"" + queue_path + str(int(svc['sid'], 16)) + "\","
73            ns_clients = svc['non_secure_clients']
74            print(str(svc))
75            if ns_clients == "true":
76                nsacl = nsacl + "1, "
77            else:
78                nsacl = nsacl + "0, "
79            try:
80                versions = versions + str(svc['minor_version']) + ", "
81            except KeyError:
82                versions = versions + "1, "
83
84            strict = 0
85            try:
86                if str(svc['minor_policy']).lower() == "strict":
87                    strict = 1
88                    policy = policy + "1, "
89                else:
90                    policy = policy + "0, "
91            except KeyError:
92                strict = 0
93                policy = policy + "0, "
94
95            count = count+1
96
97        sigcode = ""
98        handlercode = "void __sig_handler(int signo) {\n"
99        irqcount = count
100        for irq in irqs:
101            manifest_content.append("#define {}    0x{:08x}".format(irq['signal'], 2**irqcount))
102            sigcode = sigcode + "    signal({}, __sig_handler);\n".format(irq['source'])
103            handlercode = handlercode + \
104                          "    if (signo == {}) {{ raise_signal(0x{:08x}); }};\n".format(irq['source'], 2**irqcount)
105            irqcount = irqcount+1
106
107        handlercode = handlercode + "}\n"
108
109        while (count < 32):
110            qcode = qcode + "\"\", "
111            nsacl = nsacl + "0, "
112            versions = versions + "0, "
113            policy = policy + "0, "
114            count = count + 1
115
116        qcode = qcode + "};\n"
117        nsacl = nsacl + "};\n"
118        versions = versions + "};\n"
119        policy = policy + "};\n"
120
121        with open(MANIFEST_FILE, "wt") as output:
122            output.write("\n".join(manifest_content))
123        with open(SID_FILE, "wt") as output:
124            output.write("\n".join(sids_content))
125        with open(PID_FILE, "wt") as output:
126            output.write("\n".join(pids_content))
127
128        symbols = []
129
130        # Go through source files and look for the entrypoint
131        for root, directories, filenames in os.walk(GENERATED_C_PATH):
132            for filename in filenames:
133                if "psa_ff_bootstrap" in filename or filename == "psa_manifest":
134                    continue
135                try:
136                    fullpath = os.path.join(root,filename)
137                    with open(fullpath, encoding='utf-8') as currentFile:
138                        text = currentFile.read()
139                        if str(entry_point + "(") in text:
140                            symbols.append(filename)
141                except IOError:
142                    print("Couldn't open " + filename)
143                except UnicodeDecodeError:
144                    pass
145
146        print(str("Number of entrypoints detected: " + str(len(symbols))))
147        if len(symbols) < 1:
148            print("Couldn't find function " + entry_point)
149            sys.exit(1)
150        elif len(symbols) > 1:
151            print("Duplicate entrypoint symbol detected: " + str(symbols))
152            sys.exit(2)
153        else:
154            C_FILENAME = os.path.join(GENERATED_C_PATH, "psa_ff_bootstrap_" + partition_name + ".c")
155            c_content = []
156            c_content.append("#include <init.h>")
157            c_content.append("#include \"" + symbols[0] + "\"")
158            c_content.append("#include <signal.h>")
159            c_content.append(qcode)
160            c_content.append(nsacl)
161            c_content.append(policy)
162            c_content.append(versions)
163            c_content.append(handlercode)
164            c_content.append("int main(int argc, char *argv[]) {")
165            c_content.append("    (void) argc;")
166            c_content.append(sigcode)
167            c_content.append("    __init_psasim(psa_queues, 32, ns_allowed, versions,"
168                             "strict_policy);")
169            c_content.append("    " + entry_point + "(argc, argv);")
170            c_content.append("}")
171            with open(C_FILENAME, "wt") as output:
172                output.write("\n".join(c_content))
173
174            print("Success")
175