core: add scripts/gen_tee_bin.py for boot binaries
Adds scripts/gen_tee_bin.py which can produce the boot binaries instead
of objdump and scripts/gen_hashed_bin.py.
Reviewed-by: Jerome Forissier <jerome@forissier.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/scripts/gen_tee_bin.py b/scripts/gen_tee_bin.py
new file mode 100755
index 0000000..3afacf5
--- /dev/null
+++ b/scripts/gen_tee_bin.py
@@ -0,0 +1,281 @@
+#!/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('<IBBHIIIII', magic, version, arch_id, flags,
+ init_size, init_load_addr[0], init_load_addr[1],
+ init_mem_usage, paged_size))
+ outf.write(pager_bin)
+ outf.write(pageable_bin[:init_bin_size])
+ for n in range(0, len(pageable_bin), small_page_size):
+ page = pageable_bin[n:n + small_page_size]
+ outf.write(hashlib.sha256(page).digest())
+ outf.write(pageable_bin[init_bin_size:])
+
+
+def output_header_v2(elffile, outf):
+ arch_id = get_arch_id(elffile)
+ init_load_addr = get_init_load_addr(elffile)
+ init_bin_size = get_symbol(elffile, '__init_size')['st_value']
+ pager_bin_size = len(get_pager_bin(elffile))
+ paged_area_size = len(get_pageable_bin(elffile))
+ hash_size = (paged_area_size // small_page_size *
+ hashlib.sha256().digest_size)
+
+ if paged_area_size % small_page_size != 0:
+ eprint("pageable size not a multiple of 4K: "
+ "{}".format(paged_area_size))
+ sys.exit(1)
+
+ 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)
+
+ magic = 0x4554504f # 'OPTE'
+ version = 2
+ flags = 0
+ nb_images = 1 if paged_size == 0 else 2
+ outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags,
+ nb_images))
+ outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1],
+ 0, init_size))
+ if nb_images == 2:
+ outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))
+
+
+def output_pager_v2(elffile, outf):
+ init_bin_size = get_symbol(elffile, '__init_size')['st_value']
+ pageable_bin = get_pageable_bin(elffile)
+
+ if len(pageable_bin) % small_page_size != 0:
+ eprint("pageable size not a multiple of 4K: "
+ "{}".format(paged_area_size))
+ sys.exit(1)
+
+ outf.write(get_pager_bin(elffile))
+ outf.write(pageable_bin[:init_bin_size])
+ for n in range(0, len(pageable_bin), small_page_size):
+ page = pageable_bin[n:n + small_page_size]
+ outf.write(hashlib.sha256(page).digest())
+
+
+def output_pageable_v2(elffile, outf):
+ init_bin_size = get_symbol(elffile, '__init_size')['st_value']
+ outf.write(get_pageable_bin(elffile)[init_bin_size:])
+
+
+def get_args():
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument('--input',
+ required=True, type=argparse.FileType('rb'),
+ help='The input tee.elf')
+
+ parser.add_argument('--out_tee_bin',
+ required=False, type=argparse.FileType('wb'),
+ help='The output tee.bin')
+
+ parser.add_argument('--out_tee_pager_bin',
+ required=False, type=argparse.FileType('wb'),
+ help='The output tee_pager.bin')
+
+ parser.add_argument('--out_tee_pageable_bin',
+ required=False, type=argparse.FileType('wb'),
+ help='The output tee_pageable.bin')
+
+ parser.add_argument('--out_header_v2',
+ required=False, type=argparse.FileType('wb'),
+ help='The output tee_header_v2.bin')
+
+ parser.add_argument('--out_pager_v2',
+ required=False, type=argparse.FileType('wb'),
+ help='The output tee_pager_v2.bin')
+
+ parser.add_argument('--out_pageable_v2',
+ required=False, type=argparse.FileType('wb'),
+ help='The output tee_pageable_v2.bin')
+
+ return parser.parse_args()
+
+
+def main():
+ args = get_args()
+
+ elffile = ELFFile(args.input)
+
+ if args.out_tee_bin:
+ output_header_v1(elffile, args.out_tee_bin)
+
+ if args.out_tee_pager_bin:
+ output_pager_bin(elffile, args.out_tee_pager_bin)
+
+ if args.out_tee_pageable_bin:
+ output_pageable_bin(elffile, args.out_tee_pageable_bin)
+
+ if args.out_header_v2:
+ output_header_v2(elffile, args.out_header_v2)
+
+ if args.out_pager_v2:
+ output_pager_v2(elffile, args.out_pager_v2)
+
+ if args.out_pageable_v2:
+ output_pageable_v2(elffile, args.out_pageable_v2)
+
+
+if __name__ == "__main__":
+ main()