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 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 83def get_sections(elffile, pad_to, dump_names): 84 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 90 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 113 dump_names = re.compile(r'^\..*_(pageable|init)$') 114 tee_pageable_bin = get_sections(elffile, pad_to, dump_names) 115 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'] 122 dump_names = re.compile( 123 r'^\.(text|rodata|got|data|ARM\.exidx|ARM\.extab)$') 124 tee_pager_bin = get_sections(elffile, pad_to, dump_names) 125 126 return tee_pager_bin 127 128 129def 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 167def 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) 186 reloc_bin = get_reloc_bin(elffile) 187 188 num_entries = 2 189 hash_offs = 2 * 4 + num_entries * (2 * 4) 190 hash_pad = round_up(len(hashes_bin), 8) - len(hashes_bin) 191 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 194 195 tee_embdata_bin = struct.pack('<IIIIII', total_len, num_entries, 196 hash_offs, len(hashes_bin), 197 reloc_offs, len(reloc_bin)) 198 tee_embdata_bin += hashes_bin + bytearray(hash_pad) 199 tee_embdata_bin += reloc_bin + bytearray(reloc_pad) 200 201 # The embedded data region is designed to be easy to extend when 202 # needed, it's formatted as: 203 # +---------------------------------------------------------+ 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 # +---------------------------------------------------------+ 220 221 return tee_embdata_bin 222 223 224def 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 232def 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) 243 embdata_bin = get_embdata_bin(elffile) 244 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) 248 249 init_mem_usage = (get_symbol(elffile, '__init_end')['st_value'] - 250 get_symbol(elffile, '__text_start')['st_value'] + 251 len(embdata_bin)) 252 253 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) + 254 len(embdata_bin)) 255 paged_size = paged_area_size - min(init_bin_size, paged_area_size) 256 257 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]) 265 outf.write(embdata_bin) 266 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)) 275 embdata_bin_size = len(get_embdata_bin(elffile)) 276 277 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) + 278 embdata_bin_size) 279 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'] 295 pager_bin = get_pager_bin(elffile) 296 pageable_bin = get_pageable_bin(elffile) 297 embdata_bin = get_embdata_bin(elffile) 298 299 outf.write(pager_bin) 300 outf.write(pageable_bin[:init_bin_size]) 301 outf.write(embdata_bin) 302 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() 369