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 38 39 40def eprint(*args, **kwargs): 41 print(*args, file=sys.stderr, **kwargs) 42 43 44def get_symbol(elffile, name): 45 global elffile_symbols 46 if elffile_symbols is None: 47 elffile_symbols = dict() 48 symbol_tables = [s for s in elffile.iter_sections() 49 if isinstance(s, SymbolTableSection)] 50 for section in symbol_tables: 51 for symbol in section.iter_symbols(): 52 if symbol['st_info']['bind'] == 'STB_GLOBAL': 53 elffile_symbols[symbol.name] = symbol 54 55 try: 56 return elffile_symbols[name] 57 except (KeyError): 58 eprint("Cannot find symbol %s" % name) 59 sys.exit(1) 60 61 62def get_sections(elffile, pad_to, skip_names, dump_names): 63 last_end = 0 64 bin_data = bytearray() 65 66 for section in elffile.iter_sections(): 67 if (section['sh_type'] == 'SHT_NOBITS' or 68 not (section['sh_flags'] & SH_FLAGS.SHF_ALLOC) or 69 skip_names.match(section.name) or 70 not dump_names.match(section.name)): 71 continue 72 73 if last_end == 0: 74 bin_data = section.data() 75 else: 76 if section['sh_addr'] > last_end: 77 bin_data += bytearray(section['sh_addr'] - last_end) 78 bin_data += section.data() 79 80 last_end = section['sh_addr'] + section['sh_size'] 81 82 if pad_to > last_end: 83 bin_data += bytearray(pad_to - last_end) 84 last_end = pad_to 85 86 return bin_data 87 88 89def get_pageable_bin(elffile): 90 global tee_pageable_bin 91 if tee_pageable_bin is None: 92 pad_to = 0 93 skip_names = re.compile(r'^$') 94 dump_names = re.compile(r'^\..*_(pageable|init)$') 95 tee_pageable_bin = get_sections(elffile, pad_to, skip_names, 96 dump_names) 97 return tee_pageable_bin 98 99 100def get_pager_bin(elffile): 101 global tee_pager_bin 102 if tee_pager_bin is None: 103 pad_to = get_symbol(elffile, '__data_end')['st_value'] 104 skip_names = re.compile(r'^\..*_(pageable|init)$') 105 dump_names = re.compile(r'') 106 tee_pager_bin = get_sections(elffile, pad_to, skip_names, dump_names) 107 108 return tee_pager_bin 109 110 111def output_pager_bin(elffile, outf): 112 outf.write(get_pager_bin(elffile)) 113 114 115def output_pageable_bin(elffile, outf): 116 outf.write(get_pageable_bin(elffile)) 117 118 119def get_arch_id(elffile): 120 e_machine = elffile.header['e_machine'] 121 if e_machine == 'EM_ARM': 122 return 0 123 if e_machine == 'EM_AARCH64': 124 return 1 125 eprint('Unknown e_machine "%s"' % e_machine) 126 sys.exit(1) 127 128 129def get_init_load_addr(elffile): 130 init_load_addr = get_symbol(elffile, '_start')['st_value'] 131 init_load_addr_hi = init_load_addr >> 32 132 init_load_addr_lo = init_load_addr & 0xffffffff 133 return init_load_addr_hi, init_load_addr_lo 134 135 136def output_header_v1(elffile, outf): 137 arch_id = get_arch_id(elffile) 138 pager_bin = get_pager_bin(elffile) 139 pageable_bin = get_pageable_bin(elffile) 140 init_mem_usage = get_symbol(elffile, '__init_mem_usage')['st_value'] 141 init_load_addr = get_init_load_addr(elffile) 142 init_bin_size = get_symbol(elffile, '__init_size')['st_value'] 143 pager_bin_size = len(pager_bin) 144 paged_area_size = len(pageable_bin) 145 hash_size = (paged_area_size // small_page_size * 146 hashlib.sha256().digest_size) 147 148 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) + 149 hash_size) 150 paged_size = paged_area_size - min(init_bin_size, paged_area_size) 151 152 if paged_area_size % small_page_size != 0: 153 eprint("pageable size not a multiple of 4K: " 154 "{}".format(paged_area_size)) 155 sys.exit(1) 156 157 magic = 0x4554504f # 'OPTE' 158 version = 1 159 flags = 0 160 outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags, 161 init_size, init_load_addr[0], init_load_addr[1], 162 init_mem_usage, paged_size)) 163 outf.write(pager_bin) 164 outf.write(pageable_bin[:init_bin_size]) 165 for n in range(0, len(pageable_bin), small_page_size): 166 page = pageable_bin[n:n + small_page_size] 167 outf.write(hashlib.sha256(page).digest()) 168 outf.write(pageable_bin[init_bin_size:]) 169 170 171def output_header_v2(elffile, outf): 172 arch_id = get_arch_id(elffile) 173 init_load_addr = get_init_load_addr(elffile) 174 init_bin_size = get_symbol(elffile, '__init_size')['st_value'] 175 pager_bin_size = len(get_pager_bin(elffile)) 176 paged_area_size = len(get_pageable_bin(elffile)) 177 hash_size = (paged_area_size // small_page_size * 178 hashlib.sha256().digest_size) 179 180 if paged_area_size % small_page_size != 0: 181 eprint("pageable size not a multiple of 4K: " 182 "{}".format(paged_area_size)) 183 sys.exit(1) 184 185 init_size = (pager_bin_size + min(init_bin_size, paged_area_size) + 186 hash_size) 187 paged_size = paged_area_size - min(init_bin_size, paged_area_size) 188 189 magic = 0x4554504f # 'OPTE' 190 version = 2 191 flags = 0 192 nb_images = 1 if paged_size == 0 else 2 193 outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags, 194 nb_images)) 195 outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1], 196 0, init_size)) 197 if nb_images == 2: 198 outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size)) 199 200 201def output_pager_v2(elffile, outf): 202 init_bin_size = get_symbol(elffile, '__init_size')['st_value'] 203 pageable_bin = get_pageable_bin(elffile) 204 205 if len(pageable_bin) % small_page_size != 0: 206 eprint("pageable size not a multiple of 4K: " 207 "{}".format(paged_area_size)) 208 sys.exit(1) 209 210 outf.write(get_pager_bin(elffile)) 211 outf.write(pageable_bin[:init_bin_size]) 212 for n in range(0, len(pageable_bin), small_page_size): 213 page = pageable_bin[n:n + small_page_size] 214 outf.write(hashlib.sha256(page).digest()) 215 216 217def output_pageable_v2(elffile, outf): 218 init_bin_size = get_symbol(elffile, '__init_size')['st_value'] 219 outf.write(get_pageable_bin(elffile)[init_bin_size:]) 220 221 222def get_args(): 223 parser = argparse.ArgumentParser() 224 225 parser.add_argument('--input', 226 required=True, type=argparse.FileType('rb'), 227 help='The input tee.elf') 228 229 parser.add_argument('--out_tee_bin', 230 required=False, type=argparse.FileType('wb'), 231 help='The output tee.bin') 232 233 parser.add_argument('--out_tee_pager_bin', 234 required=False, type=argparse.FileType('wb'), 235 help='The output tee_pager.bin') 236 237 parser.add_argument('--out_tee_pageable_bin', 238 required=False, type=argparse.FileType('wb'), 239 help='The output tee_pageable.bin') 240 241 parser.add_argument('--out_header_v2', 242 required=False, type=argparse.FileType('wb'), 243 help='The output tee_header_v2.bin') 244 245 parser.add_argument('--out_pager_v2', 246 required=False, type=argparse.FileType('wb'), 247 help='The output tee_pager_v2.bin') 248 249 parser.add_argument('--out_pageable_v2', 250 required=False, type=argparse.FileType('wb'), 251 help='The output tee_pageable_v2.bin') 252 253 return parser.parse_args() 254 255 256def main(): 257 args = get_args() 258 259 elffile = ELFFile(args.input) 260 261 if args.out_tee_bin: 262 output_header_v1(elffile, args.out_tee_bin) 263 264 if args.out_tee_pager_bin: 265 output_pager_bin(elffile, args.out_tee_pager_bin) 266 267 if args.out_tee_pageable_bin: 268 output_pageable_bin(elffile, args.out_tee_pageable_bin) 269 270 if args.out_header_v2: 271 output_header_v2(elffile, args.out_header_v2) 272 273 if args.out_pager_v2: 274 output_pager_v2(elffile, args.out_pager_v2) 275 276 if args.out_pageable_v2: 277 output_pageable_v2(elffile, args.out_pageable_v2) 278 279 280if __name__ == "__main__": 281 main() 282