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