diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-06-24 21:19:53 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-06-24 21:19:53 +0100 |
commit | 27c77b1f55323fae772699e05cd5107aa32f9e9a (patch) | |
tree | 3ed67330e72f694e5b2548a0940d943bea0ee2ac /hw | |
parent | d4b78317b7cf8c0c635b70086503813f79ff21ec (diff) | |
parent | ca64b08638e259c313a3e7c3da106116b59be8e9 (diff) | |
download | qemu-27c77b1f55323fae772699e05cd5107aa32f9e9a.zip qemu-27c77b1f55323fae772699e05cd5107aa32f9e9a.tar.gz qemu-27c77b1f55323fae772699e05cd5107aa32f9e9a.tar.bz2 |
Merge remote-tracking branch 'remotes/stefanberger/tags/pull-tpm-2020-06-23-1' into staging
Merge tpm 2020/06/23 v1
# gpg: Signature made Tue 23 Jun 2020 12:35:03 BST
# gpg: using RSA key B818B9CADF9089C2D5CEC66B75AD65802A0B4211
# gpg: Good signature from "Stefan Berger <stefanb@linux.vnet.ibm.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: B818 B9CA DF90 89C2 D5CE C66B 75AD 6580 2A0B 4211
* remotes/stefanberger/tags/pull-tpm-2020-06-23-1:
tpm: Move backend code under the 'backends/' directory
hw/tpm: Make 'tpm_util.h' publicly accessible as "sysemu/tpm_util.h"
hw/tpm: Move DEFINE_PROP_TPMBE() macro to 'tmp_prop.h' local header
hw/tpm: Move few declarations from 'tpm_util.h' to 'tpm_int.h'
hw/tpm: Make TRACE_TPM_UTIL_SHOW_BUFFER check local to tpm_util.c
hw/tpm: Remove unnecessary 'tpm_int.h' header inclusion
hw/tpm: Move 'hw/acpi/tpm.h' inclusion from header to sources
hw/tpm: Include missing 'qemu/option.h' header
hw/tpm: Do not include 'qemu/osdep.h' in header
hw/tpm: Rename TPMDEV as TPM_BACKEND in Kconfig
backends: Add TPM files into their own directory
docs/specs/tpm: Correct header path name
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/tpm/Kconfig | 21 | ||||
-rw-r--r-- | hw/tpm/Makefile.objs | 3 | ||||
-rw-r--r-- | hw/tpm/tpm_crb.c | 4 | ||||
-rw-r--r-- | hw/tpm/tpm_emulator.c | 997 | ||||
-rw-r--r-- | hw/tpm/tpm_int.h | 75 | ||||
-rw-r--r-- | hw/tpm/tpm_ioctl.h | 271 | ||||
-rw-r--r-- | hw/tpm/tpm_passthrough.c | 405 | ||||
-rw-r--r-- | hw/tpm/tpm_ppi.c | 1 | ||||
-rw-r--r-- | hw/tpm/tpm_ppi.h | 1 | ||||
-rw-r--r-- | hw/tpm/tpm_prop.h | 31 | ||||
-rw-r--r-- | hw/tpm/tpm_spapr.c | 4 | ||||
-rw-r--r-- | hw/tpm/tpm_tis.h | 1 | ||||
-rw-r--r-- | hw/tpm/tpm_tis_common.c | 11 | ||||
-rw-r--r-- | hw/tpm/tpm_tis_isa.c | 3 | ||||
-rw-r--r-- | hw/tpm/tpm_tis_sysbus.c | 3 | ||||
-rw-r--r-- | hw/tpm/tpm_util.c | 377 | ||||
-rw-r--r-- | hw/tpm/tpm_util.h | 85 | ||||
-rw-r--r-- | hw/tpm/trace-events | 34 |
18 files changed, 47 insertions, 2280 deletions
diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig index 4794e7f..29e82f3 100644 --- a/hw/tpm/Kconfig +++ b/hw/tpm/Kconfig @@ -1,7 +1,3 @@ -config TPMDEV - bool - depends on TPM - config TPM_TIS_ISA bool depends on TPM && ISA_BUS @@ -15,26 +11,15 @@ config TPM_TIS_SYSBUS config TPM_TIS bool depends on TPM - select TPMDEV + select TPM_BACKEND config TPM_CRB bool depends on TPM && PC - select TPMDEV - -config TPM_PASSTHROUGH - bool - default y - # FIXME: should check for x86 host as well - depends on TPMDEV && LINUX - -config TPM_EMULATOR - bool - default y - depends on TPMDEV + select TPM_BACKEND config TPM_SPAPR bool default y depends on TPM && PSERIES - select TPMDEV + select TPM_BACKEND diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index f1ec4be..6fc05be 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,9 +1,6 @@ -common-obj-$(CONFIG_TPM) += tpm_util.o obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o common-obj-$(CONFIG_TPM_TIS_SYSBUS) += tpm_tis_sysbus.o common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o -common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o -common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o obj-$(CONFIG_TPM_SPAPR) += tpm_spapr.o diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index cd004e7..6024729 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -24,9 +24,9 @@ #include "hw/acpi/tpm.h" #include "migration/vmstate.h" #include "sysemu/tpm_backend.h" +#include "sysemu/tpm_util.h" #include "sysemu/reset.h" -#include "tpm_int.h" -#include "tpm_util.h" +#include "tpm_prop.h" #include "tpm_ppi.h" #include "trace.h" diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c deleted file mode 100644 index 3a0fc44..0000000 --- a/hw/tpm/tpm_emulator.c +++ /dev/null @@ -1,997 +0,0 @@ -/* - * Emulator TPM driver - * - * Copyright (c) 2017 Intel Corporation - * Author: Amarnath Valluri <amarnath.valluri@intel.com> - * - * Copyright (c) 2010 - 2013, 2018 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/> - * - */ - -#include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qemu/sockets.h" -#include "io/channel-socket.h" -#include "sysemu/tpm_backend.h" -#include "tpm_int.h" -#include "tpm_util.h" -#include "tpm_ioctl.h" -#include "migration/blocker.h" -#include "migration/vmstate.h" -#include "qapi/error.h" -#include "qapi/clone-visitor.h" -#include "qapi/qapi-visit-tpm.h" -#include "chardev/char-fe.h" -#include "trace.h" - -#define TYPE_TPM_EMULATOR "tpm-emulator" -#define TPM_EMULATOR(obj) \ - OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR) - -#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap)) - -/* data structures */ - -/* blobs from the TPM; part of VM state when migrating */ -typedef struct TPMBlobBuffers { - uint32_t permanent_flags; - TPMSizedBuffer permanent; - - uint32_t volatil_flags; - TPMSizedBuffer volatil; - - uint32_t savestate_flags; - TPMSizedBuffer savestate; -} TPMBlobBuffers; - -typedef struct TPMEmulator { - TPMBackend parent; - - TPMEmulatorOptions *options; - CharBackend ctrl_chr; - QIOChannel *data_ioc; - TPMVersion tpm_version; - ptm_cap caps; /* capabilities of the TPM */ - uint8_t cur_locty_number; /* last set locality */ - Error *migration_blocker; - - QemuMutex mutex; - - unsigned int established_flag:1; - unsigned int established_flag_cached:1; - - TPMBlobBuffers state_blobs; -} TPMEmulator; - -struct tpm_error { - uint32_t tpm_result; - const char *string; -}; - -static const struct tpm_error tpm_errors[] = { - /* TPM 1.2 error codes */ - { TPM_BAD_PARAMETER , "a parameter is bad" }, - { TPM_FAIL , "operation failed" }, - { TPM_KEYNOTFOUND , "key could not be found" }, - { TPM_BAD_PARAM_SIZE , "bad parameter size"}, - { TPM_ENCRYPT_ERROR , "encryption error" }, - { TPM_DECRYPT_ERROR , "decryption error" }, - { TPM_BAD_KEY_PROPERTY, "bad key property" }, - { TPM_BAD_MODE , "bad (encryption) mode" }, - { TPM_BAD_VERSION , "bad version identifier" }, - { TPM_BAD_LOCALITY , "bad locality" }, - /* TPM 2 error codes */ - { TPM_RC_FAILURE , "operation failed" }, - { TPM_RC_LOCALITY , "bad locality" }, - { TPM_RC_INSUFFICIENT, "insufficient amount of data" }, -}; - -static const char *tpm_emulator_strerror(uint32_t tpm_result) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(tpm_errors); i++) { - if (tpm_errors[i].tpm_result == tpm_result) { - return tpm_errors[i].string; - } - } - return ""; -} - -static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg, - size_t msg_len_in, size_t msg_len_out) -{ - CharBackend *dev = &tpm->ctrl_chr; - uint32_t cmd_no = cpu_to_be32(cmd); - ssize_t n = sizeof(uint32_t) + msg_len_in; - uint8_t *buf = NULL; - int ret = -1; - - qemu_mutex_lock(&tpm->mutex); - - buf = g_alloca(n); - memcpy(buf, &cmd_no, sizeof(cmd_no)); - memcpy(buf + sizeof(cmd_no), msg, msg_len_in); - - n = qemu_chr_fe_write_all(dev, buf, n); - if (n <= 0) { - goto end; - } - - if (msg_len_out != 0) { - n = qemu_chr_fe_read_all(dev, msg, msg_len_out); - if (n <= 0) { - goto end; - } - } - - ret = 0; - -end: - qemu_mutex_unlock(&tpm->mutex); - return ret; -} - -static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, - const uint8_t *in, uint32_t in_len, - uint8_t *out, uint32_t out_len, - bool *selftest_done, - Error **errp) -{ - ssize_t ret; - bool is_selftest = false; - - if (selftest_done) { - *selftest_done = false; - is_selftest = tpm_util_is_selftest(in, in_len); - } - - ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, errp); - if (ret != 0) { - return -1; - } - - ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out, - sizeof(struct tpm_resp_hdr), errp); - if (ret != 0) { - return -1; - } - - ret = qio_channel_read_all(tpm_emu->data_ioc, - (char *)out + sizeof(struct tpm_resp_hdr), - tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), errp); - if (ret != 0) { - return -1; - } - - if (is_selftest) { - *selftest_done = tpm_cmd_get_errcode(out) == 0; - } - - return 0; -} - -static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number, - Error **errp) -{ - ptm_loc loc; - - if (tpm_emu->cur_locty_number == locty_number) { - return 0; - } - - trace_tpm_emulator_set_locality(locty_number); - - memset(&loc, 0, sizeof(loc)); - loc.u.req.loc = locty_number; - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_LOCALITY, &loc, - sizeof(loc), sizeof(loc)) < 0) { - error_setg(errp, "tpm-emulator: could not set locality : %s", - strerror(errno)); - return -1; - } - - loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result); - if (loc.u.resp.tpm_result != 0) { - error_setg(errp, "tpm-emulator: TPM result for set locality : 0x%x", - loc.u.resp.tpm_result); - return -1; - } - - tpm_emu->cur_locty_number = locty_number; - - return 0; -} - -static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd, - Error **errp) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - - trace_tpm_emulator_handle_request(); - - if (tpm_emulator_set_locality(tpm_emu, cmd->locty, errp) < 0 || - tpm_emulator_unix_tx_bufs(tpm_emu, cmd->in, cmd->in_len, - cmd->out, cmd->out_len, - &cmd->selftest_done, errp) < 0) { - tpm_util_write_fatal_error_response(cmd->out, cmd->out_len); - } -} - -static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu) -{ - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_CAPABILITY, - &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) { - error_report("tpm-emulator: probing failed : %s", strerror(errno)); - return -1; - } - - tpm_emu->caps = be64_to_cpu(tpm_emu->caps); - - trace_tpm_emulator_probe_caps(tpm_emu->caps); - - return 0; -} - -static int tpm_emulator_check_caps(TPMEmulator *tpm_emu) -{ - ptm_cap caps = 0; - const char *tpm = NULL; - - /* check for min. required capabilities */ - switch (tpm_emu->tpm_version) { - case TPM_VERSION_1_2: - caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | - PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP | - PTM_CAP_SET_BUFFERSIZE; - tpm = "1.2"; - break; - case TPM_VERSION_2_0: - caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | - PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED | - PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE; - tpm = "2"; - break; - case TPM_VERSION_UNSPEC: - error_report("tpm-emulator: TPM version has not been set"); - return -1; - } - - if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) { - error_report("tpm-emulator: TPM does not implement minimum set of " - "required capabilities for TPM %s (0x%x)", tpm, (int)caps); - return -1; - } - - return 0; -} - -static int tpm_emulator_stop_tpm(TPMBackend *tb) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - ptm_res res; - - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) { - error_report("tpm-emulator: Could not stop TPM: %s", - strerror(errno)); - return -1; - } - - res = be32_to_cpu(res); - if (res) { - error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x %s", res, - tpm_emulator_strerror(res)); - return -1; - } - - return 0; -} - -static int tpm_emulator_set_buffer_size(TPMBackend *tb, - size_t wanted_size, - size_t *actual_size) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - ptm_setbuffersize psbs; - - if (tpm_emulator_stop_tpm(tb) < 0) { - return -1; - } - - psbs.u.req.buffersize = cpu_to_be32(wanted_size); - - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs, - sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) { - error_report("tpm-emulator: Could not set buffer size: %s", - strerror(errno)); - return -1; - } - - psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result); - if (psbs.u.resp.tpm_result != 0) { - error_report("tpm-emulator: TPM result for set buffer size : 0x%x %s", - psbs.u.resp.tpm_result, - tpm_emulator_strerror(psbs.u.resp.tpm_result)); - return -1; - } - - if (actual_size) { - *actual_size = be32_to_cpu(psbs.u.resp.buffersize); - } - - trace_tpm_emulator_set_buffer_size( - be32_to_cpu(psbs.u.resp.buffersize), - be32_to_cpu(psbs.u.resp.minsize), - be32_to_cpu(psbs.u.resp.maxsize)); - - return 0; -} - -static int tpm_emulator_startup_tpm_resume(TPMBackend *tb, size_t buffersize, - bool is_resume) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - ptm_init init = { - .u.req.init_flags = 0, - }; - ptm_res res; - - trace_tpm_emulator_startup_tpm_resume(is_resume, buffersize); - - if (buffersize != 0 && - tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) { - goto err_exit; - } - - if (is_resume) { - init.u.req.init_flags |= cpu_to_be32(PTM_INIT_FLAG_DELETE_VOLATILE); - } - - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init), - sizeof(init)) < 0) { - error_report("tpm-emulator: could not send INIT: %s", - strerror(errno)); - goto err_exit; - } - - res = be32_to_cpu(init.u.resp.tpm_result); - if (res) { - error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x %s", res, - tpm_emulator_strerror(res)); - goto err_exit; - } - return 0; - -err_exit: - return -1; -} - -static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize) -{ - return tpm_emulator_startup_tpm_resume(tb, buffersize, false); -} - -static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - ptm_est est; - - if (tpm_emu->established_flag_cached) { - return tpm_emu->established_flag; - } - - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est, - 0, sizeof(est)) < 0) { - error_report("tpm-emulator: Could not get the TPM established flag: %s", - strerror(errno)); - return false; - } - trace_tpm_emulator_get_tpm_established_flag(est.u.resp.bit); - - tpm_emu->established_flag_cached = 1; - tpm_emu->established_flag = (est.u.resp.bit != 0); - - return tpm_emu->established_flag; -} - -static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb, - uint8_t locty) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - ptm_reset_est reset_est; - ptm_res res; - - /* only a TPM 2.0 will support this */ - if (tpm_emu->tpm_version != TPM_VERSION_2_0) { - return 0; - } - - reset_est.u.req.loc = tpm_emu->cur_locty_number; - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_RESET_TPMESTABLISHED, - &reset_est, sizeof(reset_est), - sizeof(reset_est)) < 0) { - error_report("tpm-emulator: Could not reset the establishment bit: %s", - strerror(errno)); - return -1; - } - - res = be32_to_cpu(reset_est.u.resp.tpm_result); - if (res) { - error_report( - "tpm-emulator: TPM result for rest established flag: 0x%x %s", - res, tpm_emulator_strerror(res)); - return -1; - } - - tpm_emu->established_flag_cached = 0; - - return 0; -} - -static void tpm_emulator_cancel_cmd(TPMBackend *tb) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - ptm_res res; - - if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) { - trace_tpm_emulator_cancel_cmd_not_supt(); - return; - } - - /* FIXME: make the function non-blocking, or it may block a VCPU */ - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0, - sizeof(res)) < 0) { - error_report("tpm-emulator: Could not cancel command: %s", - strerror(errno)); - } else if (res != 0) { - error_report("tpm-emulator: Failed to cancel TPM: 0x%x", - be32_to_cpu(res)); - } -} - -static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - - return tpm_emu->tpm_version; -} - -static size_t tpm_emulator_get_buffer_size(TPMBackend *tb) -{ - size_t actual_size; - - if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) { - return 4096; - } - - return actual_size; -} - -static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) -{ - Error *err = NULL; - ptm_cap caps = PTM_CAP_GET_STATEBLOB | PTM_CAP_SET_STATEBLOB | - PTM_CAP_STOP; - - if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) { - error_setg(&tpm_emu->migration_blocker, - "Migration disabled: TPM emulator does not support " - "migration"); - migrate_add_blocker(tpm_emu->migration_blocker, &err); - if (err) { - error_report_err(err); - error_free(tpm_emu->migration_blocker); - tpm_emu->migration_blocker = NULL; - - return -1; - } - } - - return 0; -} - -static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu) -{ - ptm_res res; - Error *err = NULL; - int fds[2] = { -1, -1 }; - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - error_report("tpm-emulator: Failed to create socketpair"); - return -1; - } - - qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1); - - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_DATAFD, &res, 0, - sizeof(res)) < 0 || res != 0) { - error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s", - strerror(errno)); - goto err_exit; - } - - tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err)); - if (err) { - error_prepend(&err, "tpm-emulator: Failed to create io channel: "); - error_report_err(err); - goto err_exit; - } - - closesocket(fds[1]); - - return 0; - -err_exit: - closesocket(fds[0]); - closesocket(fds[1]); - return -1; -} - -static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts) -{ - const char *value; - - value = qemu_opt_get(opts, "chardev"); - if (value) { - Error *err = NULL; - Chardev *dev = qemu_chr_find(value); - - if (!dev) { - error_report("tpm-emulator: tpm chardev '%s' not found.", value); - goto err; - } - - if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) { - error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':", - value); - error_report_err(err); - goto err; - } - - tpm_emu->options->chardev = g_strdup(value); - } - - if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) { - goto err; - } - - /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used - * by passthrough driver, which not yet using GIOChannel. - */ - if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd, - &tpm_emu->tpm_version)) { - error_report("'%s' is not emulating TPM device. Error: %s", - tpm_emu->options->chardev, strerror(errno)); - goto err; - } - - switch (tpm_emu->tpm_version) { - case TPM_VERSION_1_2: - trace_tpm_emulator_handle_device_opts_tpm12(); - break; - case TPM_VERSION_2_0: - trace_tpm_emulator_handle_device_opts_tpm2(); - break; - default: - trace_tpm_emulator_handle_device_opts_unspec(); - } - - if (tpm_emulator_probe_caps(tpm_emu) || - tpm_emulator_check_caps(tpm_emu)) { - goto err; - } - - return tpm_emulator_block_migration(tpm_emu); - -err: - trace_tpm_emulator_handle_device_opts_startup_error(); - - return -1; -} - -static TPMBackend *tpm_emulator_create(QemuOpts *opts) -{ - TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR)); - - if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) { - object_unref(OBJECT(tb)); - return NULL; - } - - return tb; -} - -static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - TpmTypeOptions *options = g_new0(TpmTypeOptions, 1); - - options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR; - options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options); - - return options; -} - -static const QemuOptDesc tpm_emulator_cmdline_opts[] = { - TPM_STANDARD_CMDLINE_OPTS, - { - .name = "chardev", - .type = QEMU_OPT_STRING, - .help = "Character device to use for out-of-band control messages", - }, - { /* end of list */ }, -}; - -/* - * Transfer a TPM state blob from the TPM into a provided buffer. - * - * @tpm_emu: TPMEmulator - * @type: the type of blob to transfer - * @tsb: the TPMSizeBuffer to fill with the blob - * @flags: the flags to return to the caller - */ -static int tpm_emulator_get_state_blob(TPMEmulator *tpm_emu, - uint8_t type, - TPMSizedBuffer *tsb, - uint32_t *flags) -{ - ptm_getstate pgs; - ptm_res res; - ssize_t n; - uint32_t totlength, length; - - tpm_sized_buffer_reset(tsb); - - pgs.u.req.state_flags = cpu_to_be32(PTM_STATE_FLAG_DECRYPTED); - pgs.u.req.type = cpu_to_be32(type); - pgs.u.req.offset = 0; - - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_STATEBLOB, - &pgs, sizeof(pgs.u.req), - offsetof(ptm_getstate, u.resp.data)) < 0) { - error_report("tpm-emulator: could not get state blob type %d : %s", - type, strerror(errno)); - return -1; - } - - res = be32_to_cpu(pgs.u.resp.tpm_result); - if (res != 0 && (res & 0x800) == 0) { - error_report("tpm-emulator: Getting the stateblob (type %d) failed " - "with a TPM error 0x%x %s", type, res, - tpm_emulator_strerror(res)); - return -1; - } - - totlength = be32_to_cpu(pgs.u.resp.totlength); - length = be32_to_cpu(pgs.u.resp.length); - if (totlength != length) { - error_report("tpm-emulator: Expecting to read %u bytes " - "but would get %u", totlength, length); - return -1; - } - - *flags = be32_to_cpu(pgs.u.resp.state_flags); - - if (totlength > 0) { - tsb->buffer = g_try_malloc(totlength); - if (!tsb->buffer) { - error_report("tpm-emulator: Out of memory allocating %u bytes", - totlength); - return -1; - } - - n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr, tsb->buffer, totlength); - if (n != totlength) { - error_report("tpm-emulator: Could not read stateblob (type %d); " - "expected %u bytes, got %zd", - type, totlength, n); - return -1; - } - } - tsb->size = totlength; - - trace_tpm_emulator_get_state_blob(type, tsb->size, *flags); - - return 0; -} - -static int tpm_emulator_get_state_blobs(TPMEmulator *tpm_emu) -{ - TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs; - - if (tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT, - &state_blobs->permanent, - &state_blobs->permanent_flags) < 0 || - tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE, - &state_blobs->volatil, - &state_blobs->volatil_flags) < 0 || - tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE, - &state_blobs->savestate, - &state_blobs->savestate_flags) < 0) { - goto err_exit; - } - - return 0; - - err_exit: - tpm_sized_buffer_reset(&state_blobs->volatil); - tpm_sized_buffer_reset(&state_blobs->permanent); - tpm_sized_buffer_reset(&state_blobs->savestate); - - return -1; -} - -/* - * Transfer a TPM state blob to the TPM emulator. - * - * @tpm_emu: TPMEmulator - * @type: the type of TPM state blob to transfer - * @tsb: TPMSizedBuffer containing the TPM state blob - * @flags: Flags describing the (encryption) state of the TPM state blob - */ -static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu, - uint32_t type, - TPMSizedBuffer *tsb, - uint32_t flags) -{ - ssize_t n; - ptm_setstate pss; - ptm_res tpm_result; - - if (tsb->size == 0) { - return 0; - } - - pss = (ptm_setstate) { - .u.req.state_flags = cpu_to_be32(flags), - .u.req.type = cpu_to_be32(type), - .u.req.length = cpu_to_be32(tsb->size), - }; - - /* write the header only */ - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_STATEBLOB, &pss, - offsetof(ptm_setstate, u.req.data), 0) < 0) { - error_report("tpm-emulator: could not set state blob type %d : %s", - type, strerror(errno)); - return -1; - } - - /* now the body */ - n = qemu_chr_fe_write_all(&tpm_emu->ctrl_chr, tsb->buffer, tsb->size); - if (n != tsb->size) { - error_report("tpm-emulator: Writing the stateblob (type %d) " - "failed; could not write %u bytes, but only %zd", - type, tsb->size, n); - return -1; - } - - /* now get the result */ - n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr, - (uint8_t *)&pss, sizeof(pss.u.resp)); - if (n != sizeof(pss.u.resp)) { - error_report("tpm-emulator: Reading response from writing stateblob " - "(type %d) failed; expected %zu bytes, got %zd", type, - sizeof(pss.u.resp), n); - return -1; - } - - tpm_result = be32_to_cpu(pss.u.resp.tpm_result); - if (tpm_result != 0) { - error_report("tpm-emulator: Setting the stateblob (type %d) failed " - "with a TPM error 0x%x %s", type, tpm_result, - tpm_emulator_strerror(tpm_result)); - return -1; - } - - trace_tpm_emulator_set_state_blob(type, tsb->size, flags); - - return 0; -} - -/* - * Set all the TPM state blobs. - * - * Returns a negative errno code in case of error. - */ -static int tpm_emulator_set_state_blobs(TPMBackend *tb) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs; - - trace_tpm_emulator_set_state_blobs(); - - if (tpm_emulator_stop_tpm(tb) < 0) { - trace_tpm_emulator_set_state_blobs_error("Could not stop TPM"); - return -EIO; - } - - if (tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT, - &state_blobs->permanent, - state_blobs->permanent_flags) < 0 || - tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE, - &state_blobs->volatil, - state_blobs->volatil_flags) < 0 || - tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE, - &state_blobs->savestate, - state_blobs->savestate_flags) < 0) { - return -EIO; - } - - trace_tpm_emulator_set_state_blobs_done(); - - return 0; -} - -static int tpm_emulator_pre_save(void *opaque) -{ - TPMBackend *tb = opaque; - TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - - trace_tpm_emulator_pre_save(); - - tpm_backend_finish_sync(tb); - - /* get the state blobs from the TPM */ - return tpm_emulator_get_state_blobs(tpm_emu); -} - -/* - * Load the TPM state blobs into the TPM. - * - * Returns negative errno codes in case of error. - */ -static int tpm_emulator_post_load(void *opaque, int version_id) -{ - TPMBackend *tb = opaque; - int ret; - - ret = tpm_emulator_set_state_blobs(tb); - if (ret < 0) { - return ret; - } - - if (tpm_emulator_startup_tpm_resume(tb, 0, true) < 0) { - return -EIO; - } - - return 0; -} - -static const VMStateDescription vmstate_tpm_emulator = { - .name = "tpm-emulator", - .version_id = 0, - .pre_save = tpm_emulator_pre_save, - .post_load = tpm_emulator_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(state_blobs.permanent_flags, TPMEmulator), - VMSTATE_UINT32(state_blobs.permanent.size, TPMEmulator), - VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.permanent.buffer, - TPMEmulator, 0, 0, - state_blobs.permanent.size), - - VMSTATE_UINT32(state_blobs.volatil_flags, TPMEmulator), - VMSTATE_UINT32(state_blobs.volatil.size, TPMEmulator), - VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.volatil.buffer, - TPMEmulator, 0, 0, - state_blobs.volatil.size), - - VMSTATE_UINT32(state_blobs.savestate_flags, TPMEmulator), - VMSTATE_UINT32(state_blobs.savestate.size, TPMEmulator), - VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.savestate.buffer, - TPMEmulator, 0, 0, - state_blobs.savestate.size), - - VMSTATE_END_OF_LIST() - } -}; - -static void tpm_emulator_inst_init(Object *obj) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(obj); - - trace_tpm_emulator_inst_init(); - - tpm_emu->options = g_new0(TPMEmulatorOptions, 1); - tpm_emu->cur_locty_number = ~0; - qemu_mutex_init(&tpm_emu->mutex); - - vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, - &vmstate_tpm_emulator, obj); -} - -/* - * Gracefully shut down the external TPM - */ -static void tpm_emulator_shutdown(TPMEmulator *tpm_emu) -{ - ptm_res res; - - if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, sizeof(res)) < 0) { - error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s", - strerror(errno)); - } else if (res != 0) { - error_report("tpm-emulator: TPM result for shutdown: 0x%x %s", - be32_to_cpu(res), tpm_emulator_strerror(be32_to_cpu(res))); - } -} - -static void tpm_emulator_inst_finalize(Object *obj) -{ - TPMEmulator *tpm_emu = TPM_EMULATOR(obj); - TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs; - - tpm_emulator_shutdown(tpm_emu); - - object_unref(OBJECT(tpm_emu->data_ioc)); - - qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false); - - qapi_free_TPMEmulatorOptions(tpm_emu->options); - - if (tpm_emu->migration_blocker) { - migrate_del_blocker(tpm_emu->migration_blocker); - error_free(tpm_emu->migration_blocker); - } - - tpm_sized_buffer_reset(&state_blobs->volatil); - tpm_sized_buffer_reset(&state_blobs->permanent); - tpm_sized_buffer_reset(&state_blobs->savestate); - - qemu_mutex_destroy(&tpm_emu->mutex); - - vmstate_unregister(NULL, &vmstate_tpm_emulator, obj); -} - -static void tpm_emulator_class_init(ObjectClass *klass, void *data) -{ - TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); - - tbc->type = TPM_TYPE_EMULATOR; - tbc->opts = tpm_emulator_cmdline_opts; - tbc->desc = "TPM emulator backend driver"; - tbc->create = tpm_emulator_create; - tbc->startup_tpm = tpm_emulator_startup_tpm; - tbc->cancel_cmd = tpm_emulator_cancel_cmd; - tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag; - tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag; - tbc->get_tpm_version = tpm_emulator_get_tpm_version; - tbc->get_buffer_size = tpm_emulator_get_buffer_size; - tbc->get_tpm_options = tpm_emulator_get_tpm_options; - - tbc->handle_request = tpm_emulator_handle_request; -} - -static const TypeInfo tpm_emulator_info = { - .name = TYPE_TPM_EMULATOR, - .parent = TYPE_TPM_BACKEND, - .instance_size = sizeof(TPMEmulator), - .class_init = tpm_emulator_class_init, - .instance_init = tpm_emulator_inst_init, - .instance_finalize = tpm_emulator_inst_finalize, -}; - -static void tpm_emulator_register(void) -{ - type_register_static(&tpm_emulator_info); -} - -type_init(tpm_emulator_register) diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h deleted file mode 100644 index 3fb28a9..0000000 --- a/hw/tpm/tpm_int.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * TPM configuration - * - * Copyright (C) 2011-2013 IBM Corporation - * - * Authors: - * Stefan Berger <stefanb@us.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ -#ifndef TPM_TPM_INT_H -#define TPM_TPM_INT_H - -#define TPM_STANDARD_CMDLINE_OPTS \ - { \ - .name = "type", \ - .type = QEMU_OPT_STRING, \ - .help = "Type of TPM backend", \ - } - -struct tpm_req_hdr { - uint16_t tag; - uint32_t len; - uint32_t ordinal; -} QEMU_PACKED; - -struct tpm_resp_hdr { - uint16_t tag; - uint32_t len; - uint32_t errcode; -} QEMU_PACKED; - -#define TPM_TAG_RQU_COMMAND 0xc1 -#define TPM_TAG_RQU_AUTH1_COMMAND 0xc2 -#define TPM_TAG_RQU_AUTH2_COMMAND 0xc3 - -#define TPM_TAG_RSP_COMMAND 0xc4 -#define TPM_TAG_RSP_AUTH1_COMMAND 0xc5 -#define TPM_TAG_RSP_AUTH2_COMMAND 0xc6 - -#define TPM_BAD_PARAMETER 3 -#define TPM_FAIL 9 -#define TPM_KEYNOTFOUND 13 -#define TPM_BAD_PARAM_SIZE 25 -#define TPM_ENCRYPT_ERROR 32 -#define TPM_DECRYPT_ERROR 33 -#define TPM_BAD_KEY_PROPERTY 40 -#define TPM_BAD_MODE 44 -#define TPM_BAD_VERSION 46 -#define TPM_BAD_LOCALITY 61 - -#define TPM_ORD_ContinueSelfTest 0x53 -#define TPM_ORD_GetTicks 0xf1 -#define TPM_ORD_GetCapability 0x65 - -#define TPM_CAP_PROPERTY 0x05 - -#define TPM_CAP_PROP_INPUT_BUFFER 0x124 - -/* TPM2 defines */ -#define TPM2_ST_NO_SESSIONS 0x8001 - -#define TPM2_CC_ReadClock 0x00000181 -#define TPM2_CC_GetCapability 0x0000017a - -#define TPM2_CAP_TPM_PROPERTIES 0x6 - -#define TPM2_PT_MAX_COMMAND_SIZE 0x11e - -#define TPM_RC_INSUFFICIENT 0x9a -#define TPM_RC_FAILURE 0x101 -#define TPM_RC_LOCALITY 0x907 - -#endif /* TPM_TPM_INT_H */ diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h deleted file mode 100644 index f5f5c55..0000000 --- a/hw/tpm/tpm_ioctl.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * tpm_ioctl.h - * - * (c) Copyright IBM Corporation 2014, 2015. - * - * This file is licensed under the terms of the 3-clause BSD license - */ - -#ifndef TPM_IOCTL_H -#define TPM_IOCTL_H - -#include <sys/uio.h> -#include <sys/ioctl.h> - -/* - * Every response from a command involving a TPM command execution must hold - * the ptm_res as the first element. - * ptm_res corresponds to the error code of a command executed by the TPM. - */ - -typedef uint32_t ptm_res; - -/* PTM_GET_TPMESTABLISHED: get the establishment bit */ -struct ptm_est { - union { - struct { - ptm_res tpm_result; - unsigned char bit; /* TPM established bit */ - } resp; /* response */ - } u; -}; - -/* PTM_RESET_TPMESTABLISHED: reset establishment bit */ -struct ptm_reset_est { - union { - struct { - uint8_t loc; /* locality to use */ - } req; /* request */ - struct { - ptm_res tpm_result; - } resp; /* response */ - } u; -}; - -/* PTM_INIT */ -struct ptm_init { - union { - struct { - uint32_t init_flags; /* see definitions below */ - } req; /* request */ - struct { - ptm_res tpm_result; - } resp; /* response */ - } u; -}; - -/* above init_flags */ -#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0) - /* delete volatile state file after reading it */ - -/* PTM_SET_LOCALITY */ -struct ptm_loc { - union { - struct { - uint8_t loc; /* locality to set */ - } req; /* request */ - struct { - ptm_res tpm_result; - } resp; /* response */ - } u; -}; - -/* PTM_HASH_DATA: hash given data */ -struct ptm_hdata { - union { - struct { - uint32_t length; - uint8_t data[4096]; - } req; /* request */ - struct { - ptm_res tpm_result; - } resp; /* response */ - } u; -}; - -/* - * size of the TPM state blob to transfer; x86_64 can handle 8k, - * ppc64le only ~7k; keep the response below a 4k page size - */ -#define PTM_STATE_BLOB_SIZE (3 * 1024) - -/* - * The following is the data structure to get state blobs from the TPM. - * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple reads - * with this ioctl and with adjusted offset are necessary. All bytes - * must be transferred and the transfer is done once the last byte has been - * returned. - * It is possible to use the read() interface for reading the data; however, the - * first bytes of the state blob will be part of the response to the ioctl(); a - * subsequent read() is only necessary if the total length (totlength) exceeds - * the number of received bytes. seek() is not supported. - */ -struct ptm_getstate { - union { - struct { - uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */ - uint32_t type; /* which blob to pull */ - uint32_t offset; /* offset from where to read */ - } req; /* request */ - struct { - ptm_res tpm_result; - uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */ - uint32_t totlength; /* total length that will be transferred */ - uint32_t length; /* number of bytes in following buffer */ - uint8_t data[PTM_STATE_BLOB_SIZE]; - } resp; /* response */ - } u; -}; - -/* TPM state blob types */ -#define PTM_BLOB_TYPE_PERMANENT 1 -#define PTM_BLOB_TYPE_VOLATILE 2 -#define PTM_BLOB_TYPE_SAVESTATE 3 - -/* state_flags above : */ -#define PTM_STATE_FLAG_DECRYPTED 1 /* on input: get decrypted state */ -#define PTM_STATE_FLAG_ENCRYPTED 2 /* on output: state is encrypted */ - -/* - * The following is the data structure to set state blobs in the TPM. - * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple - * 'writes' using this ioctl are necessary. The last packet is indicated - * by the length being smaller than the PTM_STATE_BLOB_SIZE. - * The very first packet may have a length indicator of '0' enabling - * a write() with all the bytes from a buffer. If the write() interface - * is used, a final ioctl with a non-full buffer must be made to indicate - * that all data were transferred (a write with 0 bytes would not work). - */ -struct ptm_setstate { - union { - struct { - uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */ - uint32_t type; /* which blob to set */ - uint32_t length; /* length of the data; - use 0 on the first packet to - transfer using write() */ - uint8_t data[PTM_STATE_BLOB_SIZE]; - } req; /* request */ - struct { - ptm_res tpm_result; - } resp; /* response */ - } u; -}; - -/* - * PTM_GET_CONFIG: Data structure to get runtime configuration information - * such as which keys are applied. - */ -struct ptm_getconfig { - union { - struct { - ptm_res tpm_result; - uint32_t flags; - } resp; /* response */ - } u; -}; - -#define PTM_CONFIG_FLAG_FILE_KEY 0x1 -#define PTM_CONFIG_FLAG_MIGRATION_KEY 0x2 - -/* - * PTM_SET_BUFFERSIZE: Set the buffer size to be used by the TPM. - * A 0 on input queries for the current buffer size. Any other - * number will try to set the buffer size. The returned number is - * the buffer size that will be used, which can be larger than the - * requested one, if it was below the minimum, or smaller than the - * requested one, if it was above the maximum. - */ -struct ptm_setbuffersize { - union { - struct { - uint32_t buffersize; /* 0 to query for current buffer size */ - } req; /* request */ - struct { - ptm_res tpm_result; - uint32_t buffersize; /* buffer size in use */ - uint32_t minsize; /* min. supported buffer size */ - uint32_t maxsize; /* max. supported buffer size */ - } resp; /* response */ - } u; -}; - - -typedef uint64_t ptm_cap; -typedef struct ptm_est ptm_est; -typedef struct ptm_reset_est ptm_reset_est; -typedef struct ptm_loc ptm_loc; -typedef struct ptm_hdata ptm_hdata; -typedef struct ptm_init ptm_init; -typedef struct ptm_getstate ptm_getstate; -typedef struct ptm_setstate ptm_setstate; -typedef struct ptm_getconfig ptm_getconfig; -typedef struct ptm_setbuffersize ptm_setbuffersize; - -/* capability flags returned by PTM_GET_CAPABILITY */ -#define PTM_CAP_INIT (1) -#define PTM_CAP_SHUTDOWN (1 << 1) -#define PTM_CAP_GET_TPMESTABLISHED (1 << 2) -#define PTM_CAP_SET_LOCALITY (1 << 3) -#define PTM_CAP_HASHING (1 << 4) -#define PTM_CAP_CANCEL_TPM_CMD (1 << 5) -#define PTM_CAP_STORE_VOLATILE (1 << 6) -#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7) -#define PTM_CAP_GET_STATEBLOB (1 << 8) -#define PTM_CAP_SET_STATEBLOB (1 << 9) -#define PTM_CAP_STOP (1 << 10) -#define PTM_CAP_GET_CONFIG (1 << 11) -#define PTM_CAP_SET_DATAFD (1 << 12) -#define PTM_CAP_SET_BUFFERSIZE (1 << 13) - -enum { - PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap), - PTM_INIT = _IOWR('P', 1, ptm_init), - PTM_SHUTDOWN = _IOR('P', 2, ptm_res), - PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est), - PTM_SET_LOCALITY = _IOWR('P', 4, ptm_loc), - PTM_HASH_START = _IOR('P', 5, ptm_res), - PTM_HASH_DATA = _IOWR('P', 6, ptm_hdata), - PTM_HASH_END = _IOR('P', 7, ptm_res), - PTM_CANCEL_TPM_CMD = _IOR('P', 8, ptm_res), - PTM_STORE_VOLATILE = _IOR('P', 9, ptm_res), - PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est), - PTM_GET_STATEBLOB = _IOWR('P', 11, ptm_getstate), - PTM_SET_STATEBLOB = _IOWR('P', 12, ptm_setstate), - PTM_STOP = _IOR('P', 13, ptm_res), - PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig), - PTM_SET_DATAFD = _IOR('P', 15, ptm_res), - PTM_SET_BUFFERSIZE = _IOWR('P', 16, ptm_setbuffersize), -}; - -/* - * Commands used by the non-CUSE TPMs - * - * All messages container big-endian data. - * - * The return messages only contain the 'resp' part of the unions - * in the data structures above. Besides that the limits in the - * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data - * and ptm_set_state:u.req.data) are 0xffffffff. - */ -enum { - CMD_GET_CAPABILITY = 1, - CMD_INIT, - CMD_SHUTDOWN, - CMD_GET_TPMESTABLISHED, - CMD_SET_LOCALITY, - CMD_HASH_START, - CMD_HASH_DATA, - CMD_HASH_END, - CMD_CANCEL_TPM_CMD, - CMD_STORE_VOLATILE, - CMD_RESET_TPMESTABLISHED, - CMD_GET_STATEBLOB, - CMD_SET_STATEBLOB, - CMD_STOP, - CMD_GET_CONFIG, - CMD_SET_DATAFD, - CMD_SET_BUFFERSIZE, -}; - -#endif /* TPM_IOCTL_H */ diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c deleted file mode 100644 index f67244b..0000000 --- a/hw/tpm/tpm_passthrough.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - * 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/> - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qemu/sockets.h" -#include "sysemu/tpm_backend.h" -#include "tpm_int.h" -#include "qapi/clone-visitor.h" -#include "qapi/qapi-visit-tpm.h" -#include "tpm_util.h" -#include "trace.h" - -#define TYPE_TPM_PASSTHROUGH "tpm-passthrough" -#define TPM_PASSTHROUGH(obj) \ - OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH) - -/* data structures */ -struct TPMPassthruState { - TPMBackend parent; - - TPMPassthroughOptions *options; - const char *tpm_dev; - int tpm_fd; - bool tpm_executing; - bool tpm_op_canceled; - int cancel_fd; - - TPMVersion tpm_version; - size_t tpm_buffersize; -}; - -typedef struct TPMPassthruState TPMPassthruState; - -#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0" - -/* functions */ - -static void tpm_passthrough_cancel_cmd(TPMBackend *tb); - -static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len) -{ - int ret; - reread: - ret = read(fd, buf, len); - if (ret < 0) { - if (errno != EINTR && errno != EAGAIN) { - return -1; - } - goto reread; - } - return ret; -} - -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) -{ - ssize_t ret; - bool is_selftest; - - /* FIXME: protect shared variables or use other sync mechanism */ - tpm_pt->tpm_op_canceled = false; - tpm_pt->tpm_executing = true; - *selftest_done = false; - - is_selftest = tpm_util_is_selftest(in, in_len); - - ret = qemu_write_full(tpm_pt->tpm_fd, in, in_len); - if (ret != in_len) { - if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) { - error_setg_errno(errp, errno, "tpm_passthrough: error while " - "transmitting data to TPM"); - } - goto err_exit; - } - - tpm_pt->tpm_executing = false; - - ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len); - if (ret < 0) { - if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) { - error_setg_errno(errp, errno, "tpm_passthrough: error while " - "reading data from TPM"); - } - } else if (ret < sizeof(struct tpm_resp_hdr) || - tpm_cmd_get_size(out) != ret) { - ret = -1; - error_setg_errno(errp, errno, "tpm_passthrough: received invalid " - "response packet from TPM"); - } - - if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) { - *selftest_done = tpm_cmd_get_errcode(out) == 0; - } - -err_exit: - if (ret < 0) { - tpm_util_write_fatal_error_response(out, out_len); - } - - tpm_pt->tpm_executing = false; -} - -static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *cmd, - Error **errp) -{ - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); - - trace_tpm_passthrough_handle_request(cmd); - - tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len, - cmd->out, cmd->out_len, &cmd->selftest_done, - errp); -} - -static void tpm_passthrough_reset(TPMBackend *tb) -{ - trace_tpm_passthrough_reset(); - - tpm_passthrough_cancel_cmd(tb); -} - -static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb) -{ - return false; -} - -static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb, - uint8_t locty) -{ - /* only a TPM 2.0 will support this */ - return 0; -} - -static void tpm_passthrough_cancel_cmd(TPMBackend *tb) -{ - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); - 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) { - tpm_pt->tpm_op_canceled = true; - n = write(tpm_pt->cancel_fd, "-", 1); - if (n != 1) { - error_report("Canceling TPM command failed: %s", - strerror(errno)); - } - } else { - error_report("Cannot cancel TPM command due to missing " - "TPM sysfs cancel entry"); - } - } -} - -static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb) -{ - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); - - return tpm_pt->tpm_version; -} - -static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb) -{ - 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; -} - -/* - * 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. - * From /dev/tpm0 create /sys/class/tpm/tpm0/device/cancel - * before 4.0: /sys/class/misc/tpm0/device/cancel - */ -static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) -{ - int fd = -1; - char *dev; - char path[PATH_MAX]; - - if (tpm_pt->options->cancel_path) { - fd = qemu_open(tpm_pt->options->cancel_path, O_WRONLY); - if (fd < 0) { - error_report("tpm_passthrough: Could not open TPM cancel path: %s", - strerror(errno)); - } - return fd; - } - - dev = strrchr(tpm_pt->tpm_dev, '/'); - 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); - } - } - } - - if (fd < 0) { - error_report("tpm_passthrough: Could not guess TPM cancel path"); - } else { - tpm_pt->options->cancel_path = g_strdup(path); - } - - return fd; -} - -static int -tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) -{ - const char *value; - - value = qemu_opt_get(opts, "cancel-path"); - if (value) { - tpm_pt->options->cancel_path = g_strdup(value); - tpm_pt->options->has_cancel_path = true; - } - - value = qemu_opt_get(opts, "path"); - if (value) { - tpm_pt->options->has_path = true; - tpm_pt->options->path = g_strdup(value); - } - - tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE; - tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR); - if (tpm_pt->tpm_fd < 0) { - error_report("Cannot access TPM device using '%s': %s", - tpm_pt->tpm_dev, strerror(errno)); - return -1; - } - - if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) { - error_report("'%s' is not a TPM device.", - tpm_pt->tpm_dev); - return -1; - } - - tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt); - if (tpm_pt->cancel_fd < 0) { - return -1; - } - - return 0; -} - -static TPMBackend *tpm_passthrough_create(QemuOpts *opts) -{ - Object *obj = object_new(TYPE_TPM_PASSTHROUGH); - - if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) { - object_unref(obj); - return NULL; - } - - return TPM_BACKEND(obj); -} - -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; -} - -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; -} - -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 */ }, -}; - -static void tpm_passthrough_inst_init(Object *obj) -{ - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); - - tpm_pt->options = g_new0(TPMPassthroughOptions, 1); - tpm_pt->tpm_fd = -1; - tpm_pt->cancel_fd = -1; -} - -static void tpm_passthrough_inst_finalize(Object *obj) -{ - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); - - tpm_passthrough_cancel_cmd(TPM_BACKEND(obj)); - - if (tpm_pt->tpm_fd >= 0) { - qemu_close(tpm_pt->tpm_fd); - } - if (tpm_pt->cancel_fd >= 0) { - qemu_close(tpm_pt->cancel_fd); - } - qapi_free_TPMPassthroughOptions(tpm_pt->options); -} - -static void tpm_passthrough_class_init(ObjectClass *klass, void *data) -{ - TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); - - tbc->type = TPM_TYPE_PASSTHROUGH; - tbc->opts = tpm_passthrough_cmdline_opts; - tbc->desc = "Passthrough TPM backend driver"; - tbc->create = tpm_passthrough_create; - tbc->startup_tpm = tpm_passthrough_startup_tpm; - 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; - tbc->get_buffer_size = tpm_passthrough_get_buffer_size; - tbc->get_tpm_options = tpm_passthrough_get_tpm_options; - tbc->handle_request = tpm_passthrough_handle_request; -} - -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, -}; - -static void tpm_passthrough_register(void) -{ - type_register_static(&tpm_passthrough_info); -} - -type_init(tpm_passthrough_register) diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c index 6d9c1a3..72d7a3d 100644 --- a/hw/tpm/tpm_ppi.c +++ b/hw/tpm/tpm_ppi.c @@ -17,6 +17,7 @@ #include "cpu.h" #include "sysemu/memory_mapping.h" #include "migration/vmstate.h" +#include "hw/acpi/tpm.h" #include "tpm_ppi.h" #include "trace.h" diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h index d33ef27..6f773c2 100644 --- a/hw/tpm/tpm_ppi.h +++ b/hw/tpm/tpm_ppi.h @@ -12,7 +12,6 @@ #ifndef TPM_TPM_PPI_H #define TPM_TPM_PPI_H -#include "hw/acpi/tpm.h" #include "exec/address-spaces.h" typedef struct TPMPPI { diff --git a/hw/tpm/tpm_prop.h b/hw/tpm/tpm_prop.h new file mode 100644 index 0000000..85e1ae5 --- /dev/null +++ b/hw/tpm/tpm_prop.h @@ -0,0 +1,31 @@ +/* + * TPM utility functions + * + * Copyright (c) 2010 - 2015 IBM Corporation + * Authors: + * Stefan Berger <stefanb@us.ibm.com> + * + * 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/> + */ + +#ifndef HW_TPM_PROP_H +#define HW_TPM_PROP_H + +#include "sysemu/tpm_backend.h" +#include "hw/qdev-properties.h" + +#define DEFINE_PROP_TPMBE(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *) + +#endif /* HW_TPM_PROP_H */ diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c index ce65eb2..cb4dfd1 100644 --- a/hw/tpm/tpm_spapr.c +++ b/hw/tpm/tpm_spapr.c @@ -20,8 +20,8 @@ #include "migration/vmstate.h" #include "sysemu/tpm_backend.h" -#include "tpm_int.h" -#include "tpm_util.h" +#include "sysemu/tpm_util.h" +#include "tpm_prop.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h index 5554989..f6b5872 100644 --- a/hw/tpm/tpm_tis.h +++ b/hw/tpm/tpm_tis.h @@ -24,7 +24,6 @@ #ifndef TPM_TPM_TIS_H #define TPM_TPM_TIS_H -#include "qemu/osdep.h" #include "sysemu/tpm_backend.h" #include "tpm_ppi.h" diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c index 1af4bce..e700d82 100644 --- a/hw/tpm/tpm_tis_common.c +++ b/hw/tpm/tpm_tis_common.c @@ -33,8 +33,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "sysemu/tpm_backend.h" -#include "tpm_int.h" -#include "tpm_util.h" +#include "sysemu/tpm_util.h" #include "tpm_ppi.h" #include "trace.h" @@ -79,9 +78,7 @@ static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) */ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) { - if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { - tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); - } + tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); /* * rw_offset serves as length indicator for length of data; @@ -247,9 +244,7 @@ void tpm_tis_request_completed(TPMState *s, int ret) s->loc[locty].state = TPM_TIS_STATE_COMPLETION; s->rw_offset = 0; - if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { - tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); - } + tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { tpm_tis_abort(s); diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c index 30ba370..5faf623 100644 --- a/hw/tpm/tpm_tis_isa.c +++ b/hw/tpm/tpm_tis_isa.c @@ -26,7 +26,8 @@ #include "hw/isa/isa.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "tpm_util.h" +#include "hw/acpi/tpm.h" +#include "tpm_prop.h" #include "tpm_tis.h" typedef struct TPMStateISA { diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c index eced1fc..4a3bc70 100644 --- a/hw/tpm/tpm_tis_sysbus.c +++ b/hw/tpm/tpm_tis_sysbus.c @@ -25,7 +25,8 @@ #include "qemu/osdep.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "tpm_util.h" +#include "hw/acpi/tpm.h" +#include "tpm_prop.h" #include "hw/sysbus.h" #include "tpm_tis.h" diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c deleted file mode 100644 index c0a0f3d..0000000 --- a/hw/tpm/tpm_util.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * TPM utility functions - * - * Copyright (c) 2010 - 2015 IBM Corporation - * Authors: - * Stefan Berger <stefanb@us.ibm.com> - * - * 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/> - */ - -#include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "qapi/error.h" -#include "qapi/visitor.h" -#include "tpm_util.h" -#include "tpm_int.h" -#include "exec/memory.h" -#include "hw/qdev-properties.h" -#include "sysemu/tpm_backend.h" -#include "trace.h" - -/* tpm backend property */ - -static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque, - Error **errp) -{ - DeviceState *dev = DEVICE(obj); - TPMBackend **be = qdev_get_prop_ptr(dev, opaque); - char *p; - - p = g_strdup(*be ? (*be)->id : ""); - visit_type_str(v, name, &p, errp); - g_free(p); -} - -static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque, - Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Error *local_err = NULL; - Property *prop = opaque; - TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop); - char *str; - - if (dev->realized) { - qdev_prop_set_after_realize(dev, name, errp); - return; - } - - visit_type_str(v, name, &str, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - s = qemu_find_tpm_be(str); - if (s == NULL) { - error_setg(errp, "Property '%s.%s' can't find value '%s'", - object_get_typename(obj), prop->name, str); - } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) { - *be = s; /* weak reference, avoid cyclic ref */ - } - g_free(str); -} - -static void release_tpm(Object *obj, const char *name, void *opaque) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - TPMBackend **be = qdev_get_prop_ptr(dev, prop); - - if (*be) { - tpm_backend_reset(*be); - } -} - -const PropertyInfo qdev_prop_tpm = { - .name = "str", - .description = "ID of a tpm to use as a backend", - .get = get_tpm, - .set = set_tpm, - .release = release_tpm, -}; - -/* - * Write an error message in the given output buffer. - */ -void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len) -{ - if (out_len >= sizeof(struct tpm_resp_hdr)) { - tpm_cmd_set_tag(out, TPM_TAG_RSP_COMMAND); - tpm_cmd_set_size(out, sizeof(struct tpm_resp_hdr)); - tpm_cmd_set_error(out, TPM_FAIL); - } -} - -bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len) -{ - if (in_len >= sizeof(struct tpm_req_hdr)) { - return tpm_cmd_get_ordinal(in) == TPM_ORD_ContinueSelfTest; - } - - return false; -} - -/* - * Send request to a TPM device. We expect a response within one second. - */ -static int tpm_util_request(int fd, - const void *request, - size_t requestlen, - void *response, - size_t responselen) -{ - fd_set readfds; - int n; - struct timeval tv = { - .tv_sec = 1, - .tv_usec = 0, - }; - - n = write(fd, request, requestlen); - if (n < 0) { - return -errno; - } - if (n != requestlen) { - return -EFAULT; - } - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - - /* wait for a second */ - n = select(fd + 1, &readfds, NULL, NULL, &tv); - if (n != 1) { - return -errno; - } - - n = read(fd, response, responselen); - if (n < sizeof(struct tpm_resp_hdr)) { - return -EFAULT; - } - - /* check the header */ - if (tpm_cmd_get_size(response) != n) { - return -EMSGSIZE; - } - - return 0; -} - -/* - * A basic test of a TPM device. We expect a well formatted response header - * (error response is fine). - */ -static int tpm_util_test(int fd, - const void *request, - size_t requestlen, - uint16_t *return_tag) -{ - char buf[1024]; - ssize_t ret; - - ret = tpm_util_request(fd, request, requestlen, - buf, sizeof(buf)); - if (ret < 0) { - return ret; - } - - *return_tag = tpm_cmd_get_tag(buf); - - return 0; -} - -/* - * Probe for the TPM device in the back - * Returns 0 on success with the version of the probed TPM set, 1 on failure. - */ -int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version) -{ - /* - * Sending a TPM1.2 command to a TPM2 should return a TPM1.2 - * header (tag = 0xc4) and error code (TPM_BADTAG = 0x1e) - * - * Sending a TPM2 command to a TPM 2 will give a TPM 2 tag in the - * header. - * Sending a TPM2 command to a TPM 1.2 will give a TPM 1.2 tag - * in the header and an error code. - */ - const struct tpm_req_hdr test_req = { - .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), - .len = cpu_to_be32(sizeof(test_req)), - .ordinal = cpu_to_be32(TPM_ORD_GetTicks), - }; - - const struct tpm_req_hdr test_req_tpm2 = { - .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), - .len = cpu_to_be32(sizeof(test_req_tpm2)), - .ordinal = cpu_to_be32(TPM2_CC_ReadClock), - }; - uint16_t return_tag; - int ret; - - /* Send TPM 2 command */ - ret = tpm_util_test(tpm_fd, &test_req_tpm2, - sizeof(test_req_tpm2), &return_tag); - /* TPM 2 would respond with a tag of TPM2_ST_NO_SESSIONS */ - if (!ret && return_tag == TPM2_ST_NO_SESSIONS) { - *tpm_version = TPM_VERSION_2_0; - return 0; - } - - /* Send TPM 1.2 command */ - ret = tpm_util_test(tpm_fd, &test_req, - sizeof(test_req), &return_tag); - if (!ret && return_tag == TPM_TAG_RSP_COMMAND) { - *tpm_version = TPM_VERSION_1_2; - /* this is a TPM 1.2 */ - return 0; - } - - *tpm_version = TPM_VERSION_UNSPEC; - - return 1; -} - -int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, - size_t *buffersize) -{ - int ret; - - switch (tpm_version) { - case TPM_VERSION_1_2: { - const struct tpm_req_get_buffer_size { - struct tpm_req_hdr hdr; - uint32_t capability; - uint32_t len; - uint32_t subcap; - } QEMU_PACKED tpm_get_buffer_size = { - .hdr = { - .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), - .len = cpu_to_be32(sizeof(tpm_get_buffer_size)), - .ordinal = cpu_to_be32(TPM_ORD_GetCapability), - }, - .capability = cpu_to_be32(TPM_CAP_PROPERTY), - .len = cpu_to_be32(sizeof(uint32_t)), - .subcap = cpu_to_be32(TPM_CAP_PROP_INPUT_BUFFER), - }; - struct tpm_resp_get_buffer_size { - struct tpm_resp_hdr hdr; - uint32_t len; - uint32_t buffersize; - } QEMU_PACKED tpm_resp; - - ret = tpm_util_request(tpm_fd, &tpm_get_buffer_size, - sizeof(tpm_get_buffer_size), - &tpm_resp, sizeof(tpm_resp)); - if (ret < 0) { - return ret; - } - - if (be32_to_cpu(tpm_resp.hdr.len) != sizeof(tpm_resp) || - be32_to_cpu(tpm_resp.len) != sizeof(uint32_t)) { - trace_tpm_util_get_buffer_size_hdr_len( - be32_to_cpu(tpm_resp.hdr.len), - sizeof(tpm_resp)); - trace_tpm_util_get_buffer_size_len(be32_to_cpu(tpm_resp.len), - sizeof(uint32_t)); - error_report("tpm_util: Got unexpected response to " - "TPM_GetCapability; errcode: 0x%x", - be32_to_cpu(tpm_resp.hdr.errcode)); - return -EFAULT; - } - *buffersize = be32_to_cpu(tpm_resp.buffersize); - break; - } - case TPM_VERSION_2_0: { - const struct tpm2_req_get_buffer_size { - struct tpm_req_hdr hdr; - uint32_t capability; - uint32_t property; - uint32_t count; - } QEMU_PACKED tpm2_get_buffer_size = { - .hdr = { - .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), - .len = cpu_to_be32(sizeof(tpm2_get_buffer_size)), - .ordinal = cpu_to_be32(TPM2_CC_GetCapability), - }, - .capability = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES), - .property = cpu_to_be32(TPM2_PT_MAX_COMMAND_SIZE), - .count = cpu_to_be32(2), /* also get TPM2_PT_MAX_RESPONSE_SIZE */ - }; - struct tpm2_resp_get_buffer_size { - struct tpm_resp_hdr hdr; - uint8_t more; - uint32_t capability; - uint32_t count; - uint32_t property1; - uint32_t value1; - uint32_t property2; - uint32_t value2; - } QEMU_PACKED tpm2_resp; - - ret = tpm_util_request(tpm_fd, &tpm2_get_buffer_size, - sizeof(tpm2_get_buffer_size), - &tpm2_resp, sizeof(tpm2_resp)); - if (ret < 0) { - return ret; - } - - if (be32_to_cpu(tpm2_resp.hdr.len) != sizeof(tpm2_resp) || - be32_to_cpu(tpm2_resp.count) != 2) { - trace_tpm_util_get_buffer_size_hdr_len2( - be32_to_cpu(tpm2_resp.hdr.len), - sizeof(tpm2_resp)); - trace_tpm_util_get_buffer_size_len2( - be32_to_cpu(tpm2_resp.count), 2); - error_report("tpm_util: Got unexpected response to " - "TPM2_GetCapability; errcode: 0x%x", - be32_to_cpu(tpm2_resp.hdr.errcode)); - return -EFAULT; - } - *buffersize = MAX(be32_to_cpu(tpm2_resp.value1), - be32_to_cpu(tpm2_resp.value2)); - break; - } - case TPM_VERSION_UNSPEC: - return -EFAULT; - } - - trace_tpm_util_get_buffer_size(*buffersize); - - return 0; -} - -void tpm_sized_buffer_reset(TPMSizedBuffer *tsb) -{ - g_free(tsb->buffer); - tsb->buffer = NULL; - tsb->size = 0; -} - -void tpm_util_show_buffer(const unsigned char *buffer, - size_t buffer_size, const char *string) -{ - size_t len, i; - char *line_buffer, *p; - - len = MIN(tpm_cmd_get_size(buffer), buffer_size); - - /* - * allocate enough room for 3 chars per buffer entry plus a - * newline after every 16 chars and a final null terminator. - */ - line_buffer = g_malloc(len * 3 + (len / 16) + 1); - - for (i = 0, p = line_buffer; i < len; i++) { - if (i && !(i % 16)) { - p += sprintf(p, "\n"); - } - p += sprintf(p, "%.2X ", buffer[i]); - } - trace_tpm_util_show_buffer(string, len, line_buffer); - - g_free(line_buffer); -} diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h deleted file mode 100644 index 7889081..0000000 --- a/hw/tpm/tpm_util.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * TPM utility functions - * - * Copyright (c) 2010 - 2015 IBM Corporation - * Authors: - * Stefan Berger <stefanb@us.ibm.com> - * - * 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/> - */ - -#ifndef TPM_TPM_UTIL_H -#define TPM_TPM_UTIL_H - -#include "sysemu/tpm.h" -#include "qemu/bswap.h" - -void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len); - -bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len); - -int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version); - -static inline uint16_t tpm_cmd_get_tag(const void *b) -{ - return lduw_be_p(b); -} - -static inline void tpm_cmd_set_tag(void *b, uint16_t tag) -{ - stw_be_p(b, tag); -} - -static inline uint32_t tpm_cmd_get_size(const void *b) -{ - return ldl_be_p(b + 2); -} - -static inline void tpm_cmd_set_size(void *b, uint32_t size) -{ - stl_be_p(b + 2, size); -} - -static inline uint32_t tpm_cmd_get_ordinal(const void *b) -{ - return ldl_be_p(b + 6); -} - -static inline uint32_t tpm_cmd_get_errcode(const void *b) -{ - return ldl_be_p(b + 6); -} - -static inline void tpm_cmd_set_error(void *b, uint32_t error) -{ - stl_be_p(b + 6, error); -} - -int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, - size_t *buffersize); - -#define DEFINE_PROP_TPMBE(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *) - -typedef struct TPMSizedBuffer { - uint32_t size; - uint8_t *buffer; -} TPMSizedBuffer; - -void tpm_sized_buffer_reset(TPMSizedBuffer *tsb); - -void tpm_util_show_buffer(const unsigned char *buffer, - size_t buffer_size, const char *string); - -#endif /* TPM_TPM_UTIL_H */ diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events index 439e514..de9bf1e 100644 --- a/hw/tpm/trace-events +++ b/hw/tpm/trace-events @@ -4,38 +4,6 @@ tpm_crb_mmio_read(uint64_t addr, unsigned size, uint32_t val) "CRB read 0x%016" PRIx64 " len:%u val: 0x%" PRIx32 tpm_crb_mmio_write(uint64_t addr, unsigned size, uint32_t val) "CRB write 0x%016" PRIx64 " len:%u val: 0x%" PRIx32 -# tpm_passthrough.c -tpm_passthrough_handle_request(void *cmd) "processing command %p" -tpm_passthrough_reset(void) "reset" - -# tpm_util.c -tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu" -tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu" -tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu" -tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu" -tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu" -tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" - -# tpm_emulator.c -tpm_emulator_set_locality(uint8_t locty) "setting locality to %d" -tpm_emulator_handle_request(void) "processing TPM command" -tpm_emulator_probe_caps(uint64_t caps) "capabilities: 0x%"PRIx64 -tpm_emulator_set_buffer_size(uint32_t buffersize, uint32_t minsize, uint32_t maxsize) "buffer size: %u, min: %u, max: %u" -tpm_emulator_startup_tpm_resume(bool is_resume, size_t buffersize) "is_resume: %d, buffer size: %zu" -tpm_emulator_get_tpm_established_flag(uint8_t flag) "got established flag: %d" -tpm_emulator_cancel_cmd_not_supt(void) "Backend does not support CANCEL_TPM_CMD" -tpm_emulator_handle_device_opts_tpm12(void) "TPM Version 1.2" -tpm_emulator_handle_device_opts_tpm2(void) "TPM Version 2" -tpm_emulator_handle_device_opts_unspec(void) "TPM Version Unspecified" -tpm_emulator_handle_device_opts_startup_error(void) "Startup error" -tpm_emulator_get_state_blob(uint8_t type, uint32_t size, uint32_t flags) "got state blob type %d, %u bytes, flags 0x%08x" -tpm_emulator_set_state_blob(uint8_t type, uint32_t size, uint32_t flags) "set state blob type %d, %u bytes, flags 0x%08x" -tpm_emulator_set_state_blobs(void) "setting state blobs" -tpm_emulator_set_state_blobs_error(const char *msg) "error while setting state blobs: %s" -tpm_emulator_set_state_blobs_done(void) "Done setting state blobs" -tpm_emulator_pre_save(void) "" -tpm_emulator_inst_init(void) "" - # tpm_tis.c tpm_tis_raise_irq(uint32_t irqmask) "Raising IRQ for flag 0x%08x" tpm_tis_new_active_locality(uint8_t locty) "Active locality is now %d" @@ -56,7 +24,7 @@ tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u" # tpm_ppi.c tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu" -# hw/tpm/tpm_spapr.c +# tpm_spapr.c tpm_spapr_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" tpm_spapr_do_crq(uint8_t raw1, uint8_t raw2) "1st 2 bytes in CRQ: 0x%02x 0x%02x" tpm_spapr_do_crq_crq_result(void) "SPAPR_VTPM_INIT_CRQ_RESULT" |