Merge tpm 2017/12/15 v1

-----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJaM1MfAAoJEHWtZYAqC0IRAj8H/AgVHuAf5huzKZkju/OwQ4z0
 MxQwNFHbBgT5reRCjK3JAxTviOHUR7JTVLFFyLIbHQDX+VRDoxXWsuVPNdAgd8SF
 bA/ywmKlQcYJrdyf1Fole4JY+ZIndkgtUJnwuvC4LWmt/s7LYsNlwOfnARkvtpul
 0QH+mlJYv+EeEIjeJDNlgcqxFo4qr8HfuJi2/qC7IEXIHcTYNpdk6gh7auCUVvGl
 tojocW0Da0G0Ce1ncFIME9doWlBu0ZiU+b3mjjDf5OVtXiT6Xce3o9bNTWsboHia
 iuvyEaFU/wXbHkn+i/50/DIP6o+u9wJ4MmYp3uJKlpen0SZndZ+UFxcBY7ZrP4g=
 =s0pV
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/stefanberger/tags/pull-tpm-2017-12-15-1' into staging

Merge tpm 2017/12/15 v1

# gpg: Signature made Fri 15 Dec 2017 04:44:15 GMT
# gpg:                using RSA key 0x75AD65802A0B4211
# gpg: Good signature from "Stefan Berger <stefanb@linux.vnet.ibm.com>"
# 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-2017-12-15-1: (32 commits)
  tpm: tpm_passthrough: Fail startup if FE buffer size < BE buffer size
  tpm: tpm_emulator: get and set buffer size of device
  tpm: tpm_passthrough: Read the buffer size from the host device
  tpm: pull tpm_util_request() out of tpm_util_test()
  tpm: Move getting TPM buffer size to backends
  tpm: remove tpm_register_model()
  tpm-tis: use DEFINE_PROP_TPMBE
  qdev: add DEFINE_PROP_TPMBE
  tpm-tis: check that at most one TPM device exists
  tpm-tis: remove redundant 'tpm_tis:' in error messages
  tpm-emulator: add a FIXME comment about blocking cancel
  acpi: change TPM TIS data conditions
  tpm: add tpm_cmd_get_size() to tpm_util
  tpm: add TPM interface to lookup TPM version
  tpm: lookup the the TPM interface instead of TIS device
  tpm: rename qemu_find_tpm() -> qemu_find_tpm_be()
  tpm-tis: simplify header inclusion
  tpm-passthrough: workaround a possible race
  tpm-passthrough: simplify create()
  tpm-passthrough: make it safer to destroy after creation
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-12-17 15:27:41 +00:00
commit 411ad78115
14 changed files with 562 additions and 275 deletions

View File

