1 /*****************************************************************************
2 * Copyright (c) 2015-2020 IBM Corporation
3 * All rights reserved.
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
8 *
9 * Contributors:
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
12
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <stdbool.h>
16
17 #include "string.h"
18 #include "helpers.h"
19 #include "byteorder.h"
20 #include "tcgbios_int.h"
21 #include "tpm_drivers.h"
22 #include "libhvcall.h"
23 #include "paflof.h"
24
25 #undef PAPR_VTPM_DEBUG
26 //#define PAPR_VTPM_DEBUG
27 #ifdef PAPR_VTPM_DEBUG
28 #define dprintf(_x ...) do { printf("VTPM CRQ: " _x); } while(0)
29 #else
30 #define dprintf(_x ...)
31 #endif
32
33 #define MIN(a, b) ((a) > (b) ? (b) : (a))
34
35 /* layout of the command request queue for vTPM; all fields are big endian */
36 struct crq {
37 uint8_t valid;
38 uint8_t msg;
39 uint16_t len;
40 uint32_t data;
41 uint64_t reserved;
42 } __attribute__((packed));
43
44 #define PAPR_VTPM_INIT_CRQ_COMMAND 0xC0
45 #define PAPR_VTPM_VALID_COMMAND 0x80
46 #define PAPR_VTPM_MSG_RESULT 0x80
47
48 /* crq.msg request types when crq.valid = PAPR_VTPM_INIT_CRQ_COMMAND */
49 #define PAPR_VTPM_INIT_CRQ_RESULT 0x1
50
51 /* crq.msg request types when crq.valid = PAPR_VTPM_VALID_COMMAND */
52 #define PAPR_VTPM_GET_VERSION 0x1
53 #define PAPR_VTPM_TPM_COMMAND 0x2
54 #define PAPR_VTPM_GET_RTCE_BUFFER_SIZE 0x3
55
56 #define TPM2_DEFAULT_DURATION_SHORT 750000 /* us */
57 #define TPM2_DEFAULT_DURATION_MEDIUM 2000000 /* us */
58 #define TPM2_DEFAULT_DURATION_LONG 2000000 /* us */
59
60 static const uint32_t tpm2_durations[3] = {
61 TPM2_DEFAULT_DURATION_SHORT,
62 TPM2_DEFAULT_DURATION_MEDIUM,
63 TPM2_DEFAULT_DURATION_LONG,
64 };
65
66 #define QUEUE_SIZE 4096
67
68 /* state of the PAPR CRQ VTPM driver */
69 static struct {
70 /* whether it driver been initialized */
71 bool initialized;
72
73 /* unit number */
74 unsigned long unit;
75
76 /* CRQ queue address and size */
77 unsigned char *qaddr;
78 unsigned long qsize;
79
80 /* current q_entry */
81 unsigned int curr_q_entry;
82
83 /* current response CRQ */
84 struct crq *response;
85
86 /* power firmware defined state and error code */
87 vtpm_drv_state driver_state;
88 vtpm_drv_error driver_error;
89
90 /* size of buffer supported by hypervisor */
91 unsigned int buffer_size;
92
93 /* buffer for commands and responses */
94 char *buffer;
95 } spapr_vtpm = {
96 .qsize = QUEUE_SIZE,
97 .driver_state = VTPM_DRV_STATE_INVALID,
98 .driver_error = VTPM_DRV_ERROR_NO_FAILURE,
99 };
100
vtpm_drv_state_set(vtpm_drv_state s,vtpm_drv_error e)101 static void vtpm_drv_state_set(vtpm_drv_state s, vtpm_drv_error e)
102 {
103 spapr_vtpm.driver_state = s;
104 spapr_vtpm.driver_error = e;
105 }
106
vtpm_drv_error_get(void)107 static vtpm_drv_error vtpm_drv_error_get(void)
108 {
109 return spapr_vtpm.driver_error;
110 }
111
spapr_get_crq(void * qaddr,unsigned long q_entry)112 static struct crq *spapr_get_crq(void *qaddr, unsigned long q_entry)
113 {
114 return &((struct crq *)qaddr)[q_entry];
115 }
116
117 /*
118 * Get the crq where the response will be found. This
119 * function will clear the CRQ's valid field and advance
120 * the entry counter to the next entry.
121 */
spapr_get_response_crq(void)122 static struct crq *spapr_get_response_crq(void)
123 {
124 struct crq *crq;
125
126 dprintf("curr_q_entry = %d\n", spapr_vtpm.curr_q_entry);
127
128 crq = spapr_get_crq(spapr_vtpm.qaddr, spapr_vtpm.curr_q_entry);
129 memset(crq, 0, sizeof(*crq));
130
131 spapr_vtpm.curr_q_entry += 1;
132 if (spapr_vtpm.curr_q_entry == (spapr_vtpm.qsize / sizeof(struct crq)))
133 spapr_vtpm.curr_q_entry = 0;
134
135 return crq;
136 }
137
138 /*
139 * Send a message via CRQ and wait for the response
140 */
spapr_send_crq_and_wait(unsigned long unit,struct crq * crq,struct crq ** response,unsigned timeout,vtpm_drv_state state1,vtpm_drv_state state2)141 static bool spapr_send_crq_and_wait(unsigned long unit,
142 struct crq *crq,
143 struct crq **response,
144 unsigned timeout,
145 vtpm_drv_state state1,
146 vtpm_drv_state state2)
147 {
148 long rc;
149 unsigned i;
150
151 *response = spapr_get_response_crq();
152
153 vtpm_drv_state_set(state1, VTPM_DRV_ERROR_NO_FAILURE);
154
155 rc = hv_send_crq(unit, (uint64_t *)crq);
156 if (rc != H_SUCCESS) {
157 vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_INIT,
158 VTPM_DRV_ERROR_TPM_CRQ_ERROR);
159 return false;
160 }
161
162 vtpm_drv_state_set(state2, VTPM_DRV_ERROR_NO_FAILURE);
163
164 for (i = 0; i < timeout; i += 1000) {
165 if (((*response)->valid & PAPR_VTPM_MSG_RESULT))
166 return true;
167 SLOF_usleep(1000);
168 }
169
170 vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE,
171 VTPM_DRV_ERROR_WAIT_TIMEOUT);
172
173 dprintf("Received no response from CRQ\n");
174 return false;
175 }
176
177 /*
178 * Get parameters from the CRQ
179 */
spapr_vtpm_get_params(void)180 static bool spapr_vtpm_get_params(void)
181 {
182 struct crq crq, *response;
183 static bool completed = false; /* only once */
184
185 if (completed)
186 return true;
187
188 /* get the TPM's buffer size */
189 crq.valid = PAPR_VTPM_VALID_COMMAND;
190 crq.msg = PAPR_VTPM_GET_RTCE_BUFFER_SIZE;
191
192 if (!spapr_send_crq_and_wait(spapr_vtpm.unit, &crq, &response, 10,
193 VTPM_DRV_STATE_SEND_BUFSIZE_REQ,
194 VTPM_DRV_STATE_WAIT_BUFSIZE)) {
195 printf("%s: Failure getting RTCE buffer size from CRQ\n",
196 __func__);
197 return false;
198 }
199
200 vtpm_drv_state_set(VTPM_DRV_STATE_ALLOC_RTCE_BUF,
201 VTPM_DRV_ERROR_NO_FAILURE);
202
203 dprintf("RTCE buffer size: %u\n", be16_to_cpu(response->len));
204 spapr_vtpm.buffer_size = be16_to_cpu(response->len);
205 if (spapr_vtpm.buffer_size < 1024) {
206 printf("%s: RTCE buffer size of %u bytes is too small. "
207 "Minimum is 1024 bytes.\n", __func__,
208 spapr_vtpm.buffer_size);
209 vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE,
210 VTPM_DRV_ERROR_BAD_RTCE_SIZE);
211 return false;
212 }
213 spapr_vtpm.buffer = SLOF_alloc_mem(spapr_vtpm.buffer_size);
214 if (!spapr_vtpm.buffer) {
215 printf("%s: Could not allocate buffer of size %u.\n",
216 __func__, spapr_vtpm.buffer_size);
217 vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE,
218 VTPM_DRV_ERROR_BAD_RTCE_SIZE);
219 return false;
220 }
221
222 completed = true;
223
224 return true;
225 }
226
spapr_vtpm_activate(void)227 static bool spapr_vtpm_activate(void)
228 {
229 long rc;
230 struct crq crq, *response;
231
232 if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) {
233 printf("%s: CRQ: In failure mode\n", __func__);
234 return false;
235 }
236
237 vtpm_drv_state_set(VTPM_DRV_STATE_REG_CRQ,
238 VTPM_DRV_ERROR_NO_FAILURE);
239
240 rc = hv_reg_crq(spapr_vtpm.unit, (unsigned long)spapr_vtpm.qaddr,
241 spapr_vtpm.qsize);
242 if (rc != H_SUCCESS) {
243 vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_INIT,
244 VTPM_DRV_ERROR_UNEXPECTED_REG_ERROR);
245 printf("%s: CRQ registration failed\n", __func__);
246 return false;
247 }
248
249 /* we always start with curr_q_entry 0 */
250 spapr_vtpm.curr_q_entry = 0;
251
252 if (!spapr_vtpm.initialized) {
253
254 crq.valid = PAPR_VTPM_INIT_CRQ_COMMAND;
255 crq.msg = PAPR_VTPM_INIT_CRQ_RESULT;
256
257 if (!spapr_send_crq_and_wait(spapr_vtpm.unit,
258 &crq,
259 &response,
260 10,
261 VTPM_DRV_STATE_SEND_INIT,
262 VTPM_DRV_STATE_WAIT_INIT_COMP)) {
263 printf("%s: Initializing CRQ failed\n", __func__);
264 goto err_exit;
265 }
266 dprintf("Successfully initialized CRQ\n");
267
268 spapr_vtpm.initialized = true;
269 }
270
271 if (spapr_vtpm_get_params())
272 return true;
273
274 err_exit:
275 hv_free_crq(spapr_vtpm.unit);
276 spapr_vtpm.unit = 0;
277
278 return false;
279 }
280
spapr_vtpm_finalize(void)281 void spapr_vtpm_finalize(void)
282 {
283 if (spapr_vtpm.unit) {
284 hv_free_crq(spapr_vtpm.unit);
285 spapr_vtpm.unit = 0;
286 }
287 }
288
289 /*
290 * Check whether we have a CRQ underneath us; if we do, the CRQ will
291 * be left open.
292 */
spapr_vtpm_probe(void)293 static bool spapr_vtpm_probe(void)
294 {
295 if (!spapr_vtpm.qaddr) {
296 spapr_vtpm.qaddr = SLOF_alloc_mem(spapr_vtpm.qsize);
297 if (!spapr_vtpm.qaddr) {
298 printf("%s: Unable to allocate memory\n", __func__);
299 return false;
300 }
301 memset(spapr_vtpm.qaddr, 0, spapr_vtpm.qsize);
302
303 dprintf("getting FORTH vtpm-unit\n");
304 spapr_vtpm.unit = SLOF_get_vtpm_unit();
305 if (!spapr_vtpm.unit) {
306 printf("%s: Could not get valid vtpm-unit\n", __func__);
307 return false;
308 }
309 }
310
311 dprintf("vtpm_unit = %lx, buffer = %p\n",
312 spapr_vtpm.unit, spapr_vtpm.qaddr);
313
314 if (!spapr_vtpm_activate())
315 return false;
316
317 return true;
318 }
319
spapr_vtpm_senddata(const uint8_t * const data,uint32_t len)320 static bool spapr_vtpm_senddata(const uint8_t *const data, uint32_t len)
321 {
322 struct crq crq;
323 long rc;
324
325 if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) {
326 printf("%s: VTPM CRQ: In failure mode\n", __func__);
327 return false;
328 }
329
330 if (len > spapr_vtpm.buffer_size) {
331 printf("%s: VTPM CRQ: Send buffer too large: %u > %u\n",
332 __func__, len, spapr_vtpm.buffer_size);
333 return false;
334 }
335
336 spapr_vtpm.response = spapr_get_response_crq();
337 spapr_vtpm.response->data = (uint64_t)spapr_vtpm.buffer;
338
339 crq.valid = PAPR_VTPM_VALID_COMMAND;
340 crq.msg = PAPR_VTPM_TPM_COMMAND;
341 crq.len = cpu_to_be16(len);
342 crq.data = (uint64_t)spapr_vtpm.buffer;
343 memcpy(spapr_vtpm.buffer, data, MIN(len, spapr_vtpm.buffer_size));
344
345 vtpm_drv_state_set(VTPM_DRV_STATE_SEND_TPM_CMD,
346 VTPM_DRV_ERROR_NO_FAILURE);
347
348 rc = hv_send_crq(spapr_vtpm.unit, (uint64_t *)&crq);
349
350 if (rc == H_SUCCESS)
351 vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_TPM_RSP,
352 VTPM_DRV_ERROR_NO_FAILURE);
353 else
354 vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_INIT,
355 VTPM_DRV_ERROR_UNEXPECTED_SEND_ERROR);
356
357 return (rc == H_SUCCESS);
358 }
359
spapr_vtpm_waitresponseready(enum tpm_duration_type to_t)360 static bool spapr_vtpm_waitresponseready(enum tpm_duration_type to_t)
361 {
362 uint32_t timeout = tpm2_durations[to_t];
363 int i;
364
365 if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) {
366 printf("%s: VTPM CRQ: In failure mode\n", __func__);
367 return false;
368 }
369
370 for (i = 0; i < timeout; i += 1000) {
371 if (spapr_vtpm.response->valid & PAPR_VTPM_MSG_RESULT) {
372 /* TPM responded: move to Send tpm-cmd state */
373 vtpm_drv_state_set(VTPM_DRV_STATE_SEND_TPM_CMD,
374 VTPM_DRV_ERROR_NO_FAILURE);
375 dprintf("Received response to TPM command\n");
376 return true;
377 }
378 SLOF_usleep(1000);
379 }
380
381 vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE,
382 VTPM_DRV_ERROR_WAIT_TIMEOUT);
383
384 dprintf("Received NO response to TPM command");
385
386 return false;
387 }
388
spapr_vtpm_readresponse(uint8_t * buffer,uint32_t * len)389 static bool spapr_vtpm_readresponse(uint8_t *buffer, uint32_t *len)
390 {
391 uint32_t length;
392
393 if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) {
394 printf("%s: VTPM CRQ: In failure mode\n", __func__);
395 return false;
396 }
397
398 length = MIN(*len, be32_to_cpu(spapr_vtpm.response->len));
399
400 memcpy(buffer, (void *)(uint64_t)spapr_vtpm.response->data, length);
401
402 dprintf("Length of copied response: %d\n", length);
403
404 spapr_vtpm.response = NULL;
405 *len = length;
406
407 return true;
408 }
409
410 /**** higher layer interface ****/
411
spapr_vtpm_get_error(void)412 vtpm_drv_error spapr_vtpm_get_error(void)
413 {
414 return vtpm_drv_error_get();
415 }
416
spapr_vtpm_set_error(vtpm_drv_error errcode)417 void spapr_vtpm_set_error(vtpm_drv_error errcode)
418 {
419 spapr_vtpm.driver_error = errcode;
420 }
421
spapr_is_vtpm_present(void)422 bool spapr_is_vtpm_present(void)
423 {
424 return spapr_vtpm_probe();
425 }
426
spapr_transmit(uint8_t locty,struct tpm_req_header * req,void * respbuffer,uint32_t * respbufferlen,enum tpm_duration_type to_t)427 int spapr_transmit(uint8_t locty, struct tpm_req_header *req,
428 void *respbuffer, uint32_t *respbufferlen,
429 enum tpm_duration_type to_t)
430 {
431 if (!spapr_vtpm_senddata((uint8_t *)req, be32_to_cpu(req->totlen)) ||
432 !spapr_vtpm_waitresponseready(to_t) ||
433 !spapr_vtpm_readresponse(respbuffer, respbufferlen) ||
434 *respbufferlen < sizeof(struct tpm_rsp_header))
435 return -1;
436 return 0;
437 }
438