From: Stefan Berger <stefanb@linux.vnet.ibm.com>
To: stefanb@linux.vnet.ibm.com, qemu-devel@nongnu.org
Cc: andreas.niederl@iaik.tugraz.at
Subject: [Qemu-devel] [PATCH V2 7/9] Add a TPM backend skeleton implementation
Date: Wed, 30 Mar 2011 15:42:18 -0400 [thread overview]
Message-ID: <20110330194238.345360626@linux.vnet.ibm.com> (raw)
In-Reply-To: 20110330194211.732385449@linux.vnet.ibm.com
[-- Attachment #1: qemu_tpm_be_skeleton.diff --]
[-- Type: text/plain, Size: 10934 bytes --]
This patch provides a TPM backend skelteon implementation. It doesn't do
anything but it compiles.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
Makefile.target | 5
hw/tpm_builtin.c | 372 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/tpm_tis.c | 3
3 files changed, 380 insertions(+)
Index: qemu-git/hw/tpm_builtin.c
===================================================================
--- /dev/null
+++ qemu-git/hw/tpm_builtin.c
@@ -0,0 +1,372 @@
+/*
+ *
+ * Copyright (c) 2010, 2011 IBM Corporation
+ * Copyright (c) 2010, 2011 Stefan Berger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "hw/tpm_tis.h"
+#include "hw/pc.h"
+
+//#define DEBUG_TPM
+//#define DEBUG_TPM_SR /* suspend - resume */
+
+
+/* data structures */
+
+typedef struct ThreadParams {
+ TPMState *tpm_state;
+
+ TPMRecvDataCB *recv_data_callback;
+} ThreadParams;
+
+
+/* local variables */
+
+static QemuThread thread;
+
+static QemuMutex state_mutex; /* protects *_state below */
+
+static bool thread_terminate = false;
+static bool tpm_initialized = false;
+static bool had_fatal_error = false;
+static bool had_startup_error = false;
+
+static ThreadParams tpm_thread_params;
+
+/* locality of the command being executed by libtpms */
+static uint8_t g_locty;
+
+static const unsigned char tpm_std_fatal_error_response[10] = {
+ 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x09 /* TPM_FAIL */
+};
+
+static char dev_description[80];
+
+
+/**
+ * Start the TPM. If it had been started before, then terminate and start
+ * it again.
+ */
+static int startup_tpm(void)
+{
+ tpm_initialized = true;
+
+#if defined DEBUG_TPM || defined DEBUG_TPM_SR
+ fprintf(stderr,"tpm: *** tpm startup was successful! ***\n");
+#endif
+
+ return 0;
+}
+
+
+/*
+ * Start up the TPM before it sees the first command.
+ * We need to do this late since only now we will have the
+ * block storage encryption key and can read the previous
+ * TPM state. During 'reset' the key would not be available.
+ */
+static int late_startup_tpm(void)
+{
+ int rc;
+
+ rc = startup_tpm();
+ if (rc) {
+ had_fatal_error = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void terminate_tpm_thread(void)
+{
+ if (!thread_terminate) {
+ thread_terminate = true;
+
+ qemu_mutex_lock (&tpm_thread_params.tpm_state->state_lock);
+ qemu_cond_signal (&tpm_thread_params.tpm_state->to_tpm_cond);
+ qemu_mutex_unlock(&tpm_thread_params.tpm_state->state_lock);
+
+ qemu_thread_join(&thread, NULL);
+ memset(&thread, 0, sizeof(thread));
+
+ if (tpm_initialized) {
+ tpm_initialized = false;
+ }
+ }
+}
+
+
+static void tpm_atexit(void)
+{
+ terminate_tpm_thread();
+}
+
+
+static void *mainLoop(void *d)
+{
+ int res = 0;
+ ThreadParams *tParams = (ThreadParams *)d;
+ uint32_t in_len, out_len;
+ uint8_t *in, *out;
+ uint32_t resp_size; /* total length of response */
+
+ /* start command processing */
+ while (!thread_terminate) {
+ /* receive and handle commands */
+ in_len = 0;
+ do {
+#ifdef DEBUG_TPM
+ fprintf(stderr,"waiting for commands...\n");
+#endif
+
+ if (thread_terminate) {
+ break;
+ }
+
+ qemu_mutex_lock(&tParams->tpm_state->state_lock);
+
+ /* in case we were to slow and missed the signal, the
+ to_tpm_execute boolean tells us about a pending command */
+ if (!tParams->tpm_state->to_tpm_execute) {
+ qemu_cond_wait(&tParams->tpm_state->to_tpm_cond,
+ &tParams->tpm_state->state_lock);
+ }
+
+ tParams->tpm_state->to_tpm_execute = false;
+
+ qemu_mutex_unlock(&tParams->tpm_state->state_lock);
+
+ if (thread_terminate) {
+ break;
+ }
+
+ g_locty = tParams->tpm_state->command_locty;
+
+ in = tParams->tpm_state->loc[g_locty].w_buffer.buffer;
+ in_len = tParams->tpm_state->loc[g_locty].w_offset;
+
+ if (!had_fatal_error) {
+
+ out_len = tParams->tpm_state->loc[g_locty].r_buffer.size;
+
+#ifdef DEBUG_TPM
+ fprintf(stderr,
+ "tpm: received %d bytes from VM in locality %d\n",
+ in_len,
+ g_locty);
+ dumpBuffer(stdout, in, in_len);
+#endif
+
+ resp_size = 0;
+
+
+ // !!! Send command to TPM & wait for response
+
+
+ if (res != 0) {
+#ifdef DEBUG_TPM
+ fprintf(stderr,
+ "Sending/receiving TPM request/response "
+ "failed\n");
+#endif
+ had_fatal_error = 1;
+ }
+ }
+
+ if (had_fatal_error) {
+ out = tParams->tpm_state->loc[g_locty].r_buffer.buffer;
+ resp_size = sizeof(tpm_std_fatal_error_response);
+ memcpy(out, tpm_std_fatal_error_response, resp_size);
+ out[1] = (in_len > 2 && in[1] >= 0xc1 && in[1] <= 0xc3)
+ ? in[1] + 3
+ : 0xc4;
+ }
+#ifdef DEBUG_TPM
+ fprintf(stderr,"sending %d bytes to VM\n", resp_size);
+ dumpBuffer(stdout, out, resp_size);
+#endif
+ tParams->recv_data_callback(tParams->tpm_state, g_locty);
+ } while (in_len > 0);
+ }
+
+ return NULL;
+}
+
+
+
+/*****************************************************************/
+
+
+static void reset(void)
+{
+ static bool thread_running;
+
+#if defined DEBUG_TPM || defined DEBUG_TPM_SR
+ fprintf(stderr,"tpm: CALL TO TPM_RESET!\n");
+#endif
+
+ if (thread_running) {
+#if defined DEBUG_TPM || defined DEBUG_TPM_SR
+ fprintf(stderr,"tpm: TERMINATING RUNNING TPM THREAD\n");
+#endif
+ terminate_tpm_thread();
+ }
+
+ had_fatal_error = false;
+ thread_terminate = false;
+ had_startup_error = false;
+
+ qemu_thread_create(&thread, mainLoop, &tpm_thread_params);
+ thread_running = true;
+}
+
+
+/*
+ * restore TPM volatile state from given data
+ *
+ * The data are ignore by this driver, instead we read the volatile state
+ * from the TPM block store.
+ *
+ * This function gets called by Qemu when
+ * (1) resuming after a suspend
+ * (2) resuming a snapshot
+ *
+ * (1) works fine since we get call to the reset function as well
+ * (2) requires us to call the reset function ourselves; we do this
+ * indirectly by calling the tis_reset_for_snapshot_resume();
+ * a sure indicator of whether this function is called due to a resume
+ * of a snapshot is that the tpm_initialized variable is 'true'.
+ *
+ */
+static int instantiate_with_volatile_data(TPMState *s)
+{
+ if (tpm_initialized) {
+#ifdef DEBUG_TPM_SR
+ fprintf(stderr,"tpm: This is resume of a SNAPSHOT?!\n");
+#endif
+ // !!! Xen does not support this ...
+ tis_reset_for_snapshot_resume(s);
+ }
+
+ return 0;
+}
+
+
+static int init(TPMState *s, TPMRecvDataCB *recv_data_cb)
+{
+ tpm_thread_params.tpm_state = s;
+ tpm_thread_params.recv_data_callback = recv_data_cb;
+
+ qemu_mutex_init(&state_mutex);
+
+ // !!! Do necessary initialization here
+
+ atexit(tpm_atexit);
+
+ return 0;
+}
+
+
+static bool get_tpm_established_flag(void)
+{
+ return false;
+}
+
+
+static bool get_startup_error(void)
+{
+ return had_startup_error;
+}
+
+
+/**
+ * This function is called by tpm_tis.c once the TPM has processed
+ * the last command and returned the response to the TIS.
+ */
+static int save_volatile_data(void)
+{
+ if (!tpm_initialized) {
+ /* TPM was never initialized
+ volatile_state.buffer may be NULL if TPM was never used.
+ */
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static size_t realloc_buffer(TPMSizedBuffer *sb)
+{
+ size_t wanted_size = 4096;
+
+ if (sb->size != wanted_size) {
+ sb->buffer = qemu_realloc(&sb->buffer, wanted_size);
+ if (sb->buffer != NULL)
+ sb->size = wanted_size;
+ else
+ sb->size = 0;
+ }
+ return sb->size;
+}
+
+
+static const char *create_desc(void)
+{
+ static int done;
+
+ if (!done) {
+ snprintf(dev_description, sizeof(dev_description),
+ "Skeleton TPM backend");
+ done = 1;
+ }
+
+ return dev_description;
+}
+
+
+static bool handle_options(QemuOpts *opts)
+{
+ const char *value;
+
+ value = qemu_opt_get(opts, "path");
+ if (value) {
+ // !!! handle path parameter
+ } else {
+ fprintf(stderr,"-tpm is missing path= parameter\n");
+ return false;
+ }
+ return true;
+}
+
+
+BackendTPMDriver skeleton = {
+ .id = "skeleton",
+ .desc = create_desc,
+ .handle_options = handle_options,
+ .init = init,
+ .late_startup_tpm = late_startup_tpm,
+ .realloc_buffer = realloc_buffer,
+ .reset = reset,
+ .had_startup_error = get_startup_error,
+ .save_volatile_data = save_volatile_data,
+ .load_volatile_data = instantiate_with_volatile_data,
+ .get_tpm_established_flag = get_tpm_established_flag,
+};
Index: qemu-git/Makefile.target
===================================================================
--- qemu-git.orig/Makefile.target
+++ qemu-git/Makefile.target
@@ -307,6 +307,11 @@ obj-sparc-y += grlib_gptimer.o grlib_irq
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),i386 x86_64))
obj-i386-$(CONFIG_TPM) += tpm_tis.o
+obj-i386-$(CONFIG_TPM_BUILTIN) += tpm_builtin.o
+
+ifdef CONFIG_TPM_BUILTIN
+LIBS+=-ltpms
+endif
endif
Index: qemu-git/hw/tpm_tis.c
===================================================================
--- qemu-git.orig/hw/tpm_tis.c
+++ qemu-git/hw/tpm_tis.c
@@ -95,6 +95,9 @@ static uint32_t tis_mem_readl(void *opaq
static const BackendTPMDriver *bes[] = {
+#ifdef CONFIG_TPM_BUILTIN
+ &builtin,
+#endif
NULL,
};
next prev parent reply other threads:[~2011-03-30 19:42 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-03-30 19:42 [Qemu-devel] [PATCH V2 0/9] Qemu Trusted Platform Module (TPM) integration Stefan Berger
2011-03-30 19:42 ` [Qemu-devel] [PATCH V2 1/9] Support for TPM command line options Stefan Berger
2011-03-30 19:42 ` [Qemu-devel] [PATCH V2 2/9] Add TPM (frontend) hardware interface (TPM TIS) to Qemu Stefan Berger
2011-03-30 19:42 ` [Qemu-devel] [PATCH V2 3/9] Add persistent state handling to TPM TIS frontend driver Stefan Berger
2011-03-30 19:42 ` [Qemu-devel] [PATCH V2 4/9] Add tpm_tis driver to build process Stefan Berger
2011-04-01 18:14 ` Blue Swirl
2011-04-01 19:57 ` Stefan Berger
2011-04-03 9:20 ` Blue Swirl
2011-04-05 2:08 ` Stefan Berger
2011-04-05 17:45 ` Blue Swirl
2011-04-05 18:33 ` Stefan Berger
2011-04-05 18:55 ` Blue Swirl
2011-04-06 0:12 ` Stefan Berger
2011-03-30 19:42 ` [Qemu-devel] [PATCH V2 5/9] Add a debug register Stefan Berger
2011-03-30 19:42 ` [Qemu-devel] [PATCH V2 6/9] Implement qemu_thread_join function Stefan Berger
2011-03-30 19:42 ` Stefan Berger [this message]
2011-03-30 19:42 ` [Qemu-devel] [PATCH V2 8/9] Implementation of the libtpms-based backend Stefan Berger
2011-03-30 19:42 ` [Qemu-devel] [PATCH V2 9/9] Add block storage support for libtpms based TPM backend Stefan Berger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110330194238.345360626@linux.vnet.ibm.com \
--to=stefanb@linux.vnet.ibm.com \
--cc=andreas.niederl@iaik.tugraz.at \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.