@ -17,16 +17,25 @@
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/tpm.h"
#include "hw/tpm/tpm_int.h"
#include "qemu/thread.h"
#include "qemu/main-loop.h"
static void tpm_backend_request_completed_bh(void *opaque)
{
TPMBackend *s = TPM_BACKEND(opaque);
TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
tic->request_completed(s->tpmif);
}
static void tpm_backend_worker_thread(gpointer data, gpointer user_data)
{
TPMBackend *s = TPM_BACKEND(user_data);
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
assert(k->handle_request != NULL);
k->handle_request(s, (TPMBackendCmd *)data);
qemu_bh_schedule(s->bh);
}
static void tpm_backend_thread_end(TPMBackend *s)
@ -44,15 +53,22 @@ enum TpmType tpm_backend_get_type(TPMBackend *s)
return k->type;
}
int tpm_backend_init(TPMBackend *s, TPMState *state)
int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp)
{
s->tpm_state = state;
if (s->tpmif) {
error_setg(errp, "TPM backend '%s' is already initialized", s->id);
return -1;
}
s->tpmif = tpmif;
object_ref(OBJECT(tpmif));
s->had_startup_error = false;
return 0;
}
int tpm_backend_startup_tpm(TPMBackend *s)
int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize)
{
int res = 0;
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
@ -63,7 +79,7 @@ int tpm_backend_startup_tpm(TPMBackend *s)
s->thread_pool = g_thread_pool_new(tpm_backend_worker_thread, s, 1, TRUE,
NULL);
res = k->startup_tpm ? k->startup_tpm(s) : 0;
res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0;
s->had_startup_error = (res != 0);
@ -97,8 +113,6 @@ void tpm_backend_cancel_cmd(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
assert(k->cancel_cmd);
k->cancel_cmd(s);
}
@ -122,80 +136,44 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
assert(k->get_tpm_version);
return k->get_tpm_version(s);
}
size_t tpm_backend_get_buffer_size(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
return k->get_buffer_size(s);
}
TPMInfo *tpm_backend_query_tpm(TPMBackend *s)
{
TPMInfo *info = g_new0(TPMInfo, 1);
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
info->id = g_strdup(s->id);
info->model = s->fe_model;
if (k->get_tpm_options) {
info->options = k->get_tpm_options(s);
}
info->model = tic->model;
info->options = k->get_tpm_options(s);
return info;
}
static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
{
TPMBackend *s = TPM_BACKEND(obj);
return s->opened;
}
void tpm_backend_open(TPMBackend *s, Error **errp)
{
object_property_set_bool(OBJECT(s), true, "opened", errp);
}
static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
{
TPMBackend *s = TPM_BACKEND(obj);
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
Error *local_err = NULL;
if (value == s->opened) {
return;
}
if (!value && s->opened) {
error_setg(errp, QERR_PERMISSION_DENIED);
return;
}
if (k->opened) {
k->opened(s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
s->opened = true;
}
static void tpm_backend_instance_init(Object *obj)
{
TPMBackend *s = TPM_BACKEND(obj);
object_property_add_bool(obj, "opened",
tpm_backend_prop_get_opened,
tpm_backend_prop_set_opened,
NULL);
s->fe_model = -1;
s->bh = qemu_bh_new(tpm_backend_request_completed_bh, s);
}
static void tpm_backend_instance_finalize(Object *obj)
{
TPMBackend *s = TPM_BACKEND(obj);
object_unref(OBJECT(s->tpmif));
g_free(s->id);
tpm_backend_thread_end(s);
qemu_bh_delete(s->bh);
}
static const TypeInfo tpm_backend_info = {

View File

@ -21,6 +21,7 @@
#include "net/hub.h"
#include "qapi/visitor.h"
#include "chardev/char-fe.h"
#include "sysemu/tpm_backend.h"
#include "sysemu/iothread.h"
static void get_pointer(Object *obj, Visitor *v, Property *prop,
@ -236,6 +237,69 @@ const PropertyInfo qdev_prop_chr = {
.release = release_chr,
};
/* --- character device --- */
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,
};
/* --- netdev device --- */
static void get_netdev(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)

View File

@ -208,7 +208,7 @@ static void acpi_get_misc_info(AcpiMiscInfo *info)
}
info->has_hpet = hpet_find();
info->tpm_version = tpm_get_version();
info->tpm_version = tpm_get_version(tpm_find());
info->pvpanic_port = pvpanic_port();
info->applesmc_io_base = applesmc_port();
}
@ -2038,7 +2038,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
}
if (misc->tpm_version != TPM_VERSION_UNSPEC) {
if (TPM_IS_TIS(tpm_find())) {
aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
}
@ -2204,7 +2204,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
/* Scan all PCI buses. Generate tables to support hotplug. */
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
if (misc->tpm_version != TPM_VERSION_UNSPEC) {
if (TPM_IS_TIS(tpm_find())) {
dev = aml_device("ISA.TPM");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
@ -2281,8 +2281,12 @@ build_tpm2(GArray *table_data, BIOSLinker *linker)
tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);
tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT);
tpm2_ptr->control_area_address = cpu_to_le64(0);
tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
if (TPM_IS_TIS(tpm_find())) {
tpm2_ptr->control_area_address = cpu_to_le64(0);
tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
} else {
g_warn_if_reached();
}
build_header(linker, table_data,
(void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL);

View File

@ -186,7 +186,6 @@ static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number,
static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd)
{
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpm_state);
Error *err = NULL;
DPRINTF("processing TPM command");
@ -201,7 +200,6 @@ static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd)
goto error;
}
tic->request_completed(TPM_IF(tb->tpm_state));
return;
error:
@ -234,13 +232,14 @@ static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
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_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_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE;
tpm = "2";
break;
case TPM_VERSION_UNSPEC:
@ -257,12 +256,76 @@ static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
return 0;
}
static int tpm_emulator_startup_tpm(TPMBackend *tb)
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", 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",
psbs.u.resp.tpm_result);
return -1;
}
if (actual_size) {
*actual_size = be32_to_cpu(psbs.u.resp.buffersize);
}
DPRINTF("buffer size: %u, min: %u, max: %u\n",
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(TPMBackend *tb, size_t buffersize)
{
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
ptm_init init;
ptm_res res;
if (buffersize != 0 &&
tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) {
goto err_exit;
}
DPRINTF("%s", __func__);
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init),
sizeof(init)) < 0) {
@ -340,6 +403,7 @@ static void tpm_emulator_cancel_cmd(TPMBackend *tb)
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",
@ -357,6 +421,17 @@ static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *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;
@ -465,22 +540,16 @@ err:
return -1;
}
static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)
static TPMBackend *tpm_emulator_create(QemuOpts *opts)
{
TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
tb->id = g_strdup(id);
if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
goto err_exit;
object_unref(OBJECT(tb));
return NULL;
}
return tb;
err_exit:
object_unref(OBJECT(tb));
return NULL;
}
static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
@ -563,6 +632,7 @@ static void tpm_emulator_class_init(ObjectClass *klass, void *data)
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;

