ia64/xen-unstable

view tools/ioemu/hw/tpm_tis.c @ 15789:8e9ec8711efa

ioemu: Avoid struct members clashing with POSIX apis

The TPM code in tools/ioemu/hw/tpm_tis.c has a struct containing a
number of function pointers with names open, close, read, write which
are the same as various POSIX apis already #included in the
file. POSIX allows these functions to be defined as macros and latest
GCC/glibc does indeed define them as macros depending on compiler
flags. This causes compile errors when deferencing the struct
members. The solution is either to change calls like ctx->open () to
be (* ctx->open) (), or simply to rename the struct members. Since
this struct was only used inside that one file I simply renamed them.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author kfraser@localhost.localdomain
date Tue Aug 28 16:13:35 2007 +0100 (2007-08-28)
parents 5f09e34f56d7
children 6730dfe7ec69
line source
1 /*
2 * tpm_tis.c - QEMU emulator for a 1.2 TPM with TIS interface
3 *
4 * Copyright (C) 2006 IBM Corporation
5 *
6 * Author: Stefan Berger <stefanb@us.ibm.com>
7 * David Safford <safford@us.ibm.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
12 * License.
13 *
14 *
15 * Implementation of the TIS interface according to specs at
16 * https://www.trustedcomputinggroup.org/groups/pc_client/TCG_PCClientTPMSpecification_1-20_1-00_FINAL.pdf
17 *
18 */
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include "vl.h"
28 //#define DEBUG_TPM
30 #define TPM_MAX_PKT 4096
32 #define VTPM_BAD_INSTANCE (uint32_t)0xffffffff
34 #define TIS_ADDR_BASE 0xFED40000
36 /* tis registers */
37 #define TPM_REG_ACCESS 0x00
38 #define TPM_REG_INT_ENABLE 0x08
39 #define TPM_REG_INT_VECTOR 0x0c
40 #define TPM_REG_INT_STATUS 0x10
41 #define TPM_REG_INTF_CAPABILITY 0x14
42 #define TPM_REG_STS 0x18
43 #define TPM_REG_DATA_FIFO 0x24
44 #define TPM_REG_DID_VID 0xf00
45 #define TPM_REG_RID 0xf04
47 #define STS_VALID (1 << 7)
48 #define STS_COMMAND_READY (1 << 6)
49 #define STS_TPM_GO (1 << 5)
50 #define STS_DATA_AVAILABLE (1 << 4)
51 #define STS_EXPECT (1 << 3)
52 #define STS_RESPONSE_RETRY (1 << 1)
54 #define ACCESS_TPM_REG_VALID_STS (1 << 7)
55 #define ACCESS_ACTIVE_LOCALITY (1 << 5)
56 #define ACCESS_BEEN_SEIZED (1 << 4)
57 #define ACCESS_SEIZE (1 << 3)
58 #define ACCESS_PENDING_REQUEST (1 << 2)
59 #define ACCESS_REQUEST_USE (1 << 1)
60 #define ACCESS_TPM_ESTABLISHMENT (1 << 0)
62 #define INT_ENABLED (1 << 31)
63 #define INT_DATA_AVAILABLE (1 << 0)
64 #define INT_LOCALITY_CHANGED (1 << 2)
65 #define INT_COMMAND_READY (1 << 7)
67 #define INTERRUPTS_SUPPORTED (INT_LOCALITY_CHANGED | \
68 INT_DATA_AVAILABLE | \
69 INT_COMMAND_READY)
70 #define CAPABILITIES_SUPPORTED ((1 << 4) | \
71 INTERRUPTS_SUPPORTED)
73 enum {
74 STATE_IDLE = 0,
75 STATE_READY,
76 STATE_COMPLETION,
77 STATE_EXECUTION,
78 STATE_RECEPTION
79 };
81 #define NUM_LOCALITIES 5
82 #define NO_LOCALITY 0xff
84 #define IS_VALID_LOC(x) ((x) < NUM_LOCALITIES)
86 #define TPM_DID 0x0001
87 #define TPM_VID 0x0001
88 #define TPM_RID 0x0001
90 /* if the connection to the vTPM should be closed after a successfully
91 received response; set to '0' to allow keeping the connection */
92 #define FORCE_CLOSE 0
94 /* local data structures */
96 typedef struct TPMTx {
97 int fd[2];
98 } tpmTx;
100 typedef struct TPMBuffer {
101 uint8_t instance[4]; /* instance number in network byte order */
102 uint8_t buf[TPM_MAX_PKT];
103 } __attribute__((packed)) tpmBuffer;
105 /* locality data */
106 typedef struct TPMLocal {
107 uint32_t state;
108 uint8_t access;
109 uint8_t sts;
110 uint32_t inte;
111 uint32_t ints;
112 } tpmLoc;
114 /* overall state of the TPM interface; 's' marks as save upon suspension */
115 typedef struct TPMState {
116 uint32_t offset; /* s */
117 tpmBuffer buffer; /* s */
118 uint8_t active_loc; /* s */
119 uint8_t aborting_locty;
120 uint8_t next_locty;
121 uint8_t irq_pending; /* s */
122 tpmLoc loc[NUM_LOCALITIES]; /* s */
123 QEMUTimer *poll_timer;
124 SetIRQFunc *set_irq;
125 void *irq_opaque;
126 int irq;
127 int poll_attempts;
128 uint32_t vtpm_instance; /* vtpm inst. number; determined from xenstore*/
129 int Transmitlayer;
130 tpmTx tpmTx;
131 } tpmState;
134 /* local prototypes */
135 static int TPM_Send(tpmState *s, tpmBuffer *buffer, uint8_t locty, char *msg);
136 static int TPM_Receive(tpmState *s, tpmBuffer *buffer);
137 static uint32_t vtpm_instance_from_xenstore(void);
138 static void tis_poll_timer(void *opaque);
139 static void tis_prep_next_interrupt(tpmState *s);
140 static void tis_raise_irq(tpmState *s, uint8_t locty, uint32_t irqmask);
141 static void close_vtpm_channel(tpmState *s, int force);
142 static void open_vtpm_channel(tpmState *s);
143 static void tis_attempt_receive(tpmState *s, uint8_t locty);
145 /* transport layer functions: local sockets */
146 static int create_local_socket(tpmState *s, uint32_t vtpm_instance);
147 static int write_local_socket(tpmState *s, const tpmBuffer *);
148 static int read_local_socket(tpmState *s, tpmBuffer *);
149 static int close_local_socket(tpmState *s, int force);
150 static int has_channel_local_socket(tpmState *s);
151 #define LOCAL_SOCKET_PATH "/var/vtpm/socks/%d.socket"
154 #define NUM_TRANSPORTS 1
156 struct vTPM_transmit {
157 int (*open_fn) (tpmState *s, uint32_t vtpm_instance);
158 int (*write_fn) (tpmState *s, const tpmBuffer *);
159 int (*read_fn) (tpmState *s, tpmBuffer *);
160 int (*close_fn) (tpmState *s, int);
161 int (*has_channel) (tpmState *s);
162 } vTPMTransmit[NUM_TRANSPORTS] = {
163 { .open_fn = create_local_socket,
164 .write_fn = write_local_socket,
165 .read_fn = read_local_socket,
166 .close_fn = close_local_socket,
167 .has_channel = has_channel_local_socket,
168 }
169 };
172 #define IS_COMM_WITH_VTPM(s) \
173 ((s)->Transmitlayer >= 0 && \
174 vTPMTransmit[(s)->Transmitlayer].has_channel(s))
177 /**********************************************************************
178 helper functions
179 *********************************************************************/
181 static inline uint32_t tpm_get_size_from_buffer(const uint8_t *buffer)
182 {
183 uint32_t len = (buffer[4] << 8) + buffer[5];
184 return len;
185 }
187 static inline void tpm_initialize_instance(tpmState *s, uint32_t instance)
188 {
189 s->buffer.instance[0] = (instance >> 24) & 0xff;
190 s->buffer.instance[1] = (instance >> 16) & 0xff;
191 s->buffer.instance[2] = (instance >> 8) & 0xff;
192 s->buffer.instance[3] = (instance >> 0) & 0xff;
193 }
195 /*
196 * open communication channel with a vTPM
197 */
198 static void open_vtpm_channel(tpmState *s)
199 {
200 int idx;
201 /* search a usable transmit layer */
202 for (idx = 0; idx < NUM_TRANSPORTS; idx++) {
203 if (1 == vTPMTransmit[idx].open_fn(s, s->vtpm_instance)) {
204 /* found one */
205 s->Transmitlayer = idx;
206 break;
207 }
208 }
209 }
211 /*
212 * close the communication channel with the vTPM
213 */
214 static inline void close_vtpm_channel(tpmState *s, int force)
215 {
216 if (1 == vTPMTransmit[s->Transmitlayer].close_fn(s, force)) {
217 s->Transmitlayer = -1;
218 }
219 }
221 static inline uint8_t locality_from_addr(target_phys_addr_t addr)
222 {
223 return (uint8_t)((addr >> 12) & 0x7);
224 }
227 /**********************************************************************
228 low-level transmission layer methods
229 *********************************************************************/
231 /*
232 * the 'open' method that creates the filedescriptor for communicating
233 * only one is needed for reading and writing
234 */
235 static int create_local_socket(tpmState *s, uint32_t vtpm_instance)
236 {
237 int success = 1;
238 if (s->tpmTx.fd[0] < 0) {
239 s->tpmTx.fd[0] = socket(PF_LOCAL, SOCK_STREAM, 0);
241 #ifdef DEBUG_TPM
242 fprintf(logfile," SOCKET FD %d errno %d \n", s->tpmTx.fd[0], errno );
243 #endif
244 if (has_channel_local_socket(s)) {
245 int ret;
246 struct sockaddr_un addr;
247 memset(&addr, 0x0, sizeof(addr));
248 addr.sun_family = AF_LOCAL;
249 snprintf(addr.sun_path, sizeof(addr.sun_path)-1,
250 LOCAL_SOCKET_PATH, (uint32_t) vtpm_instance);
251 #ifdef DEBUG_TPM
252 fprintf(logfile," SOCKET NAME %s \n", addr.sun_path );
253 #endif
255 if ((ret = connect(s->tpmTx.fd[0], (struct sockaddr *)&addr,
256 sizeof(addr))) != 0) {
257 close_local_socket(s, 1);
258 #ifdef DEBUG_TPM
259 fprintf(logfile," RET %d errno %d\n", ret, errno );
260 #endif
261 success = 0;
262 } else {
263 /* put filedescriptor in non-blocking mode for polling */
264 #ifdef DEBUG_TPM
265 fprintf(logfile," put filedescriptor in non-blocking mode "
266 "for polling \n");
267 #endif
268 int flags = fcntl(s->tpmTx.fd[0], F_GETFL);
269 fcntl(s->tpmTx.fd[0], F_SETFL, flags | O_NONBLOCK);
270 }
271 #ifdef DEBUG_TPM
272 if (success)
273 fprintf(logfile,"Successfully connected using local socket "
274 LOCAL_SOCKET_PATH ".\n");
275 else
276 fprintf(logfile,"Could not connect to local socket "
277 LOCAL_SOCKET_PATH ".\n");
278 #endif
279 } else {
280 success = 0;
281 }
282 }
283 return success;
284 }
286 /*
287 * the 'write' method for sending requests to the vTPM
288 * four bytes with the vTPM instance number are prepended to each request
289 * the locality in which the command was sent is transmitted in the
290 * highest 3 bits
291 */
292 static int write_local_socket(tpmState *s, const tpmBuffer *buffer)
293 {
294 uint32_t size = tpm_get_size_from_buffer(buffer->buf);
295 int len;
297 len = write(s->tpmTx.fd[0],
298 buffer->instance,
299 sizeof(buffer->instance) + size);
300 if (len == sizeof(buffer->instance) + size) {
301 return len;
302 } else {
303 return -1;
304 }
305 }
307 /*
308 * the 'read' method for receiving of responses from the TPM
309 * this function expects that four bytes with the instance number
310 * are received from the vTPM
311 */
312 static int read_local_socket(tpmState *s, tpmBuffer *buffer)
313 {
314 int off;
315 #ifdef DEBUG_TPM
316 fprintf(logfile, "Reading from fd %d\n", s->tpmTx.fd[0]);
317 #endif
318 off = read(s->tpmTx.fd[0],
319 buffer->instance,
320 sizeof(buffer->instance)+TPM_MAX_PKT);
321 #ifdef DEBUG_TPM
322 fprintf(logfile, "Read %d bytes\n", off);
323 #endif
324 return off;
325 }
327 /*
328 * the 'close' method
329 * shut down communication with the vTPM
330 * 'force' = 1 indicates that the socket *must* be closed
331 * 'force' = 0 indicates that a connection may be maintained
332 */
333 static int close_local_socket(tpmState *s, int force)
334 {
335 if (force) {
336 close(s->tpmTx.fd[0]);
337 #ifdef DEBUG_TPM
338 fprintf(logfile,"Closed connection with fd %d\n",s->tpmTx.fd[0]);
339 #endif
340 s->tpmTx.fd[0] = -1;
341 return 1; /* socket was closed */
342 }
343 #ifdef DEBUG_TPM
344 fprintf(logfile,"Keeping connection with fd %d\n",s->tpmTx.fd[0]);
345 #endif
346 return 0;
347 }
349 /*
350 * the 'has_channel' method that checks whether there's a communication
351 * channel with the vTPM
352 */
353 static int has_channel_local_socket(tpmState *s)
354 {
355 return (s->tpmTx.fd[0] > 0);
356 }
358 /**********************************************************************/
360 /*
361 * read a byte of response data
362 */
363 static uint32_t tpm_data_read(tpmState *s, uint8_t locty)
364 {
365 uint32_t ret, len;
367 /* try to receive data, if none are there it is ok */
368 tis_attempt_receive(s, locty);
370 if (s->loc[locty].state != STATE_COMPLETION) {
371 return 0xff;
372 }
374 len = tpm_get_size_from_buffer(s->buffer.buf);
375 ret = s->buffer.buf[s->offset++];
376 if (s->offset >= len) {
377 s->loc[locty].sts = STS_VALID ;
378 s->offset = 0;
379 }
380 #ifdef DEBUG_TPM
381 fprintf(logfile,"tpm_data_read byte x%02x [%d]\n",ret,s->offset-1);
382 #endif
383 return ret;
384 }
388 /* raise an interrupt if allowed */
389 static void tis_raise_irq(tpmState *s, uint8_t locty, uint32_t irqmask)
390 {
391 if (!s->irq_pending &&
392 (s->loc[locty].inte & INT_ENABLED) &&
393 (s->loc[locty].inte & irqmask)) {
394 if ((irqmask & s->loc[locty].ints) == 0) {
395 #ifdef DEBUG_TPM
396 fprintf(logfile,"Raising IRQ for flag %08x\n",irqmask);
397 #endif
398 s->set_irq(s->irq_opaque, s->irq, 1);
399 s->irq_pending = 1;
400 s->loc[locty].ints |= irqmask;
401 }
402 }
403 }
405 /* abort execution of command */
406 static void tis_abort(tpmState *s)
407 {
408 s->offset = 0;
409 s->active_loc = s->next_locty;
411 /*
412 * Need to react differently depending on who's aborting now and
413 * which locality will become active afterwards.
414 */
415 if (s->aborting_locty == s->next_locty) {
416 s->loc[s->aborting_locty].state = STATE_READY;
417 s->loc[s->aborting_locty].sts = STS_COMMAND_READY;
418 tis_raise_irq(s, s->aborting_locty, INT_COMMAND_READY);
419 }
421 /* locality after abort is another one than the current one */
422 if (s->aborting_locty != s->next_locty && s->next_locty != NO_LOCALITY) {
423 s->loc[s->aborting_locty].access &= ~ACCESS_ACTIVE_LOCALITY;
424 s->loc[s->next_locty].access |= ACCESS_ACTIVE_LOCALITY;
425 tis_raise_irq(s, s->next_locty, INT_LOCALITY_CHANGED);
426 }
428 s->aborting_locty = NO_LOCALITY; /* nobody's aborting a command anymore */
430 qemu_del_timer(s->poll_timer);
431 }
433 /* abort current command */
434 static void tis_prep_abort(tpmState *s, uint8_t locty, uint8_t newlocty)
435 {
436 s->aborting_locty = locty; /* current locality */
437 s->next_locty = newlocty; /* locality after successful abort */
439 /*
440 * only abort a command using an interrupt if currently executing
441 * a command AND if there's a valid connection to the vTPM.
442 */
443 if (s->loc[locty].state == STATE_EXECUTION &&
444 IS_COMM_WITH_VTPM(s)) {
445 /* start timer and inside the timer wait for the result */
446 s->poll_attempts = 0;
447 tis_prep_next_interrupt(s);
448 } else {
449 tis_abort(s);
450 }
451 }
454 /*
455 * Try to receive a response from the vTPM
456 */
457 static void tis_attempt_receive(tpmState *s, uint8_t locty)
458 {
459 /*
460 * Attempt to read from the vTPM here if
461 * - not aborting a command
462 * - command has been sent and state is 'EXECUTION' now
463 * - no data are already available (data have already been read)
464 * - there's a communication path to the vTPM established
465 */
466 if (!IS_VALID_LOC(s->aborting_locty)) {
467 if (s->loc[locty].state == STATE_EXECUTION) {
468 if (0 == (s->loc[locty].sts & STS_DATA_AVAILABLE)){
469 if (IS_COMM_WITH_VTPM(s)) {
470 int n = TPM_Receive(s, &s->buffer);
471 if (n > 0) {
472 s->loc[locty].sts = STS_VALID | STS_DATA_AVAILABLE;
473 s->loc[locty].state = STATE_COMPLETION;
474 close_vtpm_channel(s, FORCE_CLOSE);
475 tis_raise_irq(s, locty, INT_DATA_AVAILABLE);
476 }
477 }
478 }
479 }
480 }
481 }
483 /*
484 * Read a register of the TIS interface
485 * See specs pages 33-63 for description of the registers
486 */
487 static uint32_t tis_mem_readl(void *opaque, target_phys_addr_t addr)
488 {
489 tpmState *s = (tpmState *)opaque;
490 uint16_t offset = addr & 0xffc;
491 uint8_t shift = (addr & 0x3) * 8;
492 uint32_t val = 0;
493 uint8_t locty = locality_from_addr(addr);
495 if (offset == TPM_REG_ACCESS) {
496 if (s->active_loc == locty) {
497 s->loc[locty].access |= (1 << 5);
498 } else {
499 s->loc[locty].access &= ~(1 << 5);
500 }
501 val = s->loc[locty].access;
502 } else
503 if (offset == TPM_REG_INT_ENABLE) {
504 val = s->loc[locty].inte;
505 } else
506 if (offset == TPM_REG_INT_VECTOR) {
507 val = s->irq;
508 } else
509 if (offset == TPM_REG_INT_STATUS) {
510 tis_attempt_receive(s, locty);
511 val = s->loc[locty].ints;
512 } else
513 if (offset == TPM_REG_INTF_CAPABILITY) {
514 val = CAPABILITIES_SUPPORTED;
515 } else
516 if (offset == TPM_REG_STS) { /* status register */
517 tis_attempt_receive(s, locty);
518 val = (sizeof(s->buffer.buf) - s->offset) << 8 | s->loc[locty].sts;
519 } else
520 if (offset == TPM_REG_DATA_FIFO) {
521 val = tpm_data_read(s, locty);
522 } else
523 if (offset == TPM_REG_DID_VID) {
524 val = (TPM_DID << 16) | TPM_VID;
525 } else
526 if (offset == TPM_REG_RID) {
527 val = TPM_RID;
528 }
530 if (shift)
531 val >>= shift;
533 #ifdef DEBUG_TPM
534 fprintf(logfile," read(%08x) = %08x\n",
535 (int)addr,
536 val);
537 #endif
539 return val;
540 }
542 /*
543 * Write a value to a register of the TIS interface
544 * See specs pages 33-63 for description of the registers
545 */
546 static void tis_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
547 {
548 tpmState* s=(tpmState*)opaque;
549 uint16_t off = addr & 0xfff;
550 uint8_t locty = locality_from_addr(addr);
551 int n, c;
552 uint32_t len;
554 #ifdef DEBUG_TPM
555 fprintf(logfile,"write(%08x) = %08x\n",
556 (int)addr,
557 val);
558 #endif
560 if (off == TPM_REG_ACCESS) {
561 if (val & ACCESS_ACTIVE_LOCALITY) {
562 /* give up locality if currently owned */
563 if (s->active_loc == locty) {
564 uint8_t newlocty = NO_LOCALITY;
565 s->loc[locty].access &= ~(ACCESS_PENDING_REQUEST);
566 /* anybody wants the locality ? */
567 for (c = NUM_LOCALITIES - 1; c >= 0; c--) {
568 if (s->loc[c].access & ACCESS_REQUEST_USE) {
569 s->loc[c].access |= ACCESS_TPM_REG_VALID_STS;
570 s->loc[c].access &= ~ACCESS_REQUEST_USE;
571 newlocty = c;
572 break;
573 }
574 }
575 tis_prep_abort(s, locty, newlocty);
576 }
577 }
578 if (val & ACCESS_BEEN_SEIZED) {
579 /* clear the flag */
580 s->loc[locty].access &= ~ACCESS_BEEN_SEIZED;
581 }
582 if (val & ACCESS_SEIZE) {
583 if (locty > s->active_loc && IS_VALID_LOC(s->active_loc)) {
584 s->loc[s->active_loc].access |= ACCESS_BEEN_SEIZED;
585 s->loc[locty].access = ACCESS_TPM_REG_VALID_STS;
586 tis_prep_abort(s, s->active_loc, locty);
587 }
588 }
589 if (val & ACCESS_REQUEST_USE) {
590 if (IS_VALID_LOC(s->active_loc)) {
591 /* locality election */
592 s->loc[s->active_loc].access |= ACCESS_PENDING_REQUEST;
593 } else {
594 /* no locality active -> make this one active now */
595 s->loc[locty].access |= ACCESS_ACTIVE_LOCALITY;
596 s->active_loc = locty;
597 tis_raise_irq(s, locty, INT_LOCALITY_CHANGED);
598 }
599 }
600 } else
601 if (off == TPM_REG_INT_ENABLE) {
602 s->loc[locty].inte = (val & (INT_ENABLED | (0x3 << 3) |
603 INTERRUPTS_SUPPORTED));
604 } else
605 if (off == TPM_REG_INT_STATUS) {
606 /* clearing of interrupt flags */
607 if ((val & INTERRUPTS_SUPPORTED) &&
608 (s->loc[locty].ints & INTERRUPTS_SUPPORTED)) {
609 s->set_irq(s->irq_opaque, s->irq, 0);
610 s->irq_pending = 0;
611 }
612 s->loc[locty].ints &= ~(val & INTERRUPTS_SUPPORTED);
613 } else
614 if (off == TPM_REG_STS) {
615 if (val & STS_COMMAND_READY) {
616 if (s->loc[locty].state == STATE_IDLE) {
617 s->loc[locty].sts = STS_COMMAND_READY;
618 s->loc[locty].state = STATE_READY;
619 tis_raise_irq(s, locty, INT_COMMAND_READY);
620 } else if (s->loc[locty].state == STATE_COMPLETION ||
621 s->loc[locty].state == STATE_EXECUTION ||
622 s->loc[locty].state == STATE_RECEPTION) {
623 /* abort currently running command */
624 tis_prep_abort(s, locty, locty);
625 }
626 }
627 if (val & STS_TPM_GO) {
628 n = TPM_Send(s, &s->buffer, locty, "tpm_data_write");
629 if (n > 0) {
630 /* sending of data was successful */
631 s->offset = 0;
632 s->loc[locty].state = STATE_EXECUTION;
633 if (s->loc[locty].inte & (INT_ENABLED | INT_DATA_AVAILABLE)) {
634 s->poll_attempts = 0;
635 tis_prep_next_interrupt(s);
636 }
637 }
638 }
639 if (val & STS_RESPONSE_RETRY) {
640 s->offset = 0;
641 }
642 } else if (off == TPM_REG_DATA_FIFO) {
643 /* data fifo */
644 if (s->loc[locty].state == STATE_IDLE ||
645 s->loc[locty].state == STATE_EXECUTION ||
646 s->loc[locty].state == STATE_COMPLETION) {
647 /* drop the byte */
648 } else {
649 #ifdef TPM_DEBUG
650 fprintf(logfile,"Byte to send to TPM: %02x\n", val);
651 #endif
652 s->loc[locty].state = STATE_RECEPTION;
654 if (s->offset < sizeof(s->buffer.buf))
655 s->buffer.buf[s->offset++] = (uint8_t)val;
657 if (s->offset > 5) {
658 /* we have a packet length - see if we have all of it */
659 len = tpm_get_size_from_buffer(s->buffer.buf);
660 if (len > s->offset) {
661 s->loc[locty].sts = STS_EXPECT | STS_VALID;
662 } else {
663 s->loc[locty].sts = STS_VALID;
664 }
665 }
666 }
667 }
668 }
670 /*
671 * Prepare the next interrupt for example after a command has
672 * been sent out for the purpose of receiving the response.
673 * Depending on how many interrupts (used for polling on the fd) have
674 * already been schedule, this function determines the delta in time
675 * to the next interrupt. This accomodates for commands that finish
676 * quickly.
677 */
678 static void tis_prep_next_interrupt(tpmState *s)
679 {
680 int64_t expiration;
681 int rate = 5; /* 5 times per second */
683 /*
684 poll often at the beginning for quickly finished commands,
685 then back off
686 */
687 if (s->poll_attempts < 5) {
688 rate = 20;
689 } else if (s->poll_attempts < 10) {
690 rate = 10;
691 }
693 expiration = qemu_get_clock(vm_clock) + (ticks_per_sec / rate);
694 qemu_mod_timer(s->poll_timer, expiration);
695 s->poll_attempts++;
696 }
699 /*
700 * The polling routine called when the 'timer interrupt' fires.
701 * Tries to receive a command from the vTPM.
702 */
703 static void tis_poll_timer(void *opaque)
704 {
705 tpmState* s=(tpmState*)opaque;
706 uint8_t locty = s->active_loc;
708 if (!IS_VALID_LOC(locty) ||
709 (!(s->loc[locty].inte & INT_ENABLED) &&
710 (s->aborting_locty != NO_LOCALITY)) ||
711 !IS_COMM_WITH_VTPM(s)) {
712 /* no more interrupts requested, so no more polling needed */
713 qemu_del_timer(s->poll_timer);
714 }
716 if (!IS_COMM_WITH_VTPM(s)) {
717 if (s->aborting_locty != NO_LOCALITY) {
718 tis_abort(s);
719 }
720 return;
721 }
723 if (s->aborting_locty != NO_LOCALITY) {
724 int n = TPM_Receive(s, &s->buffer);
725 #ifdef DEBUG_TPM
726 fprintf(logfile,"Receiving for abort.\n");
727 #endif
728 if (n > 0) {
729 close_vtpm_channel(s, FORCE_CLOSE);
730 tis_abort(s);
731 #ifdef DEBUG_TPM
732 fprintf(logfile,"Abort is complete.\n");
733 #endif
734 } else {
735 tis_prep_next_interrupt(s);
736 }
737 } else if (IS_VALID_LOC(locty)) {
738 if (s->loc[locty].state == STATE_EXECUTION) {
739 /* poll for result */
740 int n = TPM_Receive(s, &s->buffer);
741 if (n > 0) {
742 s->loc[locty].sts = STS_VALID | STS_DATA_AVAILABLE;
743 s->loc[locty].state = STATE_COMPLETION;
744 close_vtpm_channel(s, FORCE_CLOSE);
745 tis_raise_irq(s, locty, INT_DATA_AVAILABLE);
746 } else {
747 /* nothing received */
748 tis_prep_next_interrupt(s);
749 }
750 }
751 }
752 }
755 static CPUReadMemoryFunc *tis_readfn[3]={
756 tis_mem_readl,
757 tis_mem_readl,
758 tis_mem_readl
759 };
761 static CPUWriteMemoryFunc *tis_writefn[3]={
762 tis_mem_writel,
763 tis_mem_writel,
764 tis_mem_writel
765 };
767 /*
768 * Save the internal state of this interface for later resumption.
769 * Need to get any outstanding responses from the vTPM back, so
770 * this might delay the suspend for a while.
771 */
772 static void tpm_save(QEMUFile* f,void* opaque)
773 {
774 tpmState* s=(tpmState*)opaque;
775 uint8_t locty = s->active_loc;
776 int c;
778 /* need to wait for outstanding requests to complete */
779 if (s->loc[locty].state == STATE_EXECUTION) {
780 int repeats = 30; /* 30 seconds; really should be infty */
781 while (repeats > 0 &&
782 !(s->loc[s->active_loc].sts & STS_DATA_AVAILABLE)) {
783 int n = TPM_Receive(s, &s->buffer);
784 if (n > 0) {
785 if (IS_VALID_LOC(s->active_loc)) {
786 s->loc[s->active_loc].sts = STS_VALID | STS_DATA_AVAILABLE;
787 s->loc[s->active_loc].state = STATE_COMPLETION;
788 tis_raise_irq(s, s->active_loc, INT_DATA_AVAILABLE);
789 }
790 /* close the connection with the vTPM for good */
791 close_vtpm_channel(s, 1);
792 break;
793 }
794 sleep(1);
795 }
796 }
798 if (IS_COMM_WITH_VTPM(s)) {
799 close_vtpm_channel(s, 1);
800 }
802 qemu_put_be32s(f,&s->offset);
803 qemu_put_buffer(f, s->buffer.buf, TPM_MAX_PKT);
804 qemu_put_8s(f, &s->active_loc);
805 qemu_put_8s(f, &s->irq_pending);
806 for (c = 0; c < NUM_LOCALITIES; c++) {
807 qemu_put_be32s(f, &s->loc[c].state);
808 qemu_put_8s(f, &s->loc[c].access);
809 qemu_put_8s(f, &s->loc[c].sts);
810 qemu_put_be32s(f, &s->loc[c].inte);
811 qemu_put_be32s(f, &s->loc[c].ints);
812 }
813 }
815 /*
816 * load TIS interface state
817 */
818 static int tpm_load(QEMUFile* f,void* opaque,int version_id)
819 {
820 tpmState* s=(tpmState*)opaque;
821 int c;
823 if (version_id != 1)
824 return -EINVAL;
826 qemu_get_be32s(f,&s->offset);
827 qemu_get_buffer(f, s->buffer.buf, TPM_MAX_PKT);
828 qemu_get_8s(f, &s->active_loc);
829 qemu_get_8s(f, &s->irq_pending);
830 for (c = 0; c < NUM_LOCALITIES; c++) {
831 qemu_get_be32s(f, &s->loc[c].state);
832 qemu_get_8s(f, &s->loc[c].access);
833 qemu_get_8s(f, &s->loc[c].sts);
834 qemu_get_be32s(f, &s->loc[c].inte);
835 qemu_get_be32s(f, &s->loc[c].ints);
836 }
838 /* need to be able to get the instance number from the xenstore */
839 s->vtpm_instance = vtpm_instance_from_xenstore();
840 if (s->vtpm_instance == VTPM_BAD_INSTANCE)
841 return -EINVAL;
842 tpm_initialize_instance(s, s->vtpm_instance);
844 return 0;
845 }
848 typedef struct LPCtpmState {
849 tpmState tpm;
850 int mem;
851 } LPCtpmState;
854 /*
855 * initialize TIS interface
856 */
857 void tpm_tis_init(SetIRQFunc *set_irq, void *opaque, int irq)
858 {
859 LPCtpmState *d;
860 tpmState *s;
861 int c = 0;
862 uint32_t vtpm_in;
864 vtpm_in = vtpm_instance_from_xenstore();
865 /* no valid vtpm instance -> no device */
866 if (vtpm_in == VTPM_BAD_INSTANCE)
867 return;
869 d = qemu_mallocz(sizeof(LPCtpmState));
870 d->mem = cpu_register_io_memory(0, tis_readfn, tis_writefn, d);
872 if (d->mem == -1) {
873 return;
874 }
876 cpu_register_physical_memory(TIS_ADDR_BASE,
877 0x1000 * NUM_LOCALITIES, d->mem);
879 /* initialize tpmState */
880 s = &d->tpm;
882 s->offset = 0;
883 s->active_loc = NO_LOCALITY;
885 while (c < NUM_LOCALITIES) {
886 s->loc[c].access = (1 << 7);
887 s->loc[c].sts = 0;
888 s->loc[c].inte = (1 << 3);
889 s->loc[c].ints = 0;
890 s->loc[c].state = STATE_IDLE;
891 c++;
892 }
893 s->poll_timer = qemu_new_timer(vm_clock, tis_poll_timer, s);
894 s->set_irq = set_irq;
895 s->irq_opaque = opaque;
896 s->irq = irq;
897 s->vtpm_instance = vtpm_in;
898 s->Transmitlayer = -1;
899 s->tpmTx.fd[0] = -1;
900 s->tpmTx.fd[1] = -1;
901 s->aborting_locty = NO_LOCALITY;
903 tpm_initialize_instance(s, s->vtpm_instance);
904 memset(s->buffer.buf,0,sizeof(s->buffer.buf));
906 register_savevm("tpm-tis", 0, 1, tpm_save, tpm_load, s);
907 }
909 /****************************************************************************/
910 /* optional verbose logging of data to/from vtpm */
911 /****************************************************************************/
912 #ifdef DEBUG_TPM
913 static void showBuff(unsigned char *buff, char *string)
914 {
915 uint32_t i, len;
917 len = tpm_get_size_from_buffer(buff);
918 fprintf(logfile,"%s length = %d\n", string, len);
919 for (i = 0; i < len; i++) {
920 if (i && !(i % 16)) {
921 fprintf(logfile,"\n");
922 }
923 fprintf(logfile,"%.2X ", buff[i]);
924 }
925 fprintf(logfile,"\n");
926 }
927 #endif
929 /****************************************************************************/
930 /* Transmit request to TPM and read Response */
931 /****************************************************************************/
933 const static unsigned char tpm_failure[] = {
934 0x00, 0x00,
935 0x00, 0x00, 0x00, 0x0a,
936 0x00, 0x00, 0x00, 0x09
937 };
940 /*
941 * Send a TPM request.
942 */
943 static int TPM_Send(tpmState *s, tpmBuffer *buffer, uint8_t locty, char *msg)
944 {
945 int len;
946 uint32_t size = tpm_get_size_from_buffer(buffer->buf);
948 /* try to establish a connection to the vTPM */
949 if ( !IS_COMM_WITH_VTPM(s)) {
950 open_vtpm_channel(s);
951 }
953 if ( !IS_COMM_WITH_VTPM(s)) {
954 unsigned char tag = buffer->buf[1];
956 /* there's a failure response from the TPM */
957 memcpy(buffer->buf, tpm_failure, sizeof(tpm_failure));
958 buffer->buf[1] = tag + 3;
959 if (IS_VALID_LOC(s->active_loc)) {
960 s->loc[s->active_loc].sts = STS_DATA_AVAILABLE | STS_VALID;
961 }
962 #ifdef DEBUG_TPM
963 fprintf(logfile,"No TPM running!\n");
964 #endif
965 /* the request went out ok. */
966 return sizeof(buffer->instance) + size;
967 }
969 #ifdef DEBUG_TPM
970 showBuff(buffer->buf, "To TPM");
971 #endif
973 /* transmit the locality in the highest 3 bits */
974 buffer->instance[0] &= 0x1f;
975 buffer->instance[0] |= (locty << 5);
977 len = vTPMTransmit[s->Transmitlayer].write_fn(s, buffer);
978 if (len < 0) {
979 s->Transmitlayer = -1;
980 }
981 return len;
982 }
984 /*
985 * Try to receive data from the file descriptor. Since it is in
986 * non-blocking mode it is possible that no data are actually received -
987 * whatever calls this function needs to try again later.
988 */
989 static int TPM_Receive(tpmState *s, tpmBuffer *buffer)
990 {
991 int off;
993 off = vTPMTransmit[s->Transmitlayer].read_fn(s, buffer);
995 if (off < 0) {
996 /* EAGAIN is set in errno due to non-blocking mode */
997 return -1;
998 }
1000 if (off == 0) {
1001 #ifdef DEBUG_TPM
1002 fprintf(logfile,"TPM GONE? errno=%d\n",errno);
1003 #endif
1004 close_vtpm_channel(s, 1);
1005 /* pretend that data are available */
1006 if (IS_VALID_LOC(s->active_loc)) {
1007 s->loc[s->active_loc].sts = STS_VALID | STS_DATA_AVAILABLE;
1008 s->loc[s->active_loc].state = STATE_COMPLETION;
1009 tis_raise_irq(s, s->active_loc, INT_DATA_AVAILABLE);
1011 return -1;
1014 #ifdef DEBUG_TPM
1015 if (off > sizeof(buffer->instance ) + 6) {
1016 uint32_t size = tpm_get_size_from_buffer(buffer->buf);
1017 if (size + sizeof(buffer->instance) != off) {
1018 fprintf(logfile,"TPM: Packet size is bad! %d != %d\n",
1019 (int)(size + sizeof(buffer->instance)),
1020 off);
1021 } else {
1022 uint32_t ret;
1023 showBuff(buffer->buf, "From TPM");
1024 ret = (buffer->buf[8])*256 + buffer->buf[9];
1025 if (ret)
1026 fprintf(logfile,"Receive failed with error %d\n", ret);
1027 else
1028 fprintf(logfile,"Receive succeeded. Got response of length %d (=%d)\n",
1029 size, off);
1032 #endif
1034 /* assuming reading in one chunk for now */
1035 return off;
1039 /****************************************************************************
1040 Helper functions for reading data from the xenstore such as
1041 reading virtual TPM instance information
1042 ****************************************************************************/
1043 int has_tpm_device(void)
1045 int ret = 0;
1046 struct xs_handle *handle = xs_daemon_open();
1047 if (handle) {
1048 ret = xenstore_domain_has_devtype(handle, "vtpm");
1049 xs_daemon_close(handle);
1051 return ret;
1055 /*
1056 * Wait until hotplug scripts have finished then read the vTPM instance
1057 * number from the xenstore.
1058 */
1059 static uint32_t vtpm_instance_from_xenstore(void)
1061 unsigned int num;
1062 uint32_t number = VTPM_BAD_INSTANCE;
1063 int end = 0;
1064 char *token = "tok";
1065 int subscribed = 0;
1066 int ctr = 0;
1067 fd_set readfds;
1069 struct xs_handle *handle = xs_daemon_open();
1071 FD_ZERO(&readfds);
1073 if (handle) {
1074 char **e = xenstore_domain_get_devices(handle, "vtpm", &num);
1075 int fd = xs_fileno(handle);
1076 FD_SET(fd, &readfds);
1077 if (e) {
1078 do {
1079 struct timeval tv = {
1080 .tv_sec = 30,
1081 .tv_usec = 0,
1082 };
1083 /* need to make sure that the hotplug scripts have finished */
1084 char *status = xenstore_read_hotplug_status(handle,
1085 "vtpm",
1086 e[0]);
1087 if (status) {
1088 if (!strcmp(status, "connected")) {
1089 char *inst = xenstore_backend_read_variable(handle,
1090 "vtpm",
1091 e[0],
1092 "instance");
1093 if (1 != (sscanf(inst,"%d",&number)))
1094 number = VTPM_BAD_INSTANCE;
1095 free(inst);
1096 } else {
1097 fprintf(logfile,
1098 "bad status '%s' from vtpm hotplug\n",
1099 status);
1101 free(status);
1102 end = 1;
1103 } else {
1104 /* no status, yet */
1105 int rc;
1106 unsigned int nr;
1107 char **f;
1109 if (!subscribed) {
1110 rc = xenstore_subscribe_to_hotplug_status(handle,
1111 "vtpm",
1112 e[0],
1113 token);
1114 if (rc != 0)
1115 break;
1116 subscribed = 1;
1118 rc = select(fd+1, &readfds, NULL, NULL, &tv);
1119 /* get what's available -- drain the fd */
1120 f = xs_read_watch(handle, &nr);
1121 ctr++;
1122 free(f);
1123 if (ctr > 2)
1124 end = 1;
1126 } while (end == 0);
1127 free(e);
1129 if (subscribed) {
1130 /* clean up */
1131 xenstore_unsubscribe_from_hotplug_status(handle,
1132 "vtpm",
1133 e[0],
1134 token);
1136 xs_daemon_close(handle);
1138 if (number == VTPM_BAD_INSTANCE)
1139 fprintf(logfile, "no valid vtpm instance");
1140 else
1141 fprintf(logfile,"vtpm instance:%d\n",number);
1142 return number;