Revision 4549a8b7

b/include/qemu/sockets.h
38 38
void socket_set_block(int fd);
39 39
void socket_set_nonblock(int fd);
40 40
int send_all(int fd, const void *buf, int len1);
41
int recv_all(int fd, void *buf, int len1, bool single_read);
41 42

  
42 43
/* callback function for nonblocking connect
43 44
 * valid fd on success, negative error code on failure
b/qemu-char.c
533 533
    }
534 534
    return len1 - len;
535 535
}
536

  
537
int recv_all(int fd, void *_buf, int len1, bool single_read)
538
{
539
    int ret, len;
540
    uint8_t *buf = _buf;
541

  
542
    len = len1;
543
    while ((len > 0) && (ret = read(fd, buf, len)) != 0) {
544
        if (ret < 0) {
545
            if (errno != EINTR && errno != EAGAIN) {
546
                return -1;
547
            }
548
            continue;
549
        } else {
550
            if (single_read) {
551
                return ret;
552
            }
553
            buf += ret;
554
            len -= ret;
555
        }
556
    }
557
    return len1 - len;
558
}
559

  
536 560
#endif /* !_WIN32 */
537 561

  
538 562
typedef struct IOWatchPoll
b/qemu-options.hx
2221 2221
DEFHEADING(TPM device options:)
2222 2222

  
2223 2223
DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
2224
    "-tpmdev [<type>],id=str[,option][,option][,...]\n",
2224
    "-tpmdev passthrough,id=id[,path=path]\n"
2225
    "                use path to provide path to a character device; default is /dev/tpm0\n",
2225 2226
    QEMU_ARCH_ALL)
2226 2227
STEXI
2227 2228

  
......
2231 2232
@item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]
2232 2233
@findex -tpmdev
2233 2234
Backend type must be:
2235
@option{passthrough}.
2234 2236

  
2235 2237
The specific backend type will determine the applicable options.
2236 2238
The @code{-tpmdev} option requires a @code{-device} option.
......
2242 2244
qemu -tpmdev help
2243 2245
@end example
2244 2246

  
2247
@item -tpmdev passthrough, id=@var{id}, path=@var{path}
2248

  
2249
(Linux-host only) Enable access to the host's TPM using the passthrough
2250
driver.
2251

  
2252
@option{path} specifies the path to the host's TPM device, i.e., on
2253
a Linux host this would be @code{/dev/tpm0}.
2254
@option{path} is optional and by default @code{/dev/tpm0} is used.
2255

  
2256
Some notes about using the host's TPM with the passthrough driver:
2257

  
2258
The TPM device accessed by the passthrough driver must not be
2259
used by any other application on the host.
2260

  
2261
Since the host's firmware (BIOS/UEFI) has already initialized the TPM,
2262
the VM's firmware (BIOS/UEFI) will not be able to initialize the
2263
TPM again and may therefore not show a TPM-specific menu that would
2264
otherwise allow the user to configure the TPM, e.g., allow the user to
2265
enable/disable or activate/deactivate the TPM.
2266
Further, if TPM ownership is released from within a VM then the host's TPM
2267
will get disabled and deactivated. To enable and activate the
2268
TPM again afterwards, the host has to be rebooted and the user is
2269
required to enter the firmware's menu to enable and activate the TPM.
2270
If the TPM is left disabled and/or deactivated most TPM commands will fail.
2271

  
2272
To create a passthrough TPM use the following two options:
2273
@example
2274
-tpmdev passthrough,id=tpm0 -device tpm-tis,tpmdev=tpm0
2275
@end example
2276
Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
2277
@code{tpmdev=tpm0} in the device option.
2278

  
2245 2279
@end table
2246 2280

  
2247 2281
ETEXI
b/tpm/Makefile.objs
1 1
common-obj-y = tpm.o
2 2
ifeq ($(CONFIG_TPM),y)
3
common-obj-y += tpm_backend.o
3 4
common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
5
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
4 6
endif
b/tpm/tpm.c
61 61
    return false;
62 62
}
63 63

  
64
/*
65
 * Write an error message in the given output buffer.
66
 */
67
void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
68
{
69
    if (out_len >= sizeof(struct tpm_resp_hdr)) {
70
        struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out;
71

  
72
        resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND);
73
        resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr));
74
        resp->errcode = cpu_to_be32(TPM_FAIL);
75
    }
