xref: /optee_os/scripts/gen_tee_bin.py (revision 3c51966baa0357e0b150e3946c91d7a91ba6d0f4)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2019, Linaro Limited
5#
6
7from __future__ import print_function
8from __future__ import division
9
10import argparse
11import sys
12import struct
13import re
14import hashlib
15try:
16    from elftools.elf.elffile import ELFFile
17    from elftools.elf.constants import SH_FLAGS
18    from elftools.elf.sections import SymbolTableSection
19
20except ImportError:
21    print("""
22***
23Can't find elftools module. Probably it is not installed on your system.
24You can install this module with
25
26$ apt install python3-pyelftools
27
28if you are using Ubuntu. Or try to search for "pyelftools" or "elftools" in
29your package manager if you are using some other distribution.
30***
31""")
32    raise
33
34small_page_size = 4 * 1024
35elffile_symbols = None
36tee_pageable_bin = None
37tee_pager_bin = None
38
39
40def eprint(*args, **kwargs):
41    print(*args, file=sys.stderr, **kwargs)
42
43
44def get_symbol(elffile, name):
45    global elffile_symbols
46    if elffile_symbols is None:
47        elffile_symbols = dict()
48        symbol_tables = [s for s in elffile.iter_sections()
49                         if isinstance(s, SymbolTableSection)]
50        for section in symbol_tables:
51            for symbol in section.iter_symbols():
52                if symbol['st_info']['bind'] == 'STB_GLOBAL':
53                    elffile_symbols[symbol.name] = symbol
54
55    try:
56        return elffile_symbols[name]
57    except (KeyError):
58        eprint("Cannot find symbol %s" % name)
59        sys.exit(1)
60
61
62def get_sections(elffile, pad_to, skip_names, dump_names):
63    last_end = 0
64    bin_data = bytearray()
65
66    for section in elffile.iter_sections():
67        if (section['sh_type'] == 'SHT_NOBITS' or
68                not (section['sh_flags'] & SH_FLAGS.SHF_ALLOC) or
69                skip_names.match(section.name) or
70                not dump_names.match(section.name)):
71            continue
72
73        if last_end == 0:
74            bin_data = section.data()
75        else:
76            if section['sh_addr'] > last_end:
77                bin_data += bytearray(section['sh_addr'] - last_end)
78            bin_data += section.data()
79
80        last_end = section['sh_addr'] + section['sh_size']
81
82    if pad_to > last_end:
83        bin_data += bytearray(pad_to - last_end)
84        last_end = pad_to
85
86    return bin_data
87
88
89def get_pageable_bin(elffile):
90    global tee_pageable_bin
91    if tee_pageable_bin is None:
92        pad_to = 0
93        skip_names = re.compile(r'^$')
94        dump_names = re.compile(r'^\..*_(pageable|init)$')
95        tee_pageable_bin = get_sections(elffile, pad_to, skip_names,
96                                        dump_names)
97    return tee_pageable_bin
98
99
100def get_pager_bin(elffile):
101    global tee_pager_bin
102    if tee_pager_bin is None:
103        pad_to = get_symbol(elffile, '__data_end')['st_value']
104        skip_names = re.compile(r'^\..*_(pageable|init)$')
105        dump_names = re.compile(r'')
106        tee_pager_bin = get_sections(elffile, pad_to, skip_names, dump_names)
107
108    return tee_pager_bin
109
110
111def output_pager_bin(elffile, outf):
112    outf.write(get_pager_bin(elffile))
113
114
115def output_pageable_bin(elffile, outf):
116    outf.write(get_pageable_bin(elffile))
117
118
119def get_arch_id(elffile):
120    e_machine = elffile.header['e_machine']
121    if e_machine == 'EM_ARM':
122        return 0
123    if e_machine == 'EM_AARCH64':
124        return 1
125    eprint('Unknown e_machine "%s"' % e_machine)
126    sys.exit(1)
127
128
129def get_init_load_addr(elffile):
130    init_load_addr = get_symbol(elffile, '_start')['st_value']
131    init_load_addr_hi = init_load_addr >> 32
132    init_load_addr_lo = init_load_addr & 0xffffffff
133    return init_load_addr_hi, init_load_addr_lo
134
135
136def output_header_v1(elffile, outf):
137    arch_id = get_arch_id(elffile)
138    pager_bin = get_pager_bin(elffile)
139    pageable_bin = get_pageable_bin(elffile)
140    init_mem_usage = get_symbol(elffile, '__init_mem_usage')['st_value']
141    init_load_addr = get_init_load_addr(elffile)
142    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
143    pager_bin_size = len(pager_bin)
144    paged_area_size = len(pageable_bin)
145    hash_size = (paged_area_size // small_page_size *
146                 hashlib.sha256().digest_size)
147
148    init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
149                 hash_size)
150    paged_size = paged_area_size - min(init_bin_size, paged_area_size)
151
152    if paged_area_size % small_page_size != 0:
153        eprint("pageable size not a multiple of 4K: "
154               "{}".format(paged_area_size))
155        sys.exit(1)
156
157    magic = 0x4554504f  # 'OPTE'
158    version = 1
159    flags = 0
160    outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags,
161                           init_size, init_load_addr[0], init_load_addr[1],
162                           init_mem_usage, paged_size))
163    outf.write(pager_bin)
164    outf.write(pageable_bin[:init_bin_size])
165    for n in range(0, len(pageable_bin), small_page_size):
166        page = pageable_bin[n:n + small_page_size]
167        outf.write(hashlib.sha256(page).digest())
168    outf.write(pageable_bin[init_bin_size:])
169
170
171def output_header_v2(elffile, outf):
172    arch_id = get_arch_id(elffile)
173    init_load_addr = get_init_load_addr(elffile)
174    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
175    pager_bin_size = len(get_pager_bin(elffile))
176    paged_area_size = len(get_pageable_bin(elffile))
177    hash_size = (paged_area_size // small_page_size *
178                 hashlib.sha256().digest_size)
179
180    if paged_area_size % small_page_size != 0:
181        eprint("pageable size not a multiple of 4K: "
182               "{}".format(paged_area_size))
183        sys.exit(1)
184
185    init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
186                 hash_size)
187    paged_size = paged_area_size - min(init_bin_size, paged_area_size)
188
189    magic = 0x4554504f  # 'OPTE'
190    version = 2
191    flags = 0
192    nb_images = 1 if paged_size == 0 else 2
193    outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags,
194                           nb_images))
195    outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1],
196                           0, init_size))
197    if nb_images == 2:
198        outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))
199
200
201def output_pager_v2(elffile, outf):
202    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
203    pageable_bin = get_pageable_bin(elffile)
204
205    if len(pageable_bin) % small_page_size != 0:
206        eprint("pageable size not a multiple of 4K: "
207               "{}".format(paged_area_size))
208        sys.exit(1)
209
210    outf.write(get_pager_bin(elffile))
211    outf.write(pageable_bin[:init_bin_size])
212    for n in range(0, len(pageable_bin), small_page_size):
213        page = pageable_bin[n:n + small_page_size]
214        outf.write(hashlib.sha256(page).digest())
215
216
217def output_pageable_v2(elffile, outf):
218    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
219    outf.write(get_pageable_bin(elffile)[init_bin_size:])
220
221
222def get_args():
223    parser = argparse.ArgumentParser()
224
225    parser.add_argument('--input',
226                        required=True, type=argparse.FileType('rb'),
227                        help='The input tee.elf')
228
229    parser.add_argument('--out_tee_bin',
230                        required=False, type=argparse.FileType('wb'),
231                        help='The output tee.bin')
232
233    parser.add_argument('--out_tee_pager_bin',
234                        required=False, type=argparse.FileType('wb'),
235                        help='The output tee_pager.bin')
236
237    parser.add_argument('--out_tee_pageable_bin',
238                        required=False, type=argparse.FileType('wb'),
239                        help='The output tee_pageable.bin')
240
241    parser.add_argument('--out_header_v2',
242                        required=False, type=argparse.FileType('wb'),
243                        help='The output tee_header_v2.bin')
244
245    parser.add_argument('--out_pager_v2',
246                        required=False, type=argparse.FileType('wb'),
247                        help='The output tee_pager_v2.bin')
248
249    parser.add_argument('--out_pageable_v2',
250                        required=False, type=argparse.FileType('wb'),
251                        help='The output tee_pageable_v2.bin')
252
253    return parser.parse_args()
254
255
256def main():
257    args = get_args()
258
259    elffile = ELFFile(args.input)
260
261    if args.out_tee_bin:
262        output_header_v1(elffile, args.out_tee_bin)
263
264    if args.out_tee_pager_bin:
265        output_pager_bin(elffile, args.out_tee_pager_bin)
266
267    if args.out_tee_pageable_bin:
268        output_pageable_bin(elffile, args.out_tee_pageable_bin)
269
270    if args.out_header_v2:
271        output_header_v2(elffile, args.out_header_v2)
272
273    if args.out_pager_v2:
274        output_pager_v2(elffile, args.out_pager_v2)
275
276    if args.out_pageable_v2:
277        output_pageable_v2(elffile, args.out_pageable_v2)
278
279
280if __name__ == "__main__":
281    main()
282