blob: 504d6b33d4162353ce9cfe9eaa302c3e82e45a55 [file] [log] [blame]
Jens Wiklander3c519662019-10-18 16:01:17 +02001#!/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
Jens Wiklander59666602019-10-21 23:17:43 +020018 from elftools.elf.enums import ENUM_RELOC_TYPE_ARM
19 from elftools.elf.enums import ENUM_RELOC_TYPE_AARCH64
Jens Wiklander3c519662019-10-18 16:01:17 +020020 from elftools.elf.sections import SymbolTableSection
Jens Wiklander59666602019-10-21 23:17:43 +020021 from elftools.elf.relocation import RelocationSection
Jens Wiklander3c519662019-10-18 16:01:17 +020022
23except ImportError:
24 print("""
25***
26Can't find elftools module. Probably it is not installed on your system.
27You can install this module with
28
29$ apt install python3-pyelftools
30
31if you are using Ubuntu. Or try to search for "pyelftools" or "elftools" in
32your package manager if you are using some other distribution.
33***
34""")
35 raise
36
37small_page_size = 4 * 1024
38elffile_symbols = None
39tee_pageable_bin = None
40tee_pager_bin = None
Jens Wiklander5dd15702019-10-21 23:17:43 +020041tee_embdata_bin = None
Jens Wiklander3c519662019-10-18 16:01:17 +020042
43
44def eprint(*args, **kwargs):
45 print(*args, file=sys.stderr, **kwargs)
46
47
Jens Wiklander5dd15702019-10-21 23:17:43 +020048def round_up(n, m):
49 if n == 0:
50 return 0
51 else:
52 return (((n - 1) // m) + 1) * m
53
54
55def get_arch_id(elffile):
56 e_machine = elffile.header['e_machine']
57 if e_machine == 'EM_ARM':
58 return 0
59 if e_machine == 'EM_AARCH64':
60 return 1
61 eprint('Unknown e_machine "%s"' % e_machine)
62 sys.exit(1)
63
64
Jens Wiklander3c519662019-10-18 16:01:17 +020065def get_symbol(elffile, name):
66 global elffile_symbols
67 if elffile_symbols is None:
68 elffile_symbols = dict()
69 symbol_tables = [s for s in elffile.iter_sections()
70 if isinstance(s, SymbolTableSection)]
71 for section in symbol_tables:
72 for symbol in section.iter_symbols():
73 if symbol['st_info']['bind'] == 'STB_GLOBAL':
74 elffile_symbols[symbol.name] = symbol
75
76 try:
77 return elffile_symbols[name]
78 except (KeyError):
79 eprint("Cannot find symbol %s" % name)
80 sys.exit(1)
81
82
Jens Wiklander5dd15702019-10-21 23:17:43 +020083def get_sections(elffile, pad_to, dump_names):
Jens Wiklander3c519662019-10-18 16:01:17 +020084 last_end = 0
85 bin_data = bytearray()
86
87 for section in elffile.iter_sections():
88 if (section['sh_type'] == 'SHT_NOBITS' or
89 not (section['sh_flags'] & SH_FLAGS.SHF_ALLOC) or
Jens Wiklander3c519662019-10-18 16:01:17 +020090 not dump_names.match(section.name)):
91 continue
92
93 if last_end == 0:
94 bin_data = section.data()
95 else:
96 if section['sh_addr'] > last_end:
97 bin_data += bytearray(section['sh_addr'] - last_end)
98 bin_data += section.data()
99
100 last_end = section['sh_addr'] + section['sh_size']
101
102 if pad_to > last_end:
103 bin_data += bytearray(pad_to - last_end)
104 last_end = pad_to
105
106 return bin_data
107
108
109def get_pageable_bin(elffile):
110 global tee_pageable_bin
111 if tee_pageable_bin is None:
112 pad_to = 0
Jens Wiklander3c519662019-10-18 16:01:17 +0200113 dump_names = re.compile(r'^\..*_(pageable|init)$')
Jens Wiklander5dd15702019-10-21 23:17:43 +0200114 tee_pageable_bin = get_sections(elffile, pad_to, dump_names)
Jens Wiklander3c519662019-10-18 16:01:17 +0200115 return tee_pageable_bin
116
117
118def get_pager_bin(elffile):
119 global tee_pager_bin
120 if tee_pager_bin is None:
121 pad_to = get_symbol(elffile, '__data_end')['st_value']
Jens Wiklander5dd15702019-10-21 23:17:43 +0200122 dump_names = re.compile(
Jens Wiklander59666602019-10-21 23:17:43 +0200123 r'^\.(text|rodata|got|data|ARM\.exidx|ARM\.extab)$')
Jens Wiklander5dd15702019-10-21 23:17:43 +0200124 tee_pager_bin = get_sections(elffile, pad_to, dump_names)
Jens Wiklander3c519662019-10-18 16:01:17 +0200125
126 return tee_pager_bin
127
128
Jens Wiklander59666602019-10-21 23:17:43 +0200129def get_reloc_bin(elffile):
130 if get_arch_id(elffile) == 0:
131 exp_rel_type = ENUM_RELOC_TYPE_ARM['R_ARM_RELATIVE']
132 else:
133 exp_rel_type = ENUM_RELOC_TYPE_AARCH64['R_AARCH64_RELATIVE']
134
135 link_address = get_symbol(elffile, '__text_start')['st_value']
136
137 addrs = []
138 for section in elffile.iter_sections():
139 if not isinstance(section, RelocationSection):
140 continue
141 for rel in section.iter_relocations():
142 if rel['r_info_type'] == 0:
143 continue
144 if rel['r_info_type'] != exp_rel_type:
145 eprint("Unexpected relocation type 0x%x" %
146 rel['r_info_type'])
147 sys.exit(1)
148 addrs.append(rel['r_offset'] - link_address)
149
150 addrs.sort()
151 data = bytearray()
152 for a in addrs:
153 data += struct.pack('<I', a)
154
155 # Relocations has been reduced to only become the relative type with
156 # addend at the address (r_offset) of relocation, that is, increase by
157 # load_offset. The addresses (r_offset) are also sorted. The format is
158 # then:
159 # uint32_t: relocation #1
160 # uint32_t: relocation #2
161 # ...
162 # uint32_t: relocation #n
163
164 return data
165
166
Jens Wiklander5dd15702019-10-21 23:17:43 +0200167def get_hashes_bin(elffile):
168 pageable_bin = get_pageable_bin(elffile)
169 if len(pageable_bin) % small_page_size != 0:
170 eprint("pageable size not a multiple of 4K: "
171 "{}".format(paged_area_size))
172 sys.exit(1)
173
174 data = bytearray()
175 for n in range(0, len(pageable_bin), small_page_size):
176 page = pageable_bin[n:n + small_page_size]
177 data += hashlib.sha256(page).digest()
178
179 return data
180
181
182def get_embdata_bin(elffile):
183 global tee_embdata_bin
184 if tee_embdata_bin is None:
185 hashes_bin = get_hashes_bin(elffile)
Jens Wiklander59666602019-10-21 23:17:43 +0200186 reloc_bin = get_reloc_bin(elffile)
Jens Wiklander5dd15702019-10-21 23:17:43 +0200187
Jens Wiklander59666602019-10-21 23:17:43 +0200188 num_entries = 2
Jens Wiklander5dd15702019-10-21 23:17:43 +0200189 hash_offs = 2 * 4 + num_entries * (2 * 4)
190 hash_pad = round_up(len(hashes_bin), 8) - len(hashes_bin)
Jens Wiklander59666602019-10-21 23:17:43 +0200191 reloc_offs = hash_offs + len(hashes_bin) + hash_pad
192 reloc_pad = round_up(len(reloc_bin), 8) - len(reloc_bin)
193 total_len = reloc_offs + len(reloc_bin) + reloc_pad
Jens Wiklander5dd15702019-10-21 23:17:43 +0200194
Jens Wiklander59666602019-10-21 23:17:43 +0200195 tee_embdata_bin = struct.pack('<IIIIII', total_len, num_entries,
196 hash_offs, len(hashes_bin),
197 reloc_offs, len(reloc_bin))
Jens Wiklander5dd15702019-10-21 23:17:43 +0200198 tee_embdata_bin += hashes_bin + bytearray(hash_pad)
Jens Wiklander59666602019-10-21 23:17:43 +0200199 tee_embdata_bin += reloc_bin + bytearray(reloc_pad)
Jens Wiklander5dd15702019-10-21 23:17:43 +0200200
201 # The embedded data region is designed to be easy to extend when
202 # needed, it's formatted as:
Jens Wiklander59666602019-10-21 23:17:43 +0200203 # +---------------------------------------------------------+
204 # | uint32_t: Length of entire area including this field |
205 # +---------------------------------------------------------+
206 # | uint32_t: Number of entries "2" |
207 # +---------------------------------------------------------+
208 # | uint32_t: Offset of hashes from beginning of table |
209 # +---------------------------------------------------------+
210 # | uint32_t: Length of hashes |
211 # +---------------------------------------------------------+
212 # | uint32_t: Offset of relocations from beginning of table |
213 # +---------------------------------------------------------+
214 # | uint32_t: Length of relocations |
215 # +---------------------------------------------------------+
216 # | Data of hashes + eventual padding |
217 # +---------------------------------------------------------+
218 # | Data of relocations + eventual padding |
219 # +---------------------------------------------------------+
Jens Wiklander5dd15702019-10-21 23:17:43 +0200220
221 return tee_embdata_bin
222
223
Jens Wiklander3c519662019-10-18 16:01:17 +0200224def output_pager_bin(elffile, outf):
225 outf.write(get_pager_bin(elffile))
226
227
228def output_pageable_bin(elffile, outf):
229 outf.write(get_pageable_bin(elffile))
230
231
Jens Wiklander3c519662019-10-18 16:01:17 +0200232def get_init_load_addr(elffile):
233 init_load_addr = get_symbol(elffile, '_start')['st_value']
234 init_load_addr_hi = init_load_addr >> 32
235 init_load_addr_lo = init_load_addr & 0xffffffff
236 return init_load_addr_hi, init_load_addr_lo
237
238
239def output_header_v1(elffile, outf):
240 arch_id = get_arch_id(elffile)
241 pager_bin = get_pager_bin(elffile)
242 pageable_bin = get_pageable_bin(elffile)
Jens Wiklander5dd15702019-10-21 23:17:43 +0200243 embdata_bin = get_embdata_bin(elffile)
Jens Wiklander3c519662019-10-18 16:01:17 +0200244 init_load_addr = get_init_load_addr(elffile)
245 init_bin_size = get_symbol(elffile, '__init_size')['st_value']
246 pager_bin_size = len(pager_bin)
247 paged_area_size = len(pageable_bin)
Jens Wiklander5dd15702019-10-21 23:17:43 +0200248
249 init_mem_usage = (get_symbol(elffile, '__init_end')['st_value'] -
250 get_symbol(elffile, '__text_start')['st_value'] +
251 len(embdata_bin))
Jens Wiklander3c519662019-10-18 16:01:17 +0200252
253 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
Jens Wiklander5dd15702019-10-21 23:17:43 +0200254 len(embdata_bin))
Jens Wiklander3c519662019-10-18 16:01:17 +0200255 paged_size = paged_area_size - min(init_bin_size, paged_area_size)
256
Jens Wiklander3c519662019-10-18 16:01:17 +0200257 magic = 0x4554504f # 'OPTE'
258 version = 1
259 flags = 0
260 outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags,
261 init_size, init_load_addr[0], init_load_addr[1],
262 init_mem_usage, paged_size))
263 outf.write(pager_bin)
264 outf.write(pageable_bin[:init_bin_size])
Jens Wiklander5dd15702019-10-21 23:17:43 +0200265 outf.write(embdata_bin)
Jens Wiklander3c519662019-10-18 16:01:17 +0200266 outf.write(pageable_bin[init_bin_size:])
267
268
269def output_header_v2(elffile, outf):
270 arch_id = get_arch_id(elffile)
271 init_load_addr = get_init_load_addr(elffile)
272 init_bin_size = get_symbol(elffile, '__init_size')['st_value']
273 pager_bin_size = len(get_pager_bin(elffile))
274 paged_area_size = len(get_pageable_bin(elffile))
Jens Wiklander5dd15702019-10-21 23:17:43 +0200275 embdata_bin_size = len(get_embdata_bin(elffile))
Jens Wiklander3c519662019-10-18 16:01:17 +0200276
277 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
Jens Wiklander5dd15702019-10-21 23:17:43 +0200278 embdata_bin_size)
Jens Wiklander3c519662019-10-18 16:01:17 +0200279 paged_size = paged_area_size - min(init_bin_size, paged_area_size)
280
281 magic = 0x4554504f # 'OPTE'
282 version = 2
283 flags = 0
284 nb_images = 1 if paged_size == 0 else 2
285 outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags,
286 nb_images))
287 outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1],
288 0, init_size))
289 if nb_images == 2:
290 outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))
291
292
293def output_pager_v2(elffile, outf):
294 init_bin_size = get_symbol(elffile, '__init_size')['st_value']
Jens Wiklander5dd15702019-10-21 23:17:43 +0200295 pager_bin = get_pager_bin(elffile)
Jens Wiklander3c519662019-10-18 16:01:17 +0200296 pageable_bin = get_pageable_bin(elffile)
Jens Wiklander5dd15702019-10-21 23:17:43 +0200297 embdata_bin = get_embdata_bin(elffile)
Jens Wiklander3c519662019-10-18 16:01:17 +0200298
Jens Wiklander5dd15702019-10-21 23:17:43 +0200299 outf.write(pager_bin)
Jens Wiklander3c519662019-10-18 16:01:17 +0200300 outf.write(pageable_bin[:init_bin_size])
Jens Wiklander5dd15702019-10-21 23:17:43 +0200301 outf.write(embdata_bin)
Jens Wiklander3c519662019-10-18 16:01:17 +0200302
303
304def output_pageable_v2(elffile, outf):
305 init_bin_size = get_symbol(elffile, '__init_size')['st_value']
306 outf.write(get_pageable_bin(elffile)[init_bin_size:])
307
308
309def get_args():
310 parser = argparse.ArgumentParser()
311
312 parser.add_argument('--input',
313 required=True, type=argparse.FileType('rb'),
314 help='The input tee.elf')
315
316 parser.add_argument('--out_tee_bin',
317 required=False, type=argparse.FileType('wb'),
318 help='The output tee.bin')
319
320 parser.add_argument('--out_tee_pager_bin',
321 required=False, type=argparse.FileType('wb'),
322 help='The output tee_pager.bin')
323
324 parser.add_argument('--out_tee_pageable_bin',
325 required=False, type=argparse.FileType('wb'),
326 help='The output tee_pageable.bin')
327
328 parser.add_argument('--out_header_v2',
329 required=False, type=argparse.FileType('wb'),
330 help='The output tee_header_v2.bin')
331
332 parser.add_argument('--out_pager_v2',
333 required=False, type=argparse.FileType('wb'),
334 help='The output tee_pager_v2.bin')
335
336 parser.add_argument('--out_pageable_v2',
337 required=False, type=argparse.FileType('wb'),
338 help='The output tee_pageable_v2.bin')
339
340 return parser.parse_args()
341
342
343def main():
344 args = get_args()
345
346 elffile = ELFFile(args.input)
347
348 if args.out_tee_bin:
349 output_header_v1(elffile, args.out_tee_bin)
350
351 if args.out_tee_pager_bin:
352 output_pager_bin(elffile, args.out_tee_pager_bin)
353
354 if args.out_tee_pageable_bin:
355 output_pageable_bin(elffile, args.out_tee_pageable_bin)
356
357 if args.out_header_v2:
358 output_header_v2(elffile, args.out_header_v2)
359
360 if args.out_pager_v2:
361 output_pager_v2(elffile, args.out_pager_v2)
362
363 if args.out_pageable_v2:
364 output_pageable_v2(elffile, args.out_pageable_v2)
365
366
367if __name__ == "__main__":
368 main()