76
}
77

  
64 78
const TPMDriverOps *tpm_get_backend_driver(const char *type)
65 79
{
66 80
    int i;
b/tpm/tpm_backend.c
1
/*
2
 *  common TPM backend driver functions
3
 *
4
 *  Copyright (c) 2012-2013 IBM Corporation
5
 *  Authors:
6
 *    Stefan Berger <stefanb@us.ibm.com>
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, see <http://www.gnu.org/licenses/>
20
 */
21

  
22
#include "tpm/tpm.h"
23
#include "qemu/thread.h"
24
#include "tpm_backend.h"
25

  
26
void tpm_backend_thread_deliver_request(TPMBackendThread *tbt)
27
{
28
   g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_PROCESS_CMD, NULL);
29
}
30

  
31
void tpm_backend_thread_create(TPMBackendThread *tbt,
32
                               GFunc func, gpointer user_data)
33
{
34
    if (!tbt->pool) {
35
        tbt->pool = g_thread_pool_new(func, user_data, 1, TRUE, NULL);
36
        g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_INIT, NULL);
37
    }
38
}
39

  
40
void tpm_backend_thread_end(TPMBackendThread *tbt)
41
{
42
    if (tbt->pool) {
43
        g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_END, NULL);
44
        g_thread_pool_free(tbt->pool, FALSE, TRUE);
45
        tbt->pool = NULL;
46
    }
47
}
48

  
49
void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
50
                                  GFunc func, gpointer user_data)
51
{
52
    if (!tbt->pool) {
53
        tpm_backend_thread_create(tbt, func, user_data);
54
    } else {
55
        g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_TPM_RESET,
56
                           NULL);
57
    }
58
}
b/tpm/tpm_backend.h
1
/*
2
 *  common TPM backend driver functions
3
 *
4
 *  Copyright (c) 2012-2013 IBM Corporation
5
 *  Authors:
6
 *    Stefan Berger <stefanb@us.ibm.com>
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, see <http://www.gnu.org/licenses/>
20
 */
21

  
22
#ifndef TPM_TPM_BACKEND_H
23
#define TPM_TPM_BACKEND_H
24

  
25
#include <glib.h>
26

  
27
typedef struct TPMBackendThread {
28
    GThreadPool *pool;
29
} TPMBackendThread;
30

  
31
void tpm_backend_thread_deliver_request(TPMBackendThread *tbt);
32
void tpm_backend_thread_create(TPMBackendThread *tbt,
33
                               GFunc func, gpointer user_data);
34
void tpm_backend_thread_end(TPMBackendThread *tbt);
35
void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
36
                                  GFunc func, gpointer user_data);
37

  
38
typedef enum TPMBackendCmd {
39
    TPM_BACKEND_CMD_INIT = 1,
40
    TPM_BACKEND_CMD_PROCESS_CMD,
41
    TPM_BACKEND_CMD_END,
42
    TPM_BACKEND_CMD_TPM_RESET,
43
} TPMBackendCmd;
44

  
45
#endif /* TPM_TPM_BACKEND_H */
b/tpm/tpm_int.h
18 18
struct TPMDriverOps;
19 19
typedef struct TPMDriverOps TPMDriverOps;
20 20

  
21
typedef struct TPMPassthruState TPMPassthruState;
22

  
21 23
typedef struct TPMBackend {
22 24
    char *id;
23 25
    enum TpmModel fe_model;
......
25 27
    char *cancel_path;
26 28
    const TPMDriverOps *ops;
27 29

  
30
    union {
31
        TPMPassthruState *tpm_pt;
32
    } s;
33

  
28 34
    QLIST_ENTRY(TPMBackend) list;
29 35
} TPMBackend;
30 36

  
......
74 80
    bool (*get_tpm_established_flag)(TPMBackend *t);