View File

@ -13,28 +13,8 @@
#define TPM_TPM_INT_H
#include "qemu/osdep.h"
#include "qom/object.h"
#define TYPE_TPM_IF "tpm-if"
#define TPM_IF_CLASS(klass) \
OBJECT_CLASS_CHECK(TPMIfClass, (klass), TYPE_TPM_IF)
#define TPM_IF_GET_CLASS(obj) \
OBJECT_GET_CLASS(TPMIfClass, (obj), TYPE_TPM_IF)
#define TPM_IF(obj) \
INTERFACE_CHECK(TPMIf, (obj), TYPE_TPM_IF)
typedef struct TPMIf {
Object parent_obj;
} TPMIf;
typedef struct TPMIfClass {
InterfaceClass parent_class;
/* run in thread pool by backend */
void (*request_completed)(TPMIf *obj);
} TPMIfClass;
#define TPM_STANDARD_CMDLINE_OPTS \
#define TPM_STANDARD_CMDLINE_OPTS \
{ \
.name = "type", \
.type = QEMU_OPT_STRING, \
@ -65,11 +45,20 @@ struct tpm_resp_hdr {
#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
#endif /* TPM_TPM_INT_H */

View File

@ -169,6 +169,28 @@ struct ptm_getconfig {
#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;
@ -179,6 +201,7 @@ 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)
@ -194,6 +217,7 @@ typedef struct ptm_getconfig ptm_getconfig;
#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),
@ -212,6 +236,7 @@ enum {
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),
};
/*
@ -240,7 +265,8 @@ enum {
CMD_SET_STATEBLOB,
CMD_STOP,
CMD_GET_CONFIG,
CMD_SET_DATAFD
CMD_SET_DATAFD,
CMD_SET_BUFFERSIZE,
};
#endif /* _TPM_IOCTL_H */

View File

@ -57,6 +57,7 @@ struct TPMPassthruState {
int cancel_fd;
TPMVersion tpm_version;
size_t tpm_buffersize;
};
typedef struct TPMPassthruState TPMPassthruState;
@ -89,6 +90,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
bool is_selftest;
const struct tpm_resp_hdr *hdr;
/* FIXME: protect shared variables or use other sync mechanism */
tpm_pt->tpm_op_canceled = false;
tpm_pt->tpm_executing = true;
*selftest_done = false;
@ -139,14 +141,11 @@ err_exit:
static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *cmd)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpm_state);
DPRINTF("tpm_passthrough: processing command %p\n", cmd);
tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len,
cmd->out, cmd->out_len, &cmd->selftest_done);
tic->request_completed(TPM_IF(tb->tpm_state));
}
static void tpm_passthrough_reset(TPMBackend *tb)
@ -181,12 +180,11 @@ static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
*/
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 {
tpm_pt->tpm_op_canceled = true;
}
} else {
error_report("Cannot cancel TPM command due to missing "
@ -202,6 +200,19 @@ static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *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
@ -229,9 +240,7 @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel",
dev) < sizeof(path)) {
fd = qemu_open(path, O_WRONLY);
if (fd >= 0) {
tpm_pt->options->cancel_path = g_strdup(path);
} else {
if (fd < 0) {
error_report("tpm_passthrough: Could not open TPM cancel "
"path %s : %s", path, strerror(errno));
}
@ -244,9 +253,9 @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
return fd;
}
static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
static int
tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
const char *value;
value = qemu_opt_get(opts, "cancel-path");
@ -266,52 +275,47 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
if (tpm_pt->tpm_fd < 0) {
error_report("Cannot access TPM device using '%s': %s",
tpm_pt->tpm_dev, strerror(errno));
goto err_free_parameters;
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);
goto err_close_tpmdev;
}
return 0;
err_close_tpmdev:
qemu_close(tpm_pt->tpm_fd);
tpm_pt->tpm_fd = -1;
err_free_parameters:
qapi_free_TPMPassthroughOptions(tpm_pt->options);
tpm_pt->options = NULL;
tpm_pt->tpm_dev = NULL;
return 1;
}
static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
{
Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
TPMBackend *tb = TPM_BACKEND(obj);
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
tb->id = g_strdup(id);
if (tpm_passthrough_handle_device_opts(opts, tb)) {
goto err_exit;
return -1;
}
tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt);
if (tpm_pt->cancel_fd < 0) {
goto err_exit;
return -1;
}
return tb;
return 0;
}
err_exit:
object_unref(obj);
static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
{
Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
return NULL;
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)
@ -355,8 +359,12 @@ static void tpm_passthrough_inst_finalize(Object *obj)
tpm_passthrough_cancel_cmd(TPM_BACKEND(obj));
qemu_close(tpm_pt->tpm_fd);
qemu_close(tpm_pt->cancel_fd);
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);
}
@ -368,12 +376,14 @@ static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
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;
}

