summary refs log tree commit diff stats
path: root/hw/tpm/tpm_passthrough.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/tpm/tpm_passthrough.c')
-rw-r--r--hw/tpm/tpm_passthrough.c242
1 files changed, 51 insertions, 191 deletions
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 9234eb3459..e6ace28b04 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -30,7 +30,7 @@
 #include "tpm_int.h"
 #include "hw/hw.h"
 #include "hw/i386/pc.h"
-#include "sysemu/tpm_backend_int.h"
+#include "qapi/clone-visitor.h"
 #include "tpm_tis.h"
 #include "tpm_util.h"
 
@@ -46,29 +46,16 @@
 #define TPM_PASSTHROUGH(obj) \
     OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
 
-static const TPMDriverOps tpm_passthrough_driver;
-
 /* data structures */
-typedef struct TPMPassthruThreadParams {
-    TPMState *tpm_state;
-
-    TPMRecvDataCB *recv_data_callback;
-    TPMBackend *tb;
-} TPMPassthruThreadParams;
-
 struct TPMPassthruState {
     TPMBackend parent;
 
-    TPMBackendThread tbt;
-
-    TPMPassthruThreadParams tpm_thread_params;
-
-    char *tpm_dev;
+    TPMPassthroughOptions *options;
+    const char *tpm_dev;
     int tpm_fd;
     bool tpm_executing;
     bool tpm_op_canceled;
     int cancel_fd;
-    bool had_startup_error;
 
     TPMVersion tpm_version;
 };
@@ -81,27 +68,6 @@ typedef struct TPMPassthruState TPMPassthruState;
 
 static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
 
-static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len)
-{
-    int ret, remain;
-
-    remain = len;
-    while (remain > 0) {
-        ret = write(fd, buf, remain);
-        if (ret < 0) {
-            if (errno != EINTR && errno != EAGAIN) {
-                return -1;
-            }
-        } else if (ret == 0) {
-            break;
-        } else {
-            buf += ret;
-            remain -= ret;
-        }
-    }
-    return len - remain;
-}
-
 static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
 {
     int ret;
@@ -115,45 +81,12 @@ static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
     }
     return ret;
 }
-
-static uint32_t tpm_passthrough_get_size_from_buffer(const uint8_t *buf)
-{
-    struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)buf;
-
-    return be32_to_cpu(resp->len);
-}
-
-/*
- * Write an error message in the given output buffer.
- */
-static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
-{
-    if (out_len >= sizeof(struct tpm_resp_hdr)) {
-        struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out;
-
-        resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND);
-        resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr));
-        resp->errcode = cpu_to_be32(TPM_FAIL);
-    }
-}
-
-static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len)
-{
-    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
-
-    if (in_len >= sizeof(*hdr)) {
-        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
-    }
-
-    return false;
-}
-
 static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
                                         const uint8_t *in, uint32_t in_len,
                                         uint8_t *out, uint32_t out_len,
                                         bool *selftest_done)
 {
-    int ret;
+    ssize_t ret;
     bool is_selftest;
     const struct tpm_resp_hdr *hdr;
 
@@ -161,9 +94,9 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
     tpm_pt->tpm_executing = true;
     *selftest_done = false;
 
-    is_selftest = tpm_passthrough_is_selftest(in, in_len);
+    is_selftest = tpm_util_is_selftest(in, in_len);
 
-    ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
+    ret = qemu_write_full(tpm_pt->tpm_fd, (const void *)in, (size_t)in_len);
     if (ret != in_len) {
         if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
             error_report("tpm_passthrough: error while transmitting data "
@@ -183,7 +116,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
                          strerror(errno), errno);
         }
     } else if (ret < sizeof(struct tpm_resp_hdr) ||
-               tpm_passthrough_get_size_from_buffer(out) != ret) {
+               be32_to_cpu(((struct tpm_resp_hdr *)out)->len) != ret) {
         ret = -1;
         error_report("tpm_passthrough: received invalid response "
                      "packet from TPM");
@@ -196,7 +129,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
 
 err_exit:
     if (ret < 0) {
-        tpm_write_fatal_error_response(out, out_len);
+        tpm_util_write_fatal_error_response(out, out_len);
     }
 
     tpm_pt->tpm_executing = false;
@@ -216,12 +149,9 @@ static int tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt,
                                         selftest_done);
 }
 
