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