75 81
};
76 82

  
83
struct tpm_req_hdr {
84
    uint16_t tag;
85
    uint32_t len;
86
    uint32_t ordinal;
87
} QEMU_PACKED;
88

  
89
struct tpm_resp_hdr {
90
    uint16_t tag;
91
    uint32_t len;
92
    uint32_t errcode;
93
} QEMU_PACKED;
94

  
95
#define TPM_TAG_RQU_COMMAND       0xc1
96
#define TPM_TAG_RQU_AUTH1_COMMAND 0xc2
97
#define TPM_TAG_RQU_AUTH2_COMMAND 0xc3
98

  
99
#define TPM_TAG_RSP_COMMAND       0xc4
100
#define TPM_TAG_RSP_AUTH1_COMMAND 0xc5
101
#define TPM_TAG_RSP_AUTH2_COMMAND 0xc6
102

  
103
#define TPM_FAIL                  9
104

  
105
#define TPM_ORD_GetTicks          0xf1
106

  
77 107
TPMBackend *qemu_find_tpm(const char *id);
78 108
int tpm_register_model(enum TpmModel model);
79 109
int tpm_register_driver(const TPMDriverOps *tdo);
80 110
void tpm_display_backend_drivers(void);
81 111
const TPMDriverOps *tpm_get_backend_driver(const char *type);
112
void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len);
113

  
114
extern const TPMDriverOps tpm_passthrough_driver;
82 115

  
83 116
#endif /* TPM_TPM_INT_H */
b/tpm/tpm_passthrough.c
1
/*
2
 *  passthrough TPM driver
3
 *
4
 *  Copyright (c) 2010 - 2013 IBM Corporation
5
 *  Authors:
6
 *    Stefan Berger <stefanb@us.ibm.com>
7
 *
8
 *  Copyright (C) 2011 IAIK, Graz University of Technology
9
 *    Author: Andreas Niederl
10
 *
11
 * This library is free software; you can redistribute it and/or
12
 * modify it under the terms of the GNU Lesser General Public
13
 * License as published by the Free Software Foundation; either
14
 * version 2 of the License, or (at your option) any later version.
15
 *
16
 * This library is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19
 * Lesser General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Lesser General Public
22
 * License along with this library; if not, see <http://www.gnu.org/licenses/>
23
 */
24

  
25
#include "qemu-common.h"
26
#include "qapi/error.h"
27
#include "qemu/sockets.h"
28
#include "tpm_int.h"
29
#include "hw/hw.h"
30
#include "hw/pc.h"
31
#include "tpm_tis.h"
32
#include "tpm_backend.h"
33

  
34
/* #define DEBUG_TPM */
35

  
36
#ifdef DEBUG_TPM
37
#define DPRINTF(fmt, ...) \
38
    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
39
#else
40
#define DPRINTF(fmt, ...) \
41
    do { } while (0)
42
#endif
43

  
44
/* data structures */
45

  
46
typedef struct TPMPassthruThreadParams {
47
    TPMState *tpm_state;
48

  
49
    TPMRecvDataCB *recv_data_callback;
50
    TPMBackend *tb;
51
} TPMPassthruThreadParams;
52

  
53
struct TPMPassthruState {
54
    TPMBackendThread tbt;
55

  
56
    TPMPassthruThreadParams tpm_thread_params;
57

  
58
    char *tpm_dev;
59
    int tpm_fd;
60
    bool had_startup_error;
61
};
62

  
63
#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
64

  
65
static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len)
66
{
67
    return send_all(fd, buf, len);
68
}
69

  
70
static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
71
{
72
    return recv_all(fd, buf, len, true);
73
}
74

  
75
static uint32_t tpm_passthrough_get_size_from_buffer(const uint8_t *buf)
76
{
77
    struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)buf;
78

  
79
    return be32_to_cpu(resp->len);
80
}
81

  
82
static int tpm_passthrough_unix_tx_bufs(int tpm_fd,
83
                                        const uint8_t *in, uint32_t in_len,
84
                                        uint8_t *out, uint32_t out_len)
85
{
86
    int ret;
87

  
88
    ret = tpm_passthrough_unix_write(tpm_fd, in, in_len);
89
    if (ret != in_len) {
90
        error_report("tpm_passthrough: error while transmitting data "
91
                     "to TPM: %s (%i)\n",
92
                     strerror(errno), errno);
93
        goto err_exit;
94
    }
95

  
96
    ret = tpm_passthrough_unix_read(tpm_fd, out, out_len);
97
    if (ret < 0) {
98
        error_report("tpm_passthrough: error while reading data from "
99
                     "TPM: %s (%i)\n",
100
                     strerror(errno), errno);
101
    } else if (ret < sizeof(struct tpm_resp_hdr) ||
102
               tpm_passthrough_get_size_from_buffer(out) != ret) {
103
        ret = -1;
104
        error_report("tpm_passthrough: received invalid response "
105
                     "packet from TPM\n");
106
    }
107

  
108
err_exit:
109
    if (ret < 0) {
110
        tpm_write_fatal_error_response(out, out_len);
111
    }
112

  
113
    return ret;
114
}
115

  
116
static int tpm_passthrough_unix_transfer(int tpm_fd,
117
                                         const TPMLocality *locty_data)