-static void tpm_passthrough_worker_thread(gpointer data,
-                                          gpointer user_data)
+static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd cmd)
 {
-    TPMPassthruThreadParams *thr_parms = user_data;
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(thr_parms->tb);
-    TPMBackendCmd cmd = (TPMBackendCmd)data;
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
     bool selftest_done = false;
 
     DPRINTF("tpm_passthrough: processing command type %d\n", cmd);
@@ -229,12 +159,12 @@ 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_data,
+                                      tb->tpm_state->locty_data,
                                       &selftest_done);
 
-        thr_parms->recv_data_callback(thr_parms->tpm_state,
-                                      thr_parms->tpm_state->locty_number,
-                                      selftest_done);
+        tb->recv_data_callback(tb->tpm_state,
+                               tb->tpm_state->locty_number,
+                               selftest_done);
         break;
     case TPM_BACKEND_CMD_INIT:
     case TPM_BACKEND_CMD_END:
@@ -244,47 +174,11 @@ static void tpm_passthrough_worker_thread(gpointer data,
     }
 }
 
-/*
- * Start the TPM (thread). If it had been started before, then terminate
- * and start it again.
- */
-static int tpm_passthrough_startup_tpm(TPMBackend *tb)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
-    /* terminate a running TPM */
-    tpm_backend_thread_end(&tpm_pt->tbt);
-
-    tpm_backend_thread_create(&tpm_pt->tbt,
-                              tpm_passthrough_worker_thread,
-                              &tpm_pt->tpm_thread_params);
-
-    return 0;
-}
-
 static void tpm_passthrough_reset(TPMBackend *tb)
 {
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
     DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n");
 
     tpm_passthrough_cancel_cmd(tb);
-
-    tpm_backend_thread_end(&tpm_pt->tbt);
-
-    tpm_pt->had_startup_error = false;
-}
-
-static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
-                                TPMRecvDataCB *recv_data_cb)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
-    tpm_pt->tpm_thread_params.tpm_state = s;
-    tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb;
-    tpm_pt->tpm_thread_params.tb = tb;
-
-    return 0;
 }
 
 static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
@@ -299,31 +193,6 @@ static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
     return 0;
 }
 
-static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
-    return tpm_pt->had_startup_error;
-}
-
-static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb)
-{
-    size_t wanted_size = 4096; /* Linux tpm.c buffer size */
-
-    if (sb->size != wanted_size) {
-        sb->buffer = g_realloc(sb->buffer, wanted_size);
-        sb->size = wanted_size;
-    }
-    return sb->size;
-}
-
-static void tpm_passthrough_deliver_request(TPMBackend *tb)
-{
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
-    tpm_backend_thread_deliver_request(&tpm_pt->tbt);
-}
-
 static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
 {
     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
@@ -351,11 +220,6 @@ static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
     }
 }
 
