[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH V2 7/9] Add a TPM backend skeleton implementation
From: |
Stefan Berger |
Subject: |
[Qemu-devel] [PATCH V2 7/9] Add a TPM backend skeleton implementation |
Date: |
Wed, 30 Mar 2011 15:42:18 -0400 |
User-agent: |
quilt/0.48-1 |
This patch provides a TPM backend skelteon implementation. It doesn't do
anything but it compiles.
Signed-off-by: Stefan Berger <address@hidden>
---
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,
};
- [Qemu-devel] [PATCH V2 0/9] Qemu Trusted Platform Module (TPM) integration, Stefan Berger, 2011/03/30
- [Qemu-devel] [PATCH V2 8/9] Implementation of the libtpms-based backend, Stefan Berger, 2011/03/30
- [Qemu-devel] [PATCH V2 3/9] Add persistent state handling to TPM TIS frontend driver, Stefan Berger, 2011/03/30
- [Qemu-devel] [PATCH V2 5/9] Add a debug register, Stefan Berger, 2011/03/30
- [Qemu-devel] [PATCH V2 1/9] Support for TPM command line options, Stefan Berger, 2011/03/30
- [Qemu-devel] [PATCH V2 9/9] Add block storage support for libtpms based TPM backend, Stefan Berger, 2011/03/30
- [Qemu-devel] [PATCH V2 4/9] Add tpm_tis driver to build process, Stefan Berger, 2011/03/30
- [Qemu-devel] [PATCH V2 7/9] Add a TPM backend skeleton implementation,
Stefan Berger <=
- [Qemu-devel] [PATCH V2 2/9] Add TPM (frontend) hardware interface (TPM TIS) to Qemu, Stefan Berger, 2011/03/30
- [Qemu-devel] [PATCH V2 6/9] Implement qemu_thread_join function, Stefan Berger, 2011/03/30