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