1# SPDX-License-Identifier: GPL-2.0+ 2# Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ 3# 4# Entry-type module for OP-TEE Trusted OS firmware blob 5# 6 7import struct 8 9from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg 10from binman import elf 11 12class Entry_tee_os(Entry_blob_named_by_arg): 13 """Entry containing an OP-TEE Trusted OS (TEE) blob 14 15 Properties / Entry arguments: 16 - tee-os-path: Filename of file to read into entry. This is typically 17 called tee.bin or tee.elf 18 19 This entry holds the run-time firmware, typically started by U-Boot SPL. 20 See the U-Boot README for your architecture or board for how to use it. See 21 https://github.com/OP-TEE/optee_os for more information about OP-TEE. 22 23 Note that if the file is in ELF format, it must go in a FIT. In that case, 24 this entry will mark itself as absent, providing the data only through the 25 read_elf_segments() method. 26 27 Marking this entry as absent means that it if is used in the wrong context 28 it can be automatically dropped. Thus it is possible to add an OP-TEE entry 29 like this:: 30 31 binman { 32 tee-os { 33 }; 34 }; 35 36 and pass either an ELF or plain binary in with -a tee-os-path <filename> 37 and have binman do the right thing: 38 39 - include the entry if tee.bin is provided and it does NOT have the v1 40 header 41 - drop it otherwise 42 43 When used within a FIT, we can do:: 44 45 binman { 46 fit { 47 tee-os { 48 }; 49 }; 50 }; 51 52 which will split the ELF into separate nodes for each segment, if an ELF 53 file is provided (see :ref:`etype_fit`), or produce a single node if the 54 OP-TEE binary v1 format is provided (see optee_doc_) . 55 56 .. _optee_doc: https://optee.readthedocs.io/en/latest/architecture/core.html#partitioning-of-the-binary 57 """ 58 def __init__(self, section, etype, node): 59 super().__init__(section, etype, node, 'tee-os') 60 self.external = True 61 62 @staticmethod 63 def is_optee_bin_v1(data): 64 return len(data) >= 8 and data[0:5] == b'OPTE\x01' 65 66 def ObtainContents(self, fake_size=0): 67 result = super().ObtainContents(fake_size) 68 if not self.missing: 69 # If using the flat binary (without the OP-TEE header), then it is 70 # just included as a blob. But if it is an ELF or usees the v1 71 # binary header, then the FIT implementation will call 72 # read_elf_segments() to get the segment information 73 if elf.is_valid(self.data): 74 self.mark_absent('uses Elf format which must be in a FIT') 75 elif self.is_optee_bin_v1(self.data): 76 # The FIT implementation will call read_elf_segments() to get 77 # the segment information 78 self.mark_absent('uses v1 format which must be in a FIT') 79 return result 80 81 def read_elf_segments(self): 82 data = self.GetData() 83 if self.is_optee_bin_v1(data): 84 # OP-TEE v1 format (tee.bin) 85 init_sz, start_hi, start_lo, _, paged_sz = ( 86 struct.unpack_from('<5I', data, 0x8)) 87 if paged_sz != 0: 88 self.Raise("OP-TEE paged mode not supported") 89 e_entry = (start_hi << 32) + start_lo 90 p_addr = e_entry 91 p_data = data[0x1c:] 92 if len(p_data) != init_sz: 93 self.Raise("Invalid OP-TEE file: size mismatch (expected %#x, have %#x)" % 94 (init_sz, len(p_data))) 95 return [[0, p_addr, p_data]], e_entry 96 return None 97