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 "qapi/qmp/qerror.h"
  19#include "sysemu/tpm.h"
  20#include "hw/tpm/tpm_int.h"
  21#include "qemu/thread.h"
  22
  23static void tpm_backend_worker_thread(gpointer data, gpointer user_data)
  24{
  25    TPMBackend *s = TPM_BACKEND(user_data);
  26    TPMBackendClass *k  = TPM_BACKEND_GET_CLASS(s);
  27
  28    assert(k->handle_request != NULL);
  29    k->handle_request(s, (TPMBackendCmd *)data);
  30}
  31
  32static void tpm_backend_thread_end(TPMBackend *s)
  33{
  34    if (s->thread_pool) {
  35        g_thread_pool_free(s->thread_pool, FALSE, TRUE);
  36        s->thread_pool = NULL;
  37    }
  38}
  39
  40enum TpmType tpm_backend_get_type(TPMBackend *s)
  41{
  42    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
  43
  44    return k->type;
  45}
  46
  47int tpm_backend_init(TPMBackend *s, TPMState *state)
  48{
  49    s->tpm_state = state;
  50    s->had_startup_error = false;
  51
  52    return 0;
  53}
  54
  55int tpm_backend_startup_tpm(TPMBackend *s)
  56{
  57    int res = 0;
  58    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
  59
  60    /* terminate a running TPM */
  61    tpm_backend_thread_end(s);
  62
  63    s->thread_pool = g_thread_pool_new(tpm_backend_worker_thread, s, 1, TRUE,
  64                                       NULL);
  65
  66    res = k->startup_tpm ? k->startup_tpm(s) : 0;
  67
  68    s->had_startup_error = (res != 0);
  69
  70    return res;
  71}
  72
  73bool tpm_backend_had_startup_error(TPMBackend *s)
  74{
  75    return s->had_startup_error;
  76}
  77
  78void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd)
  79{
  80    g_thread_pool_push(s->thread_pool, cmd, NULL);
  81}
  82
  83void tpm_backend_reset(TPMBackend *s)
  84{
  85    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
  86
  87    if (k->reset) {
  88        k->reset(s);
  89    }
  90
  91    tpm_backend_thread_end(s);
  92
  93    s->had_startup_error = false;
  94}
  95
  96void tpm_backend_cancel_cmd(TPMBackend *s)
  97{
  98    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
  99
 100    assert(k->cancel_cmd);
 101
 102    k->cancel_cmd(s);
 103}
 104
 105bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
 106{
 107    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 108
 109    return k->get_tpm_established_flag ?
 110           k->get_tpm_established_flag(s) : false;
 111}
 112
 113int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty)
 114{
 115    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 116
 117    return k->reset_tpm_established_flag ?
 118           k->reset_tpm_established_flag(s, locty) : 0;
 119}
 120
 121TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
 122{
 123    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 124
 125    assert(k->get_tpm_version);
 126
 127    return k->get_tpm_version(s);
 128}
 129
 130TPMInfo *tpm_backend_query_tpm(TPMBackend *s)
 131{
 132    TPMInfo *info = g_new0(TPMInfo, 1);
 133    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 134
 135    info->id = g_strdup(s->id);
 136    info->model = s->fe_model;
 137    if (k->get_tpm_options) {
 138        info->options = k->get_tpm_options(s);
 139    }
 140
 141    return info;
 142}
 143
 144static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
 145{
 146    TPMBackend *s = TPM_BACKEND(obj);
 147
 148    return s->opened;
 149}
 150
 151void tpm_backend_open(TPMBackend *s, Error **errp)
 152{
 153    object_property_set_bool(OBJECT(s), true, "opened", errp);
 154}
 155
 156static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
 157{
 158    TPMBackend *s = TPM_BACKEND(obj);
 159    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
 160    Error *local_err = NULL;
 161
 162    if (value == s->opened) {
 163        return;
 164    }
 165
 166    if (!value && s->opened) {
 167        error_setg(errp, QERR_PERMISSION_DENIED);
 168        return;
 169    }
 170
 171    if (k->opened) {
 172        k->opened(s, &local_err);
 173        if (local_err) {
 174            error_propagate(errp, local_err);
 175            return;
 176        }
 177    }
 178
 179    s->opened = true;
 180}
 181
 182static void tpm_backend_instance_init(Object *obj)
 183{
 184    TPMBackend *s = TPM_BACKEND(obj);
 185
 186    object_property_add_bool(obj, "opened",
 187                             tpm_backend_prop_get_opened,
 188                             tpm_backend_prop_set_opened,
 189                             NULL);
 190    s->fe_model = -1;
 191}
 192
 193static void tpm_backend_instance_finalize(Object *obj)
 194{
 195    TPMBackend *s = TPM_BACKEND(obj);
 196
 197    g_free(s->id);
 198    tpm_backend_thread_end(s);
 199}
 200
 201static const TypeInfo tpm_backend_info = {
 202    .name = TYPE_TPM_BACKEND,
 203    .parent = TYPE_OBJECT,
 204    .instance_size = sizeof(TPMBackend),
 205    .instance_init = tpm_backend_instance_init,
 206    .instance_finalize = tpm_backend_instance_finalize,
 207    .class_size = sizeof(TPMBackendClass),
 208    .abstract = true,
 209};
 210
 211static const TypeInfo tpm_if_info = {
 212    .name = TYPE_TPM_IF,
 213    .parent = TYPE_INTERFACE,
 214    .class_size = sizeof(TPMIfClass),
 215};
 216
 217static void register_types(void)
 218{
 219    type_register_static(&tpm_backend_info);
 220    type_register_static(&tpm_if_info);
 221}
 222
 223type_init(register_types);
 224