xref: /optee_os/scripts/gen_tee_bin.py (revision 5966660c02b34dacb8ec40cd3c26a16a19287973)
13c51966bSJens Wiklander#!/usr/bin/env python3
23c51966bSJens Wiklander# SPDX-License-Identifier: BSD-2-Clause
33c51966bSJens Wiklander#
43c51966bSJens Wiklander# Copyright (c) 2019, Linaro Limited
53c51966bSJens Wiklander#
63c51966bSJens Wiklander
73c51966bSJens Wiklanderfrom __future__ import print_function
83c51966bSJens Wiklanderfrom __future__ import division
93c51966bSJens Wiklander
103c51966bSJens Wiklanderimport argparse
113c51966bSJens Wiklanderimport sys
123c51966bSJens Wiklanderimport struct
133c51966bSJens Wiklanderimport re
143c51966bSJens Wiklanderimport hashlib
153c51966bSJens Wiklandertry:
163c51966bSJens Wiklander    from elftools.elf.elffile import ELFFile
173c51966bSJens Wiklander    from elftools.elf.constants import SH_FLAGS
18*5966660cSJens Wiklander    from elftools.elf.enums import ENUM_RELOC_TYPE_ARM
19*5966660cSJens Wiklander    from elftools.elf.enums import ENUM_RELOC_TYPE_AARCH64
203c51966bSJens Wiklander    from elftools.elf.sections import SymbolTableSection
21*5966660cSJens Wiklander    from elftools.elf.relocation import RelocationSection
223c51966bSJens Wiklander
233c51966bSJens Wiklanderexcept ImportError:
243c51966bSJens Wiklander    print("""
253c51966bSJens Wiklander***
263c51966bSJens WiklanderCan't find elftools module. Probably it is not installed on your system.
273c51966bSJens WiklanderYou can install this module with
283c51966bSJens Wiklander
293c51966bSJens Wiklander$ apt install python3-pyelftools
303c51966bSJens Wiklander
313c51966bSJens Wiklanderif you are using Ubuntu. Or try to search for "pyelftools" or "elftools" in
323c51966bSJens Wiklanderyour package manager if you are using some other distribution.
333c51966bSJens Wiklander***
343c51966bSJens Wiklander""")
353c51966bSJens Wiklander    raise
363c51966bSJens Wiklander
373c51966bSJens Wiklandersmall_page_size = 4 * 1024
383c51966bSJens Wiklanderelffile_symbols = None
393c51966bSJens Wiklandertee_pageable_bin = None
403c51966bSJens Wiklandertee_pager_bin = None
415dd1570aSJens Wiklandertee_embdata_bin = None
423c51966bSJens Wiklander
433c51966bSJens Wiklander
443c51966bSJens Wiklanderdef eprint(*args, **kwargs):
453c51966bSJens Wiklander    print(*args, file=sys.stderr, **kwargs)
463c51966bSJens Wiklander
473c51966bSJens Wiklander
485dd1570aSJens Wiklanderdef round_up(n, m):
495dd1570aSJens Wiklander    if n == 0:
505dd1570aSJens Wiklander        return 0
515dd1570aSJens Wiklander    else:
525dd1570aSJens Wiklander        return (((n - 1) // m) + 1) * m
535dd1570aSJens Wiklander
545dd1570aSJens Wiklander
555dd1570aSJens Wiklanderdef get_arch_id(elffile):
565dd1570aSJens Wiklander    e_machine = elffile.header['e_machine']
575dd1570aSJens Wiklander    if e_machine == 'EM_ARM':
585dd1570aSJens Wiklander        return 0
595dd1570aSJens Wiklander    if e_machine == 'EM_AARCH64':
605dd1570aSJens Wiklander        return 1
615dd1570aSJens Wiklander    eprint('Unknown e_machine "%s"' % e_machine)
625dd1570aSJens Wiklander    sys.exit(1)
635dd1570aSJens Wiklander
645dd1570aSJens Wiklander
653c51966bSJens Wiklanderdef get_symbol(elffile, name):
663c51966bSJens Wiklander    global elffile_symbols
673c51966bSJens Wiklander    if elffile_symbols is None:
683c51966bSJens Wiklander        elffile_symbols = dict()
693c51966bSJens Wiklander        symbol_tables = [s for s in elffile.iter_sections()
703c51966bSJens Wiklander                         if isinstance(s, SymbolTableSection)]
713c51966bSJens Wiklander        for section in symbol_tables:
723c51966bSJens Wiklander            for symbol in section.iter_symbols():
733c51966bSJens Wiklander                if symbol['st_info']['bind'] == 'STB_GLOBAL':
743c51966bSJens Wiklander                    elffile_symbols[symbol.name] = symbol
753c51966bSJens Wiklander
763c51966bSJens Wiklander    try:
773c51966bSJens Wiklander        return elffile_symbols[name]
783c51966bSJens Wiklander    except (KeyError):
793c51966bSJens Wiklander        eprint("Cannot find symbol %s" % name)
803c51966bSJens Wiklander        sys.exit(1)
813c51966bSJens Wiklander
823c51966bSJens Wiklander
835dd1570aSJens Wiklanderdef get_sections(elffile, pad_to, dump_names):
843c51966bSJens Wiklander    last_end = 0
853c51966bSJens Wiklander    bin_data = bytearray()
863c51966bSJens Wiklander
873c51966bSJens Wiklander    for section in elffile.iter_sections():
883c51966bSJens Wiklander        if (section['sh_type'] == 'SHT_NOBITS' or
893c51966bSJens Wiklander                not (section['sh_flags'] & SH_FLAGS.SHF_ALLOC) or
903c51966bSJens Wiklander                not dump_names.match(section.name)):
913c51966bSJens Wiklander            continue
923c51966bSJens Wiklander
933c51966bSJens Wiklander        if last_end == 0:
943c51966bSJens Wiklander            bin_data = section.data()
953c51966bSJens Wiklander        else:
963c51966bSJens Wiklander            if section['sh_addr'] > last_end:
973c51966bSJens Wiklander                bin_data += bytearray(section['sh_addr'] - last_end)
983c51966bSJens Wiklander            bin_data += section.data()
993c51966bSJens Wiklander
1003c51966bSJens Wiklander        last_end = section['sh_addr'] + section['sh_size']
1013c51966bSJens Wiklander
1023c51966bSJens Wiklander    if pad_to > last_end:
1033c51966bSJens Wiklander        bin_data += bytearray(pad_to - last_end)
1043c51966bSJens Wiklander        last_end = pad_to
1053c51966bSJens Wiklander
1063c51966bSJens Wiklander    return bin_data
1073c51966bSJens Wiklander
1083c51966bSJens Wiklander
1093c51966bSJens Wiklanderdef get_pageable_bin(elffile):
1103c51966bSJens Wiklander    global tee_pageable_bin
1113c51966bSJens Wiklander    if tee_pageable_bin is None:
1123c51966bSJens Wiklander        pad_to = 0
1133c51966bSJens Wiklander        dump_names = re.compile(r'^\..*_(pageable|init)$')
1145dd1570aSJens Wiklander        tee_pageable_bin = get_sections(elffile, pad_to, dump_names)
1153c51966bSJens Wiklander    return tee_pageable_bin
1163c51966bSJens Wiklander
1173c51966bSJens Wiklander
1183c51966bSJens Wiklanderdef get_pager_bin(elffile):
1193c51966bSJens Wiklander    global tee_pager_bin
1203c51966bSJens Wiklander    if tee_pager_bin is None:
1213c51966bSJens Wiklander        pad_to = get_symbol(elffile, '__data_end')['st_value']
1225dd1570aSJens Wiklander        dump_names = re.compile(
123*5966660cSJens Wiklander            r'^\.(text|rodata|got|data|ARM\.exidx|ARM\.extab)$')
1245dd1570aSJens Wiklander        tee_pager_bin = get_sections(elffile, pad_to, dump_names)
1253c51966bSJens Wiklander
1263c51966bSJens Wiklander    return tee_pager_bin
1273c51966bSJens Wiklander
1283c51966bSJens Wiklander
129*5966660cSJens Wiklanderdef get_reloc_bin(elffile):
130*5966660cSJens Wiklander    if get_arch_id(elffile) == 0:
131*5966660cSJens Wiklander        exp_rel_type = ENUM_RELOC_TYPE_ARM['R_ARM_RELATIVE']
132*5966660cSJens Wiklander    else:
133*5966660cSJens Wiklander        exp_rel_type = ENUM_RELOC_TYPE_AARCH64['R_AARCH64_RELATIVE']
134*5966660cSJens Wiklander
135*5966660cSJens Wiklander    link_address = get_symbol(elffile, '__text_start')['st_value']
136*5966660cSJens Wiklander
137*5966660cSJens Wiklander    addrs = []
138*5966660cSJens Wiklander    for section in elffile.iter_sections():
139*5966660cSJens Wiklander        if not isinstance(section, RelocationSection):
140*5966660cSJens Wiklander            continue
141*5966660cSJens Wiklander        for rel in section.iter_relocations():
142*5966660cSJens Wiklander            if rel['r_info_type'] == 0:
143*5966660cSJens Wiklander                continue
144*5966660cSJens Wiklander            if rel['r_info_type'] != exp_rel_type:
145*5966660cSJens Wiklander                eprint("Unexpected relocation type 0x%x" %
146*5966660cSJens Wiklander                       rel['r_info_type'])
147*5966660cSJens Wiklander                sys.exit(1)
148*5966660cSJens Wiklander            addrs.append(rel['r_offset'] - link_address)
149*5966660cSJens Wiklander
150*5966660cSJens Wiklander    addrs.sort()
151*5966660cSJens Wiklander    data = bytearray()
152*5966660cSJens Wiklander    for a in addrs:
153*5966660cSJens Wiklander        data += struct.pack('<I', a)
154*5966660cSJens Wiklander
155*5966660cSJens Wiklander    # Relocations has been reduced to only become the relative type with
156*5966660cSJens Wiklander    # addend at the address (r_offset) of relocation, that is, increase by
157*5966660cSJens Wiklander    # load_offset. The addresses (r_offset) are also sorted. The format is
158*5966660cSJens Wiklander    # then:
159*5966660cSJens Wiklander    # uint32_t: relocation #1
160*5966660cSJens Wiklander    # uint32_t: relocation #2
161*5966660cSJens Wiklander    # ...
162*5966660cSJens Wiklander    # uint32_t: relocation #n
163*5966660cSJens Wiklander
164*5966660cSJens Wiklander    return data
165*5966660cSJens Wiklander
166*5966660cSJens Wiklander
1675dd1570aSJens Wiklanderdef get_hashes_bin(elffile):
1685dd1570aSJens Wiklander    pageable_bin = get_pageable_bin(elffile)
1695dd1570aSJens Wiklander    if len(pageable_bin) % small_page_size != 0:
1705dd1570aSJens Wiklander        eprint("pageable size not a multiple of 4K: "
1715dd1570aSJens Wiklander               "{}".format(paged_area_size))
1725dd1570aSJens Wiklander        sys.exit(1)
1735dd1570aSJens Wiklander
1745dd1570aSJens Wiklander    data = bytearray()
1755dd1570aSJens Wiklander    for n in range(0, len(pageable_bin), small_page_size):
1765dd1570aSJens Wiklander        page = pageable_bin[n:n + small_page_size]
1775dd1570aSJens Wiklander        data += hashlib.sha256(page).digest()
1785dd1570aSJens Wiklander
1795dd1570aSJens Wiklander    return data
1805dd1570aSJens Wiklander
1815dd1570aSJens Wiklander
1825dd1570aSJens Wiklanderdef get_embdata_bin(elffile):
1835dd1570aSJens Wiklander    global tee_embdata_bin
1845dd1570aSJens Wiklander    if tee_embdata_bin is None:
1855dd1570aSJens Wiklander        hashes_bin = get_hashes_bin(elffile)
186*5966660cSJens Wiklander        reloc_bin = get_reloc_bin(elffile)
1875dd1570aSJens Wiklander
188*5966660cSJens Wiklander        num_entries = 2
1895dd1570aSJens Wiklander        hash_offs = 2 * 4 + num_entries * (2 * 4)
1905dd1570aSJens Wiklander        hash_pad = round_up(len(hashes_bin), 8) - len(hashes_bin)
191*5966660cSJens Wiklander        reloc_offs = hash_offs + len(hashes_bin) + hash_pad
192*5966660cSJens Wiklander        reloc_pad = round_up(len(reloc_bin), 8) - len(reloc_bin)
193*5966660cSJens Wiklander        total_len = reloc_offs + len(reloc_bin) + reloc_pad
1945dd1570aSJens Wiklander
195*5966660cSJens Wiklander        tee_embdata_bin = struct.pack('<IIIIII', total_len, num_entries,
196*5966660cSJens Wiklander                                      hash_offs, len(hashes_bin),
197*5966660cSJens Wiklander                                      reloc_offs, len(reloc_bin))
1985dd1570aSJens Wiklander        tee_embdata_bin += hashes_bin + bytearray(hash_pad)
199*5966660cSJens Wiklander        tee_embdata_bin += reloc_bin + bytearray(reloc_pad)
2005dd1570aSJens Wiklander
2015dd1570aSJens Wiklander    # The embedded data region is designed to be easy to extend when
2025dd1570aSJens Wiklander    # needed, it's formatted as:
203*5966660cSJens Wiklander    # +---------------------------------------------------------+
2045dd1570aSJens Wiklander    # | uint32_t: Length of entire area including this field    |
205*5966660cSJens Wiklander    # +---------------------------------------------------------+
206*5966660cSJens Wiklander    # | uint32_t: Number of entries "2"                         |
207*5966660cSJens Wiklander    # +---------------------------------------------------------+
2085dd1570aSJens Wiklander    # | uint32_t: Offset of hashes from beginning of table      |
209*5966660cSJens Wiklander    # +---------------------------------------------------------+
2105dd1570aSJens Wiklander    # | uint32_t: Length of hashes                              |
211*5966660cSJens Wiklander    # +---------------------------------------------------------+
212*5966660cSJens Wiklander    # | uint32_t: Offset of relocations from beginning of table |
213*5966660cSJens Wiklander    # +---------------------------------------------------------+
214*5966660cSJens Wiklander    # | uint32_t: Length of relocations                         |
215*5966660cSJens Wiklander    # +---------------------------------------------------------+
2165dd1570aSJens Wiklander    # | Data of hashes + eventual padding                       |
217*5966660cSJens Wiklander    # +---------------------------------------------------------+
218*5966660cSJens Wiklander    # | Data of relocations + eventual padding                  |
219*5966660cSJens Wiklander    # +---------------------------------------------------------+
2205dd1570aSJens Wiklander
2215dd1570aSJens Wiklander    return tee_embdata_bin
2225dd1570aSJens Wiklander
2235dd1570aSJens Wiklander
2243c51966bSJens Wiklanderdef output_pager_bin(elffile, outf):
2253c51966bSJens Wiklander    outf.write(get_pager_bin(elffile))
2263c51966bSJens Wiklander
2273c51966bSJens Wiklander
2283c51966bSJens Wiklanderdef output_pageable_bin(elffile, outf):
2293c51966bSJens Wiklander    outf.write(get_pageable_bin(elffile))
2303c51966bSJens Wiklander
2313c51966bSJens Wiklander
2323c51966bSJens Wiklanderdef get_init_load_addr(elffile):
2333c51966bSJens Wiklander    init_load_addr = get_symbol(elffile, '_start')['st_value']
2343c51966bSJens Wiklander    init_load_addr_hi = init_load_addr >> 32
2353c51966bSJens Wiklander    init_load_addr_lo = init_load_addr & 0xffffffff
2363c51966bSJens Wiklander    return init_load_addr_hi, init_load_addr_lo
2373c51966bSJens Wiklander
2383c51966bSJens Wiklander
2393c51966bSJens Wiklanderdef output_header_v1(elffile, outf):
2403c51966bSJens Wiklander    arch_id = get_arch_id(elffile)
2413c51966bSJens Wiklander    pager_bin = get_pager_bin(elffile)
2423c51966bSJens Wiklander    pageable_bin = get_pageable_bin(elffile)
2435dd1570aSJens Wiklander    embdata_bin = get_embdata_bin(elffile)
2443c51966bSJens Wiklander    init_load_addr = get_init_load_addr(elffile)
2453c51966bSJens Wiklander    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
2463c51966bSJens Wiklander    pager_bin_size = len(pager_bin)
2473c51966bSJens Wiklander    paged_area_size = len(pageable_bin)
2485dd1570aSJens Wiklander
2495dd1570aSJens Wiklander    init_mem_usage = (get_symbol(elffile, '__init_end')['st_value'] -
2505dd1570aSJens Wiklander                      get_symbol(elffile, '__text_start')['st_value'] +
2515dd1570aSJens Wiklander                      len(embdata_bin))
2523c51966bSJens Wiklander
2533c51966bSJens Wiklander    init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
2545dd1570aSJens Wiklander                 len(embdata_bin))
2553c51966bSJens Wiklander    paged_size = paged_area_size - min(init_bin_size, paged_area_size)
2563c51966bSJens Wiklander
2573c51966bSJens Wiklander    magic = 0x4554504f  # 'OPTE'
2583c51966bSJens Wiklander    version = 1
2593c51966bSJens Wiklander    flags = 0
2603c51966bSJens Wiklander    outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags,
2613c51966bSJens Wiklander                           init_size, init_load_addr[0], init_load_addr[1],
2623c51966bSJens Wiklander                           init_mem_usage, paged_size))
2633c51966bSJens Wiklander    outf.write(pager_bin)
2643c51966bSJens Wiklander    outf.write(pageable_bin[:init_bin_size])
2655dd1570aSJens Wiklander    outf.write(embdata_bin)
2663c51966bSJens Wiklander    outf.write(pageable_bin[init_bin_size:])
2673c51966bSJens Wiklander
2683c51966bSJens Wiklander
2693c51966bSJens Wiklanderdef output_header_v2(elffile, outf):
2703c51966bSJens Wiklander    arch_id = get_arch_id(elffile)
2713c51966bSJens Wiklander    init_load_addr = get_init_load_addr(elffile)
2723c51966bSJens Wiklander    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
2733c51966bSJens Wiklander    pager_bin_size = len(get_pager_bin(elffile))
2743c51966bSJens Wiklander    paged_area_size = len(get_pageable_bin(elffile))
2755dd1570aSJens Wiklander    embdata_bin_size = len(get_embdata_bin(elffile))
2763c51966bSJens Wiklander
2773c51966bSJens Wiklander    init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
2785dd1570aSJens Wiklander                 embdata_bin_size)
2793c51966bSJens Wiklander    paged_size = paged_area_size - min(init_bin_size, paged_area_size)
2803c51966bSJens Wiklander
2813c51966bSJens Wiklander    magic = 0x4554504f  # 'OPTE'
2823c51966bSJens Wiklander    version = 2
2833c51966bSJens Wiklander    flags = 0
2843c51966bSJens Wiklander    nb_images = 1 if paged_size == 0 else 2
2853c51966bSJens Wiklander    outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags,
2863c51966bSJens Wiklander                           nb_images))
2873c51966bSJens Wiklander    outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1],
2883c51966bSJens Wiklander                           0, init_size))
2893c51966bSJens Wiklander    if nb_images == 2:
2903c51966bSJens Wiklander        outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))
2913c51966bSJens Wiklander
2923c51966bSJens Wiklander
2933c51966bSJens Wiklanderdef output_pager_v2(elffile, outf):
2943c51966bSJens Wiklander    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
2955dd1570aSJens Wiklander    pager_bin = get_pager_bin(elffile)
2963c51966bSJens Wiklander    pageable_bin = get_pageable_bin(elffile)
2975dd1570aSJens Wiklander    embdata_bin = get_embdata_bin(elffile)
2983c51966bSJens Wiklander
2995dd1570aSJens Wiklander    outf.write(pager_bin)
3003c51966bSJens Wiklander    outf.write(pageable_bin[:init_bin_size])
3015dd1570aSJens Wiklander    outf.write(embdata_bin)
3023c51966bSJens Wiklander
3033c51966bSJens Wiklander
3043c51966bSJens Wiklanderdef output_pageable_v2(elffile, outf):
3053c51966bSJens Wiklander    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
3063c51966bSJens Wiklander    outf.write(get_pageable_bin(elffile)[init_bin_size:])
3073c51966bSJens Wiklander
3083c51966bSJens Wiklander
3093c51966bSJens Wiklanderdef get_args():
3103c51966bSJens Wiklander    parser = argparse.ArgumentParser()
3113c51966bSJens Wiklander
3123c51966bSJens Wiklander    parser.add_argument('--input',
3133c51966bSJens Wiklander                        required=True, type=argparse.FileType('rb'),
3143c51966bSJens Wiklander                        help='The input tee.elf')
3153c51966bSJens Wiklander
3163c51966bSJens Wiklander    parser.add_argument('--out_tee_bin',
3173c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
3183c51966bSJens Wiklander                        help='The output tee.bin')
3193c51966bSJens Wiklander
3203c51966bSJens Wiklander    parser.add_argument('--out_tee_pager_bin',
3213c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
3223c51966bSJens Wiklander                        help='The output tee_pager.bin')
3233c51966bSJens Wiklander
3243c51966bSJens Wiklander    parser.add_argument('--out_tee_pageable_bin',
3253c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
3263c51966bSJens Wiklander                        help='The output tee_pageable.bin')
3273c51966bSJens Wiklander
3283c51966bSJens Wiklander    parser.add_argument('--out_header_v2',
3293c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
3303c51966bSJens Wiklander                        help='The output tee_header_v2.bin')
3313c51966bSJens Wiklander
3323c51966bSJens Wiklander    parser.add_argument('--out_pager_v2',
3333c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
3343c51966bSJens Wiklander                        help='The output tee_pager_v2.bin')
3353c51966bSJens Wiklander
3363c51966bSJens Wiklander    parser.add_argument('--out_pageable_v2',
3373c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
3383c51966bSJens Wiklander                        help='The output tee_pageable_v2.bin')
3393c51966bSJens Wiklander
3403c51966bSJens Wiklander    return parser.parse_args()
3413c51966bSJens Wiklander
3423c51966bSJens Wiklander
3433c51966bSJens Wiklanderdef main():
3443c51966bSJens Wiklander    args = get_args()
3453c51966bSJens Wiklander
3463c51966bSJens Wiklander    elffile = ELFFile(args.input)
3473c51966bSJens Wiklander
3483c51966bSJens Wiklander    if args.out_tee_bin:
3493c51966bSJens Wiklander        output_header_v1(elffile, args.out_tee_bin)
3503c51966bSJens Wiklander
3513c51966bSJens Wiklander    if args.out_tee_pager_bin:
3523c51966bSJens Wiklander        output_pager_bin(elffile, args.out_tee_pager_bin)
3533c51966bSJens Wiklander
3543c51966bSJens Wiklander    if args.out_tee_pageable_bin:
3553c51966bSJens Wiklander        output_pageable_bin(elffile, args.out_tee_pageable_bin)
3563c51966bSJens Wiklander
3573c51966bSJens Wiklander    if args.out_header_v2:
3583c51966bSJens Wiklander        output_header_v2(elffile, args.out_header_v2)
3593c51966bSJens Wiklander
3603c51966bSJens Wiklander    if args.out_pager_v2:
3613c51966bSJens Wiklander        output_pager_v2(elffile, args.out_pager_v2)
3623c51966bSJens Wiklander
3633c51966bSJens Wiklander    if args.out_pageable_v2:
3643c51966bSJens Wiklander        output_pageable_v2(elffile, args.out_pageable_v2)
3653c51966bSJens Wiklander
3663c51966bSJens Wiklander
3673c51966bSJens Wiklanderif __name__ == "__main__":
3683c51966bSJens Wiklander    main()
369