source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/hw/tpm_tis.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

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