118
{
119
    return tpm_passthrough_unix_tx_bufs(tpm_fd,
120
                                        locty_data->w_buffer.buffer,
121
                                        locty_data->w_offset,
122
                                        locty_data->r_buffer.buffer,
123
                                        locty_data->r_buffer.size);
124
}
125

  
126
static void tpm_passthrough_worker_thread(gpointer data,
127
                                          gpointer user_data)
128
{
129
    TPMPassthruThreadParams *thr_parms = user_data;
130
    TPMPassthruState *tpm_pt = thr_parms->tb->s.tpm_pt;
131
    TPMBackendCmd cmd = (TPMBackendCmd)data;
132

  
133
    DPRINTF("tpm_passthrough: processing command type %d\n", cmd);
134

  
135
    switch (cmd) {
136
    case TPM_BACKEND_CMD_PROCESS_CMD:
137
        tpm_passthrough_unix_transfer(tpm_pt->tpm_fd,
138
                                      thr_parms->tpm_state->locty_data);
139

  
140
        thr_parms->recv_data_callback(thr_parms->tpm_state,
141
                                      thr_parms->tpm_state->locty_number);
142
        break;
143
    case TPM_BACKEND_CMD_INIT:
144
    case TPM_BACKEND_CMD_END:
145
    case TPM_BACKEND_CMD_TPM_RESET:
146
        /* nothing to do */
147
        break;
148
    }
149
}
150

  
151
/*
152
 * Start the TPM (thread). If it had been started before, then terminate
153
 * and start it again.
154
 */
155
static int tpm_passthrough_startup_tpm(TPMBackend *tb)
156
{
157
    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
158

  
159
    /* terminate a running TPM */
160
    tpm_backend_thread_end(&tpm_pt->tbt);
161

  
162
    tpm_backend_thread_create(&tpm_pt->tbt,
163
                              tpm_passthrough_worker_thread,
164
                              &tb->s.tpm_pt->tpm_thread_params);
165

  
166
    return 0;
167
}
168

  
169
static void tpm_passthrough_reset(TPMBackend *tb)
170
{
171
    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
172

  
173
    DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n");
174

  
175
    tpm_backend_thread_end(&tpm_pt->tbt);
176

  
177
    tpm_pt->had_startup_error = false;
178
}
179

  
180
static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
181
                                TPMRecvDataCB *recv_data_cb)
182
{
183
    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
184

  
185
    tpm_pt->tpm_thread_params.tpm_state = s;
186
    tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb;
187
    tpm_pt->tpm_thread_params.tb = tb;
188

  
189
    return 0;
190
}
191

  
192
static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
193
{
194
    return false;
195
}
196

  
197
static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
198
{
199
    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
200

  
201
    return tpm_pt->had_startup_error;
202
}
203

  
204
static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb)
205
{
206
    size_t wanted_size = 4096; /* Linux tpm.c buffer size */
207

  
208
    if (sb->size != wanted_size) {
209
        sb->buffer = g_realloc(sb->buffer, wanted_size);
210
        sb->size = wanted_size;
211
    }
212
    return sb->size;
213
}
214

  
215
static void tpm_passthrough_deliver_request(TPMBackend *tb)
216
{
217
    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
218

  
219
    tpm_backend_thread_deliver_request(&tpm_pt->tbt);
220
}
221

  
222
static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
223
{
224
    /* cancelling an ongoing command is known not to work with some TPMs */
225
}
226

  
227
static const char *tpm_passthrough_create_desc(void)
228
{
229
    return "Passthrough TPM backend driver";
230
}
231

  
232
/*
233
 * A basic test of a TPM device. We expect a well formatted response header
234
 * (error response is fine) within one second.
235
 */
236
static int tpm_passthrough_test_tpmdev(int fd)
237
{
238
    struct tpm_req_hdr req = {
239
        .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
240
        .len = cpu_to_be32(sizeof(req)),
241
        .ordinal = cpu_to_be32(TPM_ORD_GetTicks),
242
    };
243
    struct tpm_resp_hdr *resp;
244
    fd_set readfds;
245
    int n;
246
    struct timeval tv = {
247
        .tv_sec = 1,
248
        .tv_usec = 0,
249
    };
250
    unsigned char buf[1024];
251

  
252
    n = write(fd, &req, sizeof(req));
253
    if (n < 0) {
254
        return errno;
255
    }
256
    if (n != sizeof(req)) {
257
        return EFAULT;
258
    }
259

  
260
    FD_ZERO(&readfds);
261
    FD_SET(fd, &readfds);
262

  
263
    /* wait for a second */
264
    n = select(fd + 1, &readfds, NULL, NULL, &tv);
265
    if (n != 1) {
266
        return errno;
267
    }
268

  
269
    n = read(fd, &buf, sizeof(buf));
270
    if (n < sizeof(struct tpm_resp_hdr)) {
271
        return EFAULT;
272
    }
273

  
274
    resp = (struct tpm_resp_hdr *)buf;
275
    /* check the header */
276
    if (be16_to_cpu(resp->tag) != TPM_TAG_RSP_COMMAND ||
277
        be32_to_cpu(resp->len) != n) {
278
        return EBADMSG;
279
    }
280

  
281
    return 0;
282
}
283

  
284
static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
285
{
286
    const char *value;
287

  
288
    value = qemu_opt_get(opts, "path");
289
    if (!value) {
290
        value = TPM_PASSTHROUGH_DEFAULT_DEVICE;
291
    }
292

  
293
    tb->s.tpm_pt->tpm_dev = g_strdup(value);
294

  
295
    tb->path = g_strdup(tb->s.tpm_pt->tpm_dev);
296

  
297
    tb->s.tpm_pt->tpm_fd = qemu_open(tb->s.tpm_pt->tpm_dev, O_RDWR);
298
    if (tb->s.tpm_pt->tpm_fd < 0) {
299
        error_report("Cannot access TPM device using '%s': %s\n",
300
                     tb->s.tpm_pt->tpm_dev, strerror(errno));
301
        goto err_free_parameters;
302
    }
303

  
304
    if (tpm_passthrough_test_tpmdev(tb->s.tpm_pt->tpm_fd)) {
305
        error_report("'%s' is not a TPM device.\n",
306
                     tb->s.tpm_pt->tpm_dev);
307
        goto err_close_tpmdev;
308
    }
309

  
310
    return 0;
311

  
312
 err_close_tpmdev:
313
    qemu_close(tb->s.tpm_pt->tpm_fd);
314
    tb->s.tpm_pt->tpm_fd = -1;
315

  
316
 err_free_parameters:
317
    g_free(tb->path);
318
    tb->path = NULL;
319

  
320
    g_free(tb->s.tpm_pt->tpm_dev);
321
    tb->s.tpm_pt->tpm_dev = NULL;
322

  
323
    return 1;
324
}
325

  
326
static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
327
{
328
    TPMBackend *tb;
329

  
330
    tb = g_new0(TPMBackend, 1);
331
    tb->s.tpm_pt = g_new0(TPMPassthruState, 1);
332
    tb->id = g_strdup(id);
333
    /* let frontend set the fe_model to proper value */
334
    tb->fe_model = -1;
335

  
336
    tb->ops = &tpm_passthrough_driver;
337

  
338
    if (tpm_passthrough_handle_device_opts(opts, tb)) {
339
        goto err_exit;
340
    }
341

  
342
    return tb;
343

  
344
err_exit:
345
    g_free(tb->id);
346
    g_free(tb->s.tpm_pt);
347
    g_free(tb);
348

  
349
    return NULL;
350
}
351

  
352
static void tpm_passthrough_destroy(TPMBackend *tb)
353
{
354
    TPMPassthruState *tpm_pt = tb->s.tpm_pt;
355

  
356
    tpm_backend_thread_end(&tpm_pt->tbt);
357

  
358
    qemu_close(tpm_pt->tpm_fd);
359

  
360
    g_free(tb->id);
361
    g_free(tb->path);
362
    g_free(tb->s.tpm_pt->tpm_dev);
363
    g_free(tb->s.tpm_pt);
364
    g_free(tb);
365
}
366

  
367
const TPMDriverOps tpm_passthrough_driver = {
368
    .type                     = TPM_TYPE_PASSTHROUGH,
369
    .desc                     = tpm_passthrough_create_desc,
370
    .create                   = tpm_passthrough_create,
371
    .destroy                  = tpm_passthrough_destroy,
372
    .init                     = tpm_passthrough_init,
373
    .startup_tpm              = tpm_passthrough_startup_tpm,
374
    .realloc_buffer           = tpm_passthrough_realloc_buffer,
375
    .reset                    = tpm_passthrough_reset,
376
    .had_startup_error        = tpm_passthrough_get_startup_error,
377
    .deliver_request          = tpm_passthrough_deliver_request,
378
    .cancel_cmd               = tpm_passthrough_cancel_cmd,
379
    .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
380
};
381

  
382
static void tpm_passthrough_register(void)
383
{
384
    tpm_register_driver(&tpm_passthrough_driver);
385
}
386

  
387
type_init(tpm_passthrough_register)

Also available in: Unified diff