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.enums import ENUM_RELOC_TYPE_ARM 19 from elftools.elf.enums import ENUM_RELOC_TYPE_AARCH64 20 from elftools.elf.sections import SymbolTableSection 21 from elftools.elf.relocation import RelocationSection 22 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 41tee_embdata_bin = None 42 43 44def eprint(*args, **kwargs): 45 print(*args, file=sys.stderr, **kwargs) 46 47 48def 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 65def get_name(obj): 66 # Symbol or section .name might be a byte array or a string, we want a 67 # string 68 try: 69 name = obj.name.decode() 70 except (UnicodeDecodeError, AttributeError): 71 name = obj.name 72 return name 73 74 75def get_symbol(elffile, name): 76 global elffile_symbols 77 global lsyms_def 78 if elffile_symbols is None: 79 elffile_symbols = dict() 80 lsyms_def = dict() 81 symbol_tables = [s for s in elffile.iter_sections() 82 if isinstance(s, SymbolTableSection)] 83 for section in symbol_tables: 84 for symbol in section.iter_symbols(): 85 symbol_name = get_name(symbol) 86 if symbol['st_info']['bind'] == 'STB_GLOBAL': 87 elffile_symbols[symbol_name] = symbol 88 elif symbol['st_info']['bind'] == 'STB_LOCAL': 89 if symbol_name not in elffile_symbols.keys(): 90 elffile_symbols[symbol_name] = symbol 91 if symbol_name not in lsyms_def.keys(): 92 lsyms_def[symbol_name] = 1 93 else: 94 lsyms_def[symbol_name] += 1 95 96 if name in lsyms_def.keys() and lsyms_def[name] > 1: 97 eprint("Multiple definitions of local symbol %s" % name) 98 sys.exit(1) 99 if name not in elffile_symbols.keys(): 100 eprint("Cannot find symbol %s" % name) 101 sys.exit(1) 102 103 return elffile_symbols[name] 104 105 106def get_sections(elffile, pad_to, dump_names): 107 last_end = 0 108 bin_data = bytearray() 109 110 for section in elffile.iter_sections(): 111 section_name = get_name(section) 112 if (section['sh_type'] == 'SHT_NOBITS' or 113 not (section['sh_flags'] & SH_FLAGS.SHF_ALLOC) or 114 not dump_names.match(section_name)): 115 continue 116 117 if last_end == 0: 118 bin_data = section.data() 119 else: 120 if section['sh_addr'] > last_end: 121 bin_data += bytearray(section['sh_addr'] - last_end) 122 bin_data += section.data() 123 124 last_end = section['sh_addr'] + section['sh_size'] 125 126 if pad_to > last_end: 127 bin_data += bytearray(pad_to - last_end) 128 last_end = pad_to 129 130 return bin_data 131 132 133def get_pageable_bin(elffile): 134 global tee_pageable_bin 135 if tee_pageable_bin is None: 136 pad_to = 0 137 dump_names = re.compile(r'^\..*_(pageable|init)$') 138 tee_pageable_bin = get_sections(elffile, pad_to, dump_names) 139 return tee_pageable_bin 140 141 142def get_pager_bin(elffile): 143 global tee_pager_bin 144 if tee_pager_bin is None: 145 pad_to = get_symbol(elffile, '__data_end')['st_value'] 146 dump_names = re.compile( 147 r'^\.(text|nex_data|rodata|got|data|ARM\.exidx|ARM\.extab)$') 148 tee_pager_bin = get_sections(elffile, pad_to, dump_names) 149 150 return tee_pager_bin 151 152 153def get_reloc_bin(elffile): 154 if get_arch_id(elffile) == 0: 155 exp_rel_type = ENUM_RELOC_TYPE_ARM['R_ARM_RELATIVE'] 156 else: 157 exp_rel_type = ENUM_RELOC_TYPE_AARCH64['R_AARCH64_RELATIVE'] 158 159 link_address = get_symbol(elffile, '__text_start')['st_value'] 160 161 addrs = [] 162 for section in elffile.iter_sections(): 163 if not isinstance(section, RelocationSection): 164 continue 165 for rel in section.iter_relocations(): 166 if rel['r_info_type'] == 0: 167 continue 168 if rel['r_info_type'] != exp_rel_type: 169 eprint("Unexpected relocation type 0x%x" % 170 rel['r_info_type']) 171 sys.exit(1) 172 addrs.append(rel['r_offset'] - link_address) 173 174 addrs.sort() 175 data = bytearray() 176 for a in addrs: 177 data += struct.pack('<I', a) 178 179 # Relocations has been reduced to only become the relative type with 180 # addend at the address (r_offset) of relocation, that is, increase by 181 # load_offset. The addresses (r_offset) are also sorted. The format is 182 # then: 183 # uint32_t: relocation #1 184 # uint32_t: relocation #2 185 # ... 186 # uint32_t: relocation #n 187 188 return data 189 190 191def get_hashes_bin(elffile): 192 pageable_bin = get_pageable_bin(elffile) 193 if len(pageable_bin) % small_page_size != 0: 194 eprint("pageable size not a multiple of 4K: " 195 "{}".format(paged_area_size)) 196 sys.exit(1) 197 198 data = bytearray() 199 for n in range(0, len(pageable_bin), small_page_size): 200 page = pageable_bin[n:n + small_page_size] 201 data += hashlib.sha256(page).digest() 202 203 return data 204 205 206def get_embdata_bin(elffile): 207 global tee_embdata_bin 208 if tee_embdata_bin is None: 209 hashes_bin = get_hashes_bin(elffile) 210 reloc_bin = get_reloc_bin(elffile) 211 212 num_entries = 2 213 hash_offs = 2 * 4 + num_entries * (2 * 4) 214 hash_pad = round_up(len(hashes_bin), 8) - len(hashes_bin) 215 reloc_offs = hash_offs + len(hashes_bin) + hash_pad 216 reloc_pad = round_up(len(reloc_bin), 8) - len(reloc_bin) 217 total_len = reloc_offs + len(reloc_bin) + reloc_pad 218 219 tee_embdata_bin = struct.pack('<IIIIII', total_len, num_entries, 220 hash_offs, len(hashes_bin), 221 reloc_offs, len(reloc_bin)) 222 tee_embdata_bin += hashes_bin + bytearray(hash_pad) 223 tee_embdata_bin += reloc_bin + bytearray(reloc_pad) 224 225 # The embedded data region is designed to be easy to extend when 226 # needed, it's formatted as: 227 # +---------------------------------------------------------+ 228 # | uint32_t: Length of entire area including this field | 229 # +---------------------------------------------------------+ 230 # | uint32_t: Number of entries "2" | 231 # +---------------------------------------------------------+ 232 # | uint32_t: Offset of hashes from beginning of table | 233 # +---------------------------------------------------------+ 234 # | uint32_t: Length of hashes | 235 # +---------------------------------------------------------+ 236 # | uint32_t: Offset of relocations from beginning of table | 237 # +---------------------------------------------------------+ 238 # | uint32_t: Length of relocations | 239 # +---------------------------------------------------------+ 240 # | Data of hashes + eventual padding | 241 # +---------------------------------------------------------+ 242 # | Data of relocations + eventual padding | 243 # +---------------------------------------------------------+ 244 245 return tee_embdata_bin 246 247 248def output_pager_bin(elffile, outf): 249 outf.write(get_pager_bin(elffile)) 250 251 252def output_pageable_bin(elffile, outf): 253 outf.write(get_pageable_bin(elffile)) 254 255 256def get_init_load_addr(elffile): 257 init_load_addr = get_symbol(elffile, '_start')['st_value'] 258 init_load_addr_hi = init_load_addr >> 32 259 init_load_addr_lo = init_load_addr & 0xffffffff 260 return init_load_addr_hi, init_load_addr_lo 261 262 263def output_raw_bin(elffile, outf): 264 pager_bin = get_pager_bin(elffile) 265 pageable_bin = get_pageable_bin(elffile) 266 embdata_bin = get_embdata_bin(elffile) 267 init_bin_size = get_symbol(elffile, '__init_size')['st_value'] 268 269 outf.write(pager_bin) 270 outf.write(pageable_bin[:init_bin_size]) 271 outf.write(embdata_bin) 272 outf.write(pageable_bin[init_bin_size:]) 273 274 275def output_header_v1(elffile, outf): 276 arch_id = get_arch_id(elffile) 277 pager_bin = get_pager_bin(elffile) 278 pageable_bin = get_pageable_bin(elffile) 279 embdata_bin = get_embdata_bin(elffile) 280 init_load_addr = get_init_load_addr(elffile) 281 init_bin_size = get_symbol(elffile, '__init_size')['st_value'] 282 pager_bin_size = len(pager_bin) 283 paged_area_size = len(pageable_bin) 284 285 init_mem_usage = (get_symbol(elffile, '__get_tee_init_end')['st_value'] - 286 get_symbol(elffile, '__text_start')['st_value'] + 287 len(embdata_bin)) 288 289 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) + 290 len(embdata_bin)) 291 paged_size = paged_area_size - min(init_bin_size, paged_area_size) 292 293 magic = 0x4554504f # 'OPTE' 294 version = 1 295 flags = 0 296 outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags, 297 init_size, init_load_addr[0], init_load_addr[1], 298 init_mem_usage, paged_size)) 299 outf.write(pager_bin) 300 outf.write(pageable_bin[:init_bin_size]) 301 outf.write(embdata_bin) 302 outf.write(pageable_bin[init_bin_size:]) 303 304 305def output_header_v2(elffile, outf): 306 arch_id = get_arch_id(elffile) 307 init_load_addr = get_init_load_addr(elffile) 308 init_bin_size = get_symbol(elffile, '__init_size')['st_value'] 309 pager_bin_size = len(get_pager_bin(elffile)) 310 paged_area_size = len(get_pageable_bin(elffile)) 311 embdata_bin_size = len(get_embdata_bin(elffile)) 312 313 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) + 314 embdata_bin_size) 315 paged_size = paged_area_size - min(init_bin_size, paged_area_size) 316 317 magic = 0x4554504f # 'OPTE' 318 version = 2 319 flags = 0 320 nb_images = 1 if paged_size == 0 else 2 321 outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags, 322 nb_images)) 323 outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1], 324 0, init_size)) 325 if nb_images == 2: 326 outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size)) 327 328 329def output_pager_v2(elffile, outf): 330 init_bin_size = get_symbol(elffile, '__init_size')['st_value'] 331 pager_bin = get_pager_bin(elffile) 332 pageable_bin = get_pageable_bin(elffile) 333 embdata_bin = get_embdata_bin(elffile) 334 335 outf.write(pager_bin) 336 outf.write(pageable_bin[:init_bin_size]) 337 outf.write(embdata_bin) 338 339 340def output_pageable_v2(elffile, outf): 341 init_bin_size = get_symbol(elffile, '__init_size')['st_value'] 342 outf.write(get_pageable_bin(elffile)[init_bin_size:]) 343 344 345def get_args(): 346 parser = argparse.ArgumentParser() 347 348 parser.add_argument('--input', 349 required=True, type=argparse.FileType('rb'), 350 help='The input tee.elf') 351 352 parser.add_argument('--out_tee_bin', 353 required=False, type=argparse.FileType('wb'), 354 help='The output tee.bin') 355 356 parser.add_argument('--out_tee_raw_bin', 357 required=False, type=argparse.FileType('wb'), 358 help='The output tee_raw.bin') 359 360 parser.add_argument('--out_tee_pager_bin', 361 required=False, type=argparse.FileType('wb'), 362 help='The output tee_pager.bin') 363 364 parser.add_argument('--out_tee_pageable_bin', 365 required=False, type=argparse.FileType('wb'), 366 help='The output tee_pageable.bin') 367 368 parser.add_argument('--out_header_v2', 369 required=False, type=argparse.FileType('wb'), 370 help='The output tee_header_v2.bin') 371 372 parser.add_argument('--out_pager_v2', 373 required=False, type=argparse.FileType('wb'), 374 help='The output tee_pager_v2.bin') 375 376 parser.add_argument('--out_pageable_v2', 377 required=False, type=argparse.FileType('wb'), 378 help='The output tee_pageable_v2.bin') 379 380 return parser.parse_args() 381 382 383def main(): 384 args = get_args() 385 386 elffile = ELFFile(args.input) 387 388 if args.out_tee_raw_bin: 389 output_raw_bin(elffile, args.out_tee_raw_bin) 390 391 if args.out_tee_bin: 392 output_header_v1(elffile, args.out_tee_bin) 393 394 if args.out_tee_pager_bin: 395 output_pager_bin(elffile, args.out_tee_pager_bin) 396 397 if args.out_tee_pageable_bin: 398 output_pageable_bin(elffile, args.out_tee_pageable_bin) 399 400 if args.out_header_v2: 401 output_header_v2(elffile, args.out_header_v2) 402 403 if args.out_pager_v2: 404 output_pager_v2(elffile, args.out_pager_v2) 405 406 if args.out_pageable_v2: 407 output_pageable_v2(elffile, args.out_pageable_v2) 408 409 410if __name__ == "__main__": 411 main() 412