View File

@ -24,17 +24,13 @@
#include "qemu/osdep.h"
#include "hw/isa/isa.h"
#include "qapi/error.h"
#include "hw/acpi/tpm.h"
#include "hw/pci/pci_ids.h"
#include "sysemu/tpm_backend.h"
#include "tpm_int.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/pci/pci_ids.h"
#include "qapi/error.h"
#include "qemu-common.h"
#include "qemu/main-loop.h"
#include "hw/acpi/tpm.h"
#include "tpm_util.h"
#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */
#define TPM_TIS_LOCALITY_SHIFT 12
@ -72,11 +68,10 @@ typedef struct TPMLocality {
TPMSizedBuffer r_buffer;
} TPMLocality;
struct TPMState {
typedef struct TPMState {
ISADevice busdev;
MemoryRegion mmio;
QEMUBH *bh;
uint32_t offset;
uint8_t buf[TPM_TIS_BUFFER_MAX];
@ -89,13 +84,13 @@ struct TPMState {
qemu_irq irq;
uint32_t irq_num;
uint8_t locty_number;
TPMBackendCmd cmd;
char *backend;
TPMBackend *be_driver;
TPMVersion be_tpm_version;
};
size_t be_buffer_size;
} TPMState;
#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
@ -222,7 +217,7 @@ static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
{
return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
return tpm_cmd_get_size(sb->buffer);
}
static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
@ -411,10 +406,20 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
tpm_tis_abort(s, locty);
}
static void tpm_tis_receive_bh(void *opaque)
/*
* Callback from the TPM to indicate that the response was received.
*/
static void tpm_tis_request_completed(TPMIf *ti)
{
TPMState *s = opaque;
TPMState *s = TPM(ti);
uint8_t locty = s->cmd.locty;
uint8_t l;
if (s->cmd.selftest_done) {
for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
s->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE;
}
}
tpm_tis_sts_set(&s->loc[locty],
TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
@ -432,23 +437,6 @@ static void tpm_tis_receive_bh(void *opaque)
TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
}
static void tpm_tis_request_completed(TPMIf *ti)
{
TPMState *s = TPM(ti);
bool is_selftest_done = s->cmd.selftest_done;
uint8_t locty = s->cmd.locty;
uint8_t l;
if (is_selftest_done) {
for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
s->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE;
}
}
qemu_bh_schedule(s->bh);
}
/*
* Read a byte of response data
*/
@ -986,15 +974,14 @@ static const MemoryRegionOps tpm_tis_memory_ops = {
},
};
static int tpm_tis_do_startup_tpm(TPMState *s)
static int tpm_tis_do_startup_tpm(TPMState *s, uint32_t buffersize)
{
return tpm_backend_startup_tpm(s->be_driver);
return tpm_backend_startup_tpm(s->be_driver, buffersize);
}
static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb)
static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb,
size_t wanted_size)
{
size_t wanted_size = 4096; /* Linux tpm.c buffer size */
if (sb->size != wanted_size) {
sb->buffer = g_realloc(sb->buffer, wanted_size);
sb->size = wanted_size;
@ -1004,9 +991,9 @@ static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb)
/*
* Get the TPMVersion of the backend device being used
*/
TPMVersion tpm_tis_get_tpm_version(Object *obj)
static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti)
{
TPMState *s = TPM(obj);
TPMState *s = TPM(ti);
if (tpm_backend_had_startup_error(s->be_driver)) {
return TPM_VERSION_UNSPEC;
@ -1025,6 +1012,7 @@ static void tpm_tis_reset(DeviceState *dev)
int c;
s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
s->be_buffer_size = tpm_backend_get_buffer_size(s->be_driver);
tpm_backend_reset(s->be_driver);
@ -1051,12 +1039,12 @@ static void tpm_tis_reset(DeviceState *dev)
s->loc[c].state = TPM_TIS_STATE_IDLE;
s->loc[c].w_offset = 0;
tpm_tis_realloc_buffer(&s->loc[c].w_buffer);
tpm_tis_realloc_buffer(&s->loc[c].w_buffer, s->be_buffer_size);
s->loc[c].r_offset = 0;
tpm_tis_realloc_buffer(&s->loc[c].r_buffer);
tpm_tis_realloc_buffer(&s->loc[c].r_buffer, s->be_buffer_size);
}
tpm_tis_do_startup_tpm(s);
tpm_tis_do_startup_tpm(s, 0);
}
static const VMStateDescription vmstate_tpm_tis = {
@ -1066,7 +1054,7 @@ static const VMStateDescription vmstate_tpm_tis = {
static Property tpm_tis_properties[] = {
DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ),
DEFINE_PROP_STRING("tpmdev", TPMState, backend),
DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver),
DEFINE_PROP_END_OF_LIST(),
};
@ -1074,29 +1062,21 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
{
TPMState *s = TPM(dev);
s->be_driver = qemu_find_tpm(s->backend);
if (!tpm_find()) {
error_setg(errp, "at most one TPM device is permitted");
return;
}
if (!s->be_driver) {
error_setg(errp, "tpm_tis: backend driver with id %s could not be "
"found", s->backend);
error_setg(errp, "'tpmdev' property is required");
return;
}
s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
if (tpm_backend_init(s->be_driver, s)) {
error_setg(errp, "tpm_tis: backend driver with id %s could not be "
"initialized", s->backend);
return;
}
if (s->irq_num > 15) {
error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
"of 0 to 15", s->irq_num);
error_setg(errp, "IRQ %d is outside valid range of 0 to 15",
s->irq_num);
return;
}
s->bh = qemu_bh_new(tpm_tis_receive_bh, s);
isa_init_irq(&s->busdev, &s->irq, s->irq_num);
memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
@ -1121,6 +1101,8 @@ static void tpm_tis_class_init(ObjectClass *klass, void *data)
dc->props = tpm_tis_properties;
dc->reset = tpm_tis_reset;
dc->vmsd = &vmstate_tpm_tis;
tc->model = TPM_MODEL_TPM_TIS;
tc->get_version = tpm_tis_get_tpm_version;
tc->request_completed = tpm_tis_request_completed;
}
@ -1139,7 +1121,6 @@ static const TypeInfo tpm_tis_info = {
static void tpm_tis_register(void)
{
type_register_static(&tpm_tis_info);
tpm_register_model(TPM_MODEL_TPM_TIS);
}
type_init(tpm_tis_register)

View File

@ -20,10 +20,19 @@
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "tpm_util.h"
#include "tpm_int.h"
#include "exec/memory.h"
#define DEBUG_TPM 0
#define DPRINTF(fmt, ...) do { \
if (DEBUG_TPM) { \
fprintf(stderr, "tpm-util:"fmt"\n", ## __VA_ARGS__); \
} \
} while (0)
/*
* Write an error message in the given output buffer.
*/
@ -50,13 +59,13 @@ bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
}
/*
* A basic test of a TPM device. We expect a well formatted response header
* (error response is fine) within one second.
* Send request to a TPM device. We expect a response within one second.
*/
static int tpm_util_test(int fd,
unsigned char *request,
size_t requestlen,
uint16_t *return_tag)
static int tpm_util_request(int fd,
unsigned char *request,
size_t requestlen,
unsigned char *response,
size_t responselen)
{
struct tpm_resp_hdr *resp;
fd_set readfds;
@ -65,7 +74,6 @@ static int tpm_util_test(int fd,
.tv_sec = 1,
.tv_usec = 0,
};
unsigned char buf[1024];
n = write(fd, request, requestlen);
if (n < 0) {
@ -84,17 +92,40 @@ static int tpm_util_test(int fd,
return -errno;
}
n = read(fd, &buf, sizeof(buf));
n = read(fd, response, responselen);
if (n < sizeof(struct tpm_resp_hdr)) {
return -EFAULT;
}
resp = (struct tpm_resp_hdr *)buf;
resp = (struct tpm_resp_hdr *)response;
/* check the header */
if (be32_to_cpu(resp->len) != 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,
unsigned char *request,
size_t requestlen,
uint16_t *return_tag)
{
struct tpm_resp_hdr *resp;
unsigned char buf[1024];
ssize_t ret;
ret = tpm_util_request(fd, request, requestlen,
buf, sizeof(buf));
if (ret < 0) {
return ret;
}
resp = (struct tpm_resp_hdr *)buf;
*return_tag = be16_to_cpu(resp->tag);
return 0;
@ -151,3 +182,109 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
return 1;
}
int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
size_t *buffersize)
{
unsigned char buf[1024];
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 = (struct tpm_resp_get_buffer_size *)buf;
ret = tpm_util_request(tpm_fd, (unsigned char *)&tpm_get_buffer_size,
sizeof(tpm_get_buffer_size), buf, sizeof(buf));
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)) {
DPRINTF("tpm_resp->hdr.len = %u, expected = %zu\n",
be32_to_cpu(tpm_resp->hdr.len), sizeof(*tpm_resp));
DPRINTF("tpm_resp->len = %u, expected = %zu\n",
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 = (struct tpm2_resp_get_buffer_size *)buf;
ret = tpm_util_request(tpm_fd, (unsigned char *)&tpm2_get_buffer_size,
sizeof(tpm2_get_buffer_size), buf, sizeof(buf));
if (ret < 0) {
return ret;
}
if (be32_to_cpu(tpm2_resp->hdr.len) != sizeof(*tpm2_resp) ||
be32_to_cpu(tpm2_resp->count) != 2) {
DPRINTF("tpm2_resp->hdr.len = %u, expected = %zu\n",
be32_to_cpu(tpm2_resp->hdr.len), sizeof(*tpm2_resp));
DPRINTF("tpm2_resp->len = %u, expected = %u\n",
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;
}
DPRINTF("buffersize of device: %zu\n", *buffersize);
return 0;
}

View File

@ -22,7 +22,8 @@
#ifndef TPM_TPM_UTIL_H
#define TPM_TPM_UTIL_H
#include "sysemu/tpm_backend.h"
#include "sysemu/tpm.h"
#include "qemu/bswap.h"
void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len);
@ -30,4 +31,12 @@ 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 uint32_t tpm_cmd_get_size(const void *b)
{
return be32_to_cpu(*(const uint32_t *)(b + 2));
}
int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
size_t *buffersize);
#endif /* TPM_TPM_UTIL_H */

