xref: /optee_os/scripts/gen_tee_bin.py (revision 5dd1570ac5b0f6563b1a9c074533a19107b8222d)
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
183c51966bSJens Wiklander    from elftools.elf.sections import SymbolTableSection
193c51966bSJens Wiklander
203c51966bSJens Wiklanderexcept ImportError:
213c51966bSJens Wiklander    print("""
223c51966bSJens Wiklander***
233c51966bSJens WiklanderCan't find elftools module. Probably it is not installed on your system.
243c51966bSJens WiklanderYou can install this module with
253c51966bSJens Wiklander
263c51966bSJens Wiklander$ apt install python3-pyelftools
273c51966bSJens Wiklander
283c51966bSJens Wiklanderif you are using Ubuntu. Or try to search for "pyelftools" or "elftools" in
293c51966bSJens Wiklanderyour package manager if you are using some other distribution.
303c51966bSJens Wiklander***
313c51966bSJens Wiklander""")
323c51966bSJens Wiklander    raise
333c51966bSJens Wiklander
343c51966bSJens Wiklandersmall_page_size = 4 * 1024
353c51966bSJens Wiklanderelffile_symbols = None
363c51966bSJens Wiklandertee_pageable_bin = None
373c51966bSJens Wiklandertee_pager_bin = None
38*5dd1570aSJens Wiklandertee_embdata_bin = None
393c51966bSJens Wiklander
403c51966bSJens Wiklander
413c51966bSJens Wiklanderdef eprint(*args, **kwargs):
423c51966bSJens Wiklander    print(*args, file=sys.stderr, **kwargs)
433c51966bSJens Wiklander
443c51966bSJens Wiklander
45*5dd1570aSJens Wiklanderdef round_up(n, m):
46*5dd1570aSJens Wiklander    if n == 0:
47*5dd1570aSJens Wiklander        return 0
48*5dd1570aSJens Wiklander    else:
49*5dd1570aSJens Wiklander        return (((n - 1) // m) + 1) * m
50*5dd1570aSJens Wiklander
51*5dd1570aSJens Wiklander
52*5dd1570aSJens Wiklanderdef get_arch_id(elffile):
53*5dd1570aSJens Wiklander    e_machine = elffile.header['e_machine']
54*5dd1570aSJens Wiklander    if e_machine == 'EM_ARM':
55*5dd1570aSJens Wiklander        return 0
56*5dd1570aSJens Wiklander    if e_machine == 'EM_AARCH64':
57*5dd1570aSJens Wiklander        return 1
58*5dd1570aSJens Wiklander    eprint('Unknown e_machine "%s"' % e_machine)
59*5dd1570aSJens Wiklander    sys.exit(1)
60*5dd1570aSJens Wiklander
61*5dd1570aSJens Wiklander
623c51966bSJens Wiklanderdef get_symbol(elffile, name):
633c51966bSJens Wiklander    global elffile_symbols
643c51966bSJens Wiklander    if elffile_symbols is None:
653c51966bSJens Wiklander        elffile_symbols = dict()
663c51966bSJens Wiklander        symbol_tables = [s for s in elffile.iter_sections()
673c51966bSJens Wiklander                         if isinstance(s, SymbolTableSection)]
683c51966bSJens Wiklander        for section in symbol_tables:
693c51966bSJens Wiklander            for symbol in section.iter_symbols():
703c51966bSJens Wiklander                if symbol['st_info']['bind'] == 'STB_GLOBAL':
713c51966bSJens Wiklander                    elffile_symbols[symbol.name] = symbol
723c51966bSJens Wiklander
733c51966bSJens Wiklander    try:
743c51966bSJens Wiklander        return elffile_symbols[name]
753c51966bSJens Wiklander    except (KeyError):
763c51966bSJens Wiklander        eprint("Cannot find symbol %s" % name)
773c51966bSJens Wiklander        sys.exit(1)
783c51966bSJens Wiklander
793c51966bSJens Wiklander
80*5dd1570aSJens Wiklanderdef get_sections(elffile, pad_to, dump_names):
813c51966bSJens Wiklander    last_end = 0
823c51966bSJens Wiklander    bin_data = bytearray()
833c51966bSJens Wiklander
843c51966bSJens Wiklander    for section in elffile.iter_sections():
853c51966bSJens Wiklander        if (section['sh_type'] == 'SHT_NOBITS' or
863c51966bSJens Wiklander                not (section['sh_flags'] & SH_FLAGS.SHF_ALLOC) or
873c51966bSJens Wiklander                not dump_names.match(section.name)):
883c51966bSJens Wiklander            continue
893c51966bSJens Wiklander
903c51966bSJens Wiklander        if last_end == 0:
913c51966bSJens Wiklander            bin_data = section.data()
923c51966bSJens Wiklander        else:
933c51966bSJens Wiklander            if section['sh_addr'] > last_end:
943c51966bSJens Wiklander                bin_data += bytearray(section['sh_addr'] - last_end)
953c51966bSJens Wiklander            bin_data += section.data()
963c51966bSJens Wiklander
973c51966bSJens Wiklander        last_end = section['sh_addr'] + section['sh_size']
983c51966bSJens Wiklander
993c51966bSJens Wiklander    if pad_to > last_end:
1003c51966bSJens Wiklander        bin_data += bytearray(pad_to - last_end)
1013c51966bSJens Wiklander        last_end = pad_to
1023c51966bSJens Wiklander
1033c51966bSJens Wiklander    return bin_data
1043c51966bSJens Wiklander
1053c51966bSJens Wiklander
1063c51966bSJens Wiklanderdef get_pageable_bin(elffile):
1073c51966bSJens Wiklander    global tee_pageable_bin
1083c51966bSJens Wiklander    if tee_pageable_bin is None:
1093c51966bSJens Wiklander        pad_to = 0
1103c51966bSJens Wiklander        dump_names = re.compile(r'^\..*_(pageable|init)$')
111*5dd1570aSJens Wiklander        tee_pageable_bin = get_sections(elffile, pad_to, dump_names)
1123c51966bSJens Wiklander    return tee_pageable_bin
1133c51966bSJens Wiklander
1143c51966bSJens Wiklander
1153c51966bSJens Wiklanderdef get_pager_bin(elffile):
1163c51966bSJens Wiklander    global tee_pager_bin
1173c51966bSJens Wiklander    if tee_pager_bin is None:
1183c51966bSJens Wiklander        pad_to = get_symbol(elffile, '__data_end')['st_value']
119*5dd1570aSJens Wiklander        dump_names = re.compile(
120*5dd1570aSJens Wiklander            r'^\.(text|rodata|got|data|ARM\.exidx|ARM\.extab|rel|rela)$')
121*5dd1570aSJens Wiklander        tee_pager_bin = get_sections(elffile, pad_to, dump_names)
1223c51966bSJens Wiklander
1233c51966bSJens Wiklander    return tee_pager_bin
1243c51966bSJens Wiklander
1253c51966bSJens Wiklander
126*5dd1570aSJens Wiklanderdef get_hashes_bin(elffile):
127*5dd1570aSJens Wiklander    pageable_bin = get_pageable_bin(elffile)
128*5dd1570aSJens Wiklander    if len(pageable_bin) % small_page_size != 0:
129*5dd1570aSJens Wiklander        eprint("pageable size not a multiple of 4K: "
130*5dd1570aSJens Wiklander               "{}".format(paged_area_size))
131*5dd1570aSJens Wiklander        sys.exit(1)
132*5dd1570aSJens Wiklander
133*5dd1570aSJens Wiklander    data = bytearray()
134*5dd1570aSJens Wiklander    for n in range(0, len(pageable_bin), small_page_size):
135*5dd1570aSJens Wiklander        page = pageable_bin[n:n + small_page_size]
136*5dd1570aSJens Wiklander        data += hashlib.sha256(page).digest()
137*5dd1570aSJens Wiklander
138*5dd1570aSJens Wiklander    return data
139*5dd1570aSJens Wiklander
140*5dd1570aSJens Wiklander
141*5dd1570aSJens Wiklanderdef get_embdata_bin(elffile):
142*5dd1570aSJens Wiklander    global tee_embdata_bin
143*5dd1570aSJens Wiklander    if tee_embdata_bin is None:
144*5dd1570aSJens Wiklander        hashes_bin = get_hashes_bin(elffile)
145*5dd1570aSJens Wiklander
146*5dd1570aSJens Wiklander        num_entries = 1
147*5dd1570aSJens Wiklander        hash_offs = 2 * 4 + num_entries * (2 * 4)
148*5dd1570aSJens Wiklander        hash_pad = round_up(len(hashes_bin), 8) - len(hashes_bin)
149*5dd1570aSJens Wiklander        total_len = hash_offs + len(hashes_bin) + hash_pad
150*5dd1570aSJens Wiklander
151*5dd1570aSJens Wiklander        tee_embdata_bin = struct.pack('<IIII', total_len, num_entries,
152*5dd1570aSJens Wiklander                                      hash_offs, len(hashes_bin))
153*5dd1570aSJens Wiklander        tee_embdata_bin += hashes_bin + bytearray(hash_pad)
154*5dd1570aSJens Wiklander
155*5dd1570aSJens Wiklander    # The embedded data region is designed to be easy to extend when
156*5dd1570aSJens Wiklander    # needed, it's formatted as:
157*5dd1570aSJens Wiklander    # +--------------------------------------------------------+
158*5dd1570aSJens Wiklander    # | uint32_t: Length of entire area including this field   |
159*5dd1570aSJens Wiklander    # +--------------------------------------------------------+
160*5dd1570aSJens Wiklander    # | uint32_t: Number of entries "1"                        |
161*5dd1570aSJens Wiklander    # +--------------------------------------------------------+
162*5dd1570aSJens Wiklander    # | uint32_t: Offset of hashes from beginning of table     |
163*5dd1570aSJens Wiklander    # +--------------------------------------------------------+
164*5dd1570aSJens Wiklander    # | uint32_t: Length of hashes                             |
165*5dd1570aSJens Wiklander    # +--------------------------------------------------------+
166*5dd1570aSJens Wiklander    # | Data of hashes + eventual padding                      |
167*5dd1570aSJens Wiklander    # +--------------------------------------------------------+
168*5dd1570aSJens Wiklander
169*5dd1570aSJens Wiklander    return tee_embdata_bin
170*5dd1570aSJens Wiklander
171*5dd1570aSJens Wiklander
1723c51966bSJens Wiklanderdef output_pager_bin(elffile, outf):
1733c51966bSJens Wiklander    outf.write(get_pager_bin(elffile))
1743c51966bSJens Wiklander
1753c51966bSJens Wiklander
1763c51966bSJens Wiklanderdef output_pageable_bin(elffile, outf):
1773c51966bSJens Wiklander    outf.write(get_pageable_bin(elffile))
1783c51966bSJens Wiklander
1793c51966bSJens Wiklander
1803c51966bSJens Wiklanderdef get_init_load_addr(elffile):
1813c51966bSJens Wiklander    init_load_addr = get_symbol(elffile, '_start')['st_value']
1823c51966bSJens Wiklander    init_load_addr_hi = init_load_addr >> 32
1833c51966bSJens Wiklander    init_load_addr_lo = init_load_addr & 0xffffffff
1843c51966bSJens Wiklander    return init_load_addr_hi, init_load_addr_lo
1853c51966bSJens Wiklander
1863c51966bSJens Wiklander
1873c51966bSJens Wiklanderdef output_header_v1(elffile, outf):
1883c51966bSJens Wiklander    arch_id = get_arch_id(elffile)
1893c51966bSJens Wiklander    pager_bin = get_pager_bin(elffile)
1903c51966bSJens Wiklander    pageable_bin = get_pageable_bin(elffile)
191*5dd1570aSJens Wiklander    embdata_bin = get_embdata_bin(elffile)
1923c51966bSJens Wiklander    init_load_addr = get_init_load_addr(elffile)
1933c51966bSJens Wiklander    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
1943c51966bSJens Wiklander    pager_bin_size = len(pager_bin)
1953c51966bSJens Wiklander    paged_area_size = len(pageable_bin)
196*5dd1570aSJens Wiklander
197*5dd1570aSJens Wiklander    init_mem_usage = (get_symbol(elffile, '__init_end')['st_value'] -
198*5dd1570aSJens Wiklander                      get_symbol(elffile, '__text_start')['st_value'] +
199*5dd1570aSJens Wiklander                      len(embdata_bin))
2003c51966bSJens Wiklander
2013c51966bSJens Wiklander    init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
202*5dd1570aSJens Wiklander                 len(embdata_bin))
2033c51966bSJens Wiklander    paged_size = paged_area_size - min(init_bin_size, paged_area_size)
2043c51966bSJens Wiklander
2053c51966bSJens Wiklander    magic = 0x4554504f  # 'OPTE'
2063c51966bSJens Wiklander    version = 1
2073c51966bSJens Wiklander    flags = 0
2083c51966bSJens Wiklander    outf.write(struct.pack('<IBBHIIIII', magic, version, arch_id, flags,
2093c51966bSJens Wiklander                           init_size, init_load_addr[0], init_load_addr[1],
2103c51966bSJens Wiklander                           init_mem_usage, paged_size))
2113c51966bSJens Wiklander    outf.write(pager_bin)
2123c51966bSJens Wiklander    outf.write(pageable_bin[:init_bin_size])
213*5dd1570aSJens Wiklander    outf.write(embdata_bin)
2143c51966bSJens Wiklander    outf.write(pageable_bin[init_bin_size:])
2153c51966bSJens Wiklander
2163c51966bSJens Wiklander
2173c51966bSJens Wiklanderdef output_header_v2(elffile, outf):
2183c51966bSJens Wiklander    arch_id = get_arch_id(elffile)
2193c51966bSJens Wiklander    init_load_addr = get_init_load_addr(elffile)
2203c51966bSJens Wiklander    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
2213c51966bSJens Wiklander    pager_bin_size = len(get_pager_bin(elffile))
2223c51966bSJens Wiklander    paged_area_size = len(get_pageable_bin(elffile))
223*5dd1570aSJens Wiklander    embdata_bin_size = len(get_embdata_bin(elffile))
2243c51966bSJens Wiklander
2253c51966bSJens Wiklander    init_size = (pager_bin_size + min(init_bin_size, paged_area_size) +
226*5dd1570aSJens Wiklander                 embdata_bin_size)
2273c51966bSJens Wiklander    paged_size = paged_area_size - min(init_bin_size, paged_area_size)
2283c51966bSJens Wiklander
2293c51966bSJens Wiklander    magic = 0x4554504f  # 'OPTE'
2303c51966bSJens Wiklander    version = 2
2313c51966bSJens Wiklander    flags = 0
2323c51966bSJens Wiklander    nb_images = 1 if paged_size == 0 else 2
2333c51966bSJens Wiklander    outf.write(struct.pack('<IBBHI', magic, version, arch_id, flags,
2343c51966bSJens Wiklander                           nb_images))
2353c51966bSJens Wiklander    outf.write(struct.pack('<IIII', init_load_addr[0], init_load_addr[1],
2363c51966bSJens Wiklander                           0, init_size))
2373c51966bSJens Wiklander    if nb_images == 2:
2383c51966bSJens Wiklander        outf.write(struct.pack('<IIII', 0xffffffff, 0xffffffff, 1, paged_size))
2393c51966bSJens Wiklander
2403c51966bSJens Wiklander
2413c51966bSJens Wiklanderdef output_pager_v2(elffile, outf):
2423c51966bSJens Wiklander    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
243*5dd1570aSJens Wiklander    pager_bin = get_pager_bin(elffile)
2443c51966bSJens Wiklander    pageable_bin = get_pageable_bin(elffile)
245*5dd1570aSJens Wiklander    embdata_bin = get_embdata_bin(elffile)
2463c51966bSJens Wiklander
247*5dd1570aSJens Wiklander    outf.write(pager_bin)
2483c51966bSJens Wiklander    outf.write(pageable_bin[:init_bin_size])
249*5dd1570aSJens Wiklander    outf.write(embdata_bin)
2503c51966bSJens Wiklander
2513c51966bSJens Wiklander
2523c51966bSJens Wiklanderdef output_pageable_v2(elffile, outf):
2533c51966bSJens Wiklander    init_bin_size = get_symbol(elffile, '__init_size')['st_value']
2543c51966bSJens Wiklander    outf.write(get_pageable_bin(elffile)[init_bin_size:])
2553c51966bSJens Wiklander
2563c51966bSJens Wiklander
2573c51966bSJens Wiklanderdef get_args():
2583c51966bSJens Wiklander    parser = argparse.ArgumentParser()
2593c51966bSJens Wiklander
2603c51966bSJens Wiklander    parser.add_argument('--input',
2613c51966bSJens Wiklander                        required=True, type=argparse.FileType('rb'),
2623c51966bSJens Wiklander                        help='The input tee.elf')
2633c51966bSJens Wiklander
2643c51966bSJens Wiklander    parser.add_argument('--out_tee_bin',
2653c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
2663c51966bSJens Wiklander                        help='The output tee.bin')
2673c51966bSJens Wiklander
2683c51966bSJens Wiklander    parser.add_argument('--out_tee_pager_bin',
2693c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
2703c51966bSJens Wiklander                        help='The output tee_pager.bin')
2713c51966bSJens Wiklander
2723c51966bSJens Wiklander    parser.add_argument('--out_tee_pageable_bin',
2733c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
2743c51966bSJens Wiklander                        help='The output tee_pageable.bin')
2753c51966bSJens Wiklander
2763c51966bSJens Wiklander    parser.add_argument('--out_header_v2',
2773c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
2783c51966bSJens Wiklander                        help='The output tee_header_v2.bin')
2793c51966bSJens Wiklander
2803c51966bSJens Wiklander    parser.add_argument('--out_pager_v2',
2813c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
2823c51966bSJens Wiklander                        help='The output tee_pager_v2.bin')
2833c51966bSJens Wiklander
2843c51966bSJens Wiklander    parser.add_argument('--out_pageable_v2',
2853c51966bSJens Wiklander                        required=False, type=argparse.FileType('wb'),
2863c51966bSJens Wiklander                        help='The output tee_pageable_v2.bin')
2873c51966bSJens Wiklander
2883c51966bSJens Wiklander    return parser.parse_args()
2893c51966bSJens Wiklander
2903c51966bSJens Wiklander
2913c51966bSJens Wiklanderdef main():
2923c51966bSJens Wiklander    args = get_args()
2933c51966bSJens Wiklander
2943c51966bSJens Wiklander    elffile = ELFFile(args.input)
2953c51966bSJens Wiklander
2963c51966bSJens Wiklander    if args.out_tee_bin:
2973c51966bSJens Wiklander        output_header_v1(elffile, args.out_tee_bin)
2983c51966bSJens Wiklander
2993c51966bSJens Wiklander    if args.out_tee_pager_bin:
3003c51966bSJens Wiklander        output_pager_bin(elffile, args.out_tee_pager_bin)
3013c51966bSJens Wiklander
3023c51966bSJens Wiklander    if args.out_tee_pageable_bin:
3033c51966bSJens Wiklander        output_pageable_bin(elffile, args.out_tee_pageable_bin)
3043c51966bSJens Wiklander
3053c51966bSJens Wiklander    if args.out_header_v2:
3063c51966bSJens Wiklander        output_header_v2(elffile, args.out_header_v2)
3073c51966bSJens Wiklander
3083c51966bSJens Wiklander    if args.out_pager_v2:
3093c51966bSJens Wiklander        output_pager_v2(elffile, args.out_pager_v2)
3103c51966bSJens Wiklander
3113c51966bSJens Wiklander    if args.out_pageable_v2:
3123c51966bSJens Wiklander        output_pageable_v2(elffile, args.out_pageable_v2)
3133c51966bSJens Wiklander
3143c51966bSJens Wiklander
3153c51966bSJens Wiklanderif __name__ == "__main__":
3163c51966bSJens Wiklander    main()
317