qemu/backends/tpm.c
<<
>>
Prefs
   1/*
   2 * QEMU TPM Backend
   3 *
   4 * Copyright IBM, Corp. 2013
   5 *
   6 * Authors:
   7 *  Stefan Berger   <stefanb@us.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 *
  12 * Based on backends/rng.c by Anthony Liguori
  13 */
  14
  15#include "qemu/osdep.h"
  16#include "sysemu/tpm_backend.h"
  17#include "qapi/error.h"
  18#include "sysemu/tpm.h"
  19#include "qemu/thread.h"
  20#include "qemu/main-loop.h"
  21#include "block/thread-pool.h"
  22#include "qemu/error-report.h"
  23
  24static void tpm_backend_request_completed(void *opaque, int ret)
  25{
  26    TPMBackend *s = TPM_BACKEND(opaque);
  27    TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
  28
  29    tic->request_completed(s->tpmif, ret);
  30
  31    /* no need for atomic, as long the BQL is taken */
  32    s->cmd = NULL;
  33    object_unref(OBJECT(s));
  34}
  35
  36static int tpm_backend_worker_thread(gpointer data)
  37{
  38    TPMBackend *s = TPM_BACKEND(data);
  39    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
  40    Error *err = NULL;
  41
  42    k->handle_request(s, s->cmd, &err);
  43    if (err) {
  44        error_report_err(err);
  45        return -1;
  46    }
  47
  48    return 0;
  49}
  50
  51void tpm_backend_finish_sync(TPMBackend *s)
  52{
  53    while (s->cmd) {
  54        aio_poll(qemu_get_aio_context(), true);
  55    }
  56}
  57
  58enum TpmType tpm_backend_get_type(TPMBackend *s)
  59{
  60    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
  61
  62    return k->type;
  63}
  64
  65int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp)
  66{
  67    if (s->tpmif) {
  68        error_setg(errp, "TPM backend '%s' is already initialized", s->id);
  69        return -1;
  70    }
  71
  72    s->tpmif = tpmif;
  73    object_ref(OBJECT(tpmif));
  74
  75    s->had_startup_error = false;
  76
  77    return 0;
  78}
  79
  80int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize)
  81{
  82    int res = 0;
  83    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
  84
  85    /* terminate a running TPM */
  86    tpm_backend_finish_sync(s);
  87
  88    res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0;
  89
  90    s->had_startup_error = (res != 0);
  91
  92    return res;
  93}
  94
  95bool tpm_backend_had_startup_error(TPMBackend *s)
  96{
  97    return s->had_startup_error;
  98}
  99
 100void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd)
 101{
 102    ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
 103
 104    if (s->cmd != NULL) {
 105        error_report("There is a TPM request pending");
 106        return;
 107    }
 108
 109    s->cmd = cmd;
 110    object_ref(OBJECT(s));
 111    thread_pool_submit_aio(pool, tpm_backend_worker_thread, s,
 112                           tpm_backend_request_completed, s);
 113}
 114
 115void tpm_backend_reset(TPMBackend *s)
 116{
 117    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 118
 119    if (k->reset) {
 120        k->reset(s);
 121    }
 122
 123    tpm_backend_finish_sync(s);
 124
 125    s->had_startup_error = false;
 126}
 127
 128void tpm_backend_cancel_cmd(TPMBackend *s)
 129{
 130    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 131
 132    k->cancel_cmd(s);
 133}
 134
 135bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
 136{
 137    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 138
 139    return k->get_tpm_established_flag ?
 140           k->get_tpm_established_flag(s) : false;
 141}
 142
 143int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty)
 144{
 145    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 146
 147    return k->reset_tpm_established_flag ?
 148           k->reset_tpm_established_flag(s, locty) : 0;
 149}
 150
 151TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
 152{
 153    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 154
 155    return k->get_tpm_version(s);
 156}
 157
 158size_t tpm_backend_get_buffer_size(TPMBackend *s)
 159{
 160    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 161
 162    return k->get_buffer_size(s);
 163}
 164
 165TPMInfo *tpm_backend_query_tpm(TPMBackend *s)
 166{
 167    TPMInfo *info = g_new0(TPMInfo, 1);
 168    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 169    TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
 170
 171    info->id = g_strdup(s->id);
 172    info->model = tic->model;
 173    info->options = k->get_tpm_options(s);
 174
 175    return info;
 176}
 177
 178static void tpm_backend_instance_finalize(Object *obj)
 179{
 180    TPMBackend *s = TPM_BACKEND(obj);
 181
 182    object_unref(OBJECT(s->tpmif));
 183    g_free(s->id);
 184}
 185
 186static const TypeInfo tpm_backend_info = {
 187    .name = TYPE_TPM_BACKEND,
 188    .parent = TYPE_OBJECT,
 189    .instance_size = sizeof(TPMBackend),
 190    .instance_finalize = tpm_backend_instance_finalize,
 191    .class_size = sizeof(TPMBackendClass),
 192    .abstract = true,
 193};
 194
 195static const TypeInfo tpm_if_info = {
 196    .name = TYPE_TPM_IF,
 197    .parent = TYPE_INTERFACE,
 198    .class_size = sizeof(TPMIfClass),
 199};
 200
 201static void register_types(void)
 202{
 203    type_register_static(&tpm_backend_info);
 204    type_register_static(&tpm_if_info);
 205}
 206
 207type_init(register_types);
 208