#!/usr/bin/env python3 # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019, Linaro Limited # from __future__ import print_function from __future__ import division import argparse import sys import struct import re import hashlib try: from elftools.elf.elffile import ELFFile from elftools.elf.constants import SH_FLAGS from elftools.elf.sections import SymbolTableSection except ImportError: print(""" *** Can't find elftools module. Probably it is not installed on your system. You can install this module with $ apt install python3-pyelftools if you are using Ubuntu. Or try to search for "pyelftools" or "elftools" in your package manager if you are using some other distribution. *** """) raise small_page_size = 4 * 1024 elffile_symbols = None tee_pageable_bin = None tee_pager_bin = None def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) def get_symbol(elffile, name): global elffile_symbols if elffile_symbols is None: elffile_symbols = dict() symbol_tables = [s for s in elffile.iter_sections() if isinstance(s, SymbolTableSection)] for section in symbol_tables: for symbol in section.iter_symbols(): if symbol['st_info']['bind'] == 'STB_GLOBAL': elffile_symbols[symbol.name] = symbol try: return elffile_symbols[name] except (KeyError): eprint("Cannot find symbol %s" % name) sys.exit(1) def get_sections(elffile, pad_to, skip_names, dump_names): last_end = 0 bin_data = bytearray() for section in elffile.iter_sections(): if (section['sh_type'] == 'SHT_NOBITS' or not (section['sh_flags'] & SH_FLAGS.SHF_ALLOC) or skip_names.match(section.name) or not dump_names.match(section.name)): continue if last_end == 0: bin_data = section.data() else: if section['sh_addr'] > last_end: bin_data += bytearray(section['sh_addr'] - last_end) bin_data += section.data() last_end = section['sh_addr'] + section['sh_size'] if pad_to > last_end: bin_data += bytearray(pad_to - last_end) last_end = pad_to return bin_data def get_pageable_bin(elffile): global tee_pageable_bin if tee_pageable_bin is None: pad_to = 0 skip_names = re.compile(r'^$') dump_names = re.compile(r'^\..*_(pageable|init)$') tee_pageable_bin = get_sections(elffile, pad_to, skip_names, dump_names) return tee_pageable_bin def get_pager_bin(elffile): global tee_pager_bin if tee_pager_bin is None: pad_to = get_symbol(elffile, '__data_end')['st_value'] skip_names = re.compile(r'^\..*_(pageable|init)$') dump_names = re.compile(r'') tee_pager_bin = get_sections(elffile, pad_to, skip_names, dump_names) return tee_pager_bin def output_pager_bin(elffile, outf): outf.write(get_pager_bin(elffile)) def output_pageable_bin(elffile, outf): outf.write(get_pageable_bin(elffile)) def get_arch_id(elffile): e_machine = elffile.header['e_machine'] if e_machine == 'EM_ARM': return 0 if e_machine == 'EM_AARCH64': return 1 eprint('Unknown e_machine "%s"' % e_machine) sys.exit(1) def get_init_load_addr(elffile): init_load_addr = get_symbol(elffile, '_start')['st_value'] init_load_addr_hi = init_load_addr >> 32 init_load_addr_lo = init_load_addr & 0xffffffff return init_load_addr_hi, init_load_addr_lo def output_header_v1(elffile, outf): arch_id = get_arch_id(elffile) pager_bin = get_pager_bin(elffile) pageable_bin = get_pageable_bin(elffile) init_mem_usage = get_symbol(elffile, '__init_mem_usage')['st_value'] init_load_addr = get_init_load_addr(elffile) init_bin_size = get_symbol(elffile, '__init_size')['st_value'] pager_bin_size = len(pager_bin) paged_area_size = len(pageable_bin) hash_size = (paged_area_size // small_page_size * hashlib.sha256().digest_size) init_size = (pager_bin_size + min(init_bin_size, paged_area_size) + hash_size) paged_size = paged_area_size - min(init_bin_size, paged_area_size) if paged_area_size % small_page_size != 0: eprint("pageable size not a multiple of 4K: " "{}".format(paged_area_size)) sys.exit(1) magic = 0x4554504f # 'OPTE' version = 1 flags = 0 outf.write(struct.pack('