]>
Commit | Line | Data |
---|---|---|
8d73be7a TA |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) Microsoft Corporation | |
4 | * | |
5 | * Authors: | |
6 | * Thirupathaiah Annapureddy <[email protected]> | |
7 | * | |
8 | * Description: | |
9 | * Device Driver for a firmware TPM as described here: | |
10 | * https://www.microsoft.com/en-us/research/publication/ftpm-software-implementation-tpm-chip/ | |
11 | * | |
12 | * A reference implementation is available here: | |
13 | * https://github.com/microsoft/ms-tpm-20-ref/tree/master/Samples/ARM32-FirmwareTPM/optee_ta/fTPM | |
14 | */ | |
15 | ||
16 | #include <common.h> | |
17 | #include <dm.h> | |
f7ae49fc | 18 | #include <log.h> |
8d73be7a TA |
19 | #include <tpm-v2.h> |
20 | #include <tee.h> | |
21 | ||
22 | #include "tpm_tis.h" | |
23 | #include "tpm2_ftpm_tee.h" | |
24 | ||
25 | /** | |
26 | * ftpm_tee_transceive() - send fTPM commands and retrieve fTPM response. | |
27 | * @sendbuf - address of the data to send, byte by byte | |
28 | * @send_size - length of the data to send | |
29 | * @recvbuf - address where to read the response, byte by byte. | |
30 | * @recv_len - pointer to the size of buffer | |
31 | * | |
32 | * Return: | |
33 | * In case of success, returns 0. | |
34 | * On failure, -errno | |
35 | */ | |
36 | static int ftpm_tee_transceive(struct udevice *dev, const u8 *sendbuf, | |
37 | size_t send_size, u8 *recvbuf, | |
38 | size_t *recv_len) | |
39 | { | |
40 | struct ftpm_tee_private *context = dev_get_priv(dev); | |
41 | int rc = 0; | |
42 | size_t resp_len; | |
43 | u8 *resp_buf; | |
44 | struct tpm_output_header *resp_header; | |
45 | struct tee_invoke_arg transceive_args; | |
46 | struct tee_param command_params[4]; | |
47 | struct tee_shm *shm; | |
48 | ||
49 | if (send_size > MAX_COMMAND_SIZE) { | |
50 | debug("%s:send_size=%zd exceeds MAX_COMMAND_SIZE\n", | |
51 | __func__, send_size); | |
52 | return -EIO; | |
53 | } | |
54 | ||
55 | shm = context->shm; | |
56 | memset(&transceive_args, 0, sizeof(transceive_args)); | |
57 | memset(command_params, 0, sizeof(command_params)); | |
58 | ||
59 | /* Invoke FTPM_OPTEE_TA_SUBMIT_COMMAND function of fTPM TA */ | |
60 | transceive_args = (struct tee_invoke_arg) { | |
61 | .func = FTPM_OPTEE_TA_SUBMIT_COMMAND, | |
62 | .session = context->session, | |
63 | }; | |
64 | ||
65 | /* Fill FTPM_OPTEE_TA_SUBMIT_COMMAND parameters */ | |
66 | /* request */ | |
67 | command_params[0] = (struct tee_param) { | |
68 | .attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT, | |
69 | .u.memref = { | |
70 | .shm = shm, | |
71 | .size = send_size, | |
72 | .shm_offs = 0, | |
73 | }, | |
74 | }; | |
75 | memset(command_params[0].u.memref.shm->addr, 0, | |
76 | (MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE)); | |
77 | memcpy(command_params[0].u.memref.shm->addr, sendbuf, send_size); | |
78 | ||
79 | /* response */ | |
80 | command_params[1] = (struct tee_param) { | |
81 | .attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT, | |
82 | .u.memref = { | |
83 | .shm = shm, | |
84 | .size = MAX_RESPONSE_SIZE, | |
85 | .shm_offs = MAX_COMMAND_SIZE, | |
86 | }, | |
87 | }; | |
88 | ||
89 | rc = tee_invoke_func(context->tee_dev, &transceive_args, 4, | |
90 | command_params); | |
91 | if ((rc < 0) || (transceive_args.ret != 0)) { | |
92 | debug("%s:SUBMIT_COMMAND invoke error: 0x%x\n", | |
93 | __func__, transceive_args.ret); | |
94 | return (rc < 0) ? rc : transceive_args.ret; | |
95 | } | |
96 | ||
97 | resp_buf = command_params[1].u.memref.shm->addr + | |
98 | command_params[1].u.memref.shm_offs; | |
99 | resp_header = (struct tpm_output_header *)resp_buf; | |
100 | resp_len = be32_to_cpu(resp_header->length); | |
101 | ||
102 | /* sanity check resp_len*/ | |
103 | if (resp_len < TPM_HEADER_SIZE) { | |
104 | debug("%s:tpm response header too small\n", __func__); | |
105 | return -EIO; | |
106 | } | |
107 | if (resp_len > MAX_RESPONSE_SIZE) { | |
108 | debug("%s:resp_len=%zd exceeds MAX_RESPONSE_SIZE\n", | |
109 | __func__, resp_len); | |
110 | return -EIO; | |
111 | } | |
112 | if (resp_len > *recv_len) { | |
113 | debug("%s:response length is bigger than receive buffer\n", | |
114 | __func__); | |
115 | return -EIO; | |
116 | } | |
117 | ||
118 | /* sanity checks look good, copy the response */ | |
119 | memcpy(recvbuf, resp_buf, resp_len); | |
120 | *recv_len = resp_len; | |
121 | ||
122 | return 0; | |
123 | } | |
124 | ||
125 | static int ftpm_tee_open(struct udevice *dev) | |
126 | { | |
127 | struct ftpm_tee_private *context = dev_get_priv(dev); | |
128 | ||
129 | if (context->is_open) | |
130 | return -EBUSY; | |
131 | ||
132 | context->is_open = 1; | |
133 | ||
134 | return 0; | |
135 | } | |
136 | ||
137 | static int ftpm_tee_close(struct udevice *dev) | |
138 | { | |
139 | struct ftpm_tee_private *context = dev_get_priv(dev); | |
140 | ||
141 | if (context->is_open) | |
142 | context->is_open = 0; | |
143 | ||
144 | return 0; | |
145 | } | |
146 | ||
147 | static int ftpm_tee_desc(struct udevice *dev, char *buf, int size) | |
148 | { | |
149 | if (size < 32) | |
150 | return -ENOSPC; | |
151 | ||
152 | return snprintf(buf, size, "Microsoft OP-TEE fTPM"); | |
153 | } | |
154 | ||
155 | static int ftpm_tee_match(struct tee_version_data *vers, const void *data) | |
156 | { | |
157 | debug("%s:vers->gen_caps =0x%x\n", __func__, vers->gen_caps); | |
158 | ||
159 | /* | |
160 | * Currently this driver only support GP Complaint OPTEE based fTPM TA | |
161 | */ | |
162 | return vers->gen_caps & TEE_GEN_CAP_GP; | |
163 | } | |
164 | ||
165 | static int ftpm_tee_probe(struct udevice *dev) | |
166 | { | |
167 | int rc; | |
168 | struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); | |
169 | struct ftpm_tee_private *context = dev_get_priv(dev); | |
170 | struct tee_open_session_arg sess_arg; | |
171 | const struct tee_optee_ta_uuid uuid = TA_FTPM_UUID; | |
172 | ||
173 | memset(context, 0, sizeof(*context)); | |
174 | ||
175 | /* Use the TPM v2 stack */ | |
176 | priv->version = TPM_V2; | |
177 | priv->pcr_count = 24; | |
178 | priv->pcr_select_min = 3; | |
179 | ||
180 | /* Find TEE device */ | |
181 | context->tee_dev = tee_find_device(NULL, ftpm_tee_match, NULL, NULL); | |
182 | if (!context->tee_dev) { | |
183 | debug("%s:tee_find_device failed\n", __func__); | |
184 | return -ENODEV; | |
185 | } | |
186 | ||
187 | /* Open a session with the fTPM TA */ | |
188 | memset(&sess_arg, 0, sizeof(sess_arg)); | |
189 | tee_optee_ta_uuid_to_octets(sess_arg.uuid, &uuid); | |
190 | ||
191 | rc = tee_open_session(context->tee_dev, &sess_arg, 0, NULL); | |
192 | if ((rc < 0) || (sess_arg.ret != 0)) { | |
193 | debug("%s:tee_open_session failed, err=%x\n", | |
194 | __func__, sess_arg.ret); | |
195 | return -EIO; | |
196 | } | |
197 | context->session = sess_arg.session; | |
198 | ||
199 | /* Allocate dynamic shared memory with fTPM TA */ | |
200 | rc = tee_shm_alloc(context->tee_dev, | |
201 | MAX_COMMAND_SIZE + MAX_RESPONSE_SIZE, | |
202 | 0, &context->shm); | |
203 | if (rc) { | |
204 | debug("%s:tee_shm_alloc failed with rc = %d\n", __func__, rc); | |
205 | goto out_shm_alloc; | |
206 | } | |
207 | ||
208 | return 0; | |
209 | ||
210 | out_shm_alloc: | |
211 | tee_close_session(context->tee_dev, context->session); | |
212 | ||
213 | return rc; | |
214 | } | |
215 | ||
216 | static int ftpm_tee_remove(struct udevice *dev) | |
217 | { | |
218 | struct ftpm_tee_private *context = dev_get_priv(dev); | |
219 | int rc; | |
220 | ||
221 | /* tee_pre_remove frees any leftover TEE shared memory */ | |
222 | ||
223 | /* close the existing session with fTPM TA*/ | |
224 | rc = tee_close_session(context->tee_dev, context->session); | |
225 | debug("%s: tee_close_session - rc =%d\n", __func__, rc); | |
226 | ||
227 | return 0; | |
228 | } | |
229 | ||
230 | static const struct tpm_ops ftpm_tee_ops = { | |
231 | .open = ftpm_tee_open, | |
232 | .close = ftpm_tee_close, | |
233 | .get_desc = ftpm_tee_desc, | |
234 | .xfer = ftpm_tee_transceive, | |
235 | }; | |
236 | ||
237 | static const struct udevice_id ftpm_tee_ids[] = { | |
238 | { .compatible = "microsoft,ftpm" }, | |
239 | { } | |
240 | }; | |
241 | ||
242 | U_BOOT_DRIVER(ftpm_tee) = { | |
243 | .name = "ftpm_tee", | |
244 | .id = UCLASS_TPM, | |
245 | .of_match = ftpm_tee_ids, | |
246 | .ops = &ftpm_tee_ops, | |
247 | .probe = ftpm_tee_probe, | |
248 | .remove = ftpm_tee_remove, | |
249 | .flags = DM_FLAG_OS_PREPARE, | |
41575d8e | 250 | .priv_auto = sizeof(struct ftpm_tee_private), |
8d73be7a | 251 | }; |