View File

@ -17,6 +17,7 @@ extern const PropertyInfo qdev_prop_int64;
extern const PropertyInfo qdev_prop_size;
extern const PropertyInfo qdev_prop_string;
extern const PropertyInfo qdev_prop_chr;
extern const PropertyInfo qdev_prop_tpm;
extern const PropertyInfo qdev_prop_ptr;
extern const PropertyInfo qdev_prop_macaddr;
extern const PropertyInfo qdev_prop_on_off_auto;
@ -186,6 +187,8 @@ extern const PropertyInfo qdev_prop_link;
#define DEFINE_PROP_CHR(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharBackend)
#define DEFINE_PROP_TPMBE(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *)
#define DEFINE_PROP_STRING(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
#define DEFINE_PROP_NETDEV(_n, _s, _f) \

View File

@ -12,35 +12,59 @@
#ifndef QEMU_TPM_H
#define QEMU_TPM_H
#include "qemu/option.h"
#include "qom/object.h"
typedef struct TPMState TPMState;
#include "qapi-types.h"
int tpm_config_parse(QemuOptsList *opts_list, const char *optarg);
int tpm_init(void);
void tpm_cleanup(void);
typedef enum TPMVersion {
typedef enum TPMVersion {
TPM_VERSION_UNSPEC = 0,
TPM_VERSION_1_2 = 1,
TPM_VERSION_2_0 = 2,
} TPMVersion;
TPMVersion tpm_tis_get_tpm_version(Object *obj);
#define TYPE_TPM_IF "tpm-if"
#define TPM_IF_CLASS(klass) \
OBJECT_CLASS_CHECK(TPMIfClass, (klass), TYPE_TPM_IF)
#define TPM_IF_GET_CLASS(obj) \
OBJECT_GET_CLASS(TPMIfClass, (obj), TYPE_TPM_IF)
#define TPM_IF(obj) \
INTERFACE_CHECK(TPMIf, (obj), TYPE_TPM_IF)
typedef struct TPMIf {
Object parent_obj;
} TPMIf;
typedef struct TPMIfClass {
InterfaceClass parent_class;
enum TpmModel model;
void (*request_completed)(TPMIf *obj);
enum TPMVersion (*get_version)(TPMIf *obj);
} TPMIfClass;
#define TYPE_TPM_TIS "tpm-tis"
static inline TPMVersion tpm_get_version(void)
{
#ifdef CONFIG_TPM
Object *obj = object_resolve_path_type("", TYPE_TPM_TIS, NULL);
#define TPM_IS_TIS(chr) \
object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS)
if (obj) {
return tpm_tis_get_tpm_version(obj);
/* returns NULL unless there is exactly one TPM device */
static inline TPMIf *tpm_find(void)
{
Object *obj = object_resolve_path_type("", TYPE_TPM_IF, NULL);
return TPM_IF(obj);
}
static inline TPMVersion tpm_get_version(TPMIf *ti)
{
if (!ti) {
return TPM_VERSION_UNSPEC;
}
#endif
return TPM_VERSION_UNSPEC;
return TPM_IF_GET_CLASS(ti)->get_version(ti);
}
#endif /* QEMU_TPM_H */

View File

@ -43,14 +43,14 @@ struct TPMBackend {
Object parent;
/*< protected >*/
TPMIf *tpmif;
bool opened;
TPMState *tpm_state;
GThreadPool *thread_pool;
bool had_startup_error;
QEMUBH *bh;
/* <public> */
char *id;
enum TpmModel fe_model;
QLIST_ENTRY(TPMBackend) list;
};
@ -63,24 +63,27 @@ struct TPMBackendClass {
/* get a descriptive text of the backend to display to the user */
const char *desc;
TPMBackend *(*create)(QemuOpts *opts, const char *id);
TPMBackend *(*create)(QemuOpts *opts);
/* start up the TPM on the backend */
int (*startup_tpm)(TPMBackend *t);
/* start up the TPM on the backend - optional */
int (*startup_tpm)(TPMBackend *t, size_t buffersize);
/* optional */
void (*reset)(TPMBackend *t);
void (*cancel_cmd)(TPMBackend *t);
/* optional */
bool (*get_tpm_established_flag)(TPMBackend *t);
/* optional */
int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty);
TPMVersion (*get_tpm_version)(TPMBackend *t);
TpmTypeOptions *(*get_tpm_options)(TPMBackend *t);
size_t (*get_buffer_size)(TPMBackend *t);
void (*opened)(TPMBackend *s, Error **errp);
TpmTypeOptions *(*get_tpm_options)(TPMBackend *t);
void (*handle_request)(TPMBackend *s, TPMBackendCmd *cmd);
};
@ -96,22 +99,25 @@ enum TpmType tpm_backend_get_type(TPMBackend *s);
/**
* tpm_backend_init:
* @s: the backend to initialized
* @state: TPMState
* @tpmif: TPM interface
* @datacb: callback for sending data to frontend
* @errp: a pointer to return the #Error object if an error occurs.
*
* Initialize the backend with the given variables.
*
* Returns 0 on success.
*/
int tpm_backend_init(TPMBackend *s, TPMState *state);
int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp);
/**
* tpm_backend_startup_tpm:
* @s: the backend whose TPM support is to be started
* @buffersize: the buffer size the TPM is supposed to use,
* 0 to leave it as-is
*
* Returns 0 on success.
*/
int tpm_backend_startup_tpm(TPMBackend *s);
int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize);
/**
* tpm_backend_had_startup_error:
@ -170,16 +176,6 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
*/
int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty);
/**
* tpm_backend_open:
* @s: the backend to open
* @errp: a pointer to return the #Error object if an error occurs.
*
* This function will open the backend if it is not already open. Calling this
* function on an already opened backend will not result in an error.
*/
void tpm_backend_open(TPMBackend *s, Error **errp);
/**
* tpm_backend_get_tpm_version:
* @s: the backend to call into
@ -190,6 +186,16 @@ void tpm_backend_open(TPMBackend *s, Error **errp);
*/
TPMVersion tpm_backend_get_tpm_version(TPMBackend *s);
/**
* tpm_backend_get_buffer_size:
* @s: the backend to call into
*
* Get the TPM's buffer size.
*
* Returns buffer size.
*/
size_t tpm_backend_get_buffer_size(TPMBackend *s);
/**
* tpm_backend_query_tpm:
* @s: the backend
@ -200,8 +206,6 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s);
*/
TPMInfo *tpm_backend_query_tpm(TPMBackend *s);
TPMBackend *qemu_find_tpm(const char *id);
void tpm_register_model(enum TpmModel model);
TPMBackend *qemu_find_tpm_be(const char *id);
#endif

34
tpm.c
View File

@ -23,13 +23,6 @@
static QLIST_HEAD(, TPMBackend) tpm_backends =
QLIST_HEAD_INITIALIZER(tpm_backends);
static bool tpm_models[TPM_MODEL__MAX];
void tpm_register_model(enum TpmModel model)
{
tpm_models[model] = true;
}
static const TPMBackendClass *
tpm_be_find_by_type(enum TpmType type)
{
@ -69,7 +62,7 @@ static void tpm_display_backend_drivers(void)
/*
* Find the TPM with the given Id
*/
TPMBackend *qemu_find_tpm(const char *id)
TPMBackend *qemu_find_tpm_be(const char *id)
{
TPMBackend *drv;
@ -127,17 +120,12 @@ static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp)
return 1;
}
drv = be->create(opts, id);
drv = be->create(opts);
if (!drv) {
return 1;
}
tpm_backend_open(drv, &local_err);
if (local_err) {
error_report_err(local_err);
return 1;
}
drv->id = g_strdup(id);
QLIST_INSERT_HEAD(&tpm_backends, drv, list);
return 0;
@ -200,9 +188,10 @@ TPMInfoList *qmp_query_tpm(Error **errp)
TPMInfoList *info, *head = NULL, *cur_item = NULL;
QLIST_FOREACH(drv, &tpm_backends, list) {
if (!tpm_models[drv->fe_model]) {
if (!drv->tpmif) {
continue;
}
info = g_new0(TPMInfoList, 1);
info->value = tpm_backend_query_tpm(drv);
@ -240,18 +229,16 @@ TpmTypeList *qmp_query_tpm_types(Error **errp)
return head;
}
TpmModelList *qmp_query_tpm_models(Error **errp)
{
unsigned int i = 0;
TpmModelList *head = NULL, *prev = NULL, *cur_item;
GSList *e, *l = object_class_get_list(TYPE_TPM_IF, false);
for (e = l; e; e = e->next) {
TPMIfClass *c = TPM_IF_CLASS(e->data);
for (i = 0; i < TPM_MODEL__MAX; i++) {
if (!tpm_models[i]) {
continue;
}
cur_item = g_new0(TpmModelList, 1);
cur_item->value = i;
cur_item->value = c->model;
if (prev) {
prev->next = cur_item;
@ -261,6 +248,7 @@ TpmModelList *qmp_query_tpm_models(Error **errp)
}
prev = cur_item;
}
g_slist_free(l);
return head;
}