* [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM
@ 2015-05-26 21:33 Stefan Berger
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 1/6] Provide support for the CUSE TPM Stefan Berger
` (6 more replies)
0 siblings, 7 replies; 25+ messages in thread
From: Stefan Berger @ 2015-05-26 21:33 UTC (permalink / raw)
To: mst, qemu-devel, imammedo; +Cc: quan.xu, Stefan Berger
The following series of patches extends TPM support with an
external TPM that offers a Linux CUSE (character device in userspace)
interface. This TPM lets each VM access its own private vTPM.
The CUSE TPM supports suspend/resume and migration. Much
out-of-band functionality necessary to control the CUSE TPM is
implemented using ioctl's.
The series extends the TPM support so far that most functionality of
TPM support on a physical platform is now available to each x86 VM,
this includes the Physical Presence Interface support that has
its counter-part in the SeaBIOS and is implemented using ACPI.
Stefan Berger (6):
Provide support for the CUSE TPM
Introduce RAM location in vendor specific area in TIS
Support Physical Presence Interface Spec
Introduce condition to notifiy waiters of completed command
Introduce condition in TPM backend for notification
Add support for VM suspend/resume for TPM TIS
hmp.c | 6 +
hw/i386/ssdt-tpm-common.dsl | 182 ++++++++++++++
hw/i386/ssdt-tpm.dsl | 1 +
hw/i386/ssdt-tpm.hex.generated | 540 +++++++++++++++++++++++++++++++++++++++-
hw/i386/ssdt-tpm2.dsl | 1 +
hw/i386/ssdt-tpm2.hex.generated | 516 +++++++++++++++++++++++++++++++++++++-
hw/tpm/tpm_int.h | 4 +
hw/tpm/tpm_ioctl.h | 178 +++++++++++++
hw/tpm/tpm_passthrough.c | 423 ++++++++++++++++++++++++++++++-
hw/tpm/tpm_tis.c | 180 +++++++++++++-
hw/tpm/tpm_tis.h | 4 +
hw/tpm/tpm_util.c | 206 +++++++++++++++
hw/tpm/tpm_util.h | 7 +
include/hw/acpi/tpm.h | 19 ++
include/sysemu/tpm_backend.h | 12 +
qapi-schema.json | 17 +-
qemu-options.hx | 21 +-
qmp-commands.hx | 2 +-
tpm.c | 11 +-
19 files changed, 2298 insertions(+), 32 deletions(-)
create mode 100644 hw/tpm/tpm_ioctl.h
--
1.9.3
^ permalink raw reply [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH v3 1/6] Provide support for the CUSE TPM
2015-05-26 21:33 [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Stefan Berger
@ 2015-05-26 21:33 ` Stefan Berger
2015-05-26 23:05 ` Eric Blake
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 2/6] Introduce RAM location in vendor specific area in TIS Stefan Berger
` (5 subsequent siblings)
6 siblings, 1 reply; 25+ messages in thread
From: Stefan Berger @ 2015-05-26 21:33 UTC (permalink / raw)
To: mst, qemu-devel, imammedo; +Cc: quan.xu, Stefan Berger
Rather than integrating TPM functionality into QEMU directly
using the TPM emulation of libtpms, we now integrate an external
emulated TPM device. This device is expected to implement a Linux
CUSE interface (CUSE = character device in userspace).
QEMU talks to the CUSE TPM using much functionality of the
passthrough driver. For example, the TPM commands and responses
are sent to the CUSE TPM using the read()/write() interface.
However, some out-of-band control needs to be done using the CUSE
TPM's ioctl's. The CUSE TPM currently defines and implements 14
different ioctls for controlling certain life-cycle aspects of
the emulated TPM. The ioctls can be regarded as a replacement for
direct function calls to a TPM emulator if the TPM were to be
directly integrated into QEMU.
One of the ioctl's allows to get a bitmask of supported capabilities.
Each returned bit indicates which capabilties have been implemented.
An include file defining the various ioctls is added to QEMU.
The CUSE TPM and associated tools can be found here:
https://github.com/stefanberger/swtpm
To use the external CUSE TPM, the CUSE TPM should be started as follows:
/usr/bin/swtpm_cuse -n vtpm-test
QEMU can then be started using the following parameters:
qemu-system-x86_64 \
[...] \
-tpmdev cuse-tpm,id=tpm0,cancel-path=/dev/null,path=/dev/vtpm-test \
-device tpm-tis,id=tpm0,tpmdev=tpm0 \
[...]
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Cc: Eric Blake <eblake@redhat.com>
---
hmp.c | 6 +
hw/tpm/tpm_int.h | 1 +
hw/tpm/tpm_ioctl.h | 178 +++++++++++++++++++++++++++++
hw/tpm/tpm_passthrough.c | 286 +++++++++++++++++++++++++++++++++++++++++++++--
qapi-schema.json | 17 ++-
qemu-options.hx | 21 +++-
qmp-commands.hx | 2 +-
tpm.c | 11 +-
8 files changed, 505 insertions(+), 17 deletions(-)
create mode 100644 hw/tpm/tpm_ioctl.h
diff --git a/hmp.c b/hmp.c
index f142d36..50cb737 100644
--- a/hmp.c
+++ b/hmp.c
@@ -814,6 +814,12 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
tpo->has_cancel_path ? ",cancel-path=" : "",
tpo->has_cancel_path ? tpo->cancel_path : "");
break;
+ case TPM_TYPE_OPTIONS_KIND_CUSE_TPM:
+ tpo = ti->options->passthrough;
+ monitor_printf(mon, "%s%s",
+ tpo->has_path ? ",path=" : "",
+ tpo->has_path ? tpo->path : "");
+ break;
case TPM_TYPE_OPTIONS_KIND_MAX:
break;
}
diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
index f2f285b..6b2c9c9 100644
--- a/hw/tpm/tpm_int.h
+++ b/hw/tpm/tpm_int.h
@@ -61,6 +61,7 @@ struct tpm_resp_hdr {
#define TPM_TAG_RSP_AUTH1_COMMAND 0xc5
#define TPM_TAG_RSP_AUTH2_COMMAND 0xc6
+#define TPM_SUCCESS 0
#define TPM_FAIL 9
#define TPM_ORD_ContinueSelfTest 0x53
diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h
new file mode 100644
index 0000000..d36e702
--- /dev/null
+++ b/hw/tpm/tpm_ioctl.h
@@ -0,0 +1,178 @@
+/*
+ * tpm_ioctl.h
+ *
+ * This file is licensed under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <stdint.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+/*
+ * Every response from a command involving a TPM command execution must hold
+ * the ptmres_t as the first element.
+ * ptmres_t corresponds to the error code of a command executed by the TPM.
+ */
+
+typedef uint32_t ptmres_t;
+
+/* PTM_GET_TPMESTABLISHED */
+struct ptmest {
+ ptmres_t tpm_result;
+ unsigned char bit; /* TPM established bit */
+};
+
+/* PTM_RESET_PTMESTABLIHSED: reset establishment bit */
+struct ptmreset_est {
+ union {
+ struct {
+ uint8_t loc; /* locality to use */
+ } req;
+ struct {
+ ptmres_t tpm_result;
+ } resp;
+ } u;
+};
+
+/* PTM_INIT */
+struct ptminit {
+ union {
+ struct {
+ uint32_t init_flags; /* see definitions below */
+ } req;
+ struct {
+ ptmres_t tpm_result;
+ } resp;
+ } u;
+};
+
+/* above init_flags */
+#define INIT_FLAG_DELETE_VOLATILE (1 << 0)
+ /* delete volatile state file after reading it */
+
+/* PTM_SET_LOCALITY */
+struct ptmloc {
+ union {
+ struct {
+ uint8_t loc; /* locality to set */
+ } req;
+ struct {
+ ptmres_t tpm_result;
+ } resp;
+ } u;
+};
+
+/* PTM_HASH_DATA: hash given data */
+struct ptmhdata {
+ union {
+ struct {
+ uint32_t length;
+ uint8_t data[4096];
+ } req;
+ struct {
+ ptmres_t tpm_result;
+ } resp;
+ } 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 STATE_BLOB_SIZE (3 * 1024)
+
+/*
+ * Data structure to get state blobs from the TPM. If the size of the
+ * blob exceeds the STATE_BLOB_SIZE, multiple reads with
+ * adjusted offset are necessary. The last packet is indicated by
+ * the length being smaller than the STATE_BLOB_SIZE.
+ */
+struct ptm_getstate {
+ union {
+ struct {
+ uint32_t state_flags; /* may be: STATE_FLAG_DECRYPTED */
+ uint32_t tpm_number; /* always set to zero */
+ uint8_t type; /* which blob to pull */
+ uint32_t offset; /* offset from where to read */
+ } req;
+ struct {
+ ptmres_t tpm_result;
+ uint32_t state_flags; /* may be: STATE_FLAG_ENCRYPTED */
+ uint32_t length;
+ uint8_t data[STATE_BLOB_SIZE];
+ } resp;
+ } 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 STATE_FLAG_DECRYPTED 1 /* on input: get decrypted state */
+#define STATE_FLAG_ENCRYPTED 2 /* on output: state is encrytped */
+
+/*
+ * Data structure to set state blobs in the TPM. If the size of the
+ * blob exceeds the STATE_BLOB_SIZE, multiple 'writes' are necessary.
+ * The last packet is indicated by the length being smaller than the
+ * STATE_BLOB_SIZE.
+ */
+struct ptm_setstate {
+ union {
+ struct {
+ uint32_t state_flags; /* may be STATE_FLAG_ENCRYPTED */
+ uint32_t tpm_number; /* always set to 0 */
+ uint8_t type; /* which blob to set */
+ uint32_t length;
+ uint8_t data[STATE_BLOB_SIZE];
+ } req;
+ struct {
+ ptmres_t tpm_result;
+ } resp;
+ } u;
+};
+
+
+typedef uint64_t ptmcap_t;
+typedef struct ptmest ptmest_t;
+typedef struct ptmreset_est ptmreset_est_t;
+typedef struct ptmloc ptmloc_t;
+typedef struct ptmhdata ptmhdata_t;
+typedef struct ptminit ptminit_t;
+typedef struct ptm_getstate ptm_getstate_t;
+typedef struct ptm_setstate ptm_setstate_t;
+
+/* 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)
+
+enum {
+ PTM_GET_CAPABILITY = _IOR('P', 0, ptmcap_t),
+ PTM_INIT = _IOWR('P', 1, ptminit_t),
+ PTM_SHUTDOWN = _IOR('P', 2, ptmres_t),
+ PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptmest_t),
+ PTM_SET_LOCALITY = _IOWR('P', 4, ptmloc_t),
+ PTM_HASH_START = _IOR('P', 5, ptmres_t),
+ PTM_HASH_DATA = _IOWR('P', 6, ptmhdata_t),
+ PTM_HASH_END = _IOR('P', 7, ptmres_t),
+ PTM_CANCEL_TPM_CMD = _IOR('P', 8, ptmres_t),
+ PTM_STORE_VOLATILE = _IOR('P', 9, ptmres_t),
+ PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptmreset_est_t),
+ PTM_GET_STATEBLOB = _IOWR('P', 11, ptm_getstate_t),
+ PTM_SET_STATEBLOB = _IOWR('P', 12, ptm_setstate_t),
+ PTM_STOP = _IOR('P', 13, ptmres_t),
+};
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 8d8523a..3926094 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -34,6 +34,7 @@
#include "sysemu/tpm_backend_int.h"
#include "tpm_tis.h"
#include "tpm_util.h"
+#include "tpm_ioctl.h"
#define DEBUG_TPM 0
@@ -46,6 +47,7 @@
#define TYPE_TPM_PASSTHROUGH "tpm-passthrough"
#define TPM_PASSTHROUGH(obj) \
OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
+#define TYPE_TPM_CUSE "tpm-cuse"
static const TPMDriverOps tpm_passthrough_driver;
@@ -72,12 +74,18 @@ struct TPMPassthruState {
bool had_startup_error;
TPMVersion tpm_version;
+ ptmcap_t cuse_cap; /* capabilties of the CUSE TPM */
+ uint8_t cur_locty_number; /* last set locality */
};
typedef struct TPMPassthruState TPMPassthruState;
#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
+#define TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt) (tpm_pt->cuse_cap != 0)
+
+#define TPM_CUSE_IMPLEMENTS(tpm_tr, cap) ((tpm_pt->cuse_cap & cap) == cap)
+
/* functions */
static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
@@ -124,7 +132,30 @@ static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len)
return false;
}
+static int tpm_passthrough_set_locality(TPMPassthruState *tpm_pt,
+ uint8_t locty_number)
+{
+ int n;
+ ptmloc_t loc;
+
+ if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
+ if (tpm_pt->cur_locty_number != locty_number) {
+ loc.u.req.loc = locty_number;
+ n = ioctl(tpm_pt->tpm_fd, PTM_SET_LOCALITY, &loc);
+ if (n < 0) {
+ error_report("tpm_cuse: could not set locality on "
+ "CUSE TPM: %s (%i)",
+ strerror(errno), errno);
+ return -1;
+ }
+ tpm_pt->cur_locty_number = locty_number;
+ }
+ }
+ return 0;
+}
+
static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
+ uint8_t locality_number,
const uint8_t *in, uint32_t in_len,
uint8_t *out, uint32_t out_len,
bool *selftest_done)
@@ -133,6 +164,11 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
bool is_selftest;
const struct tpm_resp_hdr *hdr;
+ ret = tpm_passthrough_set_locality(tpm_pt, locality_number);
+ if (ret < 0) {
+ goto err_exit;
+ }
+
tpm_pt->tpm_op_canceled = false;
tpm_pt->tpm_executing = true;
*selftest_done = false;
@@ -183,10 +219,12 @@ err_exit:
}
static int tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt,
+ uint8_t locality_number,
const TPMLocality *locty_data,
bool *selftest_done)
{
return tpm_passthrough_unix_tx_bufs(tpm_pt,
+ locality_number,
locty_data->w_buffer.buffer,
locty_data->w_offset,
locty_data->r_buffer.buffer,
@@ -207,6 +245,7 @@ static void tpm_passthrough_worker_thread(gpointer data,
switch (cmd) {
case TPM_BACKEND_CMD_PROCESS_CMD:
tpm_passthrough_unix_transfer(tpm_pt,
+ thr_parms->tpm_state->locty_number,
thr_parms->tpm_state->locty_data,
&selftest_done);
@@ -223,6 +262,99 @@ static void tpm_passthrough_worker_thread(gpointer data,
}
/*
+ * Gracefully shut down the external CUSE TPM
+ */
+static void tpm_passthrough_shutdown(TPMPassthruState *tpm_pt)
+{
+ int n;
+ ptmres_t res;
+
+ if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
+ n = ioctl(tpm_pt->tpm_fd, PTM_SHUTDOWN, &res);
+ if (n < 0) {
+ error_report("tpm_cuse: Could not cleanly shut down "
+ "the CUSE TPM: %s (%i)",
+ strerror(errno), errno);
+ }
+ }
+}
+
+/*
+ * Probe for the CUSE TPM by sending an ioctl() requesting its
+ * capability flags.
+ */
+static int tpm_passthrough_cuse_probe(TPMPassthruState *tpm_pt)
+{
+ int rc = 0;
+ int n;
+
+ n = ioctl(tpm_pt->tpm_fd, PTM_GET_CAPABILITY, &tpm_pt->cuse_cap);
+ if (n < 0) {
+ error_report("Error: CUSE TPM was requested, but probing failed.");
+ rc = -1;
+ }
+
+ return rc;
+}
+
+static int tpm_passthrough_cuse_check_caps(TPMPassthruState *tpm_pt)
+{
+ int rc = 0;
+ ptmcap_t caps = 0;
+ const char *tpm = NULL;
+
+ /* check for min. required capabilities */
+ switch (tpm_pt->tpm_version) {
+ case TPM_VERSION_1_2:
+ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
+ PTM_CAP_SET_LOCALITY;
+ 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;
+ tpm = "2";
+ break;
+ case TPM_VERSION_UNSPEC:
+ error_report("tpm_cuse: %s: TPM version has not been set.",
+ __func__);
+ return -1;
+ }
+
+ if (!TPM_CUSE_IMPLEMENTS(tpm_pt, caps)) {
+ error_report("tpm_cuse: TPM does not implement minimum set of required "
+ "capabilities for TPM %s (0x%x).", tpm, (int)caps);
+ rc = -1;
+ }
+
+ return rc;
+}
+
+/*
+ * Initialize the external CUSE TPM
+ */
+static int tpm_passthrough_cuse_init(TPMPassthruState *tpm_pt)
+{
+ int rc = 0;
+ int n;
+ ptminit_t init = {
+ .u.req.init_flags = INIT_FLAG_DELETE_VOLATILE,
+ };
+
+ if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
+ n = ioctl(tpm_pt->tpm_fd, PTM_INIT, &init);
+ if (n < 0) {
+ error_report("tpm_cuse: Detected CUSE TPM but could not "
+ "send INIT: %s (%i)",
+ strerror(errno), errno);
+ rc = -1;
+ }
+ }
+
+ return rc;
+}
+
+/*
* Start the TPM (thread). If it had been started before, then terminate
* and start it again.
*/
@@ -237,6 +369,8 @@ static int tpm_passthrough_startup_tpm(TPMBackend *tb)
tpm_passthrough_worker_thread,
&tpm_pt->tpm_thread_params);
+ tpm_passthrough_cuse_init(tpm_pt);
+
return 0;
}
@@ -267,14 +401,46 @@ static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
{
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+ ptmest_t est;
+ int n;
+
+ if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
+ n = ioctl(tpm_pt->tpm_fd, PTM_GET_TPMESTABLISHED, &est);
+ if (n < 0) {
+ error_report("tpm_cuse: Could not get the TPM established "
+ "flag from the CUSE TPM: %s (%i)",
+ strerror(errno), errno);
+ return false;
+ }
+ return (est.bit != 0);
+ }
return false;
}
static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
uint8_t locty)
{
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+ int n;
+ int rc = 0;
+ ptmreset_est_t ptmreset_est;
+
/* only a TPM 2.0 will support this */
- return 0;
+ if (tpm_pt->tpm_version == TPM_VERSION_2_0) {
+ if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
+ ptmreset_est.u.req.loc = tpm_pt->cur_locty_number;
+
+ n = ioctl(tpm_pt->tpm_fd, PTM_RESET_TPMESTABLISHED, &ptmreset_est);
+ if (n < 0) {
+ error_report("tpm_cuse: Could not reset the establishment bit "
+ "failed: %s (%i)",
+ strerror(errno), errno);
+ rc = -1;
+ }
+ }
+ }
+ return rc;
}
static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
@@ -306,6 +472,8 @@ static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
int n;
+ ptmres_t res;
+ static int error_printed;
/*
* As of Linux 3.7 the tpm_tis driver does not properly cancel
@@ -314,17 +482,36 @@ static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
* command, e.g., a command executed on the host.
*/
if (tpm_pt->tpm_executing) {
- if (tpm_pt->cancel_fd >= 0) {
- 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;
+ if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
+ if (TPM_CUSE_IMPLEMENTS(tpm_pt, PTM_CAP_CANCEL_TPM_CMD)) {
+ n = ioctl(tpm_pt->tpm_fd, PTM_CANCEL_TPM_CMD, &res);
+ if (n < 0) {
+ error_report("tpm_cuse: Could not cancel command on "
+ "CUSE TPM: %s (%i)",
+ strerror(errno), errno);
+ } else if (res != TPM_SUCCESS) {
+ if (!error_printed) {
+ error_report("TPM error code from command "
+ "cancellation of CUSE TPM: 0x%x", res);
+ error_printed = true;
+ }
+ } else {
+ tpm_pt->tpm_op_canceled = true;
+ }
}
} else {
- error_report("Cannot cancel TPM command due to missing "
- "TPM sysfs cancel entry");
+ if (tpm_pt->cancel_fd >= 0) {
+ 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 "
+ "TPM sysfs cancel entry");
+ }
}
}
}
@@ -354,6 +541,11 @@ static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb)
char *dev;
char path[PATH_MAX];
+ if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
+ /* not needed, but so we have a fd */
+ return qemu_open("/dev/null", O_WRONLY);
+ }
+
if (tb->cancel_path) {
fd = qemu_open(tb->cancel_path, O_WRONLY);
if (fd < 0) {
@@ -388,12 +580,22 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
const char *value;
+ bool have_cuse = false;
+
+ value = qemu_opt_get(opts, "type");
+ if (value != NULL && !strcmp("cuse-tpm", value)) {
+ have_cuse = true;
+ }
value = qemu_opt_get(opts, "cancel-path");
tb->cancel_path = g_strdup(value);
value = qemu_opt_get(opts, "path");
if (!value) {
+ if (have_cuse) {
+ error_report("Missing path to access CUSE TPM");
+ goto err_free_parameters;
+ }
value = TPM_PASSTHROUGH_DEFAULT_DEVICE;
}
@@ -408,15 +610,36 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
goto err_free_parameters;
}
+ tpm_pt->cur_locty_number = ~0;
+
+ if (have_cuse) {
+ if (tpm_passthrough_cuse_probe(tpm_pt)) {
+ goto err_close_tpmdev;
+ }
+ /* init TPM for probing */
+ if (tpm_passthrough_cuse_init(tpm_pt)) {
+ goto err_close_tpmdev;
+ }
+ }
+
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;
}
+ if (have_cuse) {
+ if (tpm_passthrough_cuse_check_caps(tpm_pt)) {
+ goto err_close_tpmdev;
+ }
+ }
+
+
return 0;
err_close_tpmdev:
+ tpm_passthrough_shutdown(tpm_pt);
+
qemu_close(tpm_pt->tpm_fd);
tpm_pt->tpm_fd = -1;
@@ -467,6 +690,8 @@ static void tpm_passthrough_destroy(TPMBackend *tb)
tpm_backend_thread_end(&tpm_pt->tbt);
+ tpm_passthrough_shutdown(tpm_pt);
+
qemu_close(tpm_pt->tpm_fd);
qemu_close(tpm_pt->cancel_fd);
@@ -540,3 +765,44 @@ static void tpm_passthrough_register(void)
}
type_init(tpm_passthrough_register)
+
+/* CUSE TPM */
+static const char *tpm_passthrough_cuse_create_desc(void)
+{
+ return "CUSE TPM backend driver";
+}
+
+static const TPMDriverOps tpm_cuse_driver = {
+ .type = TPM_TYPE_CUSE_TPM,
+ .opts = tpm_passthrough_cmdline_opts,
+ .desc = tpm_passthrough_cuse_create_desc,
+ .create = tpm_passthrough_create,
+ .destroy = tpm_passthrough_destroy,
+ .init = tpm_passthrough_init,
+ .startup_tpm = tpm_passthrough_startup_tpm,
+ .realloc_buffer = tpm_passthrough_realloc_buffer,
+ .reset = tpm_passthrough_reset,
+ .had_startup_error = tpm_passthrough_get_startup_error,
+ .deliver_request = tpm_passthrough_deliver_request,
+ .cancel_cmd = tpm_passthrough_cancel_cmd,
+ .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
+ .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag,
+ .get_tpm_version = tpm_passthrough_get_tpm_version,
+};
+
+static const TypeInfo tpm_cuse_info = {
+ .name = TYPE_TPM_CUSE,
+ .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_cuse_register(void)
+{
+ type_register_static(&tpm_cuse_info);
+ tpm_register_driver(&tpm_cuse_driver);
+}
+
+type_init(tpm_cuse_register)
diff --git a/qapi-schema.json b/qapi-schema.json
index ac9594d..0d7c7b6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2974,10 +2974,11 @@
# An enumeration of TPM types
#
# @passthrough: TPM passthrough type
+# @cuse-tpm: CUSE TPM type
#
# Since: 1.5
##
-{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }
+{ 'enum': 'TpmType', 'data': [ 'passthrough', 'cuse-tpm' ] }
##
# @query-tpm-types:
@@ -3006,6 +3007,17 @@
'*cancel-path' : 'str'} }
##
+# @TPMCuseOptions:
+#
+# Information about the CUSE TPM type
+#
+# @path: string describing the path used for accessing the TPM device
+#
+# Since: 2.4
+##
+{ 'type': 'TPMCuseOptions', 'data': { 'path' : 'str'}}
+
+##
# @TpmTypeOptions:
#
# A union referencing different TPM backend types' configuration options
@@ -3015,7 +3027,8 @@
# Since: 1.5
##
{ 'union': 'TpmTypeOptions',
- 'data': { 'passthrough' : 'TPMPassthroughOptions' } }
+ 'data': { 'passthrough' : 'TPMPassthroughOptions',
+ 'cuse-tpm' : 'TPMCuseOptions' } }
##
# @TpmInfo:
diff --git a/qemu-options.hx b/qemu-options.hx
index 319d971..65d4ea0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2539,7 +2539,10 @@ DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
"-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n"
" use path to provide path to a character device; default is /dev/tpm0\n"
" use cancel-path to provide path to TPM's cancel sysfs entry; if\n"
- " not provided it will be searched for in /sys/class/misc/tpm?/device\n",
+ " not provided it will be searched for in /sys/class/misc/tpm?/device\n"
+ "-tpmdev cuse-tpm,id=id,path=path\n"
+ " use path to provide path to a character device to talk to the\n"
+ " TPM emulator providing a CUSE interface\n",
QEMU_ARCH_ALL)
STEXI
@@ -2548,8 +2551,8 @@ The general form of a TPM device option is:
@item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]
@findex -tpmdev
-Backend type must be:
-@option{passthrough}.
+Backend type must be either one of the following:
+@option{passthrough}, @option{cuse-tpm}.
The specific backend type will determine the applicable options.
The @code{-tpmdev} option creates the TPM backend and requires a
@@ -2599,6 +2602,18 @@ To create a passthrough TPM use the following two options:
Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
@code{tpmdev=tpm0} in the device option.
+@item -tpmdev cuse-tpm, id=@var{id}, path=@var{path}
+
+(Linux-host only) Enable access to a TPM emulator with a CUSE interface.
+
+@option{path} specifies the path to the CUSE TPM character device.
+
+To create a backend device accessing the CUSE TPM emulator using /dev/vtpm
+use the following two options:
+@example
+-tpmdev cuse-tpm,id=tpm0,path=/dev/vtpm -device tpm-tis,tpmdev=tpm0
+@end example
+
@end table
ETEXI
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 3a42ad0..a1f45b1 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3494,7 +3494,7 @@ Arguments: None
Example:
-> { "execute": "query-tpm-types" }
-<- { "return": [ "passthrough" ] }
+<- { "return": [ "passthrough", "cuse-tpm" ] }
EQMP
diff --git a/tpm.c b/tpm.c
index 963b7ee..5443b7b 100644
--- a/tpm.c
+++ b/tpm.c
@@ -25,7 +25,7 @@ static QLIST_HEAD(, TPMBackend) tpm_backends =
#define TPM_MAX_MODELS 1
-#define TPM_MAX_DRIVERS 1
+#define TPM_MAX_DRIVERS 2
static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = {
NULL,
@@ -273,6 +273,15 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
tpo->has_cancel_path = true;
}
break;
+ case TPM_TYPE_CUSE_TPM:
+ res->options->kind = TPM_TYPE_OPTIONS_KIND_CUSE_TPM;
+ tpo = g_new0(TPMPassthroughOptions, 1);
+ res->options->passthrough = tpo;
+ if (drv->path) {
+ tpo->path = g_strdup(drv->path);
+ tpo->has_path = true;
+ }
+ break;
case TPM_TYPE_MAX:
break;
}
--
1.9.3
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH v3 2/6] Introduce RAM location in vendor specific area in TIS
2015-05-26 21:33 [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Stefan Berger
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 1/6] Provide support for the CUSE TPM Stefan Berger
@ 2015-05-26 21:33 ` Stefan Berger
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec Stefan Berger
` (4 subsequent siblings)
6 siblings, 0 replies; 25+ messages in thread
From: Stefan Berger @ 2015-05-26 21:33 UTC (permalink / raw)
To: mst, qemu-devel, imammedo; +Cc: quan.xu, Stefan Berger
Introduce RAM locations in the vendor specific area in the TIS. These
locations will survive a reset and will be part of the state written
during a suspend. Their puspose is to support the physical presence
interface where the OS (ACPI) and the firmware (SeaBIOS) use these RAM
locations to exchange data.
Only locality 0 is used, leaving localities 1-4 available for other extensions.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
hw/tpm/tpm_tis.c | 27 +++++++++++++++++++++++++++
hw/tpm/tpm_tis.h | 2 ++
2 files changed, 29 insertions(+)
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index daf2ac9..1fb4e17 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -61,6 +61,7 @@
/* vendor-specific registers */
#define TPM_TIS_REG_DEBUG 0xf90
+#define TPM_TIS_REG_RAM 0xfa0
#define TPM_TIS_STS_TPM_FAMILY_MASK (0x3 << 26)/* TPM 2.0 */
#define TPM_TIS_STS_TPM_FAMILY1_2 (0 << 26) /* TPM 2.0 */
@@ -503,6 +504,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
uint8_t locty = tpm_tis_locality_from_addr(addr);
uint32_t avail;
uint8_t v;
+ int c;
if (tpm_backend_had_startup_error(s->be_driver)) {
return val;
@@ -599,6 +601,18 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
tpm_tis_dump_state(opaque, addr);
break;
#endif
+ case TPM_TIS_REG_RAM ... 0xfff:
+ if (locty == 0) {
+ /* RAM only in locality 0 -- allow unaligned accesses */
+ offset = addr & 0xfff;
+ shift = 0;
+
+ for (c = size - 1; c >= 0; c--) {
+ val <<= 8;
+ val |= tis->locty0_ram[offset - TPM_TIS_REG_RAM + c];
+ }
+ }
+ break;
}
if (shift) {
@@ -938,6 +952,19 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
}
}
break;
+
+ case TPM_TIS_REG_RAM ... 0xfff:
+ if (locty == 0) {
+ /* RAM only in locality 0 -- allow unaligned accesses */
+ off = addr & 0xfff;
+ val >>= shift;
+ /* only support locality 0 */
+ for (c = 0; c <= size - 1; c++) {
+ tis->locty0_ram[off - TPM_TIS_REG_RAM + c] = val;
+ val >>= 8;
+ }
+ }
+ break;
}
}
diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h
index a1df41f..0e98cb0 100644
--- a/hw/tpm/tpm_tis.h
+++ b/hw/tpm/tpm_tis.h
@@ -65,6 +65,8 @@ typedef struct TPMTISEmuState {
qemu_irq irq;
uint32_t irq_num;
+
+ uint8_t locty0_ram[0x60]; /* a vendor spec. extension at 0xfa0-0xfff in locality 0 */
} TPMTISEmuState;
#endif /* TPM_TPM_TIS_H */
--
1.9.3
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-05-26 21:33 [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Stefan Berger
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 1/6] Provide support for the CUSE TPM Stefan Berger
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 2/6] Introduce RAM location in vendor specific area in TIS Stefan Berger
@ 2015-05-26 21:33 ` Stefan Berger
2015-05-31 18:11 ` Michael S. Tsirkin
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 4/6] Introduce condition to notifiy waiters of completed command Stefan Berger
` (3 subsequent siblings)
6 siblings, 1 reply; 25+ messages in thread
From: Stefan Berger @ 2015-05-26 21:33 UTC (permalink / raw)
To: mst, qemu-devel, imammedo; +Cc: Kevin O'Connor, quan.xu, Stefan Berger
For automated management of a TPM device, implement the TCG Physical Presence
Interface Specification that allows a root user on Linux (for example) to set
an opcode for a sequence of TPM operations that the BIOS is supposed to execute
upon reboot of the physical or virtual machine. A sequence of operations may for
example involve giving up ownership of the TPM and activating and enabling the
device.
The sequences of operations are defined in table 2 in the specs to be found
at the following link:
http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
As an example, in recent versions of Linux the opcode (5) can be set as
follows:
cd /sys/devices/pnp0/00\:04/ppi
echo 5 > request
This ACPI implementation assumes that the underlying firmware (SeaBIOS)
has 'thrown an anchor' into the f-segment. The anchor is identified by
two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
in the f-segment is write-protected and holds a pointer to a structure
in high memmory area where the ACPI code writes the opcode into and
where it can read the last response from the BIOS.
The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
Also '0' is supported to 'clear' an intention.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Cc: Michael Tsirkin <mst@redhat.com>
Cc: Kevin O'Connor <kevin@koconnor.net>
---
v3->v4:
- consolidated code following Igor's suggestions
- marked functions as Serialized
- added .hex.generated files
---
hw/i386/ssdt-tpm-common.dsl | 182 ++++++++++++++
hw/i386/ssdt-tpm.dsl | 1 +
hw/i386/ssdt-tpm.hex.generated | 540 +++++++++++++++++++++++++++++++++++++++-
hw/i386/ssdt-tpm2.dsl | 1 +
hw/i386/ssdt-tpm2.hex.generated | 516 +++++++++++++++++++++++++++++++++++++-
include/hw/acpi/tpm.h | 19 ++
6 files changed, 1245 insertions(+), 14 deletions(-)
diff --git a/hw/i386/ssdt-tpm-common.dsl b/hw/i386/ssdt-tpm-common.dsl
index 9da4970..81d6757 100644
--- a/hw/i386/ssdt-tpm-common.dsl
+++ b/hw/i386/ssdt-tpm-common.dsl
@@ -32,5 +32,187 @@
Method (_STA, 0, NotSerialized) {
Return (0x0F)
}
+
+ OperationRegion (TTIS, SystemMemory,
+ TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE)
+
+ // Define TPM Debug register
+ Field(TTIS, AnyAcc, NoLock, Preserve) {
+ Offset (0xf90),
+ TDBG, 32 // QEMU TIS Debug
+ }
+
+ // Last accepted opcode
+ NAME(OP, Zero)
+
+ // The base address in TIS 'RAM' where we exchange
+ // data with the BIOS lies at 0xfed40fa0
+ OperationRegion (HIGH, SystemMemory, 0xfed40fa0, TPM_PPI_STRUCT_SIZE)
+
+ // Write given opcode into 'RAM'
+ Method (WRAM, 1, Serialized) {
+ Field(HIGH, AnyAcc, NoLock, Preserve) {
+ SIG1, 32,
+ SIZE, 16,
+ CODE, 8
+ }
+ If (LAnd(
+ LEqual(SIG1, TCG_MAGIC),
+ LGreaterEqual(SIZE, 1))
+ ) {
+ // Write opcode for BIOS to find
+ Store(Arg0, CODE)
+ // Remember last opcode in CODE
+ Store(Arg0, OP)
+ Return ( 0 )
+ }
+ Return ( 1 )
+ }
+
+ // read data from 'RAM'
+ Method (RRAM, 0, Serialized) {
+ Name (OPRE, Package(3) { 1, 0, 0})
+
+ Field(HIGH, AnyAcc, NoLock, Preserve) {
+ SIG1, 32,
+ SIZE, 16,
+ CODE, 8,
+ SUCC, 8,
+ CODO, 8,
+ RESP, 32
+ }
+ // Check signature and sufficient space
+ If (LAnd(
+ LEqual(SIG1, TCG_MAGIC),
+ LGreaterEqual(SIZE, 7)
+ )) {
+ Store(SUCC, Index(OPRE, 0))
+ Store(CODO, Index(OPRE, 1))
+ Store(RESP, Index(OPRE, 2))
+ }
+ return (OPRE)
+ }
+
+#ifdef TPM_1_2
+ // check for supported opcode
+ // supported opcodes: 0, 1-11, 14, 21-22
+ Method (CKOP, 1, NotSerialized) {
+ If (LOr(
+ LOr(
+ LAnd(
+ LGreaterEqual(Arg0, 0),
+ LLessEqual(Arg0, 11)
+ ),
+ LEqual(Arg0, 14)
+ ),
+ LAnd(
+ LGreaterEqual(Arg0, 21),
+ LLessEqual(Arg0, 22)
+ )
+ )) {
+ return (1)
+ } else {
+ return (0)
+ }
+ }
+#else
+# ifdef TPM_2_0
+ // check for supported opcode
+ // supported opcodes: 0
+ Method (CKOP, 1, NotSerialized) {
+ If (LEqual(Arg0, 0)) {
+ return (1)
+ } else {
+ return (0)
+ }
+ }
+# endif
+#endif
+
+ Method (_DSM, 4, Serialized) {
+ If (LEqual (Arg0, ToUUID("3DDDFAA6-361B-4EB4-A424-8D10089D1653"))) {
+
+ // only supporting API revision 1
+ If (LNotEqual (Arg1, 1)) {
+ Return (Buffer (1) {0})
+ }
+
+ Store(ToInteger(Arg2), Local0)
+ // standard DSM query function
+ If (LEqual (Local0, 0)) {
+ Return (Buffer () {0xFF, 0x01})
+ }
+
+ // interface version
+ If (LEqual (Local0, 1)) {
+ Return ("1.2")
+ }
+
+ // submit TPM operation
+ If (LEqual (Local0, 2)) {
+ // get opcode from package
+ Store(DerefOf(Index(Arg3, 0)), Local0)
+
+ If (CKOP( Local0 ) ) {
+ // Write the OP into TPM NVRAM
+ Store(WRAM ( Local0 ), Local1)
+ return (Local1)
+ } else {
+ Return (1)
+ }
+ }
+
+ // get pending TPM operation
+ If (LEqual (Local0, 3)) {
+ NAME(PEOP, Package(2) { 0, 0 })
+
+ Store ( 0 , Index(PEOP, 0))
+ Store ( OP, Index(PEOP, 1))
+
+ Return (PEOP)
+ }
+
+ // action to transition to pre-OS env.
+ If (LEqual (Local0, 4)) {
+ return (2) // Requiring reboot
+ }
+
+ // get pre-OS TPM operation response
+ If (LEqual (Local0, 5)) {
+ Store (RRAM(), Local0)
+ return ( Local0 )
+ }
+
+ // preferred user language
+ If (LEqual (Local0, 6)) {
+ return (3) // Not implemented
+ }
+
+ // submit TPM operation v2
+ If (LEqual (Local0, 7)) {
+ Store(DerefOf(Index(Arg3, 0)), Local0)
+
+ If (CKOP( Local0 )) {
+ // Write the OP into TPM NVRAM
+ Store(WRAM ( Local0 ), Local1)
+ return (Local1)
+ } else {
+ Return (1)
+ }
+ }
+
+ // get user confirmation status
+ If (LEqual (Local0, 8)) {
+ Store(DerefOf(Index(Arg3,0)), Local0)
+
+ if (CKOP( Local0 )) {
+ Return (4) // allowed, no user required
+ } else {
+ Return (0) // not implemented
+ }
+ }
+ }
+ return (Buffer() { 0x0 })
+ }
}
}
diff --git a/hw/i386/ssdt-tpm.dsl b/hw/i386/ssdt-tpm.dsl
index d81478c..48bf112 100644
--- a/hw/i386/ssdt-tpm.dsl
+++ b/hw/i386/ssdt-tpm.dsl
@@ -25,5 +25,6 @@ DefinitionBlock (
0x1 // OEM Revision
)
{
+#define TPM_1_2
#include "ssdt-tpm-common.dsl"
}
diff --git a/hw/i386/ssdt-tpm.hex.generated b/hw/i386/ssdt-tpm.hex.generated
index 874418c..db1d31d 100644
--- a/hw/i386/ssdt-tpm.hex.generated
+++ b/hw/i386/ssdt-tpm.hex.generated
@@ -3,12 +3,12 @@ static unsigned char ssdt_tpm_aml[] = {
0x53,
0x44,
0x54,
-0x6b,
-0x0,
+0x79,
+0x2,
0x0,
0x0,
0x1,
-0x37,
+0xea,
0x42,
0x58,
0x50,
@@ -36,8 +36,8 @@ static unsigned char ssdt_tpm_aml[] = {
0x14,
0x20,
0x10,
-0x46,
-0x4,
+0x44,
+0x25,
0x5c,
0x2f,
0x3,
@@ -55,7 +55,8 @@ static unsigned char ssdt_tpm_aml[] = {
0x5f,
0x5b,
0x82,
-0x33,
+0x41,
+0x24,
0x54,
0x50,
0x4d,
@@ -105,5 +106,530 @@ static unsigned char ssdt_tpm_aml[] = {
0x0,
0xa4,
0xa,
-0xf
+0xf,
+0x5b,
+0x80,
+0x54,
+0x54,
+0x49,
+0x53,
+0x0,
+0xc,
+0x0,
+0x0,
+0xd4,
+0xfe,
+0xb,
+0x0,
+0x50,
+0x5b,
+0x81,
+0xf,
+0x54,
+0x54,
+0x49,
+0x53,
+0x0,
+0x0,
+0x80,
+0xc8,
+0x7,
+0x54,
+0x44,
+0x42,
+0x47,
+0x20,
+0x8,
+0x4f,
+0x50,
+0x5f,
+0x5f,
+0x0,
+0x5b,
+0x80,
+0x48,
+0x49,
+0x47,
+0x48,
+0x0,
+0xc,
+0xa0,
+0xf,
+0xd4,
+0xfe,
+0xa,
+0xe,
+0x14,
+0x42,
+0x4,
+0x57,
+0x52,
+0x41,
+0x4d,
+0x9,
+0x5b,
+0x81,
+0x15,
+0x48,
+0x49,
+0x47,
+0x48,
+0x0,
+0x53,
+0x49,
+0x47,
+0x31,
+0x20,
+0x53,
+0x49,
+0x5a,
+0x45,
+0x10,
+0x43,
+0x4f,
+0x44,
+0x45,
+0x8,
+0xa0,
+0x21,
+0x90,
+0x93,
+0x53,
+0x49,
+0x47,
+0x31,
+0xc,
+0x54,
+0x43,
+0x50,
+0x41,
+0x92,
+0x95,
+0x53,
+0x49,
+0x5a,
+0x45,
+0x1,
+0x70,
+0x68,
+0x43,
+0x4f,
+0x44,
+0x45,
+0x70,
+0x68,
+0x4f,
+0x50,
+0x5f,
+0x5f,
+0xa4,
+0x0,
+0xa4,
+0x1,
+0x14,
+0x47,
+0x7,
+0x52,
+0x52,
+0x41,
+0x4d,
+0x8,
+0x8,
+0x4f,
+0x50,
+0x52,
+0x45,
+0x12,
+0x5,
+0x3,
+0x1,
+0x0,
+0x0,
+0x5b,
+0x81,
+0x24,
+0x48,
+0x49,
+0x47,
+0x48,
+0x0,
+0x53,
+0x49,
+0x47,
+0x31,
+0x20,
+0x53,
+0x49,
+0x5a,
+0x45,
+0x10,
+0x43,
+0x4f,
+0x44,
+0x45,
+0x8,
+0x53,
+0x55,
+0x43,
+0x43,
+0x8,
+0x43,
+0x4f,
+0x44,
+0x4f,
+0x8,
+0x52,
+0x45,
+0x53,
+0x50,
+0x20,
+0xa0,
+0x39,
+0x90,
+0x93,
+0x53,
+0x49,
+0x47,
+0x31,
+0xc,
+0x54,
+0x43,
+0x50,
+0x41,
+0x92,
+0x95,
+0x53,
+0x49,
+0x5a,
+0x45,
+0xa,
+0x7,
+0x70,
+0x53,
+0x55,
+0x43,
+0x43,
+0x88,
+0x4f,
+0x50,
+0x52,
+0x45,
+0x0,
+0x0,
+0x70,
+0x43,
+0x4f,
+0x44,
+0x4f,
+0x88,
+0x4f,
+0x50,
+0x52,
+0x45,
+0x1,
+0x0,
+0x70,
+0x52,
+0x45,
+0x53,
+0x50,
+0x88,
+0x4f,
+0x50,
+0x52,
+0x45,
+0xa,
+0x2,
+0x0,
+0xa4,
+0x4f,
+0x50,
+0x52,
+0x45,
+0x14,
+0x29,
+0x43,
+0x4b,
+0x4f,
+0x50,
+0x1,
+0xa0,
+0x1e,
+0x91,
+0x91,
+0x90,
+0x92,
+0x95,
+0x68,
+0x0,
+0x92,
+0x94,
+0x68,
+0xa,
+0xb,
+0x93,
+0x68,
+0xa,
+0xe,
+0x90,
+0x92,
+0x95,
+0x68,
+0xa,
+0x15,
+0x92,
+0x94,
+0x68,
+0xa,
+0x16,
+0xa4,
+0x1,
+0xa1,
+0x3,
+0xa4,
+0x0,
+0x14,
+0x43,
+0xf,
+0x5f,
+0x44,
+0x53,
+0x4d,
+0xc,
+0xa0,
+0x46,
+0xe,
+0x93,
+0x68,
+0x11,
+0x13,
+0xa,
+0x10,
+0xa6,
+0xfa,
+0xdd,
+0x3d,
+0x1b,
+0x36,
+0xb4,
+0x4e,
+0xa4,
+0x24,
+0x8d,
+0x10,
+0x8,
+0x9d,
+0x16,
+0x53,
+0xa0,
+0xa,
+0x92,
+0x93,
+0x69,
+0x1,
+0xa4,
+0x11,
+0x3,
+0x1,
+0x0,
+0x70,
+0x99,
+0x6a,
+0x0,
+0x60,
+0xa0,
+0xb,
+0x93,
+0x60,
+0x0,
+0xa4,
+0x11,
+0x5,
+0xa,
+0x2,
+0xff,
+0x1,
+0xa0,
+0xa,
+0x93,
+0x60,
+0x1,
+0xa4,
+0xd,
+0x31,
+0x2e,
+0x32,
+0x0,
+0xa0,
+0x20,
+0x93,
+0x60,
+0xa,
+0x2,
+0x70,
+0x83,
+0x88,
+0x6b,
+0x0,
+0x0,
+0x60,
+0xa0,
+0xf,
+0x43,
+0x4b,
+0x4f,
+0x50,
+0x60,
+0x70,
+0x57,
+0x52,
+0x41,
+0x4d,
+0x60,
+0x61,
+0xa4,
+0x61,
+0xa1,
+0x3,
+0xa4,
+0x1,
+0xa0,
+0x29,
+0x93,
+0x60,
+0xa,
+0x3,
+0x8,
+0x50,
+0x45,
+0x4f,
+0x50,
+0x12,
+0x4,
+0x2,
+0x0,
+0x0,
+0x70,
+0x0,
+0x88,
+0x50,
+0x45,
+0x4f,
+0x50,
+0x0,
+0x0,
+0x70,
+0x4f,
+0x50,
+0x5f,
+0x5f,
+0x88,
+0x50,
+0x45,
+0x4f,
+0x50,
+0x1,
+0x0,
+0xa4,
+0x50,
+0x45,
+0x4f,
+0x50,
+0xa0,
+0x8,
+0x93,
+0x60,
+0xa,
+0x4,
+0xa4,
+0xa,
+0x2,
+0xa0,
+0xd,
+0x93,
+0x60,
+0xa,
+0x5,
+0x70,
+0x52,
+0x52,
+0x41,
+0x4d,
+0x60,
+0xa4,
+0x60,
+0xa0,
+0x8,
+0x93,
+0x60,
+0xa,
+0x6,
+0xa4,
+0xa,
+0x3,
+0xa0,
+0x20,
+0x93,
+0x60,
+0xa,
+0x7,
+0x70,
+0x83,
+0x88,
+0x6b,
+0x0,
+0x0,
+0x60,
+0xa0,
+0xf,
+0x43,
+0x4b,
+0x4f,
+0x50,
+0x60,
+0x70,
+0x57,
+0x52,
+0x41,
+0x4d,
+0x60,
+0x61,
+0xa4,
+0x61,
+0xa1,
+0x3,
+0xa4,
+0x1,
+0xa0,
+0x1a,
+0x93,
+0x60,
+0xa,
+0x8,
+0x70,
+0x83,
+0x88,
+0x6b,
+0x0,
+0x0,
+0x60,
+0xa0,
+0x9,
+0x43,
+0x4b,
+0x4f,
+0x50,
+0x60,
+0xa4,
+0xa,
+0x4,
+0xa1,
+0x3,
+0xa4,
+0x0,
+0xa4,
+0x11,
+0x3,
+0x1,
+0x0
};
diff --git a/hw/i386/ssdt-tpm2.dsl b/hw/i386/ssdt-tpm2.dsl
index 58bbbf8..29228a0 100644
--- a/hw/i386/ssdt-tpm2.dsl
+++ b/hw/i386/ssdt-tpm2.dsl
@@ -25,5 +25,6 @@ DefinitionBlock (
0x1 // OEM Revision
)
{
+#define TPM_2_0
#include "ssdt-tpm-common.dsl"
}
diff --git a/hw/i386/ssdt-tpm2.hex.generated b/hw/i386/ssdt-tpm2.hex.generated
index 9ea8271..a685533 100644
--- a/hw/i386/ssdt-tpm2.hex.generated
+++ b/hw/i386/ssdt-tpm2.hex.generated
@@ -3,12 +3,12 @@ static unsigned char ssdt_tpm2_aml[] = {
0x53,
0x44,
0x54,
-0x6b,
-0x0,
+0x61,
+0x2,
0x0,
0x0,
0x1,
-0x37,
+0xe,
0x42,
0x58,
0x50,
@@ -36,8 +36,8 @@ static unsigned char ssdt_tpm2_aml[] = {
0x14,
0x20,
0x10,
-0x46,
-0x4,
+0x4c,
+0x23,
0x5c,
0x2f,
0x3,
@@ -55,7 +55,8 @@ static unsigned char ssdt_tpm2_aml[] = {
0x5f,
0x5b,
0x82,
-0x33,
+0x49,
+0x22,
0x54,
0x50,
0x4d,
@@ -105,5 +106,506 @@ static unsigned char ssdt_tpm2_aml[] = {
0x0,
0xa4,
0xa,
-0xf
+0xf,
+0x5b,
+0x80,
+0x54,
+0x54,
+0x49,
+0x53,
+0x0,
+0xc,
+0x0,
+0x0,
+0xd4,
+0xfe,
+0xb,
+0x0,
+0x50,
+0x5b,
+0x81,
+0xf,
+0x54,
+0x54,
+0x49,
+0x53,
+0x0,
+0x0,
+0x80,
+0xc8,
+0x7,
+0x54,
+0x44,
+0x42,
+0x47,
+0x20,
+0x8,
+0x4f,
+0x50,
+0x5f,
+0x5f,
+0x0,
+0x5b,
+0x80,
+0x48,
+0x49,
+0x47,
+0x48,
+0x0,
+0xc,
+0xa0,
+0xf,
+0xd4,
+0xfe,
+0xa,
+0xe,
+0x14,
+0x42,
+0x4,
+0x57,
+0x52,
+0x41,
+0x4d,
+0x9,
+0x5b,
+0x81,
+0x15,
+0x48,
+0x49,
+0x47,
+0x48,
+0x0,
+0x53,
+0x49,
+0x47,
+0x31,
+0x20,
+0x53,
+0x49,
+0x5a,
+0x45,
+0x10,
+0x43,
+0x4f,
+0x44,
+0x45,
+0x8,
+0xa0,
+0x21,
+0x90,
+0x93,
+0x53,
+0x49,
+0x47,
+0x31,
+0xc,
+0x54,
+0x43,
+0x50,
+0x41,
+0x92,
+0x95,
+0x53,
+0x49,
+0x5a,
+0x45,
+0x1,
+0x70,
+0x68,
+0x43,
+0x4f,
+0x44,
+0x45,
+0x70,
+0x68,
+0x4f,
+0x50,
+0x5f,
+0x5f,
+0xa4,
+0x0,
+0xa4,
+0x1,
+0x14,
+0x47,
+0x7,
+0x52,
+0x52,
+0x41,
+0x4d,
+0x8,
+0x8,
+0x4f,
+0x50,
+0x52,
+0x45,
+0x12,
+0x5,
+0x3,
+0x1,
+0x0,
+0x0,
+0x5b,
+0x81,
+0x24,
+0x48,
+0x49,
+0x47,
+0x48,
+0x0,
+0x53,
+0x49,
+0x47,
+0x31,
+0x20,
+0x53,
+0x49,
+0x5a,
+0x45,
+0x10,
+0x43,
+0x4f,
+0x44,
+0x45,
+0x8,
+0x53,
+0x55,
+0x43,
+0x43,
+0x8,
+0x43,
+0x4f,
+0x44,
+0x4f,
+0x8,
+0x52,
+0x45,
+0x53,
+0x50,
+0x20,
+0xa0,
+0x39,
+0x90,
+0x93,
+0x53,
+0x49,
+0x47,
+0x31,
+0xc,
+0x54,
+0x43,
+0x50,
+0x41,
+0x92,
+0x95,
+0x53,
+0x49,
+0x5a,
+0x45,
+0xa,
+0x7,
+0x70,
+0x53,
+0x55,
+0x43,
+0x43,
+0x88,
+0x4f,
+0x50,
+0x52,
+0x45,
+0x0,
+0x0,
+0x70,
+0x43,
+0x4f,
+0x44,
+0x4f,
+0x88,
+0x4f,
+0x50,
+0x52,
+0x45,
+0x1,
+0x0,
+0x70,
+0x52,
+0x45,
+0x53,
+0x50,
+0x88,
+0x4f,
+0x50,
+0x52,
+0x45,
+0xa,
+0x2,
+0x0,
+0xa4,
+0x4f,
+0x50,
+0x52,
+0x45,
+0x14,
+0x11,
+0x43,
+0x4b,
+0x4f,
+0x50,
+0x1,
+0xa0,
+0x6,
+0x93,
+0x68,
+0x0,
+0xa4,
+0x1,
+0xa1,
+0x3,
+0xa4,
+0x0,
+0x14,
+0x43,
+0xf,
+0x5f,
+0x44,
+0x53,
+0x4d,
+0xc,
+0xa0,
+0x46,
+0xe,
+0x93,
+0x68,
+0x11,
+0x13,
+0xa,
+0x10,
+0xa6,
+0xfa,
+0xdd,
+0x3d,
+0x1b,
+0x36,
+0xb4,
+0x4e,
+0xa4,
+0x24,
+0x8d,
+0x10,
+0x8,
+0x9d,
+0x16,
+0x53,
+0xa0,
+0xa,
+0x92,
+0x93,
+0x69,
+0x1,
+0xa4,
+0x11,
+0x3,
+0x1,
+0x0,
+0x70,
+0x99,
+0x6a,
+0x0,
+0x60,
+0xa0,
+0xb,
+0x93,
+0x60,
+0x0,
+0xa4,
+0x11,
+0x5,
+0xa,
+0x2,
+0xff,
+0x1,
+0xa0,
+0xa,
+0x93,
+0x60,
+0x1,
+0xa4,
+0xd,
+0x31,
+0x2e,
+0x32,
+0x0,
+0xa0,
+0x20,
+0x93,
+0x60,
+0xa,
+0x2,
+0x70,
+0x83,
+0x88,
+0x6b,
+0x0,
+0x0,
+0x60,
+0xa0,
+0xf,
+0x43,
+0x4b,
+0x4f,
+0x50,
+0x60,
+0x70,
+0x57,
+0x52,
+0x41,
+0x4d,
+0x60,
+0x61,
+0xa4,
+0x61,
+0xa1,
+0x3,
+0xa4,
+0x1,
+0xa0,
+0x29,
+0x93,
+0x60,
+0xa,
+0x3,
+0x8,
+0x50,
+0x45,
+0x4f,
+0x50,
+0x12,
+0x4,
+0x2,
+0x0,
+0x0,
+0x70,
+0x0,
+0x88,
+0x50,
+0x45,
+0x4f,
+0x50,
+0x0,
+0x0,
+0x70,
+0x4f,
+0x50,
+0x5f,
+0x5f,
+0x88,
+0x50,
+0x45,
+0x4f,
+0x50,
+0x1,
+0x0,
+0xa4,
+0x50,
+0x45,
+0x4f,
+0x50,
+0xa0,
+0x8,
+0x93,
+0x60,
+0xa,
+0x4,
+0xa4,
+0xa,
+0x2,
+0xa0,
+0xd,
+0x93,
+0x60,
+0xa,
+0x5,
+0x70,
+0x52,
+0x52,
+0x41,
+0x4d,
+0x60,
+0xa4,
+0x60,
+0xa0,
+0x8,
+0x93,
+0x60,
+0xa,
+0x6,
+0xa4,
+0xa,
+0x3,
+0xa0,
+0x20,
+0x93,
+0x60,
+0xa,
+0x7,
+0x70,
+0x83,
+0x88,
+0x6b,
+0x0,
+0x0,
+0x60,
+0xa0,
+0xf,
+0x43,
+0x4b,
+0x4f,
+0x50,
+0x60,
+0x70,
+0x57,
+0x52,
+0x41,
+0x4d,
+0x60,
+0x61,
+0xa4,
+0x61,
+0xa1,
+0x3,
+0xa4,
+0x1,
+0xa0,
+0x1a,
+0x93,
+0x60,
+0xa,
+0x8,
+0x70,
+0x83,
+0x88,
+0x6b,
+0x0,
+0x0,
+0x60,
+0xa0,
+0x9,
+0x43,
+0x4b,
+0x4f,
+0x50,
+0x60,
+0xa4,
+0xa,
+0x4,
+0xa1,
+0x3,
+0xa4,
+0x0,
+0xa4,
+0x11,
+0x3,
+0x1,
+0x0
};
diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
index 6d516c6..4437543 100644
--- a/include/hw/acpi/tpm.h
+++ b/include/hw/acpi/tpm.h
@@ -31,4 +31,23 @@
#define TPM2_START_METHOD_MMIO 6
+/*
+ * Physical Presence Interface -- shared with the BIOS
+ */
+#define TCG_MAGIC 0x41504354
+
+#if 0
+struct tpm_ppi {
+ uint32_t sign; // TCG_MAGIC
+ uint16_t size; // number of subsequent bytes for ACPI to access
+ uint8_t opcode; // set by ACPI
+ uint8_t failure; // set by BIOS (0 = success)
+ uint8_t recent_opcode; // set by BIOS
+ uint32_t response; // set by BIOS
+ uint8_t next_step; // BIOS only
+} QEMU_PACKED;
+#endif
+
+#define TPM_PPI_STRUCT_SIZE 14
+
#endif /* HW_ACPI_TPM_H */
--
1.9.3
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH v3 4/6] Introduce condition to notifiy waiters of completed command
2015-05-26 21:33 [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Stefan Berger
` (2 preceding siblings ...)
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec Stefan Berger
@ 2015-05-26 21:33 ` Stefan Berger
2015-05-31 18:11 ` Michael S. Tsirkin
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 5/6] Introduce condition in TPM backend for notification Stefan Berger
` (2 subsequent siblings)
6 siblings, 1 reply; 25+ messages in thread
From: Stefan Berger @ 2015-05-26 21:33 UTC (permalink / raw)
To: mst, qemu-devel, imammedo; +Cc: quan.xu, Stefan Berger
Introduce a lock and a condition to notify anyone waiting for the completion
of the execution of a TPM command by the backend (thread). The backend
uses the condition to signal anyone waiting for command completion.
We need to place the condition in two locations: one is invoked by the
backend thread, the other by the bottom half thread.
We will use the signalling to wait for command completion before VM
suspend.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
hw/tpm/tpm_int.h | 3 +++
hw/tpm/tpm_tis.c | 14 ++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
index 6b2c9c9..70be1ad 100644
--- a/hw/tpm/tpm_int.h
+++ b/hw/tpm/tpm_int.h
@@ -30,6 +30,9 @@ struct TPMState {
char *backend;
TPMBackend *be_driver;
TPMVersion be_tpm_version;
+
+ QemuMutex state_lock;
+ QemuCond cmd_complete;
};
#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index 1fb4e17..f278e1e 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -367,6 +367,8 @@ static void tpm_tis_receive_bh(void *opaque)
TPMTISEmuState *tis = &s->s.tis;
uint8_t locty = s->locty_number;
+ qemu_mutex_lock(&s->state_lock);
+
tpm_tis_sts_set(&tis->loc[locty],
TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
@@ -383,6 +385,10 @@ static void tpm_tis_receive_bh(void *opaque)
tpm_tis_raise_irq(s, locty,
TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
#endif
+
+ /* notify of completed command */
+ qemu_cond_signal(&s->cmd_complete);
+ qemu_mutex_unlock(&s->state_lock);
}
/*
@@ -402,6 +408,11 @@ static void tpm_tis_receive_cb(TPMState *s, uint8_t locty,
}
}
+ qemu_mutex_lock(&s->state_lock);
+ /* notify of completed command */
+ qemu_cond_signal(&s->cmd_complete);
+ qemu_mutex_unlock(&s->state_lock);
+
qemu_bh_schedule(tis->bh);
}
@@ -1097,6 +1108,9 @@ static void tpm_tis_initfn(Object *obj)
memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
s, "tpm-tis-mmio",
TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
+
+ qemu_mutex_init(&s->state_lock);
+ qemu_cond_init(&s->cmd_complete);
}
static void tpm_tis_class_init(ObjectClass *klass, void *data)
--
1.9.3
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH v3 5/6] Introduce condition in TPM backend for notification
2015-05-26 21:33 [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Stefan Berger
` (3 preceding siblings ...)
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 4/6] Introduce condition to notifiy waiters of completed command Stefan Berger
@ 2015-05-26 21:33 ` Stefan Berger
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 6/6] Add support for VM suspend/resume for TPM TIS Stefan Berger
2015-05-31 18:11 ` [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Michael S. Tsirkin
6 siblings, 0 replies; 25+ messages in thread
From: Stefan Berger @ 2015-05-26 21:33 UTC (permalink / raw)
To: mst, qemu-devel, imammedo; +Cc: quan.xu, Stefan Berger
TPM backends will suspend independently of the frontends. Also
here we need to be able to wait for the TPM command to have been
completely processed.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
hw/tpm/tpm_passthrough.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 3926094..46b801f 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -76,6 +76,10 @@ struct TPMPassthruState {
TPMVersion tpm_version;
ptmcap_t cuse_cap; /* capabilties of the CUSE TPM */
uint8_t cur_locty_number; /* last set locality */
+
+ QemuMutex state_lock;
+ QemuCond cmd_complete; /* singnaled once tpm_busy is false */
+ bool tpm_busy;
};
typedef struct TPMPassthruState TPMPassthruState;
@@ -252,6 +256,11 @@ static void tpm_passthrough_worker_thread(gpointer data,
thr_parms->recv_data_callback(thr_parms->tpm_state,
thr_parms->tpm_state->locty_number,
selftest_done);
+ /* result delivered */
+ qemu_mutex_lock(&tpm_pt->state_lock);
+ tpm_pt->tpm_busy = false;
+ qemu_cond_signal(&tpm_pt->cmd_complete);
+ qemu_mutex_unlock(&tpm_pt->state_lock);
break;
case TPM_BACKEND_CMD_INIT:
case TPM_BACKEND_CMD_END:
@@ -385,6 +394,7 @@ static void tpm_passthrough_reset(TPMBackend *tb)
tpm_backend_thread_end(&tpm_pt->tbt);
tpm_pt->had_startup_error = false;
+ tpm_pt->tpm_busy = false;
}
static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
@@ -465,6 +475,11 @@ static void tpm_passthrough_deliver_request(TPMBackend *tb)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+ /* TPM considered busy once TPM Request scheduled for processing */
+ qemu_mutex_lock(&tpm_pt->state_lock);
+ tpm_pt->tpm_busy = true;
+ qemu_mutex_unlock(&tpm_pt->state_lock);
+
tpm_backend_thread_deliver_request(&tpm_pt->tbt);
}
@@ -736,6 +751,11 @@ static const TPMDriverOps tpm_passthrough_driver = {
static void tpm_passthrough_inst_init(Object *obj)
{
+ TPMBackend *tb = TPM_BACKEND(obj);
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+
+ qemu_mutex_init(&tpm_pt->state_lock);
+ qemu_cond_init(&tpm_pt->cmd_complete);
}
static void tpm_passthrough_inst_finalize(Object *obj)
--
1.9.3
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH v3 6/6] Add support for VM suspend/resume for TPM TIS
2015-05-26 21:33 [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Stefan Berger
` (4 preceding siblings ...)
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 5/6] Introduce condition in TPM backend for notification Stefan Berger
@ 2015-05-26 21:33 ` Stefan Berger
2015-05-31 18:11 ` [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Michael S. Tsirkin
6 siblings, 0 replies; 25+ messages in thread
From: Stefan Berger @ 2015-05-26 21:33 UTC (permalink / raw)
To: mst, qemu-devel, imammedo; +Cc: quan.xu, Stefan Berger
Extend the TPM TIS code to support suspend/resume. In case a command
is being processed by the external TPM when suspending, wait for the command
to complete to catch the result. In case the bottom half did not run,
run the one function the bottom half is supposed to run. This then
makes the resume operation work.
The passthrough backend does not support suspend/resume operation
and is therefore blocked from suspend/resume and migration.
The CUSE TPM's supported capabilities are tested and if sufficient
capabilities are implemented, suspend/resume, snapshotting and
migration are supported by the CUSE TPM.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
hw/tpm/tpm_passthrough.c | 129 +++++++++++++++++++++++++--
hw/tpm/tpm_tis.c | 139 ++++++++++++++++++++++++++++-
hw/tpm/tpm_tis.h | 2 +
hw/tpm/tpm_util.c | 206 +++++++++++++++++++++++++++++++++++++++++++
hw/tpm/tpm_util.h | 7 ++
include/sysemu/tpm_backend.h | 12 +++
6 files changed, 488 insertions(+), 7 deletions(-)
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 46b801f..f242085 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -35,6 +35,7 @@
#include "tpm_tis.h"
#include "tpm_util.h"
#include "tpm_ioctl.h"
+#include "migration/migration.h"
#define DEBUG_TPM 0
@@ -50,6 +51,7 @@
#define TYPE_TPM_CUSE "tpm-cuse"
static const TPMDriverOps tpm_passthrough_driver;
+static const VMStateDescription vmstate_tpm_cuse;
/* data structures */
typedef struct TPMPassthruThreadParams {
@@ -80,6 +82,10 @@ struct TPMPassthruState {
QemuMutex state_lock;
QemuCond cmd_complete; /* singnaled once tpm_busy is false */
bool tpm_busy;
+
+ Error *migration_blocker;
+
+ TPMBlobBuffers tpm_blobs;
};
typedef struct TPMPassthruState TPMPassthruState;
@@ -286,6 +292,10 @@ static void tpm_passthrough_shutdown(TPMPassthruState *tpm_pt)
strerror(errno), errno);
}
}
+ if (tpm_pt->migration_blocker) {
+ migrate_del_blocker(tpm_pt->migration_blocker);
+ error_free(tpm_pt->migration_blocker);
+ }
}
/*
@@ -342,13 +352,15 @@ static int tpm_passthrough_cuse_check_caps(TPMPassthruState *tpm_pt)
/*
* Initialize the external CUSE TPM
*/
-static int tpm_passthrough_cuse_init(TPMPassthruState *tpm_pt)
+static int tpm_passthrough_cuse_init(TPMPassthruState *tpm_pt,
+ bool is_resume)
{
int rc = 0;
int n;
- ptminit_t init = {
- .u.req.init_flags = INIT_FLAG_DELETE_VOLATILE,
- };
+ ptminit_t init;
+ if (is_resume) {
+ init.u.req.init_flags = INIT_FLAG_DELETE_VOLATILE;
+ }
if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
n = ioctl(tpm_pt->tpm_fd, PTM_INIT, &init);
@@ -378,7 +390,7 @@ static int tpm_passthrough_startup_tpm(TPMBackend *tb)
tpm_passthrough_worker_thread,
&tpm_pt->tpm_thread_params);
- tpm_passthrough_cuse_init(tpm_pt);
+ tpm_passthrough_cuse_init(tpm_pt, false);
return 0;
}
@@ -453,6 +465,34 @@ static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
return rc;
}
+static int tpm_cuse_get_state_blobs(TPMBackend *tb,
+ bool decrypted_blobs,
+ TPMBlobBuffers *tpm_blobs)
+{
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+
+ assert(TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt));
+
+ return tpm_util_cuse_get_state_blobs(tpm_pt->tpm_fd, decrypted_blobs,
+ tpm_blobs);
+}
+
+static int tpm_cuse_set_state_blobs(TPMBackend *tb,
+ TPMBlobBuffers *tpm_blobs)
+{
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+ int n;
+
+ assert(TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt));
+
+ n = tpm_util_cuse_set_state_blobs(tpm_pt->tpm_fd, tpm_blobs);
+ if (n) {
+ return 1;
+ }
+
+ return tpm_passthrough_cuse_init(tpm_pt, true);
+}
+
static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
@@ -591,6 +631,25 @@ static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb)
return fd;
}
+static void tpm_passthrough_block_migration(TPMPassthruState *tpm_pt)
+{
+ ptmcap_t caps;
+
+ if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
+ caps = PTM_CAP_GET_STATEBLOB | PTM_CAP_SET_STATEBLOB |
+ PTM_CAP_STOP;
+ if (!TPM_CUSE_IMPLEMENTS(tpm_pt, caps)) {
+ error_setg(&tpm_pt->migration_blocker,
+ "Migration disabled: CUSE TPM lacks necessary capabilities.");
+ migrate_add_blocker(tpm_pt->migration_blocker);
+ }
+ } else {
+ error_setg(&tpm_pt->migration_blocker,
+ "Migration disabled: Passthrough TPM does not support migration.");
+ migrate_add_blocker(tpm_pt->migration_blocker);
+ }
+}
+
static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
@@ -632,7 +691,7 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
goto err_close_tpmdev;
}
/* init TPM for probing */
- if (tpm_passthrough_cuse_init(tpm_pt)) {
+ if (tpm_passthrough_cuse_init(tpm_pt, false)) {
goto err_close_tpmdev;
}
}
@@ -649,6 +708,7 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
}
}
+ tpm_passthrough_block_migration(tpm_pt);
return 0;
@@ -756,10 +816,13 @@ static void tpm_passthrough_inst_init(Object *obj)
qemu_mutex_init(&tpm_pt->state_lock);
qemu_cond_init(&tpm_pt->cmd_complete);
+
+ vmstate_register(NULL, -1, &vmstate_tpm_cuse, obj);
}
static void tpm_passthrough_inst_finalize(Object *obj)
{
+ vmstate_unregister(NULL, &vmstate_tpm_cuse, obj);
}
static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
@@ -792,6 +855,60 @@ static const char *tpm_passthrough_cuse_create_desc(void)
return "CUSE TPM backend driver";
}
+static void tpm_cuse_pre_save(void *opaque)
+{
+ TPMPassthruState *tpm_pt = opaque;
+ TPMBackend *tb = &tpm_pt->parent;
+
+ qemu_mutex_lock(&tpm_pt->state_lock);
+ /* wait for TPM to finish processing */
+ if (tpm_pt->tpm_busy) {
+ qemu_cond_wait(&tpm_pt->cmd_complete, &tpm_pt->state_lock);
+ }
+ qemu_mutex_unlock(&tpm_pt->state_lock);
+
+ /* get the decrypted state blobs from the TPM */
+ tpm_cuse_get_state_blobs(tb, TRUE, &tpm_pt->tpm_blobs);
+}
+
+static int tpm_cuse_post_load(void *opaque,
+ int version_id __attribute__((unused)))
+{
+ TPMPassthruState *tpm_pt = opaque;
+ TPMBackend *tb = &tpm_pt->parent;
+
+ return tpm_cuse_set_state_blobs(tb, &tpm_pt->tpm_blobs);
+}
+
+static const VMStateDescription vmstate_tpm_cuse = {
+ .name = "cuse-tpm",
+ .version_id = 1,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .pre_save = tpm_cuse_pre_save,
+ .post_load = tpm_cuse_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(tpm_blobs.permanent_flags, TPMPassthruState),
+ VMSTATE_UINT32(tpm_blobs.permanent.size, TPMPassthruState),
+ VMSTATE_VBUFFER_ALLOC_UINT32(tpm_blobs.permanent.buffer,
+ TPMPassthruState, 1, NULL, 0,
+ tpm_blobs.permanent.size),
+
+ VMSTATE_UINT32(tpm_blobs.volatil_flags, TPMPassthruState),
+ VMSTATE_UINT32(tpm_blobs.volatil.size, TPMPassthruState),
+ VMSTATE_VBUFFER_ALLOC_UINT32(tpm_blobs.volatil.buffer,
+ TPMPassthruState, 1, NULL, 0,
+ tpm_blobs.volatil.size),
+
+ VMSTATE_UINT32(tpm_blobs.savestate_flags, TPMPassthruState),
+ VMSTATE_UINT32(tpm_blobs.savestate.size, TPMPassthruState),
+ VMSTATE_VBUFFER_ALLOC_UINT32(tpm_blobs.savestate.buffer,
+ TPMPassthruState, 1, NULL, 0,
+ tpm_blobs.savestate.size),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const TPMDriverOps tpm_cuse_driver = {
.type = TPM_TYPE_CUSE_TPM,
.opts = tpm_passthrough_cmdline_opts,
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index f278e1e..a9922b7 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -367,6 +367,8 @@ static void tpm_tis_receive_bh(void *opaque)
TPMTISEmuState *tis = &s->s.tis;
uint8_t locty = s->locty_number;
+ tis->bh_scheduled = false;
+
qemu_mutex_lock(&s->state_lock);
tpm_tis_sts_set(&tis->loc[locty],
@@ -414,6 +416,8 @@ static void tpm_tis_receive_cb(TPMState *s, uint8_t locty,
qemu_mutex_unlock(&s->state_lock);
qemu_bh_schedule(tis->bh);
+
+ tis->bh_scheduled = true;
}
/*
@@ -1055,9 +1059,142 @@ static void tpm_tis_reset(DeviceState *dev)
tpm_tis_do_startup_tpm(s);
}
+
+/* persistent state handling */
+
+static void tpm_tis_pre_save(void *opaque)
+{
+ TPMState *s = opaque;
+ TPMTISEmuState *tis = &s->s.tis;
+ uint8_t locty = tis->active_locty;
+
+ DPRINTF("tpm_tis: suspend: locty = %d : r_offset = %d, w_offset = %d\n",
+ locty, tis->loc[0].r_offset, tis->loc[0].w_offset);
+#ifdef DEBUG_TIS
+ tpm_tis_dump_state(opaque, 0);
+#endif
+
+ qemu_mutex_lock(&s->state_lock);
+
+ /* wait for outstanding request to complete */
+ if (TPM_TIS_IS_VALID_LOCTY(locty) &&
+ tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
+ /*
+ * If we get here when the bh is scheduled but did not run,
+ * we won't get notified...
+ */
+ if (!tis->bh_scheduled) {
+ /* backend thread to notify us */
+ qemu_cond_wait(&s->cmd_complete, &s->state_lock);
+ }
+ if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
+ /* bottom half did not run - run its function */
+ qemu_mutex_unlock(&s->state_lock);
+ tpm_tis_receive_bh(opaque);
+ qemu_mutex_lock(&s->state_lock);
+ }
+ }
+
+ qemu_mutex_unlock(&s->state_lock);
+
+ /* copy current active read or write buffer into the buffer
+ written to disk */
+ if (TPM_TIS_IS_VALID_LOCTY(locty)) {
+ switch (tis->loc[locty].state) {
+ case TPM_TIS_STATE_RECEPTION:
+ memcpy(tis->buf,
+ tis->loc[locty].w_buffer.buffer,
+ MIN(sizeof(tis->buf),
+ tis->loc[locty].w_buffer.size));
+ tis->offset = tis->loc[locty].w_offset;
+ break;
+ case TPM_TIS_STATE_COMPLETION:
+ memcpy(tis->buf,
+ tis->loc[locty].r_buffer.buffer,
+ MIN(sizeof(tis->buf),
+ tis->loc[locty].r_buffer.size));
+ tis->offset = tis->loc[locty].r_offset;
+ break;
+ default:
+ /* leak nothing */
+ memset(tis->buf, 0x0, sizeof(tis->buf));
+ break;
+ }
+ }
+}
+
+static int tpm_tis_post_load(void *opaque,
+ int version_id __attribute__((unused)))
+{
+ TPMState *s = opaque;
+ TPMTISEmuState *tis = &s->s.tis;
+
+ uint8_t locty = tis->active_locty;
+
+ if (TPM_TIS_IS_VALID_LOCTY(locty)) {
+ switch (tis->loc[locty].state) {
+ case TPM_TIS_STATE_RECEPTION:
+ memcpy(tis->loc[locty].w_buffer.buffer,
+ tis->buf,
+ MIN(sizeof(tis->buf),
+ tis->loc[locty].w_buffer.size));
+ tis->loc[locty].w_offset = tis->offset;
+ break;
+ case TPM_TIS_STATE_COMPLETION:
+ memcpy(tis->loc[locty].r_buffer.buffer,
+ tis->buf,
+ MIN(sizeof(tis->buf),
+ tis->loc[locty].r_buffer.size));
+ tis->loc[locty].r_offset = tis->offset;
+ break;
+ default:
+ break;
+ }
+ }
+
+ DPRINTF("tpm_tis: resume : locty = %d : r_offset = %d, w_offset = %d\n",
+ locty, tis->loc[0].r_offset, tis->loc[0].w_offset);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_locty = {
+ .name = "loc",
+ .version_id = 1,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(state, TPMLocality),
+ VMSTATE_UINT32(inte, TPMLocality),
+ VMSTATE_UINT32(ints, TPMLocality),
+ VMSTATE_UINT8(access, TPMLocality),
+ VMSTATE_UINT32(sts, TPMLocality),
+ VMSTATE_UINT32(iface_id, TPMLocality),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
static const VMStateDescription vmstate_tpm_tis = {
.name = "tpm",
- .unmigratable = 1,
+ .version_id = 1,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .pre_save = tpm_tis_pre_save,
+ .post_load = tpm_tis_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(s.tis.offset, TPMState),
+ VMSTATE_BUFFER(s.tis.buf, TPMState),
+ VMSTATE_UINT8(s.tis.active_locty, TPMState),
+ VMSTATE_UINT8(s.tis.aborting_locty, TPMState),
+ VMSTATE_UINT8(s.tis.next_locty, TPMState),
+
+ VMSTATE_STRUCT_ARRAY(s.tis.loc, TPMState, TPM_TIS_NUM_LOCALITIES, 1,
+ vmstate_locty, TPMLocality),
+
+ VMSTATE_BUFFER(s.tis.locty0_ram, TPMState),
+
+ VMSTATE_END_OF_LIST()
+ }
};
static Property tpm_tis_properties[] = {
diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h
index 0e98cb0..7d5849a 100644
--- a/hw/tpm/tpm_tis.h
+++ b/hw/tpm/tpm_tis.h
@@ -54,6 +54,8 @@ typedef struct TPMLocality {
typedef struct TPMTISEmuState {
QEMUBH *bh;
+ bool bh_scheduled; /* bh scheduled but did not run yet */
+
uint32_t offset;
uint8_t buf[TPM_TIS_BUFFER_MAX];
diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
index 4ace585..0f63cfc 100644
--- a/hw/tpm/tpm_util.c
+++ b/hw/tpm/tpm_util.c
@@ -21,6 +21,19 @@
#include "tpm_util.h"
#include "tpm_int.h"
+#include "tpm_ioctl.h"
+#include "qemu/error-report.h"
+
+#define DEBUG_TPM 0
+
+#define DPRINTF(fmt, ...) do { \
+ if (DEBUG_TPM) { \
+ fprintf(stderr, fmt, ## __VA_ARGS__); \
+ } \
+} while (0)
+
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
/*
* A basic test of a TPM device. We expect a well formatted response header
@@ -124,3 +137,196 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
return 1;
}
+
+static void tpm_sized_buffer_reset(TPMSizedBuffer *tsb)
+{
+ g_free(tsb->buffer);
+ tsb->buffer = NULL;
+ tsb->size = 0;
+}
+
+static int tpm_util_cuse_get_state_blob(int fd,
+ uint8_t type,
+ bool decrypted_blobs,
+ TPMSizedBuffer *tsb,
+ uint32_t *flags)
+{
+ ptm_getstate_t pgs;
+ uint16_t offset = 0;
+ int n;
+ ptmres_t res;
+
+ tpm_sized_buffer_reset(tsb);
+
+ while (true) {
+ pgs.u.req.state_flags = (decrypted_blobs) ? STATE_FLAG_DECRYPTED : 0;
+ pgs.u.req.tpm_number = 0;
+ pgs.u.req.type = type;
+ pgs.u.req.offset = offset;
+
+ n = ioctl(fd, PTM_GET_STATEBLOB, &pgs);
+ if (n < 0) {
+ error_report("CUSE TPM PTM_GET_STATEBLOB ioctl failed: %s",
+ strerror(errno));
+ goto err_exit;
+ }
+ res = pgs.u.resp.tpm_result;
+ if (res != 0 && (res & 0x800) == 0) {
+ error_report("Getting the stateblob (type %d) failed with a TPM "
+ "error 0x%x", type, res);
+ goto err_exit;
+ }
+
+ tsb->buffer = g_realloc(tsb->buffer, tsb->size + pgs.u.resp.length);
+ memcpy(&tsb->buffer[tsb->size], pgs.u.resp.data, pgs.u.resp.length);
+ tsb->size += pgs.u.resp.length;
+
+ if (pgs.u.resp.length != sizeof(pgs.u.resp.data)) {
+ *flags = pgs.u.resp.state_flags;
+ break;
+ }
+ offset += pgs.u.resp.length;
+ }
+
+ DPRINTF("tpm_util: got state blob type %d, %d bytes, flags 0x%08x, "
+ "decrypted=%d\n", type, tsb->size, *flags, decrypted_blobs);
+
+ return 0;
+
+err_exit:
+ return 1;
+}
+
+int tpm_util_cuse_get_state_blobs(int tpm_fd,
+ bool decrypted_blobs,
+ TPMBlobBuffers *tpm_blobs)
+{
+ ptmres_t res;
+ int n;
+
+ n = ioctl(tpm_fd, PTM_STORE_VOLATILE, &res);
+ if (n < 0) {
+ error_report("tpm_passthrough: Could not save the volatile "
+ "state of the CUSE TPM: %s (%i)",
+ strerror(errno), errno);
+ return 1;
+ } else if (res != TPM_SUCCESS) {
+ error_report("TPM error code from saving "
+ "volatile data of CUSE TPM: 0x%x", res);
+ return 1;
+ }
+
+ n = tpm_util_cuse_get_state_blob(tpm_fd, PTM_BLOB_TYPE_PERMANENT,
+ decrypted_blobs,
+ &tpm_blobs->permanent,
+ &tpm_blobs->permanent_flags);
+ if (n) {
+ return 1;
+ }
+ n = tpm_util_cuse_get_state_blob(tpm_fd, PTM_BLOB_TYPE_VOLATILE,
+ decrypted_blobs,
+ &tpm_blobs->volatil,
+ &tpm_blobs->volatil_flags);
+ if (n) {
+ goto exit_free_permanent;
+ }
+ n = tpm_util_cuse_get_state_blob(tpm_fd, PTM_BLOB_TYPE_SAVESTATE,
+ decrypted_blobs,
+ &tpm_blobs->savestate,
+ &tpm_blobs->savestate_flags);
+ if (n) {
+ goto exit_free_volatile;
+ }
+
+ return 0;
+
+exit_free_volatile:
+ tpm_sized_buffer_reset(&tpm_blobs->volatil);
+
+exit_free_permanent:
+ tpm_sized_buffer_reset(&tpm_blobs->permanent);
+
+ return 1;
+}
+
+static int tpm_util_cuse_set_state_blob(int fd,
+ uint8_t type,
+ TPMSizedBuffer *tsb,
+ uint32 flags)
+{
+ ptm_setstate_t pss;
+ ptmres_t res;
+ off_t offset = 0;
+ size_t to_copy;
+ int n;
+
+ while (tsb->size) {
+ pss.u.req.state_flags = flags;
+ pss.u.req.type = type;
+ pss.u.req.tpm_number = 0;
+ to_copy = min(tsb->size - offset, sizeof(pss.u.req.data));
+ memcpy(pss.u.req.data, &tsb->buffer[offset], to_copy);
+ offset += to_copy;
+ pss.u.req.length = to_copy;
+
+ n = ioctl(fd, PTM_SET_STATEBLOB, &pss);
+ if (n < 0) {
+ error_report("CUSE TPM PTM_SET_STATEBLOB ioctl failed: %s",
+ strerror(errno));
+ goto err_exit;
+ }
+ res = pss.u.resp.tpm_result;
+ if (res != 0) {
+ error_report("Setting the stateblob (type %d) failed with a TPM "
+ "error 0x%x", type, res);
+ goto err_exit;
+ }
+ if (to_copy < sizeof(pss.u.req.data)) {
+ break;
+ }
+ }
+
+ DPRINTF("tpm_util: set the state blob type %d, %d bytes, flags 0x%08x\n",
+ type, tsb->size, flags);
+
+ return 0;
+
+err_exit:
+ return 1;
+}
+
+int tpm_util_cuse_set_state_blobs(int tpm_fd,
+ TPMBlobBuffers *tpm_blobs)
+{
+ int n;
+ ptmres_t res;
+
+ n = ioctl(tpm_fd, PTM_STOP, &res);
+ if (n < 0) {
+ error_report("tpm_passthrough: Could not stop "
+ "the CUSE TPM: %s (%i)",
+ strerror(errno), errno);
+ return 1;
+ }
+
+ n = tpm_util_cuse_set_state_blob(tpm_fd, PTM_BLOB_TYPE_PERMANENT,
+ &tpm_blobs->permanent,
+ tpm_blobs->permanent_flags);
+ if (n) {
+ return 1;
+ }
+ n = tpm_util_cuse_set_state_blob(tpm_fd, PTM_BLOB_TYPE_VOLATILE,
+ &tpm_blobs->volatil,
+ tpm_blobs->volatil_flags);
+ if (n) {
+ return 1;
+ }
+ n = tpm_util_cuse_set_state_blob(tpm_fd, PTM_BLOB_TYPE_SAVESTATE,
+ &tpm_blobs->savestate,
+ tpm_blobs->savestate_flags);
+ if (n) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h
index e7f354a..04f5afd 100644
--- a/hw/tpm/tpm_util.h
+++ b/hw/tpm/tpm_util.h
@@ -25,4 +25,11 @@
int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version);
+int tpm_util_cuse_get_state_blobs(int tpm_fd,
+ bool decrypted_blobs,
+ TPMBlobBuffers *tpm_blobs);
+
+int tpm_util_cuse_set_state_blobs(int tpm_fd,
+ TPMBlobBuffers *tpm_blobs);
+
#endif /* TPM_TPM_UTILS_H */
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index 0a366be..92bc3e4 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -63,6 +63,18 @@ typedef struct TPMSizedBuffer {
uint8_t *buffer;
} TPMSizedBuffer;
+/* 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;
+
struct TPMDriverOps {
enum TpmType type;
const QemuOptDesc *opts;
--
1.9.3
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 1/6] Provide support for the CUSE TPM
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 1/6] Provide support for the CUSE TPM Stefan Berger
@ 2015-05-26 23:05 ` Eric Blake
2015-05-27 1:53 ` Stefan Berger
0 siblings, 1 reply; 25+ messages in thread
From: Eric Blake @ 2015-05-26 23:05 UTC (permalink / raw)
To: Stefan Berger, mst, qemu-devel, imammedo; +Cc: quan.xu
[-- Attachment #1: Type: text/plain, Size: 8820 bytes --]
On 05/26/2015 03:33 PM, Stefan Berger wrote:
> Rather than integrating TPM functionality into QEMU directly
> using the TPM emulation of libtpms, we now integrate an external
> emulated TPM device. This device is expected to implement a Linux
> CUSE interface (CUSE = character device in userspace).
>
> QEMU talks to the CUSE TPM using much functionality of the
> passthrough driver. For example, the TPM commands and responses
> are sent to the CUSE TPM using the read()/write() interface.
> However, some out-of-band control needs to be done using the CUSE
> TPM's ioctl's. The CUSE TPM currently defines and implements 14
> different ioctls for controlling certain life-cycle aspects of
> the emulated TPM. The ioctls can be regarded as a replacement for
> direct function calls to a TPM emulator if the TPM were to be
> directly integrated into QEMU.
>
> One of the ioctl's allows to get a bitmask of supported capabilities.
> Each returned bit indicates which capabilties have been implemented.
s/capabilties/capabilities/
> An include file defining the various ioctls is added to QEMU.
>
> The CUSE TPM and associated tools can be found here:
>
> https://github.com/stefanberger/swtpm
>
>
> To use the external CUSE TPM, the CUSE TPM should be started as follows:
>
> /usr/bin/swtpm_cuse -n vtpm-test
>
> QEMU can then be started using the following parameters:
>
> qemu-system-x86_64 \
> [...] \
> -tpmdev cuse-tpm,id=tpm0,cancel-path=/dev/null,path=/dev/vtpm-test \
> -device tpm-tis,id=tpm0,tpmdev=tpm0 \
> [...]
>
>
> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> Cc: Eric Blake <eblake@redhat.com>
> ---
At this point, I'm only doing a high-level overview (public interface,
blatant findings) and not a fine-grained reading of the implementation.
> diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h
> new file mode 100644
> index 0000000..d36e702
> --- /dev/null
> +++ b/hw/tpm/tpm_ioctl.h
> @@ -0,0 +1,178 @@
> +/*
> + * tpm_ioctl.h
> + *
> + * This file is licensed under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either version 2.1 of
> + * the License, or (at your option) any later version.
> + */
My understanding of copyleft (and insert the obligatory IANAL
disclaimer) is that it works by exploiting the copyright law - that is,
something cannot be [L]GPL unless there is also an assertion of
copyright ownership (I don't care who, merely that a copyright claim
exists somewhere in the file, nearby the license).
> +/*
> + * Data structure to get state blobs from the TPM. If the size of the
> + * blob exceeds the STATE_BLOB_SIZE, multiple reads with
> + * adjusted offset are necessary. The last packet is indicated by
> + * the length being smaller than the STATE_BLOB_SIZE.
If the read size is exactly STATE_BLOB_SIZE, does that result in 1
packet or 2? Does it cause a 0-length packet to be attempted, or is it
broken into STATE_BLOB_SIZE-1 and 1?
> +
> +/* state_flags above : */
> +#define STATE_FLAG_DECRYPTED 1 /* on input: get decrypted state */
> +#define STATE_FLAG_ENCRYPTED 2 /* on output: state is encrytped */
s/encrytped/encrypted/
> +
> +/*
> + * Data structure to set state blobs in the TPM. If the size of the
> + * blob exceeds the STATE_BLOB_SIZE, multiple 'writes' are necessary.
> + * The last packet is indicated by the length being smaller than the
> + * STATE_BLOB_SIZE.
> + */
Same question as on read about an exact STATE_BLOB_SIZE write
> +struct ptm_setstate {
> + union {
> + struct {
> + uint32_t state_flags; /* may be STATE_FLAG_ENCRYPTED */
> + uint32_t tpm_number; /* always set to 0 */
> + uint8_t type; /* which blob to set */
> + uint32_t length;
> + uint8_t data[STATE_BLOB_SIZE];
This struct has padding blanks; is that going to matter?
> +typedef uint64_t ptmcap_t;
> +typedef struct ptmest ptmest_t;
> +typedef struct ptmreset_est ptmreset_est_t;
> +typedef struct ptmloc ptmloc_t;
> +typedef struct ptmhdata ptmhdata_t;
Why a change in 1 vs. 2 spaces on some of the types?
Technically, POSIX reserves the entire *_t namespace to itself, I'm a
bit worried that by doing 'typedef struct foo foo_t' we are not being
consistent with the rest of qemu, which does 'typedef struct foo foo'.
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -72,12 +74,18 @@ struct TPMPassthruState {
> bool had_startup_error;
>
> TPMVersion tpm_version;
> + ptmcap_t cuse_cap; /* capabilties of the CUSE TPM */
> + uint8_t cur_locty_number; /* last set locality */
s/capabilties/capabilities/
> };
>
> typedef struct TPMPassthruState TPMPassthruState;
>
> #define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
>
> +#define TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt) (tpm_pt->cuse_cap != 0)
> +
> +#define TPM_CUSE_IMPLEMENTS(tpm_tr, cap) ((tpm_pt->cuse_cap & cap) == cap)
Evaluates cap more than once, which may not be ideal. Also
under-parenthesized in the face of arbitrary expressions for tpm_tr or cap.
Umm, how does the macro argument tpm_tr get used, and where is the macro
body tpm_pt scoped?
Better might be this (depending on your intent):
#define TPM_CUSE_IMPLEMENTS(tpm_tr, cap) \
(((tpm_tr)->cuse_cap & (cap)) != 0)
if you know that cap will always be passed as one bit. But if someone
intends to use the macro to test multiple bits at once, and return true
only if all of the bits are set, then living with multiple evaluation of
'cap' may be better.
> +static int tpm_passthrough_set_locality(TPMPassthruState *tpm_pt,
> + uint8_t locty_number)
> +{
> + int n;
> + ptmloc_t loc;
> +
> + if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
> + if (tpm_pt->cur_locty_number != locty_number) {
> + loc.u.req.loc = locty_number;
> + n = ioctl(tpm_pt->tpm_fd, PTM_SET_LOCALITY, &loc);
> + if (n < 0) {
> + error_report("tpm_cuse: could not set locality on "
> + "CUSE TPM: %s (%i)",
> + strerror(errno), errno);
Hmm, I wonder if error_setg_errno() followed by error_report_err() is
any nicer than manually calling strerror(). Probably not worth worrying
about.
On the other hand, this code is not strictly portable - passing both
errno and strerror(errno) as arguments to a function has no sequencing
point defined on whether errno is collected first or second; if it is
collected second, strerror() may have clobbered errno. Most code
doesn't bother with printing "%s (%i)" for errors; the %s alone is
sufficient.
> /*
> + * Gracefully shut down the external CUSE TPM
> + */
> +static void tpm_passthrough_shutdown(TPMPassthruState *tpm_pt)
> +{
> + int n;
> + ptmres_t res;
> +
> + if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
> + n = ioctl(tpm_pt->tpm_fd, PTM_SHUTDOWN, &res);
> + if (n < 0) {
> + error_report("tpm_cuse: Could not cleanly shut down "
> + "the CUSE TPM: %s (%i)",
> + strerror(errno), errno);
Why not just 'if (ioctl(...) < 0) {' without needing 'n'?
> + }
> + }
> +}
> +
> +/*
> + * Probe for the CUSE TPM by sending an ioctl() requesting its
> + * capability flags.
> + */
> +static int tpm_passthrough_cuse_probe(TPMPassthruState *tpm_pt)
> +{
> + int rc = 0;
> + int n;
> +
> + n = ioctl(tpm_pt->tpm_fd, PTM_GET_CAPABILITY, &tpm_pt->cuse_cap);
> + if (n < 0) {
> + error_report("Error: CUSE TPM was requested, but probing failed.");
Most qemu error messages intentionally do not end in period
> @@ -306,6 +472,8 @@ static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
> {
> TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> int n;
> + ptmres_t res;
> + static int error_printed;
You're using this as a bool...
> + } else if (res != TPM_SUCCESS) {
> + if (!error_printed) {
> + error_report("TPM error code from command "
> + "cancellation of CUSE TPM: 0x%x", res);
> + error_printed = true;
> + }
...so declare it as one.
> +++ b/qapi-schema.json
> @@ -2974,10 +2974,11 @@
> # An enumeration of TPM types
> #
> # @passthrough: TPM passthrough type
> +# @cuse-tpm: CUSE TPM type
Missing '(since 2.4)' designator.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 1/6] Provide support for the CUSE TPM
2015-05-26 23:05 ` Eric Blake
@ 2015-05-27 1:53 ` Stefan Berger
0 siblings, 0 replies; 25+ messages in thread
From: Stefan Berger @ 2015-05-27 1:53 UTC (permalink / raw)
To: Eric Blake, mst, qemu-devel, imammedo; +Cc: quan.xu
On 05/26/2015 07:05 PM, Eric Blake wrote:
> On 05/26/2015 03:33 PM, Stefan Berger wrote:
>> Rather than integrating TPM functionality into QEMU directly
>> using the TPM emulation of libtpms, we now integrate an external
>> emulated TPM device. This device is expected to implement a Linux
>> CUSE interface (CUSE = character device in userspace).
>>
>> QEMU talks to the CUSE TPM using much functionality of the
>> passthrough driver. For example, the TPM commands and responses
>> are sent to the CUSE TPM using the read()/write() interface.
>> However, some out-of-band control needs to be done using the CUSE
>> TPM's ioctl's. The CUSE TPM currently defines and implements 14
>> different ioctls for controlling certain life-cycle aspects of
>> the emulated TPM. The ioctls can be regarded as a replacement for
>> direct function calls to a TPM emulator if the TPM were to be
>> directly integrated into QEMU.
>>
>> One of the ioctl's allows to get a bitmask of supported capabilities.
>> Each returned bit indicates which capabilties have been implemented.
> s/capabilties/capabilities/
>
>> An include file defining the various ioctls is added to QEMU.
>>
>> The CUSE TPM and associated tools can be found here:
>>
>> https://github.com/stefanberger/swtpm
>>
>>
>> To use the external CUSE TPM, the CUSE TPM should be started as follows:
>>
>> /usr/bin/swtpm_cuse -n vtpm-test
>>
>> QEMU can then be started using the following parameters:
>>
>> qemu-system-x86_64 \
>> [...] \
>> -tpmdev cuse-tpm,id=tpm0,cancel-path=/dev/null,path=/dev/vtpm-test \
>> -device tpm-tis,id=tpm0,tpmdev=tpm0 \
>> [...]
>>
>>
>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>> Cc: Eric Blake <eblake@redhat.com>
>> ---
> At this point, I'm only doing a high-level overview (public interface,
> blatant findings) and not a fine-grained reading of the implementation.
Thanks anyway.
>
>> diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h
>> new file mode 100644
>> index 0000000..d36e702
>> --- /dev/null
>> +++ b/hw/tpm/tpm_ioctl.h
>> @@ -0,0 +1,178 @@
>> +/*
>> + * tpm_ioctl.h
>> + *
>> + * This file is licensed under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either version 2.1 of
>> + * the License, or (at your option) any later version.
>> + */
> My understanding of copyleft (and insert the obligatory IANAL
> disclaimer) is that it works by exploiting the copyright law - that is,
> something cannot be [L]GPL unless there is also an assertion of
> copyright ownership (I don't care who, merely that a copyright claim
> exists somewhere in the file, nearby the license).
I added the copyright now, which was obviously missing.
>
>> +/*
>> + * Data structure to get state blobs from the TPM. If the size of the
>> + * blob exceeds the STATE_BLOB_SIZE, multiple reads with
>> + * adjusted offset are necessary. The last packet is indicated by
>> + * the length being smaller than the STATE_BLOB_SIZE.
> If the read size is exactly STATE_BLOB_SIZE, does that result in 1
> packet or 2? Does it cause a 0-length packet to be attempted, or is it
> broken into STATE_BLOB_SIZE-1 and 1?
It would be 2 packets, the 2nd one having 0-length.
>
>> +
>> +/* state_flags above : */
>> +#define STATE_FLAG_DECRYPTED 1 /* on input: get decrypted state */
>> +#define STATE_FLAG_ENCRYPTED 2 /* on output: state is encrytped */
> s/encrytped/encrypted/
>
>> +
>> +/*
>> + * Data structure to set state blobs in the TPM. If the size of the
>> + * blob exceeds the STATE_BLOB_SIZE, multiple 'writes' are necessary.
>> + * The last packet is indicated by the length being smaller than the
>> + * STATE_BLOB_SIZE.
>> + */
> Same question as on read about an exact STATE_BLOB_SIZE write
Same here. 2 packets.
>> +struct ptm_setstate {
>> + union {
>> + struct {
>> + uint32_t state_flags; /* may be STATE_FLAG_ENCRYPTED */
>> + uint32_t tpm_number; /* always set to 0 */
>> + uint8_t type; /* which blob to set */
>> + uint32_t length;
>> + uint8_t data[STATE_BLOB_SIZE];
> This struct has padding blanks; is that going to matter?
The problem here could be a 64bit variable that would allign differently
on a 32bit machine versus a 64bit machine or a 32bit executable running
on a 64bit machine.At least there are no 64bit variables here, so it
would be ok. However, we can still make the type member 32bit.
>
>> +typedef uint64_t ptmcap_t;
>> +typedef struct ptmest ptmest_t;
>> +typedef struct ptmreset_est ptmreset_est_t;
>> +typedef struct ptmloc ptmloc_t;
>> +typedef struct ptmhdata ptmhdata_t;
> Why a change in 1 vs. 2 spaces on some of the types?
>
> Technically, POSIX reserves the entire *_t namespace to itself, I'm a
> bit worried that by doing 'typedef struct foo foo_t' we are not being
> consistent with the rest of qemu, which does 'typedef struct foo foo'.
So remove the _t entirely?
>
>> +++ b/hw/tpm/tpm_passthrough.c
>> @@ -72,12 +74,18 @@ struct TPMPassthruState {
>> bool had_startup_error;
>>
>> TPMVersion tpm_version;
>> + ptmcap_t cuse_cap; /* capabilties of the CUSE TPM */
>> + uint8_t cur_locty_number; /* last set locality */
> s/capabilties/capabilities/
>
>> };
>>
>> typedef struct TPMPassthruState TPMPassthruState;
>>
>> #define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0"
>>
>> +#define TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt) (tpm_pt->cuse_cap != 0)
>> +
>> +#define TPM_CUSE_IMPLEMENTS(tpm_tr, cap) ((tpm_pt->cuse_cap & cap) == cap)
> Evaluates cap more than once, which may not be ideal. Also
> under-parenthesized in the face of arbitrary expressions for tpm_tr or cap.
>
> Umm, how does the macro argument tpm_tr get used, and where is the macro
> body tpm_pt scoped?
>
> Better might be this (depending on your intent):
> #define TPM_CUSE_IMPLEMENTS(tpm_tr, cap) \
> (((tpm_tr)->cuse_cap & (cap)) != 0)
>
> if you know that cap will always be passed as one bit. But if someone
> intends to use the macro to test multiple bits at once, and return true
> only if all of the bits are set, then living with multiple evaluation of
> 'cap' may be better.
The usage so far asks for whether a certain set of capabilities are
_all_ implemented and for this the
evaluation above is good in call cases. I'll add the additional
parenthesis, though.
>
>> +static int tpm_passthrough_set_locality(TPMPassthruState *tpm_pt,
>> + uint8_t locty_number)
>> +{
>> + int n;
>> + ptmloc_t loc;
>> +
>> + if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
>> + if (tpm_pt->cur_locty_number != locty_number) {
>> + loc.u.req.loc = locty_number;
>> + n = ioctl(tpm_pt->tpm_fd, PTM_SET_LOCALITY, &loc);
>> + if (n < 0) {
>> + error_report("tpm_cuse: could not set locality on "
>> + "CUSE TPM: %s (%i)",
>> + strerror(errno), errno);
> Hmm, I wonder if error_setg_errno() followed by error_report_err() is
> any nicer than manually calling strerror(). Probably not worth worrying
> about.
>
> On the other hand, this code is not strictly portable - passing both
> errno and strerror(errno) as arguments to a function has no sequencing
> point defined on whether errno is collected first or second; if it is
> collected second, strerror() may have clobbered errno. Most code
> doesn't bother with printing "%s (%i)" for errors; the %s alone is
> sufficient.
Ok.
>
>
>> /*
>> + * Gracefully shut down the external CUSE TPM
>> + */
>> +static void tpm_passthrough_shutdown(TPMPassthruState *tpm_pt)
>> +{
>> + int n;
>> + ptmres_t res;
>> +
>> + if (TPM_PASSTHROUGH_USES_CUSE_TPM(tpm_pt)) {
>> + n = ioctl(tpm_pt->tpm_fd, PTM_SHUTDOWN, &res);
>> + if (n < 0) {
>> + error_report("tpm_cuse: Could not cleanly shut down "
>> + "the CUSE TPM: %s (%i)",
>> + strerror(errno), errno);
> Why not just 'if (ioctl(...) < 0) {' without needing 'n'?
Thought it was a coding style requirement .. but it isn't.
>
>> + }
>> + }
>> +}
>> +
>> +/*
>> + * Probe for the CUSE TPM by sending an ioctl() requesting its
>> + * capability flags.
>> + */
>> +static int tpm_passthrough_cuse_probe(TPMPassthruState *tpm_pt)
>> +{
>> + int rc = 0;
>> + int n;
>> +
>> + n = ioctl(tpm_pt->tpm_fd, PTM_GET_CAPABILITY, &tpm_pt->cuse_cap);
>> + if (n < 0) {
>> + error_report("Error: CUSE TPM was requested, but probing failed.");
> Most qemu error messages intentionally do not end in period
Removed.
>
>> @@ -306,6 +472,8 @@ static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
>> {
>> TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
>> int n;
>> + ptmres_t res;
>> + static int error_printed;
> You're using this as a bool...
>
>
>> + } else if (res != TPM_SUCCESS) {
>> + if (!error_printed) {
>> + error_report("TPM error code from command "
>> + "cancellation of CUSE TPM: 0x%x", res);
>> + error_printed = true;
>> + }
> ...so declare it as one.
Ok.
>
>
>> +++ b/qapi-schema.json
>> @@ -2974,10 +2974,11 @@
>> # An enumeration of TPM types
>> #
>> # @passthrough: TPM passthrough type
>> +# @cuse-tpm: CUSE TPM type
> Missing '(since 2.4)' designator.
>
Definitely.
Thanks!
Stefan
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM
2015-05-26 21:33 [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Stefan Berger
` (5 preceding siblings ...)
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 6/6] Add support for VM suspend/resume for TPM TIS Stefan Berger
@ 2015-05-31 18:11 ` Michael S. Tsirkin
2015-06-02 13:17 ` Stefan Berger
6 siblings, 1 reply; 25+ messages in thread
From: Michael S. Tsirkin @ 2015-05-31 18:11 UTC (permalink / raw)
To: Stefan Berger; +Cc: imammedo, qemu-devel, quan.xu
On Tue, May 26, 2015 at 05:33:38PM -0400, Stefan Berger wrote:
> The following series of patches extends TPM support with an
> external TPM that offers a Linux CUSE (character device in userspace)
> interface. This TPM lets each VM access its own private vTPM.
> The CUSE TPM supports suspend/resume and migration. Much
> out-of-band functionality necessary to control the CUSE TPM is
> implemented using ioctl's.
>
> The series extends the TPM support so far that most functionality of
> TPM support on a physical platform is now available to each x86 VM,
> this includes the Physical Presence Interface support that has
> its counter-part in the SeaBIOS and is implemented using ACPI.
So I'm waiting for v4 of this with Eric's comments addressed?
> Stefan Berger (6):
> Provide support for the CUSE TPM
> Introduce RAM location in vendor specific area in TIS
> Support Physical Presence Interface Spec
> Introduce condition to notifiy waiters of completed command
> Introduce condition in TPM backend for notification
> Add support for VM suspend/resume for TPM TIS
>
> hmp.c | 6 +
> hw/i386/ssdt-tpm-common.dsl | 182 ++++++++++++++
> hw/i386/ssdt-tpm.dsl | 1 +
> hw/i386/ssdt-tpm.hex.generated | 540 +++++++++++++++++++++++++++++++++++++++-
> hw/i386/ssdt-tpm2.dsl | 1 +
> hw/i386/ssdt-tpm2.hex.generated | 516 +++++++++++++++++++++++++++++++++++++-
> hw/tpm/tpm_int.h | 4 +
> hw/tpm/tpm_ioctl.h | 178 +++++++++++++
> hw/tpm/tpm_passthrough.c | 423 ++++++++++++++++++++++++++++++-
> hw/tpm/tpm_tis.c | 180 +++++++++++++-
> hw/tpm/tpm_tis.h | 4 +
> hw/tpm/tpm_util.c | 206 +++++++++++++++
> hw/tpm/tpm_util.h | 7 +
> include/hw/acpi/tpm.h | 19 ++
> include/sysemu/tpm_backend.h | 12 +
> qapi-schema.json | 17 +-
> qemu-options.hx | 21 +-
> qmp-commands.hx | 2 +-
> tpm.c | 11 +-
> 19 files changed, 2298 insertions(+), 32 deletions(-)
> create mode 100644 hw/tpm/tpm_ioctl.h
>
> --
> 1.9.3
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 4/6] Introduce condition to notifiy waiters of completed command
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 4/6] Introduce condition to notifiy waiters of completed command Stefan Berger
@ 2015-05-31 18:11 ` Michael S. Tsirkin
0 siblings, 0 replies; 25+ messages in thread
From: Michael S. Tsirkin @ 2015-05-31 18:11 UTC (permalink / raw)
To: Stefan Berger; +Cc: imammedo, qemu-devel, quan.xu
Typo in subject.
On Tue, May 26, 2015 at 05:33:42PM -0400, Stefan Berger wrote:
> Introduce a lock and a condition to notify anyone waiting for the completion
> of the execution of a TPM command by the backend (thread). The backend
> uses the condition to signal anyone waiting for command completion.
> We need to place the condition in two locations: one is invoked by the
> backend thread, the other by the bottom half thread.
> We will use the signalling to wait for command completion before VM
> suspend.
>
> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> ---
> hw/tpm/tpm_int.h | 3 +++
> hw/tpm/tpm_tis.c | 14 ++++++++++++++
> 2 files changed, 17 insertions(+)
>
> diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
> index 6b2c9c9..70be1ad 100644
> --- a/hw/tpm/tpm_int.h
> +++ b/hw/tpm/tpm_int.h
> @@ -30,6 +30,9 @@ struct TPMState {
> char *backend;
> TPMBackend *be_driver;
> TPMVersion be_tpm_version;
> +
> + QemuMutex state_lock;
> + QemuCond cmd_complete;
> };
>
> #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
> diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
> index 1fb4e17..f278e1e 100644
> --- a/hw/tpm/tpm_tis.c
> +++ b/hw/tpm/tpm_tis.c
> @@ -367,6 +367,8 @@ static void tpm_tis_receive_bh(void *opaque)
> TPMTISEmuState *tis = &s->s.tis;
> uint8_t locty = s->locty_number;
>
> + qemu_mutex_lock(&s->state_lock);
> +
> tpm_tis_sts_set(&tis->loc[locty],
> TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
> tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
> @@ -383,6 +385,10 @@ static void tpm_tis_receive_bh(void *opaque)
> tpm_tis_raise_irq(s, locty,
> TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
> #endif
> +
> + /* notify of completed command */
> + qemu_cond_signal(&s->cmd_complete);
> + qemu_mutex_unlock(&s->state_lock);
> }
>
> /*
> @@ -402,6 +408,11 @@ static void tpm_tis_receive_cb(TPMState *s, uint8_t locty,
> }
> }
>
> + qemu_mutex_lock(&s->state_lock);
> + /* notify of completed command */
> + qemu_cond_signal(&s->cmd_complete);
> + qemu_mutex_unlock(&s->state_lock);
> +
> qemu_bh_schedule(tis->bh);
> }
>
> @@ -1097,6 +1108,9 @@ static void tpm_tis_initfn(Object *obj)
> memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
> s, "tpm-tis-mmio",
> TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
> +
> + qemu_mutex_init(&s->state_lock);
> + qemu_cond_init(&s->cmd_complete);
> }
>
> static void tpm_tis_class_init(ObjectClass *klass, void *data)
> --
> 1.9.3
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec Stefan Berger
@ 2015-05-31 18:11 ` Michael S. Tsirkin
2015-06-02 3:11 ` Stefan Berger
0 siblings, 1 reply; 25+ messages in thread
From: Michael S. Tsirkin @ 2015-05-31 18:11 UTC (permalink / raw)
To: Stefan Berger; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On Tue, May 26, 2015 at 05:33:41PM -0400, Stefan Berger wrote:
> For automated management of a TPM device, implement the TCG Physical Presence
> Interface Specification that allows a root user on Linux (for example) to set
> an opcode for a sequence of TPM operations that the BIOS is supposed to execute
> upon reboot of the physical or virtual machine. A sequence of operations may for
> example involve giving up ownership of the TPM and activating and enabling the
> device.
>
> The sequences of operations are defined in table 2 in the specs to be found
> at the following link:
>
> http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
>
> As an example, in recent versions of Linux the opcode (5) can be set as
> follows:
>
> cd /sys/devices/pnp0/00\:04/ppi
>
> echo 5 > request
>
> This ACPI implementation assumes that the underlying firmware (SeaBIOS)
> has 'thrown an anchor' into the f-segment. The anchor is identified by
> two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
> in the f-segment is write-protected and holds a pointer to a structure
> in high memmory
memory
> area where the ACPI code writes the opcode into and
> where it can read the last response from the BIOS.
>
> The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
> Also '0' is supported to 'clear' an intention.
>
>
No need for 2 empty spaces.
> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> Cc: Michael Tsirkin <mst@redhat.com>
> Cc: Kevin O'Connor <kevin@koconnor.net>
All this seems somewhat messy. Is this FSEG trick what the spec says,
or is this a QEMU specific protocol?
Would DataTableRegion not be a better way to locate things in
memory?
> ---
>
> v3->v4:
> - consolidated code following Igor's suggestions
> - marked functions as Serialized
> - added .hex.generated files
> ---
> hw/i386/ssdt-tpm-common.dsl | 182 ++++++++++++++
> hw/i386/ssdt-tpm.dsl | 1 +
> hw/i386/ssdt-tpm.hex.generated | 540 +++++++++++++++++++++++++++++++++++++++-
> hw/i386/ssdt-tpm2.dsl | 1 +
> hw/i386/ssdt-tpm2.hex.generated | 516 +++++++++++++++++++++++++++++++++++++-
> include/hw/acpi/tpm.h | 19 ++
> 6 files changed, 1245 insertions(+), 14 deletions(-)
>
> diff --git a/hw/i386/ssdt-tpm-common.dsl b/hw/i386/ssdt-tpm-common.dsl
> index 9da4970..81d6757 100644
> --- a/hw/i386/ssdt-tpm-common.dsl
> +++ b/hw/i386/ssdt-tpm-common.dsl
> @@ -32,5 +32,187 @@
> Method (_STA, 0, NotSerialized) {
> Return (0x0F)
> }
> +
> + OperationRegion (TTIS, SystemMemory,
> + TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE)
> +
> + // Define TPM Debug register
> + Field(TTIS, AnyAcc, NoLock, Preserve) {
> + Offset (0xf90),
> + TDBG, 32 // QEMU TIS Debug
> + }
> +
> + // Last accepted opcode
> + NAME(OP, Zero)
> +
> + // The base address in TIS 'RAM' where we exchange
> + // data with the BIOS lies at 0xfed40fa0
> + OperationRegion (HIGH, SystemMemory, 0xfed40fa0, TPM_PPI_STRUCT_SIZE)
> +
> + // Write given opcode into 'RAM'
> + Method (WRAM, 1, Serialized) {
> + Field(HIGH, AnyAcc, NoLock, Preserve) {
> + SIG1, 32,
> + SIZE, 16,
> + CODE, 8
> + }
> + If (LAnd(
> + LEqual(SIG1, TCG_MAGIC),
> + LGreaterEqual(SIZE, 1))
> + ) {
> + // Write opcode for BIOS to find
> + Store(Arg0, CODE)
> + // Remember last opcode in CODE
> + Store(Arg0, OP)
> + Return ( 0 )
> + }
> + Return ( 1 )
> + }
> +
> + // read data from 'RAM'
> + Method (RRAM, 0, Serialized) {
> + Name (OPRE, Package(3) { 1, 0, 0})
> +
> + Field(HIGH, AnyAcc, NoLock, Preserve) {
> + SIG1, 32,
> + SIZE, 16,
> + CODE, 8,
> + SUCC, 8,
> + CODO, 8,
> + RESP, 32
> + }
> + // Check signature and sufficient space
> + If (LAnd(
> + LEqual(SIG1, TCG_MAGIC),
> + LGreaterEqual(SIZE, 7)
> + )) {
> + Store(SUCC, Index(OPRE, 0))
> + Store(CODO, Index(OPRE, 1))
> + Store(RESP, Index(OPRE, 2))
> + }
> + return (OPRE)
> + }
> +
> +#ifdef TPM_1_2
> + // check for supported opcode
> + // supported opcodes: 0, 1-11, 14, 21-22
> + Method (CKOP, 1, NotSerialized) {
> + If (LOr(
> + LOr(
> + LAnd(
> + LGreaterEqual(Arg0, 0),
> + LLessEqual(Arg0, 11)
> + ),
> + LEqual(Arg0, 14)
> + ),
> + LAnd(
> + LGreaterEqual(Arg0, 21),
> + LLessEqual(Arg0, 22)
> + )
> + )) {
> + return (1)
> + } else {
> + return (0)
> + }
> + }
> +#else
> +# ifdef TPM_2_0
> + // check for supported opcode
> + // supported opcodes: 0
> + Method (CKOP, 1, NotSerialized) {
> + If (LEqual(Arg0, 0)) {
> + return (1)
> + } else {
> + return (0)
> + }
> + }
> +# endif
> +#endif
> +
> + Method (_DSM, 4, Serialized) {
> + If (LEqual (Arg0, ToUUID("3DDDFAA6-361B-4EB4-A424-8D10089D1653"))) {
> +
> + // only supporting API revision 1
> + If (LNotEqual (Arg1, 1)) {
> + Return (Buffer (1) {0})
> + }
> +
> + Store(ToInteger(Arg2), Local0)
> + // standard DSM query function
> + If (LEqual (Local0, 0)) {
> + Return (Buffer () {0xFF, 0x01})
> + }
> +
> + // interface version
> + If (LEqual (Local0, 1)) {
> + Return ("1.2")
> + }
> +
> + // submit TPM operation
> + If (LEqual (Local0, 2)) {
> + // get opcode from package
> + Store(DerefOf(Index(Arg3, 0)), Local0)
> +
> + If (CKOP( Local0 ) ) {
> + // Write the OP into TPM NVRAM
> + Store(WRAM ( Local0 ), Local1)
> + return (Local1)
> + } else {
> + Return (1)
> + }
> + }
> +
> + // get pending TPM operation
> + If (LEqual (Local0, 3)) {
> + NAME(PEOP, Package(2) { 0, 0 })
> +
> + Store ( 0 , Index(PEOP, 0))
> + Store ( OP, Index(PEOP, 1))
> +
> + Return (PEOP)
> + }
> +
> + // action to transition to pre-OS env.
> + If (LEqual (Local0, 4)) {
> + return (2) // Requiring reboot
> + }
> +
> + // get pre-OS TPM operation response
> + If (LEqual (Local0, 5)) {
> + Store (RRAM(), Local0)
> + return ( Local0 )
> + }
> +
> + // preferred user language
> + If (LEqual (Local0, 6)) {
> + return (3) // Not implemented
> + }
> +
> + // submit TPM operation v2
> + If (LEqual (Local0, 7)) {
> + Store(DerefOf(Index(Arg3, 0)), Local0)
> +
> + If (CKOP( Local0 )) {
> + // Write the OP into TPM NVRAM
> + Store(WRAM ( Local0 ), Local1)
> + return (Local1)
> + } else {
> + Return (1)
> + }
> + }
> +
> + // get user confirmation status
> + If (LEqual (Local0, 8)) {
> + Store(DerefOf(Index(Arg3,0)), Local0)
> +
> + if (CKOP( Local0 )) {
> + Return (4) // allowed, no user required
> + } else {
> + Return (0) // not implemented
> + }
> + }
> + }
> + return (Buffer() { 0x0 })
> + }
> }
> }
> diff --git a/hw/i386/ssdt-tpm.dsl b/hw/i386/ssdt-tpm.dsl
> index d81478c..48bf112 100644
> --- a/hw/i386/ssdt-tpm.dsl
> +++ b/hw/i386/ssdt-tpm.dsl
> @@ -25,5 +25,6 @@ DefinitionBlock (
> 0x1 // OEM Revision
> )
> {
> +#define TPM_1_2
> #include "ssdt-tpm-common.dsl"
> }
> diff --git a/hw/i386/ssdt-tpm.hex.generated b/hw/i386/ssdt-tpm.hex.generated
> index 874418c..db1d31d 100644
> --- a/hw/i386/ssdt-tpm.hex.generated
> +++ b/hw/i386/ssdt-tpm.hex.generated
> @@ -3,12 +3,12 @@ static unsigned char ssdt_tpm_aml[] = {
> 0x53,
> 0x44,
> 0x54,
> -0x6b,
> -0x0,
> +0x79,
> +0x2,
> 0x0,
> 0x0,
> 0x1,
> -0x37,
> +0xea,
> 0x42,
> 0x58,
> 0x50,
> @@ -36,8 +36,8 @@ static unsigned char ssdt_tpm_aml[] = {
> 0x14,
> 0x20,
> 0x10,
> -0x46,
> -0x4,
> +0x44,
> +0x25,
> 0x5c,
> 0x2f,
> 0x3,
> @@ -55,7 +55,8 @@ static unsigned char ssdt_tpm_aml[] = {
> 0x5f,
> 0x5b,
> 0x82,
> -0x33,
> +0x41,
> +0x24,
> 0x54,
> 0x50,
> 0x4d,
> @@ -105,5 +106,530 @@ static unsigned char ssdt_tpm_aml[] = {
> 0x0,
> 0xa4,
> 0xa,
> -0xf
> +0xf,
> +0x5b,
> +0x80,
> +0x54,
> +0x54,
> +0x49,
> +0x53,
> +0x0,
> +0xc,
> +0x0,
> +0x0,
> +0xd4,
> +0xfe,
> +0xb,
> +0x0,
> +0x50,
> +0x5b,
> +0x81,
> +0xf,
> +0x54,
> +0x54,
> +0x49,
> +0x53,
> +0x0,
> +0x0,
> +0x80,
> +0xc8,
> +0x7,
> +0x54,
> +0x44,
> +0x42,
> +0x47,
> +0x20,
> +0x8,
> +0x4f,
> +0x50,
> +0x5f,
> +0x5f,
> +0x0,
> +0x5b,
> +0x80,
> +0x48,
> +0x49,
> +0x47,
> +0x48,
> +0x0,
> +0xc,
> +0xa0,
> +0xf,
> +0xd4,
> +0xfe,
> +0xa,
> +0xe,
> +0x14,
> +0x42,
> +0x4,
> +0x57,
> +0x52,
> +0x41,
> +0x4d,
> +0x9,
> +0x5b,
> +0x81,
> +0x15,
> +0x48,
> +0x49,
> +0x47,
> +0x48,
> +0x0,
> +0x53,
> +0x49,
> +0x47,
> +0x31,
> +0x20,
> +0x53,
> +0x49,
> +0x5a,
> +0x45,
> +0x10,
> +0x43,
> +0x4f,
> +0x44,
> +0x45,
> +0x8,
> +0xa0,
> +0x21,
> +0x90,
> +0x93,
> +0x53,
> +0x49,
> +0x47,
> +0x31,
> +0xc,
> +0x54,
> +0x43,
> +0x50,
> +0x41,
> +0x92,
> +0x95,
> +0x53,
> +0x49,
> +0x5a,
> +0x45,
> +0x1,
> +0x70,
> +0x68,
> +0x43,
> +0x4f,
> +0x44,
> +0x45,
> +0x70,
> +0x68,
> +0x4f,
> +0x50,
> +0x5f,
> +0x5f,
> +0xa4,
> +0x0,
> +0xa4,
> +0x1,
> +0x14,
> +0x47,
> +0x7,
> +0x52,
> +0x52,
> +0x41,
> +0x4d,
> +0x8,
> +0x8,
> +0x4f,
> +0x50,
> +0x52,
> +0x45,
> +0x12,
> +0x5,
> +0x3,
> +0x1,
> +0x0,
> +0x0,
> +0x5b,
> +0x81,
> +0x24,
> +0x48,
> +0x49,
> +0x47,
> +0x48,
> +0x0,
> +0x53,
> +0x49,
> +0x47,
> +0x31,
> +0x20,
> +0x53,
> +0x49,
> +0x5a,
> +0x45,
> +0x10,
> +0x43,
> +0x4f,
> +0x44,
> +0x45,
> +0x8,
> +0x53,
> +0x55,
> +0x43,
> +0x43,
> +0x8,
> +0x43,
> +0x4f,
> +0x44,
> +0x4f,
> +0x8,
> +0x52,
> +0x45,
> +0x53,
> +0x50,
> +0x20,
> +0xa0,
> +0x39,
> +0x90,
> +0x93,
> +0x53,
> +0x49,
> +0x47,
> +0x31,
> +0xc,
> +0x54,
> +0x43,
> +0x50,
> +0x41,
> +0x92,
> +0x95,
> +0x53,
> +0x49,
> +0x5a,
> +0x45,
> +0xa,
> +0x7,
> +0x70,
> +0x53,
> +0x55,
> +0x43,
> +0x43,
> +0x88,
> +0x4f,
> +0x50,
> +0x52,
> +0x45,
> +0x0,
> +0x0,
> +0x70,
> +0x43,
> +0x4f,
> +0x44,
> +0x4f,
> +0x88,
> +0x4f,
> +0x50,
> +0x52,
> +0x45,
> +0x1,
> +0x0,
> +0x70,
> +0x52,
> +0x45,
> +0x53,
> +0x50,
> +0x88,
> +0x4f,
> +0x50,
> +0x52,
> +0x45,
> +0xa,
> +0x2,
> +0x0,
> +0xa4,
> +0x4f,
> +0x50,
> +0x52,
> +0x45,
> +0x14,
> +0x29,
> +0x43,
> +0x4b,
> +0x4f,
> +0x50,
> +0x1,
> +0xa0,
> +0x1e,
> +0x91,
> +0x91,
> +0x90,
> +0x92,
> +0x95,
> +0x68,
> +0x0,
> +0x92,
> +0x94,
> +0x68,
> +0xa,
> +0xb,
> +0x93,
> +0x68,
> +0xa,
> +0xe,
> +0x90,
> +0x92,
> +0x95,
> +0x68,
> +0xa,
> +0x15,
> +0x92,
> +0x94,
> +0x68,
> +0xa,
> +0x16,
> +0xa4,
> +0x1,
> +0xa1,
> +0x3,
> +0xa4,
> +0x0,
> +0x14,
> +0x43,
> +0xf,
> +0x5f,
> +0x44,
> +0x53,
> +0x4d,
> +0xc,
> +0xa0,
> +0x46,
> +0xe,
> +0x93,
> +0x68,
> +0x11,
> +0x13,
> +0xa,
> +0x10,
> +0xa6,
> +0xfa,
> +0xdd,
> +0x3d,
> +0x1b,
> +0x36,
> +0xb4,
> +0x4e,
> +0xa4,
> +0x24,
> +0x8d,
> +0x10,
> +0x8,
> +0x9d,
> +0x16,
> +0x53,
> +0xa0,
> +0xa,
> +0x92,
> +0x93,
> +0x69,
> +0x1,
> +0xa4,
> +0x11,
> +0x3,
> +0x1,
> +0x0,
> +0x70,
> +0x99,
> +0x6a,
> +0x0,
> +0x60,
> +0xa0,
> +0xb,
> +0x93,
> +0x60,
> +0x0,
> +0xa4,
> +0x11,
> +0x5,
> +0xa,
> +0x2,
> +0xff,
> +0x1,
> +0xa0,
> +0xa,
> +0x93,
> +0x60,
> +0x1,
> +0xa4,
> +0xd,
> +0x31,
> +0x2e,
> +0x32,
> +0x0,
> +0xa0,
> +0x20,
> +0x93,
> +0x60,
> +0xa,
> +0x2,
> +0x70,
> +0x83,
> +0x88,
> +0x6b,
> +0x0,
> +0x0,
> +0x60,
> +0xa0,
> +0xf,
> +0x43,
> +0x4b,
> +0x4f,
> +0x50,
> +0x60,
> +0x70,
> +0x57,
> +0x52,
> +0x41,
> +0x4d,
> +0x60,
> +0x61,
> +0xa4,
> +0x61,
> +0xa1,
> +0x3,
> +0xa4,
> +0x1,
> +0xa0,
> +0x29,
> +0x93,
> +0x60,
> +0xa,
> +0x3,
> +0x8,
> +0x50,
> +0x45,
> +0x4f,
> +0x50,
> +0x12,
> +0x4,
> +0x2,
> +0x0,
> +0x0,
> +0x70,
> +0x0,
> +0x88,
> +0x50,
> +0x45,
> +0x4f,
> +0x50,
> +0x0,
> +0x0,
> +0x70,
> +0x4f,
> +0x50,
> +0x5f,
> +0x5f,
> +0x88,
> +0x50,
> +0x45,
> +0x4f,
> +0x50,
> +0x1,
> +0x0,
> +0xa4,
> +0x50,
> +0x45,
> +0x4f,
> +0x50,
> +0xa0,
> +0x8,
> +0x93,
> +0x60,
> +0xa,
> +0x4,
> +0xa4,
> +0xa,
> +0x2,
> +0xa0,
> +0xd,
> +0x93,
> +0x60,
> +0xa,
> +0x5,
> +0x70,
> +0x52,
> +0x52,
> +0x41,
> +0x4d,
> +0x60,
> +0xa4,
> +0x60,
> +0xa0,
> +0x8,
> +0x93,
> +0x60,
> +0xa,
> +0x6,
> +0xa4,
> +0xa,
> +0x3,
> +0xa0,
> +0x20,
> +0x93,
> +0x60,
> +0xa,
> +0x7,
> +0x70,
> +0x83,
> +0x88,
> +0x6b,
> +0x0,
> +0x0,
> +0x60,
> +0xa0,
> +0xf,
> +0x43,
> +0x4b,
> +0x4f,
> +0x50,
> +0x60,
> +0x70,
> +0x57,
> +0x52,
> +0x41,
> +0x4d,
> +0x60,
> +0x61,
> +0xa4,
> +0x61,
> +0xa1,
> +0x3,
> +0xa4,
> +0x1,
> +0xa0,
> +0x1a,
> +0x93,
> +0x60,
> +0xa,
> +0x8,
> +0x70,
> +0x83,
> +0x88,
> +0x6b,
> +0x0,
> +0x0,
> +0x60,
> +0xa0,
> +0x9,
> +0x43,
> +0x4b,
> +0x4f,
> +0x50,
> +0x60,
> +0xa4,
> +0xa,
> +0x4,
> +0xa1,
> +0x3,
> +0xa4,
> +0x0,
> +0xa4,
> +0x11,
> +0x3,
> +0x1,
> +0x0
> };
> diff --git a/hw/i386/ssdt-tpm2.dsl b/hw/i386/ssdt-tpm2.dsl
> index 58bbbf8..29228a0 100644
> --- a/hw/i386/ssdt-tpm2.dsl
> +++ b/hw/i386/ssdt-tpm2.dsl
> @@ -25,5 +25,6 @@ DefinitionBlock (
> 0x1 // OEM Revision
> )
> {
> +#define TPM_2_0
> #include "ssdt-tpm-common.dsl"
> }
> diff --git a/hw/i386/ssdt-tpm2.hex.generated b/hw/i386/ssdt-tpm2.hex.generated
> index 9ea8271..a685533 100644
> --- a/hw/i386/ssdt-tpm2.hex.generated
> +++ b/hw/i386/ssdt-tpm2.hex.generated
> @@ -3,12 +3,12 @@ static unsigned char ssdt_tpm2_aml[] = {
> 0x53,
> 0x44,
> 0x54,
> -0x6b,
> -0x0,
> +0x61,
> +0x2,
> 0x0,
> 0x0,
> 0x1,
> -0x37,
> +0xe,
> 0x42,
> 0x58,
> 0x50,
> @@ -36,8 +36,8 @@ static unsigned char ssdt_tpm2_aml[] = {
> 0x14,
> 0x20,
> 0x10,
> -0x46,
> -0x4,
> +0x4c,
> +0x23,
> 0x5c,
> 0x2f,
> 0x3,
> @@ -55,7 +55,8 @@ static unsigned char ssdt_tpm2_aml[] = {
> 0x5f,
> 0x5b,
> 0x82,
> -0x33,
> +0x49,
> +0x22,
> 0x54,
> 0x50,
> 0x4d,
> @@ -105,5 +106,506 @@ static unsigned char ssdt_tpm2_aml[] = {
> 0x0,
> 0xa4,
> 0xa,
> -0xf
> +0xf,
> +0x5b,
> +0x80,
> +0x54,
> +0x54,
> +0x49,
> +0x53,
> +0x0,
> +0xc,
> +0x0,
> +0x0,
> +0xd4,
> +0xfe,
> +0xb,
> +0x0,
> +0x50,
> +0x5b,
> +0x81,
> +0xf,
> +0x54,
> +0x54,
> +0x49,
> +0x53,
> +0x0,
> +0x0,
> +0x80,
> +0xc8,
> +0x7,
> +0x54,
> +0x44,
> +0x42,
> +0x47,
> +0x20,
> +0x8,
> +0x4f,
> +0x50,
> +0x5f,
> +0x5f,
> +0x0,
> +0x5b,
> +0x80,
> +0x48,
> +0x49,
> +0x47,
> +0x48,
> +0x0,
> +0xc,
> +0xa0,
> +0xf,
> +0xd4,
> +0xfe,
> +0xa,
> +0xe,
> +0x14,
> +0x42,
> +0x4,
> +0x57,
> +0x52,
> +0x41,
> +0x4d,
> +0x9,
> +0x5b,
> +0x81,
> +0x15,
> +0x48,
> +0x49,
> +0x47,
> +0x48,
> +0x0,
> +0x53,
> +0x49,
> +0x47,
> +0x31,
> +0x20,
> +0x53,
> +0x49,
> +0x5a,
> +0x45,
> +0x10,
> +0x43,
> +0x4f,
> +0x44,
> +0x45,
> +0x8,
> +0xa0,
> +0x21,
> +0x90,
> +0x93,
> +0x53,
> +0x49,
> +0x47,
> +0x31,
> +0xc,
> +0x54,
> +0x43,
> +0x50,
> +0x41,
> +0x92,
> +0x95,
> +0x53,
> +0x49,
> +0x5a,
> +0x45,
> +0x1,
> +0x70,
> +0x68,
> +0x43,
> +0x4f,
> +0x44,
> +0x45,
> +0x70,
> +0x68,
> +0x4f,
> +0x50,
> +0x5f,
> +0x5f,
> +0xa4,
> +0x0,
> +0xa4,
> +0x1,
> +0x14,
> +0x47,
> +0x7,
> +0x52,
> +0x52,
> +0x41,
> +0x4d,
> +0x8,
> +0x8,
> +0x4f,
> +0x50,
> +0x52,
> +0x45,
> +0x12,
> +0x5,
> +0x3,
> +0x1,
> +0x0,
> +0x0,
> +0x5b,
> +0x81,
> +0x24,
> +0x48,
> +0x49,
> +0x47,
> +0x48,
> +0x0,
> +0x53,
> +0x49,
> +0x47,
> +0x31,
> +0x20,
> +0x53,
> +0x49,
> +0x5a,
> +0x45,
> +0x10,
> +0x43,
> +0x4f,
> +0x44,
> +0x45,
> +0x8,
> +0x53,
> +0x55,
> +0x43,
> +0x43,
> +0x8,
> +0x43,
> +0x4f,
> +0x44,
> +0x4f,
> +0x8,
> +0x52,
> +0x45,
> +0x53,
> +0x50,
> +0x20,
> +0xa0,
> +0x39,
> +0x90,
> +0x93,
> +0x53,
> +0x49,
> +0x47,
> +0x31,
> +0xc,
> +0x54,
> +0x43,
> +0x50,
> +0x41,
> +0x92,
> +0x95,
> +0x53,
> +0x49,
> +0x5a,
> +0x45,
> +0xa,
> +0x7,
> +0x70,
> +0x53,
> +0x55,
> +0x43,
> +0x43,
> +0x88,
> +0x4f,
> +0x50,
> +0x52,
> +0x45,
> +0x0,
> +0x0,
> +0x70,
> +0x43,
> +0x4f,
> +0x44,
> +0x4f,
> +0x88,
> +0x4f,
> +0x50,
> +0x52,
> +0x45,
> +0x1,
> +0x0,
> +0x70,
> +0x52,
> +0x45,
> +0x53,
> +0x50,
> +0x88,
> +0x4f,
> +0x50,
> +0x52,
> +0x45,
> +0xa,
> +0x2,
> +0x0,
> +0xa4,
> +0x4f,
> +0x50,
> +0x52,
> +0x45,
> +0x14,
> +0x11,
> +0x43,
> +0x4b,
> +0x4f,
> +0x50,
> +0x1,
> +0xa0,
> +0x6,
> +0x93,
> +0x68,
> +0x0,
> +0xa4,
> +0x1,
> +0xa1,
> +0x3,
> +0xa4,
> +0x0,
> +0x14,
> +0x43,
> +0xf,
> +0x5f,
> +0x44,
> +0x53,
> +0x4d,
> +0xc,
> +0xa0,
> +0x46,
> +0xe,
> +0x93,
> +0x68,
> +0x11,
> +0x13,
> +0xa,
> +0x10,
> +0xa6,
> +0xfa,
> +0xdd,
> +0x3d,
> +0x1b,
> +0x36,
> +0xb4,
> +0x4e,
> +0xa4,
> +0x24,
> +0x8d,
> +0x10,
> +0x8,
> +0x9d,
> +0x16,
> +0x53,
> +0xa0,
> +0xa,
> +0x92,
> +0x93,
> +0x69,
> +0x1,
> +0xa4,
> +0x11,
> +0x3,
> +0x1,
> +0x0,
> +0x70,
> +0x99,
> +0x6a,
> +0x0,
> +0x60,
> +0xa0,
> +0xb,
> +0x93,
> +0x60,
> +0x0,
> +0xa4,
> +0x11,
> +0x5,
> +0xa,
> +0x2,
> +0xff,
> +0x1,
> +0xa0,
> +0xa,
> +0x93,
> +0x60,
> +0x1,
> +0xa4,
> +0xd,
> +0x31,
> +0x2e,
> +0x32,
> +0x0,
> +0xa0,
> +0x20,
> +0x93,
> +0x60,
> +0xa,
> +0x2,
> +0x70,
> +0x83,
> +0x88,
> +0x6b,
> +0x0,
> +0x0,
> +0x60,
> +0xa0,
> +0xf,
> +0x43,
> +0x4b,
> +0x4f,
> +0x50,
> +0x60,
> +0x70,
> +0x57,
> +0x52,
> +0x41,
> +0x4d,
> +0x60,
> +0x61,
> +0xa4,
> +0x61,
> +0xa1,
> +0x3,
> +0xa4,
> +0x1,
> +0xa0,
> +0x29,
> +0x93,
> +0x60,
> +0xa,
> +0x3,
> +0x8,
> +0x50,
> +0x45,
> +0x4f,
> +0x50,
> +0x12,
> +0x4,
> +0x2,
> +0x0,
> +0x0,
> +0x70,
> +0x0,
> +0x88,
> +0x50,
> +0x45,
> +0x4f,
> +0x50,
> +0x0,
> +0x0,
> +0x70,
> +0x4f,
> +0x50,
> +0x5f,
> +0x5f,
> +0x88,
> +0x50,
> +0x45,
> +0x4f,
> +0x50,
> +0x1,
> +0x0,
> +0xa4,
> +0x50,
> +0x45,
> +0x4f,
> +0x50,
> +0xa0,
> +0x8,
> +0x93,
> +0x60,
> +0xa,
> +0x4,
> +0xa4,
> +0xa,
> +0x2,
> +0xa0,
> +0xd,
> +0x93,
> +0x60,
> +0xa,
> +0x5,
> +0x70,
> +0x52,
> +0x52,
> +0x41,
> +0x4d,
> +0x60,
> +0xa4,
> +0x60,
> +0xa0,
> +0x8,
> +0x93,
> +0x60,
> +0xa,
> +0x6,
> +0xa4,
> +0xa,
> +0x3,
> +0xa0,
> +0x20,
> +0x93,
> +0x60,
> +0xa,
> +0x7,
> +0x70,
> +0x83,
> +0x88,
> +0x6b,
> +0x0,
> +0x0,
> +0x60,
> +0xa0,
> +0xf,
> +0x43,
> +0x4b,
> +0x4f,
> +0x50,
> +0x60,
> +0x70,
> +0x57,
> +0x52,
> +0x41,
> +0x4d,
> +0x60,
> +0x61,
> +0xa4,
> +0x61,
> +0xa1,
> +0x3,
> +0xa4,
> +0x1,
> +0xa0,
> +0x1a,
> +0x93,
> +0x60,
> +0xa,
> +0x8,
> +0x70,
> +0x83,
> +0x88,
> +0x6b,
> +0x0,
> +0x0,
> +0x60,
> +0xa0,
> +0x9,
> +0x43,
> +0x4b,
> +0x4f,
> +0x50,
> +0x60,
> +0xa4,
> +0xa,
> +0x4,
> +0xa1,
> +0x3,
> +0xa4,
> +0x0,
> +0xa4,
> +0x11,
> +0x3,
> +0x1,
> +0x0
> };
> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> index 6d516c6..4437543 100644
> --- a/include/hw/acpi/tpm.h
> +++ b/include/hw/acpi/tpm.h
> @@ -31,4 +31,23 @@
>
> #define TPM2_START_METHOD_MMIO 6
>
> +/*
> + * Physical Presence Interface -- shared with the BIOS
> + */
> +#define TCG_MAGIC 0x41504354
> +
> +#if 0
> +struct tpm_ppi {
coding style violation.
> + uint32_t sign; // TCG_MAGIC
> + uint16_t size; // number of subsequent bytes for ACPI to access
> + uint8_t opcode; // set by ACPI
> + uint8_t failure; // set by BIOS (0 = success)
> + uint8_t recent_opcode; // set by BIOS
> + uint32_t response; // set by BIOS
> + uint8_t next_step; // BIOS only
> +} QEMU_PACKED;
> +#endif
> +
> +#define TPM_PPI_STRUCT_SIZE 14
> +
> #endif /* HW_ACPI_TPM_H */
> --
> 1.9.3
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-05-31 18:11 ` Michael S. Tsirkin
@ 2015-06-02 3:11 ` Stefan Berger
2015-06-02 9:15 ` Michael S. Tsirkin
0 siblings, 1 reply; 25+ messages in thread
From: Stefan Berger @ 2015-06-02 3:11 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On 05/31/2015 02:11 PM, Michael S. Tsirkin wrote:
> On Tue, May 26, 2015 at 05:33:41PM -0400, Stefan Berger wrote:
>> For automated management of a TPM device, implement the TCG Physical Presence
>> Interface Specification that allows a root user on Linux (for example) to set
>> an opcode for a sequence of TPM operations that the BIOS is supposed to execute
>> upon reboot of the physical or virtual machine. A sequence of operations may for
>> example involve giving up ownership of the TPM and activating and enabling the
>> device.
>>
>> The sequences of operations are defined in table 2 in the specs to be found
>> at the following link:
>>
>> http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
>>
>> As an example, in recent versions of Linux the opcode (5) can be set as
>> follows:
>>
>> cd /sys/devices/pnp0/00\:04/ppi
>>
>> echo 5 > request
>>
>> This ACPI implementation assumes that the underlying firmware (SeaBIOS)
>> has 'thrown an anchor' into the f-segment. The anchor is identified by
>> two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
>> in the f-segment is write-protected and holds a pointer to a structure
>> in high memmory
> memory
>
>> area where the ACPI code writes the opcode into and
>> where it can read the last response from the BIOS.
>>
>> The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
>> Also '0' is supported to 'clear' an intention.
>>
>>
> No need for 2 empty spaces.
>
>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>> Cc: Michael Tsirkin <mst@redhat.com>
>> Cc: Kevin O'Connor <kevin@koconnor.net>
> All this seems somewhat messy. Is this FSEG trick what the spec says,
> or is this a QEMU specific protocol?
Actually, the text in the patch is outdated. We now moved the area where
the data are exchanged between ACPI and BIOS into registers provided by
the TIS -- custom registers in an area that is vendor-specific, so yes,
this is a QEMU specific solution. The address range for this is fixed
and known to SeaBIOS and QEMU. Those registers also won't reset upon
machine reboot.
> Would DataTableRegion not be a better way to locate things in
> memory?
As I said, we now move that into a memory region provide by the TIS..
Otherwise I am not very familiar with DataTableRegion.
Thanks for the comments!
Stefan
>> ---
>>
>> v3->v4:
>> - consolidated code following Igor's suggestions
>> - marked functions as Serialized
>> - added .hex.generated files
>> ---
>> hw/i386/ssdt-tpm-common.dsl | 182 ++++++++++++++
>> hw/i386/ssdt-tpm.dsl | 1 +
>> hw/i386/ssdt-tpm.hex.generated | 540 +++++++++++++++++++++++++++++++++++++++-
>> hw/i386/ssdt-tpm2.dsl | 1 +
>> hw/i386/ssdt-tpm2.hex.generated | 516 +++++++++++++++++++++++++++++++++++++-
>> include/hw/acpi/tpm.h | 19 ++
>> 6 files changed, 1245 insertions(+), 14 deletions(-)
>>
>> diff --git a/hw/i386/ssdt-tpm-common.dsl b/hw/i386/ssdt-tpm-common.dsl
>> index 9da4970..81d6757 100644
>> --- a/hw/i386/ssdt-tpm-common.dsl
>> +++ b/hw/i386/ssdt-tpm-common.dsl
>> @@ -32,5 +32,187 @@
>> Method (_STA, 0, NotSerialized) {
>> Return (0x0F)
>> }
>> +
>> + OperationRegion (TTIS, SystemMemory,
>> + TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE)
>> +
>> + // Define TPM Debug register
>> + Field(TTIS, AnyAcc, NoLock, Preserve) {
>> + Offset (0xf90),
>> + TDBG, 32 // QEMU TIS Debug
>> + }
>> +
>> + // Last accepted opcode
>> + NAME(OP, Zero)
>> +
>> + // The base address in TIS 'RAM' where we exchange
>> + // data with the BIOS lies at 0xfed40fa0
>> + OperationRegion (HIGH, SystemMemory, 0xfed40fa0, TPM_PPI_STRUCT_SIZE)
>> +
>> + // Write given opcode into 'RAM'
>> + Method (WRAM, 1, Serialized) {
>> + Field(HIGH, AnyAcc, NoLock, Preserve) {
>> + SIG1, 32,
>> + SIZE, 16,
>> + CODE, 8
>> + }
>> + If (LAnd(
>> + LEqual(SIG1, TCG_MAGIC),
>> + LGreaterEqual(SIZE, 1))
>> + ) {
>> + // Write opcode for BIOS to find
>> + Store(Arg0, CODE)
>> + // Remember last opcode in CODE
>> + Store(Arg0, OP)
>> + Return ( 0 )
>> + }
>> + Return ( 1 )
>> + }
>> +
>> + // read data from 'RAM'
>> + Method (RRAM, 0, Serialized) {
>> + Name (OPRE, Package(3) { 1, 0, 0})
>> +
>> + Field(HIGH, AnyAcc, NoLock, Preserve) {
>> + SIG1, 32,
>> + SIZE, 16,
>> + CODE, 8,
>> + SUCC, 8,
>> + CODO, 8,
>> + RESP, 32
>> + }
>> + // Check signature and sufficient space
>> + If (LAnd(
>> + LEqual(SIG1, TCG_MAGIC),
>> + LGreaterEqual(SIZE, 7)
>> + )) {
>> + Store(SUCC, Index(OPRE, 0))
>> + Store(CODO, Index(OPRE, 1))
>> + Store(RESP, Index(OPRE, 2))
>> + }
>> + return (OPRE)
>> + }
>> +
>> +#ifdef TPM_1_2
>> + // check for supported opcode
>> + // supported opcodes: 0, 1-11, 14, 21-22
>> + Method (CKOP, 1, NotSerialized) {
>> + If (LOr(
>> + LOr(
>> + LAnd(
>> + LGreaterEqual(Arg0, 0),
>> + LLessEqual(Arg0, 11)
>> + ),
>> + LEqual(Arg0, 14)
>> + ),
>> + LAnd(
>> + LGreaterEqual(Arg0, 21),
>> + LLessEqual(Arg0, 22)
>> + )
>> + )) {
>> + return (1)
>> + } else {
>> + return (0)
>> + }
>> + }
>> +#else
>> +# ifdef TPM_2_0
>> + // check for supported opcode
>> + // supported opcodes: 0
>> + Method (CKOP, 1, NotSerialized) {
>> + If (LEqual(Arg0, 0)) {
>> + return (1)
>> + } else {
>> + return (0)
>> + }
>> + }
>> +# endif
>> +#endif
>> +
>> + Method (_DSM, 4, Serialized) {
>> + If (LEqual (Arg0, ToUUID("3DDDFAA6-361B-4EB4-A424-8D10089D1653"))) {
>> +
>> + // only supporting API revision 1
>> + If (LNotEqual (Arg1, 1)) {
>> + Return (Buffer (1) {0})
>> + }
>> +
>> + Store(ToInteger(Arg2), Local0)
>> + // standard DSM query function
>> + If (LEqual (Local0, 0)) {
>> + Return (Buffer () {0xFF, 0x01})
>> + }
>> +
>> + // interface version
>> + If (LEqual (Local0, 1)) {
>> + Return ("1.2")
>> + }
>> +
>> + // submit TPM operation
>> + If (LEqual (Local0, 2)) {
>> + // get opcode from package
>> + Store(DerefOf(Index(Arg3, 0)), Local0)
>> +
>> + If (CKOP( Local0 ) ) {
>> + // Write the OP into TPM NVRAM
>> + Store(WRAM ( Local0 ), Local1)
>> + return (Local1)
>> + } else {
>> + Return (1)
>> + }
>> + }
>> +
>> + // get pending TPM operation
>> + If (LEqual (Local0, 3)) {
>> + NAME(PEOP, Package(2) { 0, 0 })
>> +
>> + Store ( 0 , Index(PEOP, 0))
>> + Store ( OP, Index(PEOP, 1))
>> +
>> + Return (PEOP)
>> + }
>> +
>> + // action to transition to pre-OS env.
>> + If (LEqual (Local0, 4)) {
>> + return (2) // Requiring reboot
>> + }
>> +
>> + // get pre-OS TPM operation response
>> + If (LEqual (Local0, 5)) {
>> + Store (RRAM(), Local0)
>> + return ( Local0 )
>> + }
>> +
>> + // preferred user language
>> + If (LEqual (Local0, 6)) {
>> + return (3) // Not implemented
>> + }
>> +
>> + // submit TPM operation v2
>> + If (LEqual (Local0, 7)) {
>> + Store(DerefOf(Index(Arg3, 0)), Local0)
>> +
>> + If (CKOP( Local0 )) {
>> + // Write the OP into TPM NVRAM
>> + Store(WRAM ( Local0 ), Local1)
>> + return (Local1)
>> + } else {
>> + Return (1)
>> + }
>> + }
>> +
>> + // get user confirmation status
>> + If (LEqual (Local0, 8)) {
>> + Store(DerefOf(Index(Arg3,0)), Local0)
>> +
>> + if (CKOP( Local0 )) {
>> + Return (4) // allowed, no user required
>> + } else {
>> + Return (0) // not implemented
>> + }
>> + }
>> + }
>> + return (Buffer() { 0x0 })
>> + }
>> }
>> }
>> diff --git a/hw/i386/ssdt-tpm.dsl b/hw/i386/ssdt-tpm.dsl
>> index d81478c..48bf112 100644
>> --- a/hw/i386/ssdt-tpm.dsl
>> +++ b/hw/i386/ssdt-tpm.dsl
>> @@ -25,5 +25,6 @@ DefinitionBlock (
>> 0x1 // OEM Revision
>> )
>> {
>> +#define TPM_1_2
>> #include "ssdt-tpm-common.dsl"
>> }
>> diff --git a/hw/i386/ssdt-tpm.hex.generated b/hw/i386/ssdt-tpm.hex.generated
>> index 874418c..db1d31d 100644
>> --- a/hw/i386/ssdt-tpm.hex.generated
>> +++ b/hw/i386/ssdt-tpm.hex.generated
>> @@ -3,12 +3,12 @@ static unsigned char ssdt_tpm_aml[] = {
>> 0x53,
>> 0x44,
>> 0x54,
>> -0x6b,
>> -0x0,
>> +0x79,
>> +0x2,
>> 0x0,
>> 0x0,
>> 0x1,
>> -0x37,
>> +0xea,
>> 0x42,
>> 0x58,
>> 0x50,
>> @@ -36,8 +36,8 @@ static unsigned char ssdt_tpm_aml[] = {
>> 0x14,
>> 0x20,
>> 0x10,
>> -0x46,
>> -0x4,
>> +0x44,
>> +0x25,
>> 0x5c,
>> 0x2f,
>> 0x3,
>> @@ -55,7 +55,8 @@ static unsigned char ssdt_tpm_aml[] = {
>> 0x5f,
>> 0x5b,
>> 0x82,
>> -0x33,
>> +0x41,
>> +0x24,
>> 0x54,
>> 0x50,
>> 0x4d,
>> @@ -105,5 +106,530 @@ static unsigned char ssdt_tpm_aml[] = {
>> 0x0,
>> 0xa4,
>> 0xa,
>> -0xf
>> +0xf,
>> +0x5b,
>> +0x80,
>> +0x54,
>> +0x54,
>> +0x49,
>> +0x53,
>> +0x0,
>> +0xc,
>> +0x0,
>> +0x0,
>> +0xd4,
>> +0xfe,
>> +0xb,
>> +0x0,
>> +0x50,
>> +0x5b,
>> +0x81,
>> +0xf,
>> +0x54,
>> +0x54,
>> +0x49,
>> +0x53,
>> +0x0,
>> +0x0,
>> +0x80,
>> +0xc8,
>> +0x7,
>> +0x54,
>> +0x44,
>> +0x42,
>> +0x47,
>> +0x20,
>> +0x8,
>> +0x4f,
>> +0x50,
>> +0x5f,
>> +0x5f,
>> +0x0,
>> +0x5b,
>> +0x80,
>> +0x48,
>> +0x49,
>> +0x47,
>> +0x48,
>> +0x0,
>> +0xc,
>> +0xa0,
>> +0xf,
>> +0xd4,
>> +0xfe,
>> +0xa,
>> +0xe,
>> +0x14,
>> +0x42,
>> +0x4,
>> +0x57,
>> +0x52,
>> +0x41,
>> +0x4d,
>> +0x9,
>> +0x5b,
>> +0x81,
>> +0x15,
>> +0x48,
>> +0x49,
>> +0x47,
>> +0x48,
>> +0x0,
>> +0x53,
>> +0x49,
>> +0x47,
>> +0x31,
>> +0x20,
>> +0x53,
>> +0x49,
>> +0x5a,
>> +0x45,
>> +0x10,
>> +0x43,
>> +0x4f,
>> +0x44,
>> +0x45,
>> +0x8,
>> +0xa0,
>> +0x21,
>> +0x90,
>> +0x93,
>> +0x53,
>> +0x49,
>> +0x47,
>> +0x31,
>> +0xc,
>> +0x54,
>> +0x43,
>> +0x50,
>> +0x41,
>> +0x92,
>> +0x95,
>> +0x53,
>> +0x49,
>> +0x5a,
>> +0x45,
>> +0x1,
>> +0x70,
>> +0x68,
>> +0x43,
>> +0x4f,
>> +0x44,
>> +0x45,
>> +0x70,
>> +0x68,
>> +0x4f,
>> +0x50,
>> +0x5f,
>> +0x5f,
>> +0xa4,
>> +0x0,
>> +0xa4,
>> +0x1,
>> +0x14,
>> +0x47,
>> +0x7,
>> +0x52,
>> +0x52,
>> +0x41,
>> +0x4d,
>> +0x8,
>> +0x8,
>> +0x4f,
>> +0x50,
>> +0x52,
>> +0x45,
>> +0x12,
>> +0x5,
>> +0x3,
>> +0x1,
>> +0x0,
>> +0x0,
>> +0x5b,
>> +0x81,
>> +0x24,
>> +0x48,
>> +0x49,
>> +0x47,
>> +0x48,
>> +0x0,
>> +0x53,
>> +0x49,
>> +0x47,
>> +0x31,
>> +0x20,
>> +0x53,
>> +0x49,
>> +0x5a,
>> +0x45,
>> +0x10,
>> +0x43,
>> +0x4f,
>> +0x44,
>> +0x45,
>> +0x8,
>> +0x53,
>> +0x55,
>> +0x43,
>> +0x43,
>> +0x8,
>> +0x43,
>> +0x4f,
>> +0x44,
>> +0x4f,
>> +0x8,
>> +0x52,
>> +0x45,
>> +0x53,
>> +0x50,
>> +0x20,
>> +0xa0,
>> +0x39,
>> +0x90,
>> +0x93,
>> +0x53,
>> +0x49,
>> +0x47,
>> +0x31,
>> +0xc,
>> +0x54,
>> +0x43,
>> +0x50,
>> +0x41,
>> +0x92,
>> +0x95,
>> +0x53,
>> +0x49,
>> +0x5a,
>> +0x45,
>> +0xa,
>> +0x7,
>> +0x70,
>> +0x53,
>> +0x55,
>> +0x43,
>> +0x43,
>> +0x88,
>> +0x4f,
>> +0x50,
>> +0x52,
>> +0x45,
>> +0x0,
>> +0x0,
>> +0x70,
>> +0x43,
>> +0x4f,
>> +0x44,
>> +0x4f,
>> +0x88,
>> +0x4f,
>> +0x50,
>> +0x52,
>> +0x45,
>> +0x1,
>> +0x0,
>> +0x70,
>> +0x52,
>> +0x45,
>> +0x53,
>> +0x50,
>> +0x88,
>> +0x4f,
>> +0x50,
>> +0x52,
>> +0x45,
>> +0xa,
>> +0x2,
>> +0x0,
>> +0xa4,
>> +0x4f,
>> +0x50,
>> +0x52,
>> +0x45,
>> +0x14,
>> +0x29,
>> +0x43,
>> +0x4b,
>> +0x4f,
>> +0x50,
>> +0x1,
>> +0xa0,
>> +0x1e,
>> +0x91,
>> +0x91,
>> +0x90,
>> +0x92,
>> +0x95,
>> +0x68,
>> +0x0,
>> +0x92,
>> +0x94,
>> +0x68,
>> +0xa,
>> +0xb,
>> +0x93,
>> +0x68,
>> +0xa,
>> +0xe,
>> +0x90,
>> +0x92,
>> +0x95,
>> +0x68,
>> +0xa,
>> +0x15,
>> +0x92,
>> +0x94,
>> +0x68,
>> +0xa,
>> +0x16,
>> +0xa4,
>> +0x1,
>> +0xa1,
>> +0x3,
>> +0xa4,
>> +0x0,
>> +0x14,
>> +0x43,
>> +0xf,
>> +0x5f,
>> +0x44,
>> +0x53,
>> +0x4d,
>> +0xc,
>> +0xa0,
>> +0x46,
>> +0xe,
>> +0x93,
>> +0x68,
>> +0x11,
>> +0x13,
>> +0xa,
>> +0x10,
>> +0xa6,
>> +0xfa,
>> +0xdd,
>> +0x3d,
>> +0x1b,
>> +0x36,
>> +0xb4,
>> +0x4e,
>> +0xa4,
>> +0x24,
>> +0x8d,
>> +0x10,
>> +0x8,
>> +0x9d,
>> +0x16,
>> +0x53,
>> +0xa0,
>> +0xa,
>> +0x92,
>> +0x93,
>> +0x69,
>> +0x1,
>> +0xa4,
>> +0x11,
>> +0x3,
>> +0x1,
>> +0x0,
>> +0x70,
>> +0x99,
>> +0x6a,
>> +0x0,
>> +0x60,
>> +0xa0,
>> +0xb,
>> +0x93,
>> +0x60,
>> +0x0,
>> +0xa4,
>> +0x11,
>> +0x5,
>> +0xa,
>> +0x2,
>> +0xff,
>> +0x1,
>> +0xa0,
>> +0xa,
>> +0x93,
>> +0x60,
>> +0x1,
>> +0xa4,
>> +0xd,
>> +0x31,
>> +0x2e,
>> +0x32,
>> +0x0,
>> +0xa0,
>> +0x20,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x2,
>> +0x70,
>> +0x83,
>> +0x88,
>> +0x6b,
>> +0x0,
>> +0x0,
>> +0x60,
>> +0xa0,
>> +0xf,
>> +0x43,
>> +0x4b,
>> +0x4f,
>> +0x50,
>> +0x60,
>> +0x70,
>> +0x57,
>> +0x52,
>> +0x41,
>> +0x4d,
>> +0x60,
>> +0x61,
>> +0xa4,
>> +0x61,
>> +0xa1,
>> +0x3,
>> +0xa4,
>> +0x1,
>> +0xa0,
>> +0x29,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x3,
>> +0x8,
>> +0x50,
>> +0x45,
>> +0x4f,
>> +0x50,
>> +0x12,
>> +0x4,
>> +0x2,
>> +0x0,
>> +0x0,
>> +0x70,
>> +0x0,
>> +0x88,
>> +0x50,
>> +0x45,
>> +0x4f,
>> +0x50,
>> +0x0,
>> +0x0,
>> +0x70,
>> +0x4f,
>> +0x50,
>> +0x5f,
>> +0x5f,
>> +0x88,
>> +0x50,
>> +0x45,
>> +0x4f,
>> +0x50,
>> +0x1,
>> +0x0,
>> +0xa4,
>> +0x50,
>> +0x45,
>> +0x4f,
>> +0x50,
>> +0xa0,
>> +0x8,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x4,
>> +0xa4,
>> +0xa,
>> +0x2,
>> +0xa0,
>> +0xd,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x5,
>> +0x70,
>> +0x52,
>> +0x52,
>> +0x41,
>> +0x4d,
>> +0x60,
>> +0xa4,
>> +0x60,
>> +0xa0,
>> +0x8,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x6,
>> +0xa4,
>> +0xa,
>> +0x3,
>> +0xa0,
>> +0x20,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x7,
>> +0x70,
>> +0x83,
>> +0x88,
>> +0x6b,
>> +0x0,
>> +0x0,
>> +0x60,
>> +0xa0,
>> +0xf,
>> +0x43,
>> +0x4b,
>> +0x4f,
>> +0x50,
>> +0x60,
>> +0x70,
>> +0x57,
>> +0x52,
>> +0x41,
>> +0x4d,
>> +0x60,
>> +0x61,
>> +0xa4,
>> +0x61,
>> +0xa1,
>> +0x3,
>> +0xa4,
>> +0x1,
>> +0xa0,
>> +0x1a,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x8,
>> +0x70,
>> +0x83,
>> +0x88,
>> +0x6b,
>> +0x0,
>> +0x0,
>> +0x60,
>> +0xa0,
>> +0x9,
>> +0x43,
>> +0x4b,
>> +0x4f,
>> +0x50,
>> +0x60,
>> +0xa4,
>> +0xa,
>> +0x4,
>> +0xa1,
>> +0x3,
>> +0xa4,
>> +0x0,
>> +0xa4,
>> +0x11,
>> +0x3,
>> +0x1,
>> +0x0
>> };
>> diff --git a/hw/i386/ssdt-tpm2.dsl b/hw/i386/ssdt-tpm2.dsl
>> index 58bbbf8..29228a0 100644
>> --- a/hw/i386/ssdt-tpm2.dsl
>> +++ b/hw/i386/ssdt-tpm2.dsl
>> @@ -25,5 +25,6 @@ DefinitionBlock (
>> 0x1 // OEM Revision
>> )
>> {
>> +#define TPM_2_0
>> #include "ssdt-tpm-common.dsl"
>> }
>> diff --git a/hw/i386/ssdt-tpm2.hex.generated b/hw/i386/ssdt-tpm2.hex.generated
>> index 9ea8271..a685533 100644
>> --- a/hw/i386/ssdt-tpm2.hex.generated
>> +++ b/hw/i386/ssdt-tpm2.hex.generated
>> @@ -3,12 +3,12 @@ static unsigned char ssdt_tpm2_aml[] = {
>> 0x53,
>> 0x44,
>> 0x54,
>> -0x6b,
>> -0x0,
>> +0x61,
>> +0x2,
>> 0x0,
>> 0x0,
>> 0x1,
>> -0x37,
>> +0xe,
>> 0x42,
>> 0x58,
>> 0x50,
>> @@ -36,8 +36,8 @@ static unsigned char ssdt_tpm2_aml[] = {
>> 0x14,
>> 0x20,
>> 0x10,
>> -0x46,
>> -0x4,
>> +0x4c,
>> +0x23,
>> 0x5c,
>> 0x2f,
>> 0x3,
>> @@ -55,7 +55,8 @@ static unsigned char ssdt_tpm2_aml[] = {
>> 0x5f,
>> 0x5b,
>> 0x82,
>> -0x33,
>> +0x49,
>> +0x22,
>> 0x54,
>> 0x50,
>> 0x4d,
>> @@ -105,5 +106,506 @@ static unsigned char ssdt_tpm2_aml[] = {
>> 0x0,
>> 0xa4,
>> 0xa,
>> -0xf
>> +0xf,
>> +0x5b,
>> +0x80,
>> +0x54,
>> +0x54,
>> +0x49,
>> +0x53,
>> +0x0,
>> +0xc,
>> +0x0,
>> +0x0,
>> +0xd4,
>> +0xfe,
>> +0xb,
>> +0x0,
>> +0x50,
>> +0x5b,
>> +0x81,
>> +0xf,
>> +0x54,
>> +0x54,
>> +0x49,
>> +0x53,
>> +0x0,
>> +0x0,
>> +0x80,
>> +0xc8,
>> +0x7,
>> +0x54,
>> +0x44,
>> +0x42,
>> +0x47,
>> +0x20,
>> +0x8,
>> +0x4f,
>> +0x50,
>> +0x5f,
>> +0x5f,
>> +0x0,
>> +0x5b,
>> +0x80,
>> +0x48,
>> +0x49,
>> +0x47,
>> +0x48,
>> +0x0,
>> +0xc,
>> +0xa0,
>> +0xf,
>> +0xd4,
>> +0xfe,
>> +0xa,
>> +0xe,
>> +0x14,
>> +0x42,
>> +0x4,
>> +0x57,
>> +0x52,
>> +0x41,
>> +0x4d,
>> +0x9,
>> +0x5b,
>> +0x81,
>> +0x15,
>> +0x48,
>> +0x49,
>> +0x47,
>> +0x48,
>> +0x0,
>> +0x53,
>> +0x49,
>> +0x47,
>> +0x31,
>> +0x20,
>> +0x53,
>> +0x49,
>> +0x5a,
>> +0x45,
>> +0x10,
>> +0x43,
>> +0x4f,
>> +0x44,
>> +0x45,
>> +0x8,
>> +0xa0,
>> +0x21,
>> +0x90,
>> +0x93,
>> +0x53,
>> +0x49,
>> +0x47,
>> +0x31,
>> +0xc,
>> +0x54,
>> +0x43,
>> +0x50,
>> +0x41,
>> +0x92,
>> +0x95,
>> +0x53,
>> +0x49,
>> +0x5a,
>> +0x45,
>> +0x1,
>> +0x70,
>> +0x68,
>> +0x43,
>> +0x4f,
>> +0x44,
>> +0x45,
>> +0x70,
>> +0x68,
>> +0x4f,
>> +0x50,
>> +0x5f,
>> +0x5f,
>> +0xa4,
>> +0x0,
>> +0xa4,
>> +0x1,
>> +0x14,
>> +0x47,
>> +0x7,
>> +0x52,
>> +0x52,
>> +0x41,
>> +0x4d,
>> +0x8,
>> +0x8,
>> +0x4f,
>> +0x50,
>> +0x52,
>> +0x45,
>> +0x12,
>> +0x5,
>> +0x3,
>> +0x1,
>> +0x0,
>> +0x0,
>> +0x5b,
>> +0x81,
>> +0x24,
>> +0x48,
>> +0x49,
>> +0x47,
>> +0x48,
>> +0x0,
>> +0x53,
>> +0x49,
>> +0x47,
>> +0x31,
>> +0x20,
>> +0x53,
>> +0x49,
>> +0x5a,
>> +0x45,
>> +0x10,
>> +0x43,
>> +0x4f,
>> +0x44,
>> +0x45,
>> +0x8,
>> +0x53,
>> +0x55,
>> +0x43,
>> +0x43,
>> +0x8,
>> +0x43,
>> +0x4f,
>> +0x44,
>> +0x4f,
>> +0x8,
>> +0x52,
>> +0x45,
>> +0x53,
>> +0x50,
>> +0x20,
>> +0xa0,
>> +0x39,
>> +0x90,
>> +0x93,
>> +0x53,
>> +0x49,
>> +0x47,
>> +0x31,
>> +0xc,
>> +0x54,
>> +0x43,
>> +0x50,
>> +0x41,
>> +0x92,
>> +0x95,
>> +0x53,
>> +0x49,
>> +0x5a,
>> +0x45,
>> +0xa,
>> +0x7,
>> +0x70,
>> +0x53,
>> +0x55,
>> +0x43,
>> +0x43,
>> +0x88,
>> +0x4f,
>> +0x50,
>> +0x52,
>> +0x45,
>> +0x0,
>> +0x0,
>> +0x70,
>> +0x43,
>> +0x4f,
>> +0x44,
>> +0x4f,
>> +0x88,
>> +0x4f,
>> +0x50,
>> +0x52,
>> +0x45,
>> +0x1,
>> +0x0,
>> +0x70,
>> +0x52,
>> +0x45,
>> +0x53,
>> +0x50,
>> +0x88,
>> +0x4f,
>> +0x50,
>> +0x52,
>> +0x45,
>> +0xa,
>> +0x2,
>> +0x0,
>> +0xa4,
>> +0x4f,
>> +0x50,
>> +0x52,
>> +0x45,
>> +0x14,
>> +0x11,
>> +0x43,
>> +0x4b,
>> +0x4f,
>> +0x50,
>> +0x1,
>> +0xa0,
>> +0x6,
>> +0x93,
>> +0x68,
>> +0x0,
>> +0xa4,
>> +0x1,
>> +0xa1,
>> +0x3,
>> +0xa4,
>> +0x0,
>> +0x14,
>> +0x43,
>> +0xf,
>> +0x5f,
>> +0x44,
>> +0x53,
>> +0x4d,
>> +0xc,
>> +0xa0,
>> +0x46,
>> +0xe,
>> +0x93,
>> +0x68,
>> +0x11,
>> +0x13,
>> +0xa,
>> +0x10,
>> +0xa6,
>> +0xfa,
>> +0xdd,
>> +0x3d,
>> +0x1b,
>> +0x36,
>> +0xb4,
>> +0x4e,
>> +0xa4,
>> +0x24,
>> +0x8d,
>> +0x10,
>> +0x8,
>> +0x9d,
>> +0x16,
>> +0x53,
>> +0xa0,
>> +0xa,
>> +0x92,
>> +0x93,
>> +0x69,
>> +0x1,
>> +0xa4,
>> +0x11,
>> +0x3,
>> +0x1,
>> +0x0,
>> +0x70,
>> +0x99,
>> +0x6a,
>> +0x0,
>> +0x60,
>> +0xa0,
>> +0xb,
>> +0x93,
>> +0x60,
>> +0x0,
>> +0xa4,
>> +0x11,
>> +0x5,
>> +0xa,
>> +0x2,
>> +0xff,
>> +0x1,
>> +0xa0,
>> +0xa,
>> +0x93,
>> +0x60,
>> +0x1,
>> +0xa4,
>> +0xd,
>> +0x31,
>> +0x2e,
>> +0x32,
>> +0x0,
>> +0xa0,
>> +0x20,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x2,
>> +0x70,
>> +0x83,
>> +0x88,
>> +0x6b,
>> +0x0,
>> +0x0,
>> +0x60,
>> +0xa0,
>> +0xf,
>> +0x43,
>> +0x4b,
>> +0x4f,
>> +0x50,
>> +0x60,
>> +0x70,
>> +0x57,
>> +0x52,
>> +0x41,
>> +0x4d,
>> +0x60,
>> +0x61,
>> +0xa4,
>> +0x61,
>> +0xa1,
>> +0x3,
>> +0xa4,
>> +0x1,
>> +0xa0,
>> +0x29,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x3,
>> +0x8,
>> +0x50,
>> +0x45,
>> +0x4f,
>> +0x50,
>> +0x12,
>> +0x4,
>> +0x2,
>> +0x0,
>> +0x0,
>> +0x70,
>> +0x0,
>> +0x88,
>> +0x50,
>> +0x45,
>> +0x4f,
>> +0x50,
>> +0x0,
>> +0x0,
>> +0x70,
>> +0x4f,
>> +0x50,
>> +0x5f,
>> +0x5f,
>> +0x88,
>> +0x50,
>> +0x45,
>> +0x4f,
>> +0x50,
>> +0x1,
>> +0x0,
>> +0xa4,
>> +0x50,
>> +0x45,
>> +0x4f,
>> +0x50,
>> +0xa0,
>> +0x8,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x4,
>> +0xa4,
>> +0xa,
>> +0x2,
>> +0xa0,
>> +0xd,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x5,
>> +0x70,
>> +0x52,
>> +0x52,
>> +0x41,
>> +0x4d,
>> +0x60,
>> +0xa4,
>> +0x60,
>> +0xa0,
>> +0x8,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x6,
>> +0xa4,
>> +0xa,
>> +0x3,
>> +0xa0,
>> +0x20,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x7,
>> +0x70,
>> +0x83,
>> +0x88,
>> +0x6b,
>> +0x0,
>> +0x0,
>> +0x60,
>> +0xa0,
>> +0xf,
>> +0x43,
>> +0x4b,
>> +0x4f,
>> +0x50,
>> +0x60,
>> +0x70,
>> +0x57,
>> +0x52,
>> +0x41,
>> +0x4d,
>> +0x60,
>> +0x61,
>> +0xa4,
>> +0x61,
>> +0xa1,
>> +0x3,
>> +0xa4,
>> +0x1,
>> +0xa0,
>> +0x1a,
>> +0x93,
>> +0x60,
>> +0xa,
>> +0x8,
>> +0x70,
>> +0x83,
>> +0x88,
>> +0x6b,
>> +0x0,
>> +0x0,
>> +0x60,
>> +0xa0,
>> +0x9,
>> +0x43,
>> +0x4b,
>> +0x4f,
>> +0x50,
>> +0x60,
>> +0xa4,
>> +0xa,
>> +0x4,
>> +0xa1,
>> +0x3,
>> +0xa4,
>> +0x0,
>> +0xa4,
>> +0x11,
>> +0x3,
>> +0x1,
>> +0x0
>> };
>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>> index 6d516c6..4437543 100644
>> --- a/include/hw/acpi/tpm.h
>> +++ b/include/hw/acpi/tpm.h
>> @@ -31,4 +31,23 @@
>>
>> #define TPM2_START_METHOD_MMIO 6
>>
>> +/*
>> + * Physical Presence Interface -- shared with the BIOS
>> + */
>> +#define TCG_MAGIC 0x41504354
>> +
>> +#if 0
>> +struct tpm_ppi {
> coding style violation.
>
>> + uint32_t sign; // TCG_MAGIC
>> + uint16_t size; // number of subsequent bytes for ACPI to access
>> + uint8_t opcode; // set by ACPI
>> + uint8_t failure; // set by BIOS (0 = success)
>> + uint8_t recent_opcode; // set by BIOS
>> + uint32_t response; // set by BIOS
>> + uint8_t next_step; // BIOS only
>> +} QEMU_PACKED;
>> +#endif
>> +
>> +#define TPM_PPI_STRUCT_SIZE 14
>> +
>> #endif /* HW_ACPI_TPM_H */
>> --
>> 1.9.3
>>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 3:11 ` Stefan Berger
@ 2015-06-02 9:15 ` Michael S. Tsirkin
2015-06-02 13:22 ` Stefan Berger
0 siblings, 1 reply; 25+ messages in thread
From: Michael S. Tsirkin @ 2015-06-02 9:15 UTC (permalink / raw)
To: Stefan Berger; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On Mon, Jun 01, 2015 at 11:11:26PM -0400, Stefan Berger wrote:
> On 05/31/2015 02:11 PM, Michael S. Tsirkin wrote:
> >On Tue, May 26, 2015 at 05:33:41PM -0400, Stefan Berger wrote:
> >>For automated management of a TPM device, implement the TCG Physical Presence
> >>Interface Specification that allows a root user on Linux (for example) to set
> >>an opcode for a sequence of TPM operations that the BIOS is supposed to execute
> >>upon reboot of the physical or virtual machine. A sequence of operations may for
> >>example involve giving up ownership of the TPM and activating and enabling the
> >>device.
> >>
> >>The sequences of operations are defined in table 2 in the specs to be found
> >>at the following link:
> >>
> >>http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
> >>
> >>As an example, in recent versions of Linux the opcode (5) can be set as
> >>follows:
> >>
> >>cd /sys/devices/pnp0/00\:04/ppi
> >>
> >>echo 5 > request
> >>
> >>This ACPI implementation assumes that the underlying firmware (SeaBIOS)
> >>has 'thrown an anchor' into the f-segment. The anchor is identified by
> >>two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
> >>in the f-segment is write-protected and holds a pointer to a structure
> >>in high memmory
> >memory
> >
> >>area where the ACPI code writes the opcode into and
> >>where it can read the last response from the BIOS.
> >>
> >>The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
> >>Also '0' is supported to 'clear' an intention.
> >>
> >>
> >No need for 2 empty spaces.
> >
> >>Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >>Cc: Michael Tsirkin <mst@redhat.com>
> >>Cc: Kevin O'Connor <kevin@koconnor.net>
> >All this seems somewhat messy. Is this FSEG trick what the spec says,
> >or is this a QEMU specific protocol?
>
> Actually, the text in the patch is outdated. We now moved the area where the
> data are exchanged between ACPI and BIOS into registers provided by the TIS
> -- custom registers in an area that is vendor-specific, so yes, this is a
> QEMU specific solution. The address range for this is fixed and known to
> SeaBIOS and QEMU. Those registers also won't reset upon machine reboot.
Hmm. One way to do a machine reboot is to exit QEMU
then restart it. Where do these registers persist?
> >Would DataTableRegion not be a better way to locate things in
> >memory?
>
> As I said, we now move that into a memory region provide by the TIS..
> Otherwise I am not very familiar with DataTableRegion.
>
> Thanks for the comments!
>
> Stefan
A data table is a structure that you define (as opposed to code).
Using linker you can allocate some memory and put a pointer
there, then use DataTableRegion to read that pointer value.
--
MST
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM
2015-05-31 18:11 ` [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Michael S. Tsirkin
@ 2015-06-02 13:17 ` Stefan Berger
0 siblings, 0 replies; 25+ messages in thread
From: Stefan Berger @ 2015-06-02 13:17 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: imammedo, qemu-devel, quan.xu
On 05/31/2015 02:11 PM, Michael S. Tsirkin wrote:
> On Tue, May 26, 2015 at 05:33:38PM -0400, Stefan Berger wrote:
>> The following series of patches extends TPM support with an
>> external TPM that offers a Linux CUSE (character device in userspace)
>> interface. This TPM lets each VM access its own private vTPM.
>> The CUSE TPM supports suspend/resume and migration. Much
>> out-of-band functionality necessary to control the CUSE TPM is
>> implemented using ioctl's.
>>
>> The series extends the TPM support so far that most functionality of
>> TPM support on a physical platform is now available to each x86 VM,
>> this includes the Physical Presence Interface support that has
>> its counter-part in the SeaBIOS and is implemented using ACPI.
> So I'm waiting for v4 of this with Eric's comments addressed?
Yes, please. I will post v4 soon.
Regards,
Stefan
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 9:15 ` Michael S. Tsirkin
@ 2015-06-02 13:22 ` Stefan Berger
2015-06-02 13:30 ` Michael S. Tsirkin
0 siblings, 1 reply; 25+ messages in thread
From: Stefan Berger @ 2015-06-02 13:22 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On 06/02/2015 05:15 AM, Michael S. Tsirkin wrote:
> On Mon, Jun 01, 2015 at 11:11:26PM -0400, Stefan Berger wrote:
>> On 05/31/2015 02:11 PM, Michael S. Tsirkin wrote:
>>> On Tue, May 26, 2015 at 05:33:41PM -0400, Stefan Berger wrote:
>>>> For automated management of a TPM device, implement the TCG Physical Presence
>>>> Interface Specification that allows a root user on Linux (for example) to set
>>>> an opcode for a sequence of TPM operations that the BIOS is supposed to execute
>>>> upon reboot of the physical or virtual machine. A sequence of operations may for
>>>> example involve giving up ownership of the TPM and activating and enabling the
>>>> device.
>>>>
>>>> The sequences of operations are defined in table 2 in the specs to be found
>>>> at the following link:
>>>>
>>>> http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
>>>>
>>>> As an example, in recent versions of Linux the opcode (5) can be set as
>>>> follows:
>>>>
>>>> cd /sys/devices/pnp0/00\:04/ppi
>>>>
>>>> echo 5 > request
>>>>
>>>> This ACPI implementation assumes that the underlying firmware (SeaBIOS)
>>>> has 'thrown an anchor' into the f-segment. The anchor is identified by
>>>> two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
>>>> in the f-segment is write-protected and holds a pointer to a structure
>>>> in high memmory
>>> memory
>>>
>>>> area where the ACPI code writes the opcode into and
>>>> where it can read the last response from the BIOS.
>>>>
>>>> The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
>>>> Also '0' is supported to 'clear' an intention.
>>>>
>>>>
>>> No need for 2 empty spaces.
>>>
>>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>> Cc: Michael Tsirkin <mst@redhat.com>
>>>> Cc: Kevin O'Connor <kevin@koconnor.net>
>>> All this seems somewhat messy. Is this FSEG trick what the spec says,
>>> or is this a QEMU specific protocol?
>> Actually, the text in the patch is outdated. We now moved the area where the
>> data are exchanged between ACPI and BIOS into registers provided by the TIS
>> -- custom registers in an area that is vendor-specific, so yes, this is a
>> QEMU specific solution. The address range for this is fixed and known to
>> SeaBIOS and QEMU. Those registers also won't reset upon machine reboot.
> Hmm. One way to do a machine reboot is to exit QEMU
> then restart it. Where do these registers persist?
They won't persist. If one powers down the physical machine, this won't
work or not that I would know of that it would have to work.
>
>>> Would DataTableRegion not be a better way to locate things in
>>> memory?
>> As I said, we now move that into a memory region provide by the TIS..
>> Otherwise I am not very familiar with DataTableRegion.
>>
>> Thanks for the comments!
>>
>> Stefan
> A data table is a structure that you define (as opposed to code).
> Using linker you can allocate some memory and put a pointer
> there, then use DataTableRegion to read that pointer value.
>
How would the BIOS then find that memory (so it can read the command
code and act on it)? Would it need to walk ACPI tables or how would it
find the base address?
Stefan
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 13:22 ` Stefan Berger
@ 2015-06-02 13:30 ` Michael S. Tsirkin
2015-06-02 14:28 ` Stefan Berger
0 siblings, 1 reply; 25+ messages in thread
From: Michael S. Tsirkin @ 2015-06-02 13:30 UTC (permalink / raw)
To: Stefan Berger; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On Tue, Jun 02, 2015 at 09:22:40AM -0400, Stefan Berger wrote:
> On 06/02/2015 05:15 AM, Michael S. Tsirkin wrote:
> >On Mon, Jun 01, 2015 at 11:11:26PM -0400, Stefan Berger wrote:
> >>On 05/31/2015 02:11 PM, Michael S. Tsirkin wrote:
> >>>On Tue, May 26, 2015 at 05:33:41PM -0400, Stefan Berger wrote:
> >>>>For automated management of a TPM device, implement the TCG Physical Presence
> >>>>Interface Specification that allows a root user on Linux (for example) to set
> >>>>an opcode for a sequence of TPM operations that the BIOS is supposed to execute
> >>>>upon reboot of the physical or virtual machine. A sequence of operations may for
> >>>>example involve giving up ownership of the TPM and activating and enabling the
> >>>>device.
> >>>>
> >>>>The sequences of operations are defined in table 2 in the specs to be found
> >>>>at the following link:
> >>>>
> >>>>http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
> >>>>
> >>>>As an example, in recent versions of Linux the opcode (5) can be set as
> >>>>follows:
> >>>>
> >>>>cd /sys/devices/pnp0/00\:04/ppi
> >>>>
> >>>>echo 5 > request
> >>>>
> >>>>This ACPI implementation assumes that the underlying firmware (SeaBIOS)
> >>>>has 'thrown an anchor' into the f-segment. The anchor is identified by
> >>>>two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
> >>>>in the f-segment is write-protected and holds a pointer to a structure
> >>>>in high memmory
> >>>memory
> >>>
> >>>>area where the ACPI code writes the opcode into and
> >>>>where it can read the last response from the BIOS.
> >>>>
> >>>>The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
> >>>>Also '0' is supported to 'clear' an intention.
> >>>>
> >>>>
> >>>No need for 2 empty spaces.
> >>>
> >>>>Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >>>>Cc: Michael Tsirkin <mst@redhat.com>
> >>>>Cc: Kevin O'Connor <kevin@koconnor.net>
> >>>All this seems somewhat messy. Is this FSEG trick what the spec says,
> >>>or is this a QEMU specific protocol?
> >>Actually, the text in the patch is outdated. We now moved the area where the
> >>data are exchanged between ACPI and BIOS into registers provided by the TIS
> >>-- custom registers in an area that is vendor-specific, so yes, this is a
> >>QEMU specific solution. The address range for this is fixed and known to
> >>SeaBIOS and QEMU. Those registers also won't reset upon machine reboot.
> >Hmm. One way to do a machine reboot is to exit QEMU
> >then restart it. Where do these registers persist?
>
>
> They won't persist. If one powers down the physical machine, this won't work
> or not that I would know of that it would have to work.
>
>
> >
> >>>Would DataTableRegion not be a better way to locate things in
> >>>memory?
> >>As I said, we now move that into a memory region provide by the TIS..
> >>Otherwise I am not very familiar with DataTableRegion.
> >>
> >>Thanks for the comments!
> >>
> >> Stefan
> >A data table is a structure that you define (as opposed to code).
> >Using linker you can allocate some memory and put a pointer
> >there, then use DataTableRegion to read that pointer value.
> >
>
> How would the BIOS then find that memory (so it can read the command code
> and act on it)? Would it need to walk ACPI tables or how would it find the
> base address?
>
> Stefan
This is similar to things like suspend/resume.
The bios walks the list of the tables RSDP->XSDT, and locates the
data table either by triple signature/vendorid/vendortableid,
or by detecting a UEFI signature and locating the matching GUID
(second option is preferable given current OVMF code).
--
MST
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 13:30 ` Michael S. Tsirkin
@ 2015-06-02 14:28 ` Stefan Berger
2015-06-02 14:46 ` Michael S. Tsirkin
2015-06-02 15:00 ` Michael S. Tsirkin
0 siblings, 2 replies; 25+ messages in thread
From: Stefan Berger @ 2015-06-02 14:28 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On 06/02/2015 09:30 AM, Michael S. Tsirkin wrote:
> On Tue, Jun 02, 2015 at 09:22:40AM -0400, Stefan Berger wrote:
>> On 06/02/2015 05:15 AM, Michael S. Tsirkin wrote:
>>> On Mon, Jun 01, 2015 at 11:11:26PM -0400, Stefan Berger wrote:
>>>> On 05/31/2015 02:11 PM, Michael S. Tsirkin wrote:
>>>>> On Tue, May 26, 2015 at 05:33:41PM -0400, Stefan Berger wrote:
>>>>>> For automated management of a TPM device, implement the TCG Physical Presence
>>>>>> Interface Specification that allows a root user on Linux (for example) to set
>>>>>> an opcode for a sequence of TPM operations that the BIOS is supposed to execute
>>>>>> upon reboot of the physical or virtual machine. A sequence of operations may for
>>>>>> example involve giving up ownership of the TPM and activating and enabling the
>>>>>> device.
>>>>>>
>>>>>> The sequences of operations are defined in table 2 in the specs to be found
>>>>>> at the following link:
>>>>>>
>>>>>> http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
>>>>>>
>>>>>> As an example, in recent versions of Linux the opcode (5) can be set as
>>>>>> follows:
>>>>>>
>>>>>> cd /sys/devices/pnp0/00\:04/ppi
>>>>>>
>>>>>> echo 5 > request
>>>>>>
>>>>>> This ACPI implementation assumes that the underlying firmware (SeaBIOS)
>>>>>> has 'thrown an anchor' into the f-segment. The anchor is identified by
>>>>>> two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
>>>>>> in the f-segment is write-protected and holds a pointer to a structure
>>>>>> in high memmory
>>>>> memory
>>>>>
>>>>>> area where the ACPI code writes the opcode into and
>>>>>> where it can read the last response from the BIOS.
>>>>>>
>>>>>> The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
>>>>>> Also '0' is supported to 'clear' an intention.
>>>>>>
>>>>>>
>>>>> No need for 2 empty spaces.
>>>>>
>>>>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>>>> Cc: Michael Tsirkin <mst@redhat.com>
>>>>>> Cc: Kevin O'Connor <kevin@koconnor.net>
>>>>> All this seems somewhat messy. Is this FSEG trick what the spec says,
>>>>> or is this a QEMU specific protocol?
>>>> Actually, the text in the patch is outdated. We now moved the area where the
>>>> data are exchanged between ACPI and BIOS into registers provided by the TIS
>>>> -- custom registers in an area that is vendor-specific, so yes, this is a
>>>> QEMU specific solution. The address range for this is fixed and known to
>>>> SeaBIOS and QEMU. Those registers also won't reset upon machine reboot.
>>> Hmm. One way to do a machine reboot is to exit QEMU
>>> then restart it. Where do these registers persist?
>>
>> They won't persist. If one powers down the physical machine, this won't work
>> or not that I would know of that it would have to work.
>>
>>
>>>>> Would DataTableRegion not be a better way to locate things in
>>>>> memory?
>>>> As I said, we now move that into a memory region provide by the TIS..
>>>> Otherwise I am not very familiar with DataTableRegion.
>>>>
>>>> Thanks for the comments!
>>>>
>>>> Stefan
>>> A data table is a structure that you define (as opposed to code).
>>> Using linker you can allocate some memory and put a pointer
>>> there, then use DataTableRegion to read that pointer value.
>>>
>> How would the BIOS then find that memory (so it can read the command code
>> and act on it)? Would it need to walk ACPI tables or how would it find the
>> base address?
>>
>> Stefan
> This is similar to things like suspend/resume.
>
> The bios walks the list of the tables RSDP->XSDT, and locates the
> data table either by triple signature/vendorid/vendortableid,
> or by detecting a UEFI signature and locating the matching GUID
> (second option is preferable given current OVMF code).
We would need to create an XSDT with at least two entries, one pointing
to the existing FADT (per spec) and one to this new table with what
signature? Do you have a pointer to a table structure identifiable by
UEFI signature and GUID to see how this looks like? ACPI will identify
it by triple signature, though, right ? Should the XSDT always be there
or only if we have a TPM?
How would I mark the DataTableRegion as AddressRangeReserved or would it
automatically be?
Would the ACPI code then internally walk the list of tables attached to
the XSDT and find the address of that table and make it available so
that we can define a Field() on it. Assuming the DataTableRegion is
called AAAA, would we then define a Field(AAAA, AnyAcc,...) on it?
Well, I am not sure how involved this is going to be, so maybe I would
defer this ACPI support for now unless we could live with the proposed
solution and UEFI could use it as well when run on QEMU. And I am glad
that I haven't converted the ASL to C code, because this would make it a
lot more difficult to develop and debug...
Stefan
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 14:28 ` Stefan Berger
@ 2015-06-02 14:46 ` Michael S. Tsirkin
2015-06-02 15:06 ` Stefan Berger
2015-06-02 15:18 ` Kevin O'Connor
2015-06-02 15:00 ` Michael S. Tsirkin
1 sibling, 2 replies; 25+ messages in thread
From: Michael S. Tsirkin @ 2015-06-02 14:46 UTC (permalink / raw)
To: Stefan Berger; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On Tue, Jun 02, 2015 at 10:28:52AM -0400, Stefan Berger wrote:
> On 06/02/2015 09:30 AM, Michael S. Tsirkin wrote:
> >On Tue, Jun 02, 2015 at 09:22:40AM -0400, Stefan Berger wrote:
> >>On 06/02/2015 05:15 AM, Michael S. Tsirkin wrote:
> >>>On Mon, Jun 01, 2015 at 11:11:26PM -0400, Stefan Berger wrote:
> >>>>On 05/31/2015 02:11 PM, Michael S. Tsirkin wrote:
> >>>>>On Tue, May 26, 2015 at 05:33:41PM -0400, Stefan Berger wrote:
> >>>>>>For automated management of a TPM device, implement the TCG Physical Presence
> >>>>>>Interface Specification that allows a root user on Linux (for example) to set
> >>>>>>an opcode for a sequence of TPM operations that the BIOS is supposed to execute
> >>>>>>upon reboot of the physical or virtual machine. A sequence of operations may for
> >>>>>>example involve giving up ownership of the TPM and activating and enabling the
> >>>>>>device.
> >>>>>>
> >>>>>>The sequences of operations are defined in table 2 in the specs to be found
> >>>>>>at the following link:
> >>>>>>
> >>>>>>http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
> >>>>>>
> >>>>>>As an example, in recent versions of Linux the opcode (5) can be set as
> >>>>>>follows:
> >>>>>>
> >>>>>>cd /sys/devices/pnp0/00\:04/ppi
> >>>>>>
> >>>>>>echo 5 > request
> >>>>>>
> >>>>>>This ACPI implementation assumes that the underlying firmware (SeaBIOS)
> >>>>>>has 'thrown an anchor' into the f-segment. The anchor is identified by
> >>>>>>two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
> >>>>>>in the f-segment is write-protected and holds a pointer to a structure
> >>>>>>in high memmory
> >>>>>memory
> >>>>>
> >>>>>>area where the ACPI code writes the opcode into and
> >>>>>>where it can read the last response from the BIOS.
> >>>>>>
> >>>>>>The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
> >>>>>>Also '0' is supported to 'clear' an intention.
> >>>>>>
> >>>>>>
> >>>>>No need for 2 empty spaces.
> >>>>>
> >>>>>>Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >>>>>>Cc: Michael Tsirkin <mst@redhat.com>
> >>>>>>Cc: Kevin O'Connor <kevin@koconnor.net>
> >>>>>All this seems somewhat messy. Is this FSEG trick what the spec says,
> >>>>>or is this a QEMU specific protocol?
> >>>>Actually, the text in the patch is outdated. We now moved the area where the
> >>>>data are exchanged between ACPI and BIOS into registers provided by the TIS
> >>>>-- custom registers in an area that is vendor-specific, so yes, this is a
> >>>>QEMU specific solution. The address range for this is fixed and known to
> >>>>SeaBIOS and QEMU. Those registers also won't reset upon machine reboot.
> >>>Hmm. One way to do a machine reboot is to exit QEMU
> >>>then restart it. Where do these registers persist?
> >>
> >>They won't persist. If one powers down the physical machine, this won't work
> >>or not that I would know of that it would have to work.
> >>
> >>
> >>>>>Would DataTableRegion not be a better way to locate things in
> >>>>>memory?
> >>>>As I said, we now move that into a memory region provide by the TIS..
> >>>>Otherwise I am not very familiar with DataTableRegion.
> >>>>
> >>>>Thanks for the comments!
> >>>>
> >>>> Stefan
> >>>A data table is a structure that you define (as opposed to code).
> >>>Using linker you can allocate some memory and put a pointer
> >>>there, then use DataTableRegion to read that pointer value.
> >>>
> >>How would the BIOS then find that memory (so it can read the command code
> >>and act on it)? Would it need to walk ACPI tables or how would it find the
> >>base address?
> >>
> >> Stefan
> >This is similar to things like suspend/resume.
> >
> >The bios walks the list of the tables RSDP->XSDT, and locates the
> >data table either by triple signature/vendorid/vendortableid,
> >or by detecting a UEFI signature and locating the matching GUID
> >(second option is preferable given current OVMF code).
>
> We would need to create an XSDT with at least two entries, one pointing to
> the existing FADT (per spec) and one to this new table with what signature?
I think XSDT has same content as RSDT + new tables from ACPI 2 spec.
> Do you have a pointer to a table structure identifiable by UEFI signature
> and GUID to see how this looks like?
Look it up in Appendix O (that a letter O, not zero) in the UEFI spec.
> ACPI will identify it by triple
> signature, though, right ? Should the XSDT always be there or only if we
> have a TPM?
I'm looking at adding it unconditionally, this let us use ACPI 2
funcitonality without crashing XP guests.
> How would I mark the DataTableRegion as AddressRangeReserved or would it
> automatically be?
It's automatically either AddressRangeReserved or AddressRangeNVS.
It doesn't look like you have control over which it is.
seabios makes it reserved, nvs makes it
> Would the ACPI code then internally walk the list of tables attached to the
> XSDT and find the address of that table and make it available so that we can
> define a Field() on it.
Yes.
> Assuming the DataTableRegion is called AAAA, would
> we then define a Field(AAAA, AnyAcc,...) on it?
Exactly.
> Well, I am not sure how involved this is going to be, so maybe I would defer
> this ACPI support for now unless we could live with the proposed solution
> and UEFI could use it as well when run on QEMU. And I am glad that I haven't
> converted the ASL to C code, because this would make it a lot more difficult
> to develop and debug...
>
> Stefan
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 14:28 ` Stefan Berger
2015-06-02 14:46 ` Michael S. Tsirkin
@ 2015-06-02 15:00 ` Michael S. Tsirkin
1 sibling, 0 replies; 25+ messages in thread
From: Michael S. Tsirkin @ 2015-06-02 15:00 UTC (permalink / raw)
To: Stefan Berger; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On Tue, Jun 02, 2015 at 10:28:52AM -0400, Stefan Berger wrote:
> And I am glad that I haven't
> converted the ASL to C code, because this would make it a lot more difficult
> to develop and debug...
>
> Stefan
Let's avoid hyperbole. Mostly there's a bunch of aml_append calls
sprinkled on each line of ASL code.
It's harder to develop since there's no compiler catching mistakes
statically, that's true.
Debugging is more or less the same since you can always
dump the tables and disassemble them with iasl.
--
MST
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 14:46 ` Michael S. Tsirkin
@ 2015-06-02 15:06 ` Stefan Berger
2015-06-02 15:11 ` Michael S. Tsirkin
2015-06-02 15:18 ` Kevin O'Connor
1 sibling, 1 reply; 25+ messages in thread
From: Stefan Berger @ 2015-06-02 15:06 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On 06/02/2015 10:46 AM, Michael S. Tsirkin wrote:
> On Tue, Jun 02, 2015 at 10:28:52AM -0400, Stefan Berger wrote:
>> On 06/02/2015 09:30 AM, Michael S. Tsirkin wrote:
>>> On Tue, Jun 02, 2015 at 09:22:40AM -0400, Stefan Berger wrote:
>>>> On 06/02/2015 05:15 AM, Michael S. Tsirkin wrote:
>>>>> On Mon, Jun 01, 2015 at 11:11:26PM -0400, Stefan Berger wrote:
>>>>>> On 05/31/2015 02:11 PM, Michael S. Tsirkin wrote:
>>>>>>> On Tue, May 26, 2015 at 05:33:41PM -0400, Stefan Berger wrote:
>>>>>>>> For automated management of a TPM device, implement the TCG Physical Presence
>>>>>>>> Interface Specification that allows a root user on Linux (for example) to set
>>>>>>>> an opcode for a sequence of TPM operations that the BIOS is supposed to execute
>>>>>>>> upon reboot of the physical or virtual machine. A sequence of operations may for
>>>>>>>> example involve giving up ownership of the TPM and activating and enabling the
>>>>>>>> device.
>>>>>>>>
>>>>>>>> The sequences of operations are defined in table 2 in the specs to be found
>>>>>>>> at the following link:
>>>>>>>>
>>>>>>>> http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
>>>>>>>>
>>>>>>>> As an example, in recent versions of Linux the opcode (5) can be set as
>>>>>>>> follows:
>>>>>>>>
>>>>>>>> cd /sys/devices/pnp0/00\:04/ppi
>>>>>>>>
>>>>>>>> echo 5 > request
>>>>>>>>
>>>>>>>> This ACPI implementation assumes that the underlying firmware (SeaBIOS)
>>>>>>>> has 'thrown an anchor' into the f-segment. The anchor is identified by
>>>>>>>> two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
>>>>>>>> in the f-segment is write-protected and holds a pointer to a structure
>>>>>>>> in high memmory
>>>>>>> memory
>>>>>>>
>>>>>>>> area where the ACPI code writes the opcode into and
>>>>>>>> where it can read the last response from the BIOS.
>>>>>>>>
>>>>>>>> The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
>>>>>>>> Also '0' is supported to 'clear' an intention.
>>>>>>>>
>>>>>>>>
>>>>>>> No need for 2 empty spaces.
>>>>>>>
>>>>>>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>>>>>> Cc: Michael Tsirkin <mst@redhat.com>
>>>>>>>> Cc: Kevin O'Connor <kevin@koconnor.net>
>>>>>>> All this seems somewhat messy. Is this FSEG trick what the spec says,
>>>>>>> or is this a QEMU specific protocol?
>>>>>> Actually, the text in the patch is outdated. We now moved the area where the
>>>>>> data are exchanged between ACPI and BIOS into registers provided by the TIS
>>>>>> -- custom registers in an area that is vendor-specific, so yes, this is a
>>>>>> QEMU specific solution. The address range for this is fixed and known to
>>>>>> SeaBIOS and QEMU. Those registers also won't reset upon machine reboot.
>>>>> Hmm. One way to do a machine reboot is to exit QEMU
>>>>> then restart it. Where do these registers persist?
>>>> They won't persist. If one powers down the physical machine, this won't work
>>>> or not that I would know of that it would have to work.
>>>>
>>>>
>>>>>>> Would DataTableRegion not be a better way to locate things in
>>>>>>> memory?
>>>>>> As I said, we now move that into a memory region provide by the TIS..
>>>>>> Otherwise I am not very familiar with DataTableRegion.
>>>>>>
>>>>>> Thanks for the comments!
>>>>>>
>>>>>> Stefan
>>>>> A data table is a structure that you define (as opposed to code).
>>>>> Using linker you can allocate some memory and put a pointer
>>>>> there, then use DataTableRegion to read that pointer value.
>>>>>
>>>> How would the BIOS then find that memory (so it can read the command code
>>>> and act on it)? Would it need to walk ACPI tables or how would it find the
>>>> base address?
>>>>
>>>> Stefan
>>> This is similar to things like suspend/resume.
>>>
>>> The bios walks the list of the tables RSDP->XSDT, and locates the
>>> data table either by triple signature/vendorid/vendortableid,
>>> or by detecting a UEFI signature and locating the matching GUID
>>> (second option is preferable given current OVMF code).
>> We would need to create an XSDT with at least two entries, one pointing to
>> the existing FADT (per spec) and one to this new table with what signature?
> I think XSDT has same content as RSDT + new tables from ACPI 2 spec.
>
>> Do you have a pointer to a table structure identifiable by UEFI signature
>> and GUID to see how this looks like?
> Look it up in Appendix O (that a letter O, not zero) in the UEFI spec.
Thanks. UEFI is the signature. OemTableIDString would have to be the
unique part. I don't see a GUID -- so not sure how to weave this in
unless it goes into the Data area.
>> ACPI will identify it by triple
>> signature, though, right ? Should the XSDT always be there or only if we
>> have a TPM?
> I'm looking at adding it unconditionally, this let us use ACPI 2
> funcitonality without crashing XP guests.
So you'll add that then? Then let me defer the ACPI support for now.
>
>> How would I mark the DataTableRegion as AddressRangeReserved or would it
>> automatically be?
> It's automatically either AddressRangeReserved or AddressRangeNVS.
> It doesn't look like you have control over which it is.
> seabios makes it reserved, nvs makes it
just by being marked as reserved via e820 ?
>
>> Would the ACPI code then internally walk the list of tables attached to the
>> XSDT and find the address of that table and make it available so that we can
>> define a Field() on it.
> Yes.
>
>> Assuming the DataTableRegion is called AAAA, would
>> we then define a Field(AAAA, AnyAcc,...) on it?
> Exactly.
Ok, so it looks like the offset where the stuff then goes would be at
offset 54.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 15:06 ` Stefan Berger
@ 2015-06-02 15:11 ` Michael S. Tsirkin
2015-06-02 16:28 ` Stefan Berger
0 siblings, 1 reply; 25+ messages in thread
From: Michael S. Tsirkin @ 2015-06-02 15:11 UTC (permalink / raw)
To: Stefan Berger; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On Tue, Jun 02, 2015 at 11:06:54AM -0400, Stefan Berger wrote:
> On 06/02/2015 10:46 AM, Michael S. Tsirkin wrote:
> >On Tue, Jun 02, 2015 at 10:28:52AM -0400, Stefan Berger wrote:
> >>On 06/02/2015 09:30 AM, Michael S. Tsirkin wrote:
> >>>On Tue, Jun 02, 2015 at 09:22:40AM -0400, Stefan Berger wrote:
> >>>>On 06/02/2015 05:15 AM, Michael S. Tsirkin wrote:
> >>>>>On Mon, Jun 01, 2015 at 11:11:26PM -0400, Stefan Berger wrote:
> >>>>>>On 05/31/2015 02:11 PM, Michael S. Tsirkin wrote:
> >>>>>>>On Tue, May 26, 2015 at 05:33:41PM -0400, Stefan Berger wrote:
> >>>>>>>>For automated management of a TPM device, implement the TCG Physical Presence
> >>>>>>>>Interface Specification that allows a root user on Linux (for example) to set
> >>>>>>>>an opcode for a sequence of TPM operations that the BIOS is supposed to execute
> >>>>>>>>upon reboot of the physical or virtual machine. A sequence of operations may for
> >>>>>>>>example involve giving up ownership of the TPM and activating and enabling the
> >>>>>>>>device.
> >>>>>>>>
> >>>>>>>>The sequences of operations are defined in table 2 in the specs to be found
> >>>>>>>>at the following link:
> >>>>>>>>
> >>>>>>>>http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
> >>>>>>>>
> >>>>>>>>As an example, in recent versions of Linux the opcode (5) can be set as
> >>>>>>>>follows:
> >>>>>>>>
> >>>>>>>>cd /sys/devices/pnp0/00\:04/ppi
> >>>>>>>>
> >>>>>>>>echo 5 > request
> >>>>>>>>
> >>>>>>>>This ACPI implementation assumes that the underlying firmware (SeaBIOS)
> >>>>>>>>has 'thrown an anchor' into the f-segment. The anchor is identified by
> >>>>>>>>two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
> >>>>>>>>in the f-segment is write-protected and holds a pointer to a structure
> >>>>>>>>in high memmory
> >>>>>>>memory
> >>>>>>>
> >>>>>>>>area where the ACPI code writes the opcode into and
> >>>>>>>>where it can read the last response from the BIOS.
> >>>>>>>>
> >>>>>>>>The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
> >>>>>>>>Also '0' is supported to 'clear' an intention.
> >>>>>>>>
> >>>>>>>>
> >>>>>>>No need for 2 empty spaces.
> >>>>>>>
> >>>>>>>>Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >>>>>>>>Cc: Michael Tsirkin <mst@redhat.com>
> >>>>>>>>Cc: Kevin O'Connor <kevin@koconnor.net>
> >>>>>>>All this seems somewhat messy. Is this FSEG trick what the spec says,
> >>>>>>>or is this a QEMU specific protocol?
> >>>>>>Actually, the text in the patch is outdated. We now moved the area where the
> >>>>>>data are exchanged between ACPI and BIOS into registers provided by the TIS
> >>>>>>-- custom registers in an area that is vendor-specific, so yes, this is a
> >>>>>>QEMU specific solution. The address range for this is fixed and known to
> >>>>>>SeaBIOS and QEMU. Those registers also won't reset upon machine reboot.
> >>>>>Hmm. One way to do a machine reboot is to exit QEMU
> >>>>>then restart it. Where do these registers persist?
> >>>>They won't persist. If one powers down the physical machine, this won't work
> >>>>or not that I would know of that it would have to work.
> >>>>
> >>>>
> >>>>>>>Would DataTableRegion not be a better way to locate things in
> >>>>>>>memory?
> >>>>>>As I said, we now move that into a memory region provide by the TIS..
> >>>>>>Otherwise I am not very familiar with DataTableRegion.
> >>>>>>
> >>>>>>Thanks for the comments!
> >>>>>>
> >>>>>> Stefan
> >>>>>A data table is a structure that you define (as opposed to code).
> >>>>>Using linker you can allocate some memory and put a pointer
> >>>>>there, then use DataTableRegion to read that pointer value.
> >>>>>
> >>>>How would the BIOS then find that memory (so it can read the command code
> >>>>and act on it)? Would it need to walk ACPI tables or how would it find the
> >>>>base address?
> >>>>
> >>>> Stefan
> >>>This is similar to things like suspend/resume.
> >>>
> >>>The bios walks the list of the tables RSDP->XSDT, and locates the
> >>>data table either by triple signature/vendorid/vendortableid,
> >>>or by detecting a UEFI signature and locating the matching GUID
> >>>(second option is preferable given current OVMF code).
> >>We would need to create an XSDT with at least two entries, one pointing to
> >>the existing FADT (per spec) and one to this new table with what signature?
> >I think XSDT has same content as RSDT + new tables from ACPI 2 spec.
>
>
>
> >
> >>Do you have a pointer to a table structure identifiable by UEFI signature
> >>and GUID to see how this looks like?
> >Look it up in Appendix O (that a letter O, not zero) in the UEFI spec.
>
> Thanks. UEFI is the signature. OemTableIDString would have to be the unique
> part. I don't see a GUID -- so not sure how to weave this in unless it goes
> into the Data area.
>
>
>
> >>ACPI will identify it by triple
> >>signature, though, right ? Should the XSDT always be there or only if we
> >>have a TPM?
> >I'm looking at adding it unconditionally, this let us use ACPI 2
> >funcitonality without crashing XP guests.
>
> So you'll add that then? Then let me defer the ACPI support for now.
>
>
> >
> >>How would I mark the DataTableRegion as AddressRangeReserved or would it
> >>automatically be?
> >It's automatically either AddressRangeReserved or AddressRangeNVS.
> >It doesn't look like you have control over which it is.
> >seabios makes it reserved, nvs makes it
>
>
> just by being marked as reserved via e820 ?
bios allocates it and marks it reserved in e820, efi allocates
it and marks it nvs in e820.
> >
> >>Would the ACPI code then internally walk the list of tables attached to the
> >>XSDT and find the address of that table and make it available so that we can
> >>define a Field() on it.
> >Yes.
> >
> >>Assuming the DataTableRegion is called AAAA, would
> >>we then define a Field(AAAA, AnyAcc,...) on it?
> >Exactly.
>
> Ok, so it looks like the offset where the stuff then goes would be at offset
> 54.
Is the stuff read-only? Or does qemu modify it while guest runs?
If readonly, you can just stick it there, right.
If qemu has to modify it, that would breaks checksum,
so it's better to allocate a blob and put the *pointer*
to blob in the data table.
All problems in computer science can be solved by another level of
indirection.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 14:46 ` Michael S. Tsirkin
2015-06-02 15:06 ` Stefan Berger
@ 2015-06-02 15:18 ` Kevin O'Connor
2015-06-02 16:18 ` Stefan Berger
1 sibling, 1 reply; 25+ messages in thread
From: Kevin O'Connor @ 2015-06-02 15:18 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: imammedo, qemu-devel, quan.xu, Stefan Berger
On Tue, Jun 02, 2015 at 04:46:06PM +0200, Michael S. Tsirkin wrote:
> On Tue, Jun 02, 2015 at 10:28:52AM -0400, Stefan Berger wrote:
> > How would I mark the DataTableRegion as AddressRangeReserved or would it
> > automatically be?
>
> It's automatically either AddressRangeReserved or AddressRangeNVS.
> It doesn't look like you have control over which it is.
> seabios makes it reserved, nvs makes it
As I understand it, Stefan wants to do something a little unusual
here. The goal is to allow the guest OS to send a signal to the BIOS
on the next boot, because the TPM stuff only allows the BIOS to change
certain settings immediately after the machine has booted (or
rebooted). So, the idea is to allow the guest OS to put some code in
reserved memory that is at a consistent address so that on a reboot
seabios can find that code and take the corresponding action. The
memory has to be non-volatile across reboots, and it must be someplace
that can be found prior to it being zero'd or overwritten by any init
process.
Did I understand this correctly?
If so, I don't see how the normal QEMU <-> seabios ACPI table
deployment mechanism will help here. SeaBIOS does reserve the space,
but nothing prevents SeaBIOS from overwriting it before extracting any
updates from a previous boot.
As an aside, I thought putting the updates in a "reserved area" of the
TPM chip was a simple solution to this problem. That way, it's easy
for the guest OS and SeaBIOS to know where the codes will be stored,
and no chance any init process will overwrite it by accident.
For reference, the original solution was for SeaBIOS to declare an
area of reserved memory and do it in such a way that the address would
be consistent across reboots and would not be overwritten by any init
process. The problem with this approach was that the guest OS didn't
implicitly know where that area of memory was, and it had to "table
scan" to find the address - that was deemed too ugly.
-Kevin
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 15:18 ` Kevin O'Connor
@ 2015-06-02 16:18 ` Stefan Berger
0 siblings, 0 replies; 25+ messages in thread
From: Stefan Berger @ 2015-06-02 16:18 UTC (permalink / raw)
To: Kevin O'Connor, Michael S. Tsirkin; +Cc: imammedo, qemu-devel, quan.xu
On 06/02/2015 11:18 AM, Kevin O'Connor wrote:
> On Tue, Jun 02, 2015 at 04:46:06PM +0200, Michael S. Tsirkin wrote:
>> On Tue, Jun 02, 2015 at 10:28:52AM -0400, Stefan Berger wrote:
>>> How would I mark the DataTableRegion as AddressRangeReserved or would it
>>> automatically be?
>> It's automatically either AddressRangeReserved or AddressRangeNVS.
>> It doesn't look like you have control over which it is.
>> seabios makes it reserved, nvs makes it
> As I understand it, Stefan wants to do something a little unusual
> here. The goal is to allow the guest OS to send a signal to the BIOS
> on the next boot, because the TPM stuff only allows the BIOS to change
> certain settings immediately after the machine has booted (or
> rebooted). So, the idea is to allow the guest OS to put some code in
> reserved memory that is at a consistent address so that on a reboot
> seabios can find that code and take the corresponding action. The
> memory has to be non-volatile across reboots, and it must be someplace
> that can be found prior to it being zero'd or overwritten by any init
> process.
>
> Did I understand this correctly?
Correct.
>
> If so, I don't see how the normal QEMU <-> seabios ACPI table
> deployment mechanism will help here. SeaBIOS does reserve the space,
> but nothing prevents SeaBIOS from overwriting it before extracting any
> updates from a previous boot.
>
> As an aside, I thought putting the updates in a "reserved area" of the
> TPM chip was a simple solution to this problem. That way, it's easy
> for the guest OS and SeaBIOS to know where the codes will be stored,
> and no chance any init process will overwrite it by accident.
>
> For reference, the original solution was for SeaBIOS to declare an
> area of reserved memory and do it in such a way that the address would
> be consistent across reboots and would not be overwritten by any init
> process. The problem with this approach was that the guest OS didn't
> implicitly know where that area of memory was, and it had to "table
> scan" to find the address - that was deemed too ugly.
>
> -Kevin
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec
2015-06-02 15:11 ` Michael S. Tsirkin
@ 2015-06-02 16:28 ` Stefan Berger
0 siblings, 0 replies; 25+ messages in thread
From: Stefan Berger @ 2015-06-02 16:28 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: imammedo, Kevin O'Connor, qemu-devel, quan.xu
On 06/02/2015 11:11 AM, Michael S. Tsirkin wrote:
> On Tue, Jun 02, 2015 at 11:06:54AM -0400, Stefan Berger wrote:
>> On 06/02/2015 10:46 AM, Michael S. Tsirkin wrote:
>>> On Tue, Jun 02, 2015 at 10:28:52AM -0400, Stefan Berger wrote:
>>>> On 06/02/2015 09:30 AM, Michael S. Tsirkin wrote:
>>>>> On Tue, Jun 02, 2015 at 09:22:40AM -0400, Stefan Berger wrote:
>>>>>> On 06/02/2015 05:15 AM, Michael S. Tsirkin wrote:
>>>>>>> On Mon, Jun 01, 2015 at 11:11:26PM -0400, Stefan Berger wrote:
>>>>>>>> On 05/31/2015 02:11 PM, Michael S. Tsirkin wrote:
>>>>>>>>> On Tue, May 26, 2015 at 05:33:41PM -0400, Stefan Berger wrote:
>>>>>>>>>> For automated management of a TPM device, implement the TCG Physical Presence
>>>>>>>>>> Interface Specification that allows a root user on Linux (for example) to set
>>>>>>>>>> an opcode for a sequence of TPM operations that the BIOS is supposed to execute
>>>>>>>>>> upon reboot of the physical or virtual machine. A sequence of operations may for
>>>>>>>>>> example involve giving up ownership of the TPM and activating and enabling the
>>>>>>>>>> device.
>>>>>>>>>>
>>>>>>>>>> The sequences of operations are defined in table 2 in the specs to be found
>>>>>>>>>> at the following link:
>>>>>>>>>>
>>>>>>>>>> http://www.trustedcomputinggroup.org/resources/tcg_physical_presence_interface_specification
>>>>>>>>>>
>>>>>>>>>> As an example, in recent versions of Linux the opcode (5) can be set as
>>>>>>>>>> follows:
>>>>>>>>>>
>>>>>>>>>> cd /sys/devices/pnp0/00\:04/ppi
>>>>>>>>>>
>>>>>>>>>> echo 5 > request
>>>>>>>>>>
>>>>>>>>>> This ACPI implementation assumes that the underlying firmware (SeaBIOS)
>>>>>>>>>> has 'thrown an anchor' into the f-segment. The anchor is identified by
>>>>>>>>>> two signatures (TCG_MAGIC) surrounding a 64bit pointer. The structure
>>>>>>>>>> in the f-segment is write-protected and holds a pointer to a structure
>>>>>>>>>> in high memmory
>>>>>>>>> memory
>>>>>>>>>
>>>>>>>>>> area where the ACPI code writes the opcode into and
>>>>>>>>>> where it can read the last response from the BIOS.
>>>>>>>>>>
>>>>>>>>>> The supported opcodes are 1-11, 14, and 21-22. (see table 2 in spec)
>>>>>>>>>> Also '0' is supported to 'clear' an intention.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>> No need for 2 empty spaces.
>>>>>>>>>
>>>>>>>>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>>>>>>>> Cc: Michael Tsirkin <mst@redhat.com>
>>>>>>>>>> Cc: Kevin O'Connor <kevin@koconnor.net>
>>>>>>>>> All this seems somewhat messy. Is this FSEG trick what the spec says,
>>>>>>>>> or is this a QEMU specific protocol?
>>>>>>>> Actually, the text in the patch is outdated. We now moved the area where the
>>>>>>>> data are exchanged between ACPI and BIOS into registers provided by the TIS
>>>>>>>> -- custom registers in an area that is vendor-specific, so yes, this is a
>>>>>>>> QEMU specific solution. The address range for this is fixed and known to
>>>>>>>> SeaBIOS and QEMU. Those registers also won't reset upon machine reboot.
>>>>>>> Hmm. One way to do a machine reboot is to exit QEMU
>>>>>>> then restart it. Where do these registers persist?
>>>>>> They won't persist. If one powers down the physical machine, this won't work
>>>>>> or not that I would know of that it would have to work.
>>>>>>
>>>>>>
>>>>>>>>> Would DataTableRegion not be a better way to locate things in
>>>>>>>>> memory?
>>>>>>>> As I said, we now move that into a memory region provide by the TIS..
>>>>>>>> Otherwise I am not very familiar with DataTableRegion.
>>>>>>>>
>>>>>>>> Thanks for the comments!
>>>>>>>>
>>>>>>>> Stefan
>>>>>>> A data table is a structure that you define (as opposed to code).
>>>>>>> Using linker you can allocate some memory and put a pointer
>>>>>>> there, then use DataTableRegion to read that pointer value.
>>>>>>>
>>>>>> How would the BIOS then find that memory (so it can read the command code
>>>>>> and act on it)? Would it need to walk ACPI tables or how would it find the
>>>>>> base address?
>>>>>>
>>>>>> Stefan
>>>>> This is similar to things like suspend/resume.
>>>>>
>>>>> The bios walks the list of the tables RSDP->XSDT, and locates the
>>>>> data table either by triple signature/vendorid/vendortableid,
>>>>> or by detecting a UEFI signature and locating the matching GUID
>>>>> (second option is preferable given current OVMF code).
>>>> We would need to create an XSDT with at least two entries, one pointing to
>>>> the existing FADT (per spec) and one to this new table with what signature?
>>> I think XSDT has same content as RSDT + new tables from ACPI 2 spec.
>>
>>
>>>> Do you have a pointer to a table structure identifiable by UEFI signature
>>>> and GUID to see how this looks like?
>>> Look it up in Appendix O (that a letter O, not zero) in the UEFI spec.
>> Thanks. UEFI is the signature. OemTableIDString would have to be the unique
>> part. I don't see a GUID -- so not sure how to weave this in unless it goes
>> into the Data area.
>>
>>
>>
>>>> ACPI will identify it by triple
>>>> signature, though, right ? Should the XSDT always be there or only if we
>>>> have a TPM?
>>> I'm looking at adding it unconditionally, this let us use ACPI 2
>>> funcitonality without crashing XP guests.
>> So you'll add that then? Then let me defer the ACPI support for now.
>>
>>
>>>> How would I mark the DataTableRegion as AddressRangeReserved or would it
>>>> automatically be?
>>> It's automatically either AddressRangeReserved or AddressRangeNVS.
>>> It doesn't look like you have control over which it is.
>>> seabios makes it reserved, nvs makes it
>>
>> just by being marked as reserved via e820 ?
> bios allocates it and marks it reserved in e820, efi allocates
> it and marks it nvs in e820.
>
>>>> Would the ACPI code then internally walk the list of tables attached to the
>>>> XSDT and find the address of that table and make it available so that we can
>>>> define a Field() on it.
>>> Yes.
>>>
>>>> Assuming the DataTableRegion is called AAAA, would
>>>> we then define a Field(AAAA, AnyAcc,...) on it?
>>> Exactly.
>> Ok, so it looks like the offset where the stuff then goes would be at offset
>> 54.
> Is the stuff read-only? Or does qemu modify it while guest runs?
QEMU does not modify it. The stuff is read-write, at least some parts of
it. The ACPI code writes the opcode that the user writes into a sysfs
file into a location in memory . The ACPI code also reads the result
code from the last TPM operation (executed by the BIOS) from that memory
area.
> If readonly, you can just stick it there, right.
> If qemu has to modify it, that would breaks checksum,
> so it's better to allocate a blob and put the *pointer*
> to blob in the data table.
Right, the checksum. So we need to declare the base address of our
memory area using OperationRegion() where the address is found in that
UEFI table using DataTableRegion() and at a certain offset declared via
Field() -- just thinking out loud here.
>
> All problems in computer science can be solved by another level of
> indirection.
True.
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2015-06-02 16:28 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-05-26 21:33 [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Stefan Berger
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 1/6] Provide support for the CUSE TPM Stefan Berger
2015-05-26 23:05 ` Eric Blake
2015-05-27 1:53 ` Stefan Berger
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 2/6] Introduce RAM location in vendor specific area in TIS Stefan Berger
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 3/6] Support Physical Presence Interface Spec Stefan Berger
2015-05-31 18:11 ` Michael S. Tsirkin
2015-06-02 3:11 ` Stefan Berger
2015-06-02 9:15 ` Michael S. Tsirkin
2015-06-02 13:22 ` Stefan Berger
2015-06-02 13:30 ` Michael S. Tsirkin
2015-06-02 14:28 ` Stefan Berger
2015-06-02 14:46 ` Michael S. Tsirkin
2015-06-02 15:06 ` Stefan Berger
2015-06-02 15:11 ` Michael S. Tsirkin
2015-06-02 16:28 ` Stefan Berger
2015-06-02 15:18 ` Kevin O'Connor
2015-06-02 16:18 ` Stefan Berger
2015-06-02 15:00 ` Michael S. Tsirkin
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 4/6] Introduce condition to notifiy waiters of completed command Stefan Berger
2015-05-31 18:11 ` Michael S. Tsirkin
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 5/6] Introduce condition in TPM backend for notification Stefan Berger
2015-05-26 21:33 ` [Qemu-devel] [PATCH v3 6/6] Add support for VM suspend/resume for TPM TIS Stefan Berger
2015-05-31 18:11 ` [Qemu-devel] [PATCH v3 0/6] Extend TPM support with a QEMU-external TPM Michael S. Tsirkin
2015-06-02 13:17 ` Stefan Berger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).