xref: /optee_os/scripts/gen_tee_bin.py (revision 5dd1570ac5b0f6563b1a9c074533a19107b8222d)
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
38tee_embdata_bin = None
39
40
41def eprint(*args, **kwargs):
42    print(*args, file=sys.stderr, **kwargs)
43
44
45def round_up(n, m):
46    if n == 0:
47        return 0
48    else:
49        return (((n - 1) // m) + 1) * m
50
51
52def get_arch_id(elffile):
53    e_machine = elffile.header['e_machine']
54    if e_machine == 'EM_ARM':
55        return 0
56    if e_machine == 'EM_AARCH64':
57        return 1
58    eprint('Unknown e_machine "%s"' % e_machine)
59    sys.exit(1)
60
61
62def get_symbol(elffile, name):
63    global elffile_symbols
64    if elffile_symbols is None:
65        elffile_symbols = dict()
66        symbol_tables = [s for s in elffile.iter_sections()
67                         if isinstance(s, SymbolTableSection)]
68        for section in symbol_tables:
69            for symbol in section.iter_symbols():
70                if symbol['st_info']['bind'] == 'STB_GLOBAL':
71                    elffile_symbols[symbol.name] = symbol
72
73    try:
74        return elffile_symbols[name]
75    except (KeyError):
76        eprint("Cannot find symbol %s" % name)
77        sys.exit(1)
78
79
80def get_sections(elffile, pad_to, dump_names):
81    last_end = 0
82    bin_data = bytearray()
83
84    for section in elffile.iter_sections():
85        if (section['sh_type'] == 'SHT_NOBITS' or
86                not (section['sh_flags'] & SH_FLAGS.SHF_ALLOC) or
87                not dump_names.match(section.name)):
88            continue
89
90        if last_end == 0:
91            bin_data = section.data()
92        else:
93            if section['sh_addr'] > last_end:
94                bin_data += bytearray(section['sh_addr'] - last_end)
95            bin_data += section.data()
96
97        last_end = section['sh_addr'] + section['sh_size']
98
99    if pad_to > last_end:
100        bin_data += bytearray(pad_to - last_end)
101        last_end = pad_to
102
103    return bin_data
104
105
106def get_pageable_bin(elffile):
107    global tee_pageable_bin
108    if tee_pageable_bin is None:
109        pad_to = 0
110        dump_names = re.compile(r'^\..*_(pageable|init)$')
111        tee_pageable_bin = get_sections(elffile, pad_to, dump_names)
112    return tee_pageable_bin
113
114
115def get_pager_bin(elffile):
116    global tee_pager_bin
117    if tee_pager_bin is None:
118        pad_to = get_symbol(elffile, '__data_end')['st_value']
119        dump_names = re.compile(
120            r'^\.(text|rodata|got|data|ARM\.exidx|ARM\.extab|rel|rela)$')
121        tee_pager_bin = get_sections(elffile, pad_to, dump_names)
122
123    return tee_pager_bin
124
125
126def get_hashes_bin(elffile):
127    pageable_bin = get_pageable_bin(elffile)
128    if len(pageable_bin) % small_page_size != 0:
129        eprint("pageable size not a multiple of 4K: "
130               "{}".format(paged_area_size))
131        sys.exit(1)
132
133    data = bytearray()
134    for n in range(0, len(pageable_bin), small_page_size):
135        page = pageable_bin[n:n + small_page_size]
136        data += hashlib.sha256(page).digest()
137
138    return data
139
140
141def get_embdata_bin(elffile):
142    global tee_embdata_bin
143    if tee_embdata_bin is None:
144        hashes_bin = get_hashes_bin(elffile)
145
146        num_entries = 1
147        hash_offs = 2 * 4 + num_entries * (2 * 4)
148        hash_pad = round_up(len(hashes_bin), 8) - len(hashes_bin)
149        total_len = hash_offs + len(hashes_bin) + hash_pad
150
151        tee_embdata_bin = struct.pack('<IIII', total_len, num_entries,
152                                      hash_offs, len(hashes_bin))
153        tee_embdata_bin += hashes_bin + bytearray(hash_pad)
154
155    # The embedded data region is designed to be easy to extend when
156    # needed, it's formatted as:
157    # +--------------------------------------------------------+
158    # | uint32_t: Length of entire area including this field   |
159    # +--------------------------------------------------------+
160    # | uint32_t: Number of entries "1"                        |
161    # +--------------------------------------------------------+
162    # | uint32_t: Offset of hashes from beginning of table     |
163    # +--------------------------------------------------------+
164    # | uint32_t: Length of hashes                             |
165    # +--------------------------------------------------------+
166    # | Data of hashes + eventual padding                      |
167    # +--------------------------------------------------------+
168
169    return tee_embdata_bin
170
171
172def output_pager_bin(elffile, outf):
173    outf.write(get_pager_bin(elffile))
174
175
176def output_pageable_bin(elffile, outf):
177    outf.write(get_pageable_bin(elffile))
178
179
180def get_init_load_addr(elffile):
181    init_load_addr = get_symbol(elffile, '_start')['st_value']
182    init_load_addr_hi = init_load_addr >> 32
183    init_load_addr_lo = init_load_addr & 0xffffffff
184    return init_load_addr_hi, init_load_addr_lo
185
186
187def output_header_v1(elffile, outf):
188    arch_id = get_arch_id(elffile)
189    pager_bin = get_pager_bin(elffile)
190    pageable_bin = get_pageable_bin(elffile)
191    embdata_bin = get_embdata_bin(elffile)
192    init_load_addr = get_init_load_addr(elffile)
193    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
194    pager_bin_size = len(pager_bin)
195    paged_area_size = len(pageable_bin)
196
197    init_mem_usage = (get_symbol(elffile, '__init_end')['st_value'] -
198                      get_symbol(elffile, '__text_start')['st_value'] +
199                      len(embdata_bin))
200
201    init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
202                 len(embdata_bin))
203    paged_size = paged_area_size - min(init_bin_size, paged_area_size)
204
205    magic = 0x4554504f  # 'OPTE'
206    version = 1
207    flags = 0
208    outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags,
209                           init_size, init_load_addr[0], init_load_addr[1],
210                           init_mem_usage, paged_size))
211    outf.write(pager_bin)
212    outf.write(pageable_bin[:init_bin_size])
213    outf.write(embdata_bin)
214    outf.write(pageable_bin[init_bin_size:])
215
216
217def output_header_v2(elffile, outf):
218    arch_id = get_arch_id(elffile)
219    init_load_addr = get_init_load_addr(elffile)
220    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
221    pager_bin_size = len(get_pager_bin(elffile))
222    paged_area_size = len(get_pageable_bin(elffile))
223    embdata_bin_size = len(get_embdata_bin(elffile))
224
225    init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
226                 embdata_bin_size)
227    paged_size = paged_area_size - min(init_bin_size, paged_area_size)
228
229    magic = 0x4554504f  # 'OPTE'
230    version = 2
231    flags = 0
232    nb_images = 1 if paged_size == 0 else 2
233    outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags,
234                           nb_images))
235    outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1],
236                           0, init_size))
237    if nb_images == 2:
238        outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))
239
240
241def output_pager_v2(elffile, outf):
242    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
243    pager_bin = get_pager_bin(elffile)
244    pageable_bin = get_pageable_bin(elffile)
245    embdata_bin = get_embdata_bin(elffile)
246
247    outf.write(pager_bin)
248    outf.write(pageable_bin[:init_bin_size])
249    outf.write(embdata_bin)
250
251
252def output_pageable_v2(elffile, outf):
253    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
254    outf.write(get_pageable_bin(elffile)[init_bin_size:])
255
256
257def get_args():
258    parser = argparse.ArgumentParser()
259
260    parser.add_argument('--input',
261                        required=True, type=argparse.FileType('rb'),
262                        help='The input tee.elf')
263
264    parser.add_argument('--out_tee_bin',
265                        required=False, type=argparse.FileType('wb'),
266                        help='The output tee.bin')
267
268    parser.add_argument('--out_tee_pager_bin',
269                        required=False, type=argparse.FileType('wb'),
270                        help='The output tee_pager.bin')
271
272    parser.add_argument('--out_tee_pageable_bin',
273                        required=False, type=argparse.FileType('wb'),
274                        help='The output tee_pageable.bin')
275
276    parser.add_argument('--out_header_v2',
277                        required=False, type=argparse.FileType('wb'),
278                        help='The output tee_header_v2.bin')
279
280    parser.add_argument('--out_pager_v2',
281                        required=False, type=argparse.FileType('wb'),
282                        help='The output tee_pager_v2.bin')
283
284    parser.add_argument('--out_pageable_v2',
285                        required=False, type=argparse.FileType('wb'),
286                        help='The output tee_pageable_v2.bin')
287
288    return parser.parse_args()
289
290
291def main():
292    args = get_args()
293
294    elffile = ELFFile(args.input)
295
296    if args.out_tee_bin:
297        output_header_v1(elffile, args.out_tee_bin)
298
299    if args.out_tee_pager_bin:
300        output_pager_bin(elffile, args.out_tee_pager_bin)
301
302    if args.out_tee_pageable_bin:
303        output_pageable_bin(elffile, args.out_tee_pageable_bin)
304
305    if args.out_header_v2:
306        output_header_v2(elffile, args.out_header_v2)
307
308    if args.out_pager_v2:
309        output_pager_v2(elffile, args.out_pager_v2)
310
311    if args.out_pageable_v2:
312        output_pageable_v2(elffile, args.out_pageable_v2)
313
314
315if __name__ == "__main__":
316    main()
317