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