2013-02-27 21:47:53 +04:00
|
|
|
/*
|
|
|
|
* passthrough TPM driver
|
|
|
|
*
|
|
|
|
* Copyright (c) 2010 - 2013 IBM Corporation
|
|
|
|
* Authors:
|
|
|
|
* Stefan Berger <stefanb@us.ibm.com>
|
|
|
|
*
|
|
|
|
* Copyright (C) 2011 IAIK, Graz University of Technology
|
|
|
|
* Author: Andreas Niederl
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
|
|
|
*/
|
|
|
|
|
2016-01-26 21:17:30 +03:00
|
|
|
#include "qemu/osdep.h"
|
2013-02-27 21:47:53 +04:00
|
|
|
#include "qemu-common.h"
|
2015-03-17 20:29:20 +03:00
|
|
|
#include "qemu/error-report.h"
|
2013-02-27 21:47:53 +04:00
|
|
|
#include "qemu/sockets.h"
|
2013-04-08 18:55:25 +04:00
|
|
|
#include "sysemu/tpm_backend.h"
|
2013-02-27 21:47:53 +04:00
|
|
|
#include "tpm_int.h"
|
|
|
|
#include "hw/hw.h"
|
2017-09-29 14:10:17 +03:00
|
|
|
#include "qapi/clone-visitor.h"
|
2015-05-26 23:51:06 +03:00
|
|
|
#include "tpm_util.h"
|
2013-02-27 21:47:53 +04:00
|
|
|
|
2015-03-31 21:49:10 +03:00
|
|
|
#define DEBUG_TPM 0
|
|
|
|
|
|
|
|
#define DPRINTF(fmt, ...) do { \
|
|
|
|
if (DEBUG_TPM) { \
|
|
|
|
fprintf(stderr, fmt, ## __VA_ARGS__); \
|
|
|
|
} \
|
maint: Fix macros with broken 'do/while(0); ' usage
The point of writing a macro embedded in a 'do { ... } while (0)'
loop (particularly if the macro has multiple statements or would
otherwise end with an 'if' statement) is so that the macro can be
used as a drop-in statement with the caller supplying the
trailing ';'. Although our coding style frowns on brace-less 'if':
if (cond)
statement;
else
something else;
that is the classic case where failure to use do/while(0) wrapping
would cause the 'else' to pair with any embedded 'if' in the macro
rather than the intended outer 'if'. But conversely, if the macro
includes an embedded ';', then the same brace-less coding style
would now have two statements, making the 'else' a syntax error
rather than pairing with the outer 'if'. Thus, even though our
coding style with required braces is not impacted, ending a macro
with ';' makes our code harder to port to projects that use
brace-less styles.
The change should have no semantic impact. I was not able to
fully compile-test all of the changes (as some of them are
examples of the ugly bit-rotting debug print statements that are
completely elided by default, and I didn't want to recompile
with the necessary -D witnesses - cleaning those up is left as a
bite-sized task for another day); I did, however, audit that for
all files touched, all callers of the changed macros DID supply
a trailing ';' at the callsite, and did not appear to be used
as part of a brace-less conditional.
Found mechanically via: $ git grep -B1 'while (0);' | grep -A1 \\\\
Signed-off-by: Eric Blake <eblake@redhat.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Message-Id: <20171201232433.25193-7-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-12-02 02:24:32 +03:00
|
|
|
} while (0)
|
2013-02-27 21:47:53 +04:00
|
|
|
|
2013-03-28 15:26:21 +04:00
|
|
|
#define TYPE_TPM_PASSTHROUGH "tpm-passthrough"
|
|
|
|
#define TPM_PASSTHROUGH(obj) \
|
|
|
|
OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
|
2013-02-27 21:47:53 +04:00
|
|
|
|
2013-03-28 15:26:21 +04:00
|
|
|
/* data structures */
|
2013-02-27 21:47:53 +04:00
|
|
|
struct TPMPassthruState {
|
2013-03-28 15:26:21 +04:00
|
|
|
TPMBackend parent;
|
|
|
|
|
2017-09-29 14:10:17 +03:00
|
|
|
TPMPassthroughOptions *options;
|
|
|
|
const char *tpm_dev;
|
2013-02-27 21:47:53 +04:00
|
|
|
int tpm_fd;
|
2013-02-27 21:47:54 +04:00
|
|
|
bool tpm_executing;
|
|
|
|
bool tpm_op_canceled;
|
|
|
|
int cancel_fd;
|
2015-05-26 23:51:06 +03:00
|
|
|
|
|
|
|
TPMVersion tpm_version;
|
2017-11-04 05:49:23 +03:00
|
|
|
size_t tpm_buffersize;
|
2013-02-27 21:47:53 +04:00
|
|
|
};
|
|
|
|
|
2013-03-28 15:26:21 +04:00
|
|
|
typedef struct TPMPassthruState TPMPassthruState;
|
|
|
|
|
2013-02-27 21:47:53 +04:00
|
|
|
#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
|
|
|
|
|
2013-02-27 21:47:54 +04:00
|
|
|
/* functions */
|
|
|
|
|
|
|
|
static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
|
|
|
|
|
2013-02-27 21:47:53 +04:00
|
|
|
static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
|
|
|
|
{
|
2015-12-23 16:59:04 +03:00
|
|
|
int ret;
|
|
|
|
reread:
|
|
|
|
ret = read(fd, buf, len);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (errno != EINTR && errno != EAGAIN) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
goto reread;
|
|
|
|
}
|
|
|
|
return ret;
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
2018-01-29 21:33:06 +03:00
|
|
|
|
|
|
|
static void tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
|
|
|
|
const uint8_t *in, uint32_t in_len,
|
|
|
|
uint8_t *out, uint32_t out_len,
|
|
|
|
bool *selftest_done, Error **errp)
|
2013-02-27 21:47:53 +04:00
|
|
|
{
|
2017-09-29 14:10:19 +03:00
|
|
|
ssize_t ret;
|
2015-02-23 17:27:19 +03:00
|
|
|
bool is_selftest;
|
2013-02-27 21:47:53 +04:00
|
|
|
|
2017-11-06 21:39:12 +03:00
|
|
|
/* FIXME: protect shared variables or use other sync mechanism */
|
2013-02-27 21:47:54 +04:00
|
|
|
tpm_pt->tpm_op_canceled = false;
|
|
|
|
tpm_pt->tpm_executing = true;
|
2015-02-23 17:27:19 +03:00
|
|
|
*selftest_done = false;
|
|
|
|
|
2017-09-29 14:10:19 +03:00
|
|
|
is_selftest = tpm_util_is_selftest(in, in_len);
|
2013-02-27 21:47:54 +04:00
|
|
|
|
2017-10-10 01:55:53 +03:00
|
|
|
ret = qemu_write_full(tpm_pt->tpm_fd, in, in_len);
|
2013-02-27 21:47:53 +04:00
|
|
|
if (ret != in_len) {
|
2016-10-12 18:33:44 +03:00
|
|
|
if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
|
2018-01-29 21:33:06 +03:00
|
|
|
error_setg_errno(errp, errno, "tpm_passthrough: error while "
|
|
|
|
"transmitting data to TPM");
|
2013-02-27 21:47:54 +04:00
|
|
|
}
|
2013-02-27 21:47:53 +04:00
|
|
|
goto err_exit;
|
|
|
|
}
|
|
|
|
|
2013-02-27 21:47:54 +04:00
|
|
|
tpm_pt->tpm_executing = false;
|
|
|
|
|
|
|
|
ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len);
|
2013-02-27 21:47:53 +04:00
|
|
|
if (ret < 0) {
|
2016-10-12 18:33:44 +03:00
|
|
|
if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
|
2018-01-29 21:33:06 +03:00
|
|
|
error_setg_errno(errp, errno, "tpm_passthrough: error while "
|
|
|
|
"reading data from TPM");
|
2013-02-27 21:47:54 +04:00
|
|
|
}
|
2013-02-27 21:47:53 +04:00
|
|
|
} else if (ret < sizeof(struct tpm_resp_hdr) ||
|
2018-01-29 21:33:03 +03:00
|
|
|
tpm_cmd_get_size(out) != ret) {
|
2013-02-27 21:47:53 +04:00
|
|
|
ret = -1;
|
2018-01-29 21:33:06 +03:00
|
|
|
error_setg_errno(errp, errno, "tpm_passthrough: received invalid "
|
|
|
|
"response packet from TPM");
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
2015-02-23 17:27:19 +03:00
|
|
|
if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
|
2018-01-29 21:33:03 +03:00
|
|
|
*selftest_done = tpm_cmd_get_errcode(out) == 0;
|
2015-02-23 17:27:19 +03:00
|
|
|
}
|
|
|
|
|
2013-02-27 21:47:53 +04:00
|
|
|
err_exit:
|
|
|
|
if (ret < 0) {
|
2017-09-29 14:10:19 +03:00
|
|
|
tpm_util_write_fatal_error_response(out, out_len);
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
2013-02-27 21:47:54 +04:00
|
|
|
tpm_pt->tpm_executing = false;
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
2018-01-29 21:33:06 +03:00
|
|
|
static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
|
|
|
|
Error **errp)
|
2013-02-27 21:47:53 +04:00
|
|
|
{
|
2017-09-29 14:10:14 +03:00
|
|
|
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
|
2013-02-27 21:47:53 +04:00
|
|
|
|
2017-10-10 01:55:55 +03:00
|
|
|
DPRINTF("tpm_passthrough: processing command %p\n", cmd);
|
2017-10-10 01:55:52 +03:00
|
|
|
|
2017-10-10 01:55:55 +03:00
|
|
|
tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len,
|
2018-01-29 21:33:06 +03:00
|
|
|
cmd->out, cmd->out_len, &cmd->selftest_done,
|
|
|
|
errp);
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tpm_passthrough_reset(TPMBackend *tb)
|
|
|
|
{
|
|
|
|
DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n");
|
|
|
|
|
2013-02-27 21:47:54 +04:00
|
|
|
tpm_passthrough_cancel_cmd(tb);
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-05-26 23:51:05 +03:00
|
|
|
static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
|
|
|
|
uint8_t locty)
|
|
|
|
{
|
|
|
|
/* only a TPM 2.0 will support this */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-27 21:47:53 +04:00
|
|
|
static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
|
|
|
|
{
|
2013-03-28 15:26:21 +04:00
|
|
|
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
|
2013-02-27 21:47:54 +04:00
|
|
|
int n;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As of Linux 3.7 the tpm_tis driver does not properly cancel
|
|
|
|
* commands on all TPM manufacturers' TPMs.
|
|
|
|
* Only cancel if we're busy so we don't cancel someone else's
|
|
|
|
* command, e.g., a command executed on the host.
|
|
|
|
*/
|
|
|
|
if (tpm_pt->tpm_executing) {
|
|
|
|
if (tpm_pt->cancel_fd >= 0) {
|
2017-11-06 21:39:12 +03:00
|
|
|
tpm_pt->tpm_op_canceled = true;
|
2013-02-27 21:47:54 +04:00
|
|
|
n = write(tpm_pt->cancel_fd, "-", 1);
|
|
|
|
if (n != 1) {
|
2015-02-25 07:22:35 +03:00
|
|
|
error_report("Canceling TPM command failed: %s",
|
2013-02-27 21:47:54 +04:00
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error_report("Cannot cancel TPM command due to missing "
|
|
|
|
"TPM sysfs cancel entry");
|
|
|
|
}
|
|
|
|
}
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
2015-05-26 23:51:05 +03:00
|
|
|
static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
|
|
|
|
{
|
2015-05-26 23:51:06 +03:00
|
|
|
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
|
2013-02-27 21:47:53 +04:00
|
|
|
|
2015-05-26 23:51:06 +03:00
|
|
|
return tpm_pt->tpm_version;
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
2017-11-04 01:10:01 +03:00
|
|
|
static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb)
|
|
|
|
{
|
2017-11-04 05:49:23 +03:00
|
|
|
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = tpm_util_get_buffer_size(tpm_pt->tpm_fd, tpm_pt->tpm_version,
|
|
|
|
&tpm_pt->tpm_buffersize);
|
|
|
|
if (ret < 0) {
|
|
|
|
tpm_pt->tpm_buffersize = 4096;
|
|
|
|
}
|
|
|
|
return tpm_pt->tpm_buffersize;
|
2017-11-04 01:10:01 +03:00
|
|
|
}
|
|
|
|
|
2013-02-27 21:47:54 +04:00
|
|
|
/*
|
|
|
|
* Unless path or file descriptor set has been provided by user,
|
|
|
|
* determine the sysfs cancel file following kernel documentation
|
|
|
|
* in Documentation/ABI/stable/sysfs-class-tpm.
|
2018-01-29 21:33:04 +03:00
|
|
|
* From /dev/tpm0 create /sys/class/tpm/tpm0/device/cancel
|
|
|
|
* before 4.0: /sys/class/misc/tpm0/device/cancel
|
2013-02-27 21:47:54 +04:00
|
|
|
*/
|
2017-09-29 14:10:17 +03:00
|
|
|
static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
|
2013-02-27 21:47:54 +04:00
|
|
|
{
|
|
|
|
int fd = -1;
|
2013-04-17 01:08:36 +04:00
|
|
|
char *dev;
|
2013-02-27 21:47:54 +04:00
|
|
|
char path[PATH_MAX];
|
|
|
|
|
2017-09-29 14:10:17 +03:00
|
|
|
if (tpm_pt->options->cancel_path) {
|
|
|
|
fd = qemu_open(tpm_pt->options->cancel_path, O_WRONLY);
|
2013-02-27 21:47:54 +04:00
|
|
|
if (fd < 0) {
|
2018-01-29 21:33:04 +03:00
|
|
|
error_report("tpm_passthrough: Could not open TPM cancel path: %s",
|
2013-02-27 21:47:54 +04:00
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2013-04-17 01:08:36 +04:00
|
|
|
dev = strrchr(tpm_pt->tpm_dev, '/');
|
2018-01-29 21:33:04 +03:00
|
|
|
if (!dev) {
|
|
|
|
error_report("tpm_passthrough: Bad TPM device path %s",
|
|
|
|
tpm_pt->tpm_dev);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev++;
|
|
|
|
if (snprintf(path, sizeof(path), "/sys/class/tpm/%s/device/cancel",
|
|
|
|
dev) < sizeof(path)) {
|
|
|
|
fd = qemu_open(path, O_WRONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel",
|
|
|
|
dev) < sizeof(path)) {
|
|
|
|
fd = qemu_open(path, O_WRONLY);
|
2013-04-17 01:08:36 +04:00
|
|
|
}
|
2013-02-27 21:47:54 +04:00
|
|
|
}
|
2018-01-29 21:33:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
error_report("tpm_passthrough: Could not guess TPM cancel path");
|
2013-04-17 01:08:36 +04:00
|
|
|
} else {
|
2018-01-29 21:33:04 +03:00
|
|
|
tpm_pt->options->cancel_path = g_strdup(path);
|
2013-02-27 21:47:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2017-11-06 21:39:08 +03:00
|
|
|
static int
|
|
|
|
tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
|
2013-02-27 21:47:53 +04:00
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
|
2013-02-27 21:47:54 +04:00
|
|
|
value = qemu_opt_get(opts, "cancel-path");
|
2017-09-29 14:10:17 +03:00
|
|
|
if (value) {
|
|
|
|
tpm_pt->options->cancel_path = g_strdup(value);
|
|
|
|
tpm_pt->options->has_cancel_path = true;
|
|
|
|
}
|
2013-02-27 21:47:54 +04:00
|
|
|
|
2013-02-27 21:47:53 +04:00
|
|
|
value = qemu_opt_get(opts, "path");
|
2017-09-29 14:10:17 +03:00
|
|
|
if (value) {
|
|
|
|
tpm_pt->options->has_path = true;
|
|
|
|
tpm_pt->options->path = g_strdup(value);
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
2017-09-29 14:10:17 +03:00
|
|
|
tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
|
2013-03-28 15:26:21 +04:00
|
|
|
tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR);
|
|
|
|
if (tpm_pt->tpm_fd < 0) {
|
2015-02-25 07:22:35 +03:00
|
|
|
error_report("Cannot access TPM device using '%s': %s",
|
2013-03-28 15:26:21 +04:00
|
|
|
tpm_pt->tpm_dev, strerror(errno));
|
2017-11-06 21:39:11 +03:00
|
|
|
return -1;
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
2015-05-26 23:51:06 +03:00
|
|
|
if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
|
2015-02-25 07:22:35 +03:00
|
|
|
error_report("'%s' is not a TPM device.",
|
2013-03-28 15:26:21 +04:00
|
|
|
tpm_pt->tpm_dev);
|
2017-11-06 21:39:11 +03:00
|
|
|
return -1;
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
2017-11-06 21:39:11 +03:00
|
|
|
tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt);
|
|
|
|
if (tpm_pt->cancel_fd < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2013-02-27 21:47:53 +04:00
|
|
|
|
2017-11-06 21:39:11 +03:00
|
|
|
return 0;
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
2017-11-06 21:39:09 +03:00
|
|
|
static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
|
2013-02-27 21:47:53 +04:00
|
|
|
{
|
2013-03-28 15:26:21 +04:00
|
|
|
Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
|
2013-02-27 21:47:53 +04:00
|
|
|
|
2017-11-06 21:39:11 +03:00
|
|
|
if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
|
|
|
|
object_unref(obj);
|
|
|
|
return NULL;
|
2013-02-27 21:47:54 +04:00
|
|
|
}
|
|
|
|
|
2017-11-06 21:39:09 +03:00
|
|
|
return TPM_BACKEND(obj);
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
2017-11-06 03:31:43 +03:00
|
|
|
static int tpm_passthrough_startup_tpm(TPMBackend *tb, size_t buffersize)
|
|
|
|
{
|
|
|
|
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
|
|
|
|
|
|
|
|
if (buffersize && buffersize < tpm_pt->tpm_buffersize) {
|
|
|
|
error_report("Requested buffer size of %zu is smaller than host TPM's "
|
|
|
|
"fixed buffer size of %zu",
|
|
|
|
buffersize, tpm_pt->tpm_buffersize);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-29 14:10:17 +03:00
|
|
|
static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb)
|
|
|
|
{
|
|
|
|
TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
|
|
|
|
|
|
|
|
options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
|
|
|
|
options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions,
|
|
|
|
TPM_PASSTHROUGH(tb)->options);
|
|
|
|
|
|
|
|
return options;
|
|
|
|
}
|
|
|
|
|
2013-04-22 18:41:39 +04:00
|
|
|
static const QemuOptDesc tpm_passthrough_cmdline_opts[] = {
|
|
|
|
TPM_STANDARD_CMDLINE_OPTS,
|
|
|
|
{
|
|
|
|
.name = "cancel-path",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
.help = "Sysfs file entry for canceling TPM commands",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "path",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
.help = "Path to TPM device on the host",
|
|
|
|
},
|
|
|
|
{ /* end of list */ },
|
|
|
|
};
|
|
|
|
|
2013-03-28 15:26:21 +04:00
|
|
|
static void tpm_passthrough_inst_init(Object *obj)
|
|
|
|
{
|
2017-09-29 14:10:15 +03:00
|
|
|
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
|
|
|
|
|
2017-09-29 14:10:17 +03:00
|
|
|
tpm_pt->options = g_new0(TPMPassthroughOptions, 1);
|
2017-09-29 14:10:15 +03:00
|
|
|
tpm_pt->tpm_fd = -1;
|
|
|
|
tpm_pt->cancel_fd = -1;
|
2013-03-28 15:26:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tpm_passthrough_inst_finalize(Object *obj)
|
|
|
|
{
|
2017-09-29 14:10:15 +03:00
|
|
|
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
|
|
|
|
|
|
|
|
tpm_passthrough_cancel_cmd(TPM_BACKEND(obj));
|
|
|
|
|
2017-11-06 21:39:10 +03:00
|
|
|
if (tpm_pt->tpm_fd >= 0) {
|
|
|
|
qemu_close(tpm_pt->tpm_fd);
|
|
|
|
}
|
|
|
|
if (tpm_pt->cancel_fd >= 0) {
|
|
|
|
qemu_close(tpm_pt->cancel_fd);
|
|
|
|
}
|
2017-09-29 14:10:17 +03:00
|
|
|
qapi_free_TPMPassthroughOptions(tpm_pt->options);
|
2013-03-28 15:26:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
|
|
|
|
|
2017-10-10 01:55:49 +03:00
|
|
|
tbc->type = TPM_TYPE_PASSTHROUGH;
|
|
|
|
tbc->opts = tpm_passthrough_cmdline_opts;
|
|
|
|
tbc->desc = "Passthrough TPM backend driver";
|
|
|
|
tbc->create = tpm_passthrough_create;
|
2017-11-06 03:31:43 +03:00
|
|
|
tbc->startup_tpm = tpm_passthrough_startup_tpm;
|
2017-10-10 01:55:49 +03:00
|
|
|
tbc->reset = tpm_passthrough_reset;
|
|
|
|
tbc->cancel_cmd = tpm_passthrough_cancel_cmd;
|
|
|
|
tbc->get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag;
|
|
|
|
tbc->reset_tpm_established_flag =
|
|
|
|
tpm_passthrough_reset_tpm_established_flag;
|
|
|
|
tbc->get_tpm_version = tpm_passthrough_get_tpm_version;
|
2017-11-04 01:10:01 +03:00
|
|
|
tbc->get_buffer_size = tpm_passthrough_get_buffer_size;
|
2017-10-10 01:55:49 +03:00
|
|
|
tbc->get_tpm_options = tpm_passthrough_get_tpm_options;
|
2017-09-29 14:10:14 +03:00
|
|
|
tbc->handle_request = tpm_passthrough_handle_request;
|
2013-03-28 15:26:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo tpm_passthrough_info = {
|
|
|
|
.name = TYPE_TPM_PASSTHROUGH,
|
|
|
|
.parent = TYPE_TPM_BACKEND,
|
|
|
|
.instance_size = sizeof(TPMPassthruState),
|
|
|
|
.class_init = tpm_passthrough_class_init,
|
|
|
|
.instance_init = tpm_passthrough_inst_init,
|
|
|
|
.instance_finalize = tpm_passthrough_inst_finalize,
|
|
|
|
};
|
|
|
|
|
2013-02-27 21:47:53 +04:00
|
|
|
static void tpm_passthrough_register(void)
|
|
|
|
{
|
2013-03-28 15:26:21 +04:00
|
|
|
type_register_static(&tpm_passthrough_info);
|
2013-02-27 21:47:53 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
type_init(tpm_passthrough_register)
|