test: stabilize test_efi_secboot
[platform/kernel/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 <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  */
35 static 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
124 static 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
136 static 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
146 static 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
154 static 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
164 static 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
209 out_shm_alloc:
210         tee_close_session(context->tee_dev, context->session);
211
212         return rc;
213 }
214
215 static 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
229 static 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
236 static const struct udevice_id ftpm_tee_ids[] = {
237         { .compatible = "microsoft,ftpm" },
238         { }
239 };
240
241 U_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 };