Merge tag 'efi-2020-07-rc6' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi
[oweals/u-boot.git] / drivers / tpm / tpm2_ftpm_tee.c
1 // 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 <log.h>
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,
250         .priv_auto_alloc_size = sizeof(struct ftpm_tee_private),
251 };