1#!/usr/bin/env python3
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2017, 2020, Linaro Limited
5# Copyright (c) 2020-2023, Arm Limited.
6#
7
8import argparse
9import array
10from elftools.elf.elffile import ELFFile, ELFError
11from elftools.elf.sections import SymbolTableSection
12import os
13import re
14import struct
15import uuid
16import zlib
17
18
19def get_args():
20    parser = argparse.ArgumentParser(
21        description='Converts a Trusted '
22        'Application ELF file into a C source file, ready for '
23        'inclusion in the TEE binary as an "early TA".')
24
25    parser.add_argument('--out', required=True,
26                        help='Name of the output C file')
27
28    parser.add_argument(
29        '--ta',
30        required=False,
31        help='Path to the TA binary. File name has to be: <uuid>.* '
32        'such as: 8aaaf200-2450-11e4-abe2-0002a5d5c51b.stripped.elf')
33
34    parser.add_argument(
35        '--sp',
36        required=False,
37        help='Path to the SP binary. File name has to be: <uuid>.* '
38        'such as: 8aaaf200-2450-11e4-abe2-0002a5d5c51b.stripped.elf')
39
40    parser.add_argument(
41        '--compress',
42        dest="compress",
43        action="store_true",
44        help='Compress the image using the DEFLATE '
45        'algorithm')
46
47    parser.add_argument(
48        '--manifest',
49        dest="manifest",
50        required=False,
51        help='path to the SP manifest file')
52
53    return parser.parse_args()
54
55
56def get_name(obj):
57    # Symbol or section .name can be a byte array or a string, we want a string
58    try:
59        name = obj.name.decode()
60    except (UnicodeDecodeError, AttributeError):
61        name = obj.name
62    return name
63
64
65def ta_get_flags(ta_f):
66    with open(ta_f, 'rb') as f:
67        elffile = ELFFile(f)
68
69        for s in elffile.iter_sections():
70            if isinstance(s, SymbolTableSection):
71                for symbol in s.iter_symbols():
72                    if symbol.name == 'ta_head':
73                        # Get the section containing the symbol
74                        s2 = elffile.get_section(symbol.entry['st_shndx'])
75                        offs = s2.header['sh_offset'] - s2.header['sh_addr']
76                        # ta_head offset into ELF binary
77                        offs = offs + symbol.entry['st_value']
78                        offs = offs + 20    # Flags offset in ta_head
79                        f.seek(offs)
80                        flags = struct.unpack('<I', f.read(4))[0]
81                        return flags
82
83        # For compatibility with older TAs
84        for s in elffile.iter_sections():
85            if get_name(s) == '.ta_head':
86                return struct.unpack('<16x4xI', s.data()[:24])[0]
87
88        raise Exception('.ta_head section not found')
89
90
91def sp_get_flags(sp_f):
92    with open(sp_f, 'rb') as f:
93        try:
94            elffile = ELFFile(f)
95        except ELFError:
96            # Binary format SP, return zero flags
97            return 0
98
99        for s in elffile.iter_sections():
100            if get_name(s) == '.sp_head':
101                return struct.unpack('<16x4xI', s.data()[:24])[0]
102
103        raise Exception('.sp_head section not found')
104
105
106def dump_bin(f, ts, compress):
107    with open(ts, 'rb') as _ts:
108        bytes = _ts.read()
109        uncompressed_size = len(bytes)
110        if compress:
111            bytes = zlib.compress(bytes)
112        size = len(bytes)
113
114    i = 0
115    while i < size:
116        if i % 8 == 0:
117            f.write('\t\t')
118        f.write(hex(bytes[i]) + ',')
119        i = i + 1
120        if i % 8 == 0 or i == size:
121            f.write('\n')
122        else:
123            f.write(' ')
124    return (size, uncompressed_size)
125
126
127def main():
128    args = get_args()
129    is_sp = False
130
131    if args.ta is None and args.sp is None:
132        raise Exception('The --ta or the --sp flag is required')
133
134    if args.ta is not None and args.sp is not None:
135        raise Exception('The --ta and the --sp can\'t be combined')
136
137    if args.ta is not None:
138        ts = args.ta
139        is_sp = False
140
141    if args.sp is not None:
142        ts = args.sp
143        is_sp = True
144
145    ts_uuid = uuid.UUID(re.sub(r'\..*', '', os.path.basename(ts)))
146
147    f = open(args.out, 'w')
148    f.write('/* Generated from ' + ts + ' by ' +
149            os.path.basename(__file__) + ' */\n\n')
150    f.write('#include <kernel/embedded_ts.h>\n\n')
151    f.write('#include <scattered_array.h>\n\n')
152    f.write('const uint8_t ts_bin_' + ts_uuid.hex + '[] = {\n')
153    ts_size, ts_uncompressed_size = dump_bin(f, ts, args.compress)
154    f.write('};\n')
155
156    if is_sp:
157
158        f.write('#include <kernel/secure_partition.h>\n\n')
159        f.write('const uint8_t fdt_bin_' + ts_uuid.hex + '[] = {\n')
160        dump_bin(f, args.manifest, False)
161        f.write('};\n')
162        f.write('SCATTERED_ARRAY_DEFINE_PG_ITEM(sp_images, struct \
163                sp_image) = {\n')
164        f.write('\t.fdt = fdt_bin_' + ts_uuid.hex + ',\n')
165
166        f.write('. image = {')
167        f.write('\t.flags = 0x{:04x},\n'.format(sp_get_flags(ts)))
168    else:
169        f.write('SCATTERED_ARRAY_DEFINE_PG_ITEM(early_tas, struct \
170                embedded_ts) = {\n')
171        f.write('\t.flags = 0x{:04x},\n'.format(ta_get_flags(ts)))
172    f.write('\t.uuid = {\n')
173    f.write('\t\t.timeLow = 0x{:08x},\n'.format(ts_uuid.time_low))
174    f.write('\t\t.timeMid = 0x{:04x},\n'.format(ts_uuid.time_mid))
175    f.write('\t\t.timeHiAndVersion = ' +
176            '0x{:04x},\n'.format(ts_uuid.time_hi_version))
177    f.write('\t\t.clockSeqAndNode = {\n')
178    csn = '{0:02x}{1:02x}{2:012x}'.format(ts_uuid.clock_seq_hi_variant,
179                                          ts_uuid.clock_seq_low, ts_uuid.node)
180    f.write('\t\t\t')
181    f.write(', '.join('0x' + csn[i:i + 2] for i in range(0, len(csn), 2)))
182    f.write('\n\t\t},\n\t},\n')
183    f.write('\t.size = sizeof(ts_bin_' + ts_uuid.hex +
184            '), /* {:d} */\n'.format(ts_size))
185    f.write('\t.ts = ts_bin_' + ts_uuid.hex + ',\n')
186    if args.compress:
187        f.write('\t.uncompressed_size = '
188                '{:d},\n'.format(ts_uncompressed_size))
189    if is_sp:
190        f.write('}\n')
191    f.write('};\n')
192    f.close()
193
194
195if __name__ == "__main__":
196    main()
197