qemu/hw/tpm/tpm_emulator.c
<<
>>
Prefs
   1/*
   2 *  Emulator TPM driver
   3 *
   4 *  Copyright (c) 2017 Intel Corporation
   5 *  Author: Amarnath Valluri <amarnath.valluri@intel.com>
   6 *
   7 *  Copyright (c) 2010 - 2013 IBM Corporation
   8 *  Authors:
   9 *    Stefan Berger <stefanb@us.ibm.com>
  10 *
  11 *  Copyright (C) 2011 IAIK, Graz University of Technology
  12 *    Author: Andreas Niederl
  13 *
  14 * This library is free software; you can redistribute it and/or
  15 * modify it under the terms of the GNU Lesser General Public
  16 * License as published by the Free Software Foundation; either
  17 * version 2 of the License, or (at your option) any later version.
  18 *
  19 * This library is distributed in the hope that it will be useful,
  20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  22 * Lesser General Public License for more details.
  23 *
  24 * You should have received a copy of the GNU Lesser General Public
  25 * License along with this library; if not, see <http://www.gnu.org/licenses/>
  26 *
  27 */
  28
  29#include "qemu/osdep.h"
  30#include "qemu/error-report.h"
  31#include "qemu/sockets.h"
  32#include "io/channel-socket.h"
  33#include "sysemu/tpm_backend.h"
  34#include "tpm_int.h"
  35#include "hw/hw.h"
  36#include "tpm_util.h"
  37#include "tpm_ioctl.h"
  38#include "migration/blocker.h"
  39#include "qapi/error.h"
  40#include "qapi/clone-visitor.h"
  41#include "qapi/qapi-visit-tpm.h"
  42#include "chardev/char-fe.h"
  43#include "trace.h"
  44
  45#define TYPE_TPM_EMULATOR "tpm-emulator"
  46#define TPM_EMULATOR(obj) \
  47    OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)
  48
  49#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))
  50
  51/* data structures */
  52typedef struct TPMEmulator {
  53    TPMBackend parent;
  54
  55    TPMEmulatorOptions *options;
  56    CharBackend ctrl_chr;
  57    QIOChannel *data_ioc;
  58    TPMVersion tpm_version;
  59    ptm_cap caps; /* capabilities of the TPM */
  60    uint8_t cur_locty_number; /* last set locality */
  61    Error *migration_blocker;
  62
  63    QemuMutex mutex;
  64
  65    unsigned int established_flag:1;
  66    unsigned int established_flag_cached:1;
  67} TPMEmulator;
  68
  69
  70static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg,
  71                                size_t msg_len_in, size_t msg_len_out)
  72{
  73    CharBackend *dev = &tpm->ctrl_chr;
  74    uint32_t cmd_no = cpu_to_be32(cmd);
  75    ssize_t n = sizeof(uint32_t) + msg_len_in;
  76    uint8_t *buf = NULL;
  77    int ret = -1;
  78
  79    qemu_mutex_lock(&tpm->mutex);
  80
  81    buf = g_alloca(n);
  82    memcpy(buf, &cmd_no, sizeof(cmd_no));
  83    memcpy(buf + sizeof(cmd_no), msg, msg_len_in);
  84
  85    n = qemu_chr_fe_write_all(dev, buf, n);
  86    if (n <= 0) {
  87        goto end;
  88    }
  89
  90    if (msg_len_out != 0) {
  91        n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
  92        if (n <= 0) {
  93            goto end;
  94        }
  95    }
  96
  97    ret = 0;
  98
  99end:
 100    qemu_mutex_unlock(&tpm->mutex);
 101    return ret;
 102}
 103
 104static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu,
 105                                     const uint8_t *in, uint32_t in_len,
 106                                     uint8_t *out, uint32_t out_len,
 107                                     bool *selftest_done,
 108                                     Error **err)
 109{
 110    ssize_t ret;
 111    bool is_selftest = false;
 112
 113    if (selftest_done) {
 114        *selftest_done = false;
 115        is_selftest = tpm_util_is_selftest(in, in_len);
 116    }
 117
 118    ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, err);
 119    if (ret != 0) {
 120        return -1;
 121    }
 122
 123    ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out,
 124              sizeof(struct tpm_resp_hdr), err);
 125    if (ret != 0) {
 126        return -1;
 127    }
 128
 129    ret = qio_channel_read_all(tpm_emu->data_ioc,
 130              (char *)out + sizeof(struct tpm_resp_hdr),
 131              tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), err);
 132    if (ret != 0) {
 133        return -1;
 134    }
 135
 136    if (is_selftest) {
 137        *selftest_done = tpm_cmd_get_errcode(out) == 0;
 138    }
 139
 140    return 0;
 141}
 142
 143static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number,
 144                                     Error **errp)
 145{
 146    ptm_loc loc;
 147
 148    if (tpm_emu->cur_locty_number == locty_number) {
 149        return 0;
 150    }
 151
 152    trace_tpm_emulator_set_locality(locty_number);
 153
 154    loc.u.req.loc = locty_number;
 155    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_LOCALITY, &loc,
 156                             sizeof(loc), sizeof(loc)) < 0) {
 157        error_setg(errp, "tpm-emulator: could not set locality : %s",
 158                   strerror(errno));
 159        return -1;
 160    }
 161
 162    loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);
 163    if (loc.u.resp.tpm_result != 0) {
 164        error_setg(errp, "tpm-emulator: TPM result for set locality : 0x%x",
 165                   loc.u.resp.tpm_result);
 166        return -1;
 167    }
 168
 169    tpm_emu->cur_locty_number = locty_number;
 170
 171    return 0;
 172}
 173
 174static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
 175                                        Error **errp)
 176{
 177    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
 178
 179    trace_tpm_emulator_handle_request();
 180
 181    if (tpm_emulator_set_locality(tpm_emu, cmd->locty, errp) < 0 ||
 182        tpm_emulator_unix_tx_bufs(tpm_emu, cmd->in, cmd->in_len,
 183                                  cmd->out, cmd->out_len,
 184                                  &cmd->selftest_done, errp) < 0) {
 185        tpm_util_write_fatal_error_response(cmd->out, cmd->out_len);
 186    }
 187}
 188
 189static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu)
 190{
 191    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_CAPABILITY,
 192                             &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) {
 193        error_report("tpm-emulator: probing failed : %s", strerror(errno));
 194        return -1;
 195    }
 196
 197    tpm_emu->caps = be64_to_cpu(tpm_emu->caps);
 198
 199    trace_tpm_emulator_probe_caps(tpm_emu->caps);
 200
 201    return 0;
 202}
 203
 204static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
 205{
 206    ptm_cap caps = 0;
 207    const char *tpm = NULL;
 208
 209    /* check for min. required capabilities */
 210    switch (tpm_emu->tpm_version) {
 211    case TPM_VERSION_1_2:
 212        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
 213               PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP |
 214               PTM_CAP_SET_BUFFERSIZE;
 215        tpm = "1.2";
 216        break;
 217    case TPM_VERSION_2_0:
 218        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
 219               PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED |
 220               PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE;
 221        tpm = "2";
 222        break;
 223    case TPM_VERSION_UNSPEC:
 224        error_report("tpm-emulator: TPM version has not been set");
 225        return -1;
 226    }
 227
 228    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
 229        error_report("tpm-emulator: TPM does not implement minimum set of "
 230                     "required capabilities for TPM %s (0x%x)", tpm, (int)caps);
 231        return -1;
 232    }
 233
 234    return 0;
 235}
 236
 237static int tpm_emulator_stop_tpm(TPMBackend *tb)
 238{
 239    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
 240    ptm_res res;
 241
 242    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) {
 243        error_report("tpm-emulator: Could not stop TPM: %s",
 244                     strerror(errno));
 245        return -1;
 246    }
 247
 248    res = be32_to_cpu(res);
 249    if (res) {
 250        error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x", res);
 251        return -1;
 252    }
 253
 254    return 0;
 255}
 256
 257static int tpm_emulator_set_buffer_size(TPMBackend *tb,
 258                                        size_t wanted_size,
 259                                        size_t *actual_size)
 260{
 261    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
 262    ptm_setbuffersize psbs;
 263
 264    if (tpm_emulator_stop_tpm(tb) < 0) {
 265        return -1;
 266    }
 267
 268    psbs.u.req.buffersize = cpu_to_be32(wanted_size);
 269
 270    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs,
 271                             sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) {
 272        error_report("tpm-emulator: Could not set buffer size: %s",
 273                     strerror(errno));
 274        return -1;
 275    }
 276
 277    psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result);
 278    if (psbs.u.resp.tpm_result != 0) {
 279        error_report("tpm-emulator: TPM result for set buffer size : 0x%x",
 280                     psbs.u.resp.tpm_result);
 281        return -1;
 282    }
 283
 284    if (actual_size) {
 285        *actual_size = be32_to_cpu(psbs.u.resp.buffersize);
 286    }
 287
 288    trace_tpm_emulator_set_buffer_size(
 289            be32_to_cpu(psbs.u.resp.buffersize),
 290            be32_to_cpu(psbs.u.resp.minsize),
 291            be32_to_cpu(psbs.u.resp.maxsize));
 292
 293    return 0;
 294}
 295
 296static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize)
 297{
 298    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
 299    ptm_init init = {
 300        .u.req.init_flags = 0,
 301    };
 302    ptm_res res;
 303
 304    if (buffersize != 0 &&
 305        tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) {
 306        goto err_exit;
 307    }
 308
 309    trace_tpm_emulator_startup_tpm();
 310    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init),
 311                             sizeof(init)) < 0) {
 312        error_report("tpm-emulator: could not send INIT: %s",
 313                     strerror(errno));
 314        goto err_exit;
 315    }
 316
 317    res = be32_to_cpu(init.u.resp.tpm_result);
 318    if (res) {
 319        error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x", res);
 320        goto err_exit;
 321    }
 322    return 0;
 323
 324err_exit:
 325    return -1;
 326}
 327
 328static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
 329{
 330    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
 331    ptm_est est;
 332
 333    if (tpm_emu->established_flag_cached) {
 334        return tpm_emu->established_flag;
 335    }
 336
 337    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est,
 338                             0, sizeof(est)) < 0) {
 339        error_report("tpm-emulator: Could not get the TPM established flag: %s",
 340                     strerror(errno));
 341        return false;
 342    }
 343    trace_tpm_emulator_get_tpm_established_flag(est.u.resp.bit);
 344
 345    tpm_emu->established_flag_cached = 1;
 346    tpm_emu->established_flag = (est.u.resp.bit != 0);
 347
 348    return tpm_emu->established_flag;
 349}
 350
 351static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
 352                                                   uint8_t locty)
 353{
 354    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
 355    ptm_reset_est reset_est;
 356    ptm_res res;
 357
 358    /* only a TPM 2.0 will support this */
 359    if (tpm_emu->tpm_version != TPM_VERSION_2_0) {
 360        return 0;
 361    }
 362
 363    reset_est.u.req.loc = tpm_emu->cur_locty_number;
 364    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_RESET_TPMESTABLISHED,
 365                             &reset_est, sizeof(reset_est),
 366                             sizeof(reset_est)) < 0) {
 367        error_report("tpm-emulator: Could not reset the establishment bit: %s",
 368                     strerror(errno));
 369        return -1;
 370    }
 371
 372    res = be32_to_cpu(reset_est.u.resp.tpm_result);
 373    if (res) {
 374        error_report("tpm-emulator: TPM result for rest establixhed flag: 0x%x",
 375                     res);
 376        return -1;
 377    }
 378
 379    tpm_emu->established_flag_cached = 0;
 380
 381    return 0;
 382}
 383
 384static void tpm_emulator_cancel_cmd(TPMBackend *tb)
 385{
 386    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
 387    ptm_res res;
 388
 389    if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) {
 390        trace_tpm_emulator_cancel_cmd_not_supt();
 391        return;
 392    }
 393
 394    /* FIXME: make the function non-blocking, or it may block a VCPU */
 395    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0,
 396                             sizeof(res)) < 0) {
 397        error_report("tpm-emulator: Could not cancel command: %s",
 398                     strerror(errno));
 399    } else if (res != 0) {
 400        error_report("tpm-emulator: Failed to cancel TPM: 0x%x",
 401                     be32_to_cpu(res));
 402    }
 403}
 404
 405static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
 406{
 407    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
 408
 409    return tpm_emu->tpm_version;
 410}
 411
 412static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
 413{
 414    size_t actual_size;
 415
 416    if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) {
 417        return 4096;
 418    }
 419
 420    return actual_size;
 421}
 422
 423static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
 424{
 425    Error *err = NULL;
 426
 427    error_setg(&tpm_emu->migration_blocker,
 428               "Migration disabled: TPM emulator not yet migratable");
 429    migrate_add_blocker(tpm_emu->migration_blocker, &err);
 430    if (err) {
 431        error_report_err(err);
 432        error_free(tpm_emu->migration_blocker);
 433        tpm_emu->migration_blocker = NULL;
 434
 435        return -1;
 436    }
 437
 438    return 0;
 439}
 440
 441static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
 442{
 443    ptm_res res;
 444    Error *err = NULL;
 445    int fds[2] = { -1, -1 };
 446
 447    if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
 448        error_report("tpm-emulator: Failed to create socketpair");
 449        return -1;
 450    }
 451
 452    qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1);
 453
 454    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_DATAFD, &res, 0,
 455                             sizeof(res)) < 0 || res != 0) {
 456        error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s",
 457                     strerror(errno));
 458        goto err_exit;
 459    }
 460
 461    tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));
 462    if (err) {
 463        error_prepend(&err, "tpm-emulator: Failed to create io channel: ");
 464        error_report_err(err);
 465        goto err_exit;
 466    }
 467
 468    closesocket(fds[1]);
 469
 470    return 0;
 471
 472err_exit:
 473    closesocket(fds[0]);
 474    closesocket(fds[1]);
 475    return -1;
 476}
 477
 478static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts)
 479{
 480    const char *value;
 481
 482    value = qemu_opt_get(opts, "chardev");
 483    if (value) {
 484        Error *err = NULL;
 485        Chardev *dev = qemu_chr_find(value);
 486
 487        if (!dev) {
 488            error_report("tpm-emulator: tpm chardev '%s' not found.", value);
 489            goto err;
 490        }
 491
 492        if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) {
 493            error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':",
 494                          value);
 495            error_report_err(err);
 496            goto err;
 497        }
 498
 499        tpm_emu->options->chardev = g_strdup(value);
 500    }
 501
 502    if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
 503        goto err;
 504    }
 505
 506    /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used
 507     * by passthrough driver, which not yet using GIOChannel.
 508     */
 509    if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd,
 510                             &tpm_emu->tpm_version)) {
 511        error_report("'%s' is not emulating TPM device. Error: %s",
 512                      tpm_emu->options->chardev, strerror(errno));
 513        goto err;
 514    }
 515
 516    switch (tpm_emu->tpm_version) {
 517    case TPM_VERSION_1_2:
 518        trace_tpm_emulator_handle_device_opts_tpm12();
 519        break;
 520    case TPM_VERSION_2_0:
 521        trace_tpm_emulator_handle_device_opts_tpm2();
 522        break;
 523    default:
 524        trace_tpm_emulator_handle_device_opts_unspec();
 525    }
 526
 527    if (tpm_emulator_probe_caps(tpm_emu) ||
 528        tpm_emulator_check_caps(tpm_emu)) {
 529        goto err;
 530    }
 531
 532    return tpm_emulator_block_migration(tpm_emu);
 533
 534err:
 535    trace_tpm_emulator_handle_device_opts_startup_error();
 536
 537    return -1;
 538}
 539
 540static TPMBackend *tpm_emulator_create(QemuOpts *opts)
 541{
 542    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
 543
 544    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
 545        object_unref(OBJECT(tb));
 546        return NULL;
 547    }
 548
 549    return tb;
 550}
 551
 552static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
 553{
 554    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
 555    TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
 556
 557    options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
 558    options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options);
 559
 560    return options;
 561}
 562
 563static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
 564    TPM_STANDARD_CMDLINE_OPTS,
 565    {
 566        .name = "chardev",
 567        .type = QEMU_OPT_STRING,
 568        .help = "Character device to use for out-of-band control messages",
 569    },
 570    { /* end of list */ },
 571};
 572
 573static void tpm_emulator_inst_init(Object *obj)
 574{
 575    TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
 576
 577    trace_tpm_emulator_inst_init();
 578
 579    tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
 580    tpm_emu->cur_locty_number = ~0;
 581    qemu_mutex_init(&tpm_emu->mutex);
 582}
 583
 584/*
 585 * Gracefully shut down the external TPM
 586 */
 587static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
 588{
 589    ptm_res res;
 590
 591    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, sizeof(res)) < 0) {
 592        error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
 593                     strerror(errno));
 594    } else if (res != 0) {
 595        error_report("tpm-emulator: TPM result for sutdown: 0x%x",
 596                     be32_to_cpu(res));
 597    }
 598}
 599
 600static void tpm_emulator_inst_finalize(Object *obj)
 601{
 602    TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
 603
 604    tpm_emulator_shutdown(tpm_emu);
 605
 606    object_unref(OBJECT(tpm_emu->data_ioc));
 607
 608    qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false);
 609
 610    qapi_free_TPMEmulatorOptions(tpm_emu->options);
 611
 612    if (tpm_emu->migration_blocker) {
 613        migrate_del_blocker(tpm_emu->migration_blocker);
 614        error_free(tpm_emu->migration_blocker);
 615    }
 616
 617    qemu_mutex_destroy(&tpm_emu->mutex);
 618}
 619
 620static void tpm_emulator_class_init(ObjectClass *klass, void *data)
 621{
 622    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
 623
 624    tbc->type = TPM_TYPE_EMULATOR;
 625    tbc->opts = tpm_emulator_cmdline_opts;
 626    tbc->desc = "TPM emulator backend driver";
 627    tbc->create = tpm_emulator_create;
 628    tbc->startup_tpm = tpm_emulator_startup_tpm;
 629    tbc->cancel_cmd = tpm_emulator_cancel_cmd;
 630    tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag;
 631    tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag;
 632    tbc->get_tpm_version = tpm_emulator_get_tpm_version;
 633    tbc->get_buffer_size = tpm_emulator_get_buffer_size;
 634    tbc->get_tpm_options = tpm_emulator_get_tpm_options;
 635
 636    tbc->handle_request = tpm_emulator_handle_request;
 637}
 638
 639static const TypeInfo tpm_emulator_info = {
 640    .name = TYPE_TPM_EMULATOR,
 641    .parent = TYPE_TPM_BACKEND,
 642    .instance_size = sizeof(TPMEmulator),
 643    .class_init = tpm_emulator_class_init,
 644    .instance_init = tpm_emulator_inst_init,
 645    .instance_finalize = tpm_emulator_inst_finalize,
 646};
 647
 648static void tpm_emulator_register(void)
 649{
 650    type_register_static(&tpm_emulator_info);
 651}
 652
 653type_init(tpm_emulator_register)
 654