-static const char *tpm_passthrough_create_desc(void)
-{
-    return "Passthrough TPM backend driver";
-}
-
 static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
 {
     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
@@ -369,15 +233,14 @@ static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
  * in Documentation/ABI/stable/sysfs-class-tpm.
  * From /dev/tpm0 create /sys/class/misc/tpm0/device/cancel
  */
-static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb)
+static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
 {
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
     int fd = -1;
     char *dev;
     char path[PATH_MAX];
 
-    if (tb->cancel_path) {
-        fd = qemu_open(tb->cancel_path, O_WRONLY);
+    if (tpm_pt->options->cancel_path) {
+        fd = qemu_open(tpm_pt->options->cancel_path, O_WRONLY);
         if (fd < 0) {
             error_report("Could not open TPM cancel path : %s",
                          strerror(errno));
@@ -392,7 +255,7 @@ static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb)
                      dev) < sizeof(path)) {
             fd = qemu_open(path, O_WRONLY);
             if (fd >= 0) {
-                tb->cancel_path = g_strdup(path);
+                tpm_pt->options->cancel_path = g_strdup(path);
             } else {
                 error_report("tpm_passthrough: Could not open TPM cancel "
                              "path %s : %s", path, strerror(errno));
@@ -412,17 +275,18 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
     const char *value;
 
     value = qemu_opt_get(opts, "cancel-path");
-    tb->cancel_path = g_strdup(value);
+    if (value) {
+        tpm_pt->options->cancel_path = g_strdup(value);
+        tpm_pt->options->has_cancel_path = true;
+    }
 
     value = qemu_opt_get(opts, "path");
-    if (!value) {
-        value = TPM_PASSTHROUGH_DEFAULT_DEVICE;
+    if (value) {
+        tpm_pt->options->has_path = true;
+        tpm_pt->options->path = g_strdup(value);
     }
 
-    tpm_pt->tpm_dev = g_strdup(value);
-
-    tb->path = g_strdup(tpm_pt->tpm_dev);
-
+    tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
     tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR);
     if (tpm_pt->tpm_fd < 0) {
         error_report("Cannot access TPM device using '%s': %s",
@@ -443,10 +307,8 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
     tpm_pt->tpm_fd = -1;
 
  err_free_parameters:
-    g_free(tb->path);
-    tb->path = NULL;
-
-    g_free(tpm_pt->tpm_dev);
+    qapi_free_TPMPassthroughOptions(tpm_pt->options);
+    tpm_pt->options = NULL;
     tpm_pt->tpm_dev = NULL;
 
     return 1;
@@ -459,16 +321,12 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
 
     tb->id = g_strdup(id);
-    /* let frontend set the fe_model to proper value */
-    tb->fe_model = -1;
-
-    tb->ops = &tpm_passthrough_driver;
 
     if (tpm_passthrough_handle_device_opts(opts, tb)) {
         goto err_exit;
     }
 
-    tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb);
+    tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt);
     if (tpm_pt->cancel_fd < 0) {
         goto err_exit;
     }
@@ -476,26 +334,20 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
     return tb;
 
 err_exit:
-    g_free(tb->id);
+    object_unref(obj);
 
     return NULL;
 }
 
-static void tpm_passthrough_destroy(TPMBackend *tb)
+static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb)
 {
-    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+    TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
 
-    tpm_passthrough_cancel_cmd(tb);
-
-    tpm_backend_thread_end(&tpm_pt->tbt);
-
-    qemu_close(tpm_pt->tpm_fd);
-    qemu_close(tpm_pt->cancel_fd);
+    options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
+    options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions,
+                                             TPM_PASSTHROUGH(tb)->options);
 
-    g_free(tb->id);
-    g_free(tb->path);
-    g_free(tb->cancel_path);
-    g_free(tpm_pt->tpm_dev);
+    return options;
 }
 
 static const QemuOptDesc tpm_passthrough_cmdline_opts[] = {
@@ -516,27 +368,34 @@ static const QemuOptDesc tpm_passthrough_cmdline_opts[] = {
 static const TPMDriverOps tpm_passthrough_driver = {
     .type                     = TPM_TYPE_PASSTHROUGH,
     .opts                     = tpm_passthrough_cmdline_opts,
-    .desc                     = tpm_passthrough_create_desc,
+    .desc                     = "Passthrough TPM backend driver",
     .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,
+    .get_tpm_options          = tpm_passthrough_get_tpm_options,
 };
 
 static void tpm_passthrough_inst_init(Object *obj)
 {
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
+
+    tpm_pt->options = g_new0(TPMPassthroughOptions, 1);
+    tpm_pt->tpm_fd = -1;
+    tpm_pt->cancel_fd = -1;
 }
 
 static void tpm_passthrough_inst_finalize(Object *obj)
 {
+    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
+
+    tpm_passthrough_cancel_cmd(TPM_BACKEND(obj));
+
+    qemu_close(tpm_pt->tpm_fd);
+    qemu_close(tpm_pt->cancel_fd);
+    qapi_free_TPMPassthroughOptions(tpm_pt->options);
 }
 
 static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
@@ -544,6 +403,7 @@ static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
     TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
 
     tbc->ops = &tpm_passthrough_driver;
+    tbc->handle_request = tpm_passthrough_handle_request;
 }
 
 static const TypeInfo tpm_passthrough_info = {