1f4ede81eSAmarnath Valluri /* 2f4ede81eSAmarnath Valluri * Emulator TPM driver 3f4ede81eSAmarnath Valluri * 4f4ede81eSAmarnath Valluri * Copyright (c) 2017 Intel Corporation 5f4ede81eSAmarnath Valluri * Author: Amarnath Valluri <amarnath.valluri@intel.com> 6f4ede81eSAmarnath Valluri * 738ab74e7SStefan Berger * Copyright (c) 2010 - 2013, 2018 IBM Corporation 8f4ede81eSAmarnath Valluri * Authors: 9f4ede81eSAmarnath Valluri * Stefan Berger <stefanb@us.ibm.com> 10f4ede81eSAmarnath Valluri * 11f4ede81eSAmarnath Valluri * Copyright (C) 2011 IAIK, Graz University of Technology 12f4ede81eSAmarnath Valluri * Author: Andreas Niederl 13f4ede81eSAmarnath Valluri * 14f4ede81eSAmarnath Valluri * This library is free software; you can redistribute it and/or 15f4ede81eSAmarnath Valluri * modify it under the terms of the GNU Lesser General Public 16f4ede81eSAmarnath Valluri * License as published by the Free Software Foundation; either 17eac2fce9SChetan Pant * version 2.1 of the License, or (at your option) any later version. 18f4ede81eSAmarnath Valluri * 19f4ede81eSAmarnath Valluri * This library is distributed in the hope that it will be useful, 20f4ede81eSAmarnath Valluri * but WITHOUT ANY WARRANTY; without even the implied warranty of 21f4ede81eSAmarnath Valluri * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22f4ede81eSAmarnath Valluri * Lesser General Public License for more details. 23f4ede81eSAmarnath Valluri * 24f4ede81eSAmarnath Valluri * You should have received a copy of the GNU Lesser General Public 25f4ede81eSAmarnath Valluri * License along with this library; if not, see <http://www.gnu.org/licenses/> 26f4ede81eSAmarnath Valluri * 27f4ede81eSAmarnath Valluri */ 28f4ede81eSAmarnath Valluri 29f4ede81eSAmarnath Valluri #include "qemu/osdep.h" 30f4ede81eSAmarnath Valluri #include "qemu/error-report.h" 310b8fa32fSMarkus Armbruster #include "qemu/module.h" 32f4ede81eSAmarnath Valluri #include "qemu/sockets.h" 33bf5dcf8fSPhilippe Mathieu-Daudé #include "qemu/lockable.h" 34f4ede81eSAmarnath Valluri #include "io/channel-socket.h" 3532cad1ffSPhilippe Mathieu-Daudé #include "system/runstate.h" 3632cad1ffSPhilippe Mathieu-Daudé #include "system/tpm_backend.h" 3732cad1ffSPhilippe Mathieu-Daudé #include "system/tpm_util.h" 38f4ede81eSAmarnath Valluri #include "tpm_int.h" 39f4ede81eSAmarnath Valluri #include "tpm_ioctl.h" 40f4ede81eSAmarnath Valluri #include "migration/blocker.h" 41d6454270SMarkus Armbruster #include "migration/vmstate.h" 42f4ede81eSAmarnath Valluri #include "qapi/error.h" 43f4ede81eSAmarnath Valluri #include "qapi/clone-visitor.h" 449af23989SMarkus Armbruster #include "qapi/qapi-visit-tpm.h" 45f4ede81eSAmarnath Valluri #include "chardev/char-fe.h" 469d9dcd96SStefan Berger #include "trace.h" 47db1015e9SEduardo Habkost #include "qom/object.h" 48f4ede81eSAmarnath Valluri 49f4ede81eSAmarnath Valluri #define TYPE_TPM_EMULATOR "tpm-emulator" 508063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(TPMEmulator, TPM_EMULATOR) 51f4ede81eSAmarnath Valluri 52f4ede81eSAmarnath Valluri #define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap)) 53f4ede81eSAmarnath Valluri 54f4ede81eSAmarnath Valluri /* data structures */ 5538ab74e7SStefan Berger 5638ab74e7SStefan Berger /* blobs from the TPM; part of VM state when migrating */ 5738ab74e7SStefan Berger typedef struct TPMBlobBuffers { 5838ab74e7SStefan Berger uint32_t permanent_flags; 5938ab74e7SStefan Berger TPMSizedBuffer permanent; 6038ab74e7SStefan Berger 6138ab74e7SStefan Berger uint32_t volatil_flags; 6238ab74e7SStefan Berger TPMSizedBuffer volatil; 6338ab74e7SStefan Berger 6438ab74e7SStefan Berger uint32_t savestate_flags; 6538ab74e7SStefan Berger TPMSizedBuffer savestate; 6638ab74e7SStefan Berger } TPMBlobBuffers; 6738ab74e7SStefan Berger 68db1015e9SEduardo Habkost struct TPMEmulator { 69f4ede81eSAmarnath Valluri TPMBackend parent; 70f4ede81eSAmarnath Valluri 71f4ede81eSAmarnath Valluri TPMEmulatorOptions *options; 72f4ede81eSAmarnath Valluri CharBackend ctrl_chr; 73f4ede81eSAmarnath Valluri QIOChannel *data_ioc; 74f4ede81eSAmarnath Valluri TPMVersion tpm_version; 75312c5404SStefan Berger uint32_t caps; /* capabilities of the TPM */ 76f4ede81eSAmarnath Valluri uint8_t cur_locty_number; /* last set locality */ 77f4ede81eSAmarnath Valluri Error *migration_blocker; 7817b1af77SMarc-André Lureau 7917b1af77SMarc-André Lureau QemuMutex mutex; 800b4c7c65SStefan Berger 810b4c7c65SStefan Berger unsigned int established_flag:1; 820b4c7c65SStefan Berger unsigned int established_flag_cached:1; 8338ab74e7SStefan Berger 8438ab74e7SStefan Berger TPMBlobBuffers state_blobs; 8599bdcd2cSStefan Berger 8699bdcd2cSStefan Berger bool relock_storage; 8799bdcd2cSStefan Berger VMChangeStateEntry *vmstate; 88db1015e9SEduardo Habkost }; 89f4ede81eSAmarnath Valluri 907e095e84SStefan Berger struct tpm_error { 917e095e84SStefan Berger uint32_t tpm_result; 927e095e84SStefan Berger const char *string; 937e095e84SStefan Berger }; 947e095e84SStefan Berger 957e095e84SStefan Berger static const struct tpm_error tpm_errors[] = { 967e095e84SStefan Berger /* TPM 1.2 error codes */ 977e095e84SStefan Berger { TPM_BAD_PARAMETER , "a parameter is bad" }, 987e095e84SStefan Berger { TPM_FAIL , "operation failed" }, 997e095e84SStefan Berger { TPM_KEYNOTFOUND , "key could not be found" }, 1007e095e84SStefan Berger { TPM_BAD_PARAM_SIZE , "bad parameter size"}, 1017e095e84SStefan Berger { TPM_ENCRYPT_ERROR , "encryption error" }, 1027e095e84SStefan Berger { TPM_DECRYPT_ERROR , "decryption error" }, 1037e095e84SStefan Berger { TPM_BAD_KEY_PROPERTY, "bad key property" }, 1047e095e84SStefan Berger { TPM_BAD_MODE , "bad (encryption) mode" }, 1057e095e84SStefan Berger { TPM_BAD_VERSION , "bad version identifier" }, 1067e095e84SStefan Berger { TPM_BAD_LOCALITY , "bad locality" }, 1077e095e84SStefan Berger /* TPM 2 error codes */ 1087e095e84SStefan Berger { TPM_RC_FAILURE , "operation failed" }, 1097e095e84SStefan Berger { TPM_RC_LOCALITY , "bad locality" }, 1107e095e84SStefan Berger { TPM_RC_INSUFFICIENT, "insufficient amount of data" }, 1117e095e84SStefan Berger }; 1127e095e84SStefan Berger 1137e095e84SStefan Berger static const char *tpm_emulator_strerror(uint32_t tpm_result) 1147e095e84SStefan Berger { 1157e095e84SStefan Berger size_t i; 1167e095e84SStefan Berger 1177e095e84SStefan Berger for (i = 0; i < ARRAY_SIZE(tpm_errors); i++) { 1187e095e84SStefan Berger if (tpm_errors[i].tpm_result == tpm_result) { 1197e095e84SStefan Berger return tpm_errors[i].string; 1207e095e84SStefan Berger } 1217e095e84SStefan Berger } 1227e095e84SStefan Berger return ""; 1237e095e84SStefan Berger } 124f4ede81eSAmarnath Valluri 12517b1af77SMarc-André Lureau static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg, 126d2bcaaccSStefan Berger size_t msg_len_in, size_t msg_len_out_err, 127d2bcaaccSStefan Berger size_t msg_len_out_total) 128f4ede81eSAmarnath Valluri { 12917b1af77SMarc-André Lureau CharBackend *dev = &tpm->ctrl_chr; 130f4ede81eSAmarnath Valluri uint32_t cmd_no = cpu_to_be32(cmd); 131f4ede81eSAmarnath Valluri ssize_t n = sizeof(uint32_t) + msg_len_in; 132f4ede81eSAmarnath Valluri uint8_t *buf = NULL; 133d2bcaaccSStefan Berger ptm_res res; 13417b1af77SMarc-André Lureau 135bf5dcf8fSPhilippe Mathieu-Daudé WITH_QEMU_LOCK_GUARD(&tpm->mutex) { 136f4ede81eSAmarnath Valluri buf = g_alloca(n); 137f4ede81eSAmarnath Valluri memcpy(buf, &cmd_no, sizeof(cmd_no)); 138f4ede81eSAmarnath Valluri memcpy(buf + sizeof(cmd_no), msg, msg_len_in); 139f4ede81eSAmarnath Valluri 140f4ede81eSAmarnath Valluri n = qemu_chr_fe_write_all(dev, buf, n); 141f4ede81eSAmarnath Valluri if (n <= 0) { 142bf5dcf8fSPhilippe Mathieu-Daudé return -1; 143f4ede81eSAmarnath Valluri } 144f4ede81eSAmarnath Valluri 145d2bcaaccSStefan Berger if (msg_len_out_total > 0) { 146d2bcaaccSStefan Berger assert(msg_len_out_total >= msg_len_out_err); 147d2bcaaccSStefan Berger 148d2bcaaccSStefan Berger n = qemu_chr_fe_read_all(dev, (uint8_t *)msg, msg_len_out_err); 149d2bcaaccSStefan Berger if (n <= 0) { 150d2bcaaccSStefan Berger return -1; 151d2bcaaccSStefan Berger } 152d2bcaaccSStefan Berger if (msg_len_out_err == msg_len_out_total) { 153d2bcaaccSStefan Berger return 0; 154d2bcaaccSStefan Berger } 155d2bcaaccSStefan Berger /* result error code is always in the first 4 bytes */ 156d2bcaaccSStefan Berger assert(sizeof(res) <= msg_len_out_err); 157d2bcaaccSStefan Berger memcpy(&res, msg, sizeof(res)); 158d2bcaaccSStefan Berger if (res) { 159d2bcaaccSStefan Berger return 0; 160d2bcaaccSStefan Berger } 161d2bcaaccSStefan Berger 162d2bcaaccSStefan Berger n = qemu_chr_fe_read_all(dev, (uint8_t *)msg + msg_len_out_err, 163d2bcaaccSStefan Berger msg_len_out_total - msg_len_out_err); 164f4ede81eSAmarnath Valluri if (n <= 0) { 165bf5dcf8fSPhilippe Mathieu-Daudé return -1; 166bf5dcf8fSPhilippe Mathieu-Daudé } 167f4ede81eSAmarnath Valluri } 168f4ede81eSAmarnath Valluri } 169f4ede81eSAmarnath Valluri 170bf5dcf8fSPhilippe Mathieu-Daudé return 0; 171f4ede81eSAmarnath Valluri } 172f4ede81eSAmarnath Valluri 173f4ede81eSAmarnath Valluri static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, 174f4ede81eSAmarnath Valluri const uint8_t *in, uint32_t in_len, 175f4ede81eSAmarnath Valluri uint8_t *out, uint32_t out_len, 176f4ede81eSAmarnath Valluri bool *selftest_done, 177e04e3321SVladimir Sementsov-Ogievskiy Error **errp) 178f4ede81eSAmarnath Valluri { 179f4ede81eSAmarnath Valluri ssize_t ret; 180f4ede81eSAmarnath Valluri bool is_selftest = false; 181f4ede81eSAmarnath Valluri 182f4ede81eSAmarnath Valluri if (selftest_done) { 183f4ede81eSAmarnath Valluri *selftest_done = false; 184f4ede81eSAmarnath Valluri is_selftest = tpm_util_is_selftest(in, in_len); 185f4ede81eSAmarnath Valluri } 186f4ede81eSAmarnath Valluri 187e04e3321SVladimir Sementsov-Ogievskiy ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, errp); 188f4ede81eSAmarnath Valluri if (ret != 0) { 189f4ede81eSAmarnath Valluri return -1; 190f4ede81eSAmarnath Valluri } 191f4ede81eSAmarnath Valluri 192cc1b6c55SMarc-André Lureau ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out, 193e04e3321SVladimir Sementsov-Ogievskiy sizeof(struct tpm_resp_hdr), errp); 194f4ede81eSAmarnath Valluri if (ret != 0) { 195f4ede81eSAmarnath Valluri return -1; 196f4ede81eSAmarnath Valluri } 197f4ede81eSAmarnath Valluri 198cc1b6c55SMarc-André Lureau ret = qio_channel_read_all(tpm_emu->data_ioc, 199cc1b6c55SMarc-André Lureau (char *)out + sizeof(struct tpm_resp_hdr), 200e04e3321SVladimir Sementsov-Ogievskiy tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), errp); 201f4ede81eSAmarnath Valluri if (ret != 0) { 202f4ede81eSAmarnath Valluri return -1; 203f4ede81eSAmarnath Valluri } 204f4ede81eSAmarnath Valluri 205f4ede81eSAmarnath Valluri if (is_selftest) { 206cc1b6c55SMarc-André Lureau *selftest_done = tpm_cmd_get_errcode(out) == 0; 207f4ede81eSAmarnath Valluri } 208f4ede81eSAmarnath Valluri 209f4ede81eSAmarnath Valluri return 0; 210f4ede81eSAmarnath Valluri } 211f4ede81eSAmarnath Valluri 212c106ede9SMarc-André Lureau static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number, 213c106ede9SMarc-André Lureau Error **errp) 214f4ede81eSAmarnath Valluri { 215f4ede81eSAmarnath Valluri ptm_loc loc; 216f4ede81eSAmarnath Valluri 217f4ede81eSAmarnath Valluri if (tpm_emu->cur_locty_number == locty_number) { 218f4ede81eSAmarnath Valluri return 0; 219f4ede81eSAmarnath Valluri } 220f4ede81eSAmarnath Valluri 2219d9dcd96SStefan Berger trace_tpm_emulator_set_locality(locty_number); 2229d9dcd96SStefan Berger 223eff1fe9fSStefan Berger memset(&loc, 0, sizeof(loc)); 224f4ede81eSAmarnath Valluri loc.u.req.loc = locty_number; 22517b1af77SMarc-André Lureau if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_LOCALITY, &loc, 226d2bcaaccSStefan Berger sizeof(loc), sizeof(loc.u.resp.tpm_result), 227d2bcaaccSStefan Berger sizeof(loc)) < 0) { 228c106ede9SMarc-André Lureau error_setg(errp, "tpm-emulator: could not set locality : %s", 229f4ede81eSAmarnath Valluri strerror(errno)); 230f4ede81eSAmarnath Valluri return -1; 231f4ede81eSAmarnath Valluri } 232f4ede81eSAmarnath Valluri 233f4ede81eSAmarnath Valluri loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result); 234f4ede81eSAmarnath Valluri if (loc.u.resp.tpm_result != 0) { 235c106ede9SMarc-André Lureau error_setg(errp, "tpm-emulator: TPM result for set locality : 0x%x", 236f4ede81eSAmarnath Valluri loc.u.resp.tpm_result); 237f4ede81eSAmarnath Valluri return -1; 238f4ede81eSAmarnath Valluri } 239f4ede81eSAmarnath Valluri 240f4ede81eSAmarnath Valluri tpm_emu->cur_locty_number = locty_number; 241f4ede81eSAmarnath Valluri 242f4ede81eSAmarnath Valluri return 0; 243f4ede81eSAmarnath Valluri } 244f4ede81eSAmarnath Valluri 2456a8a2354SMarc-André Lureau static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd, 2466a8a2354SMarc-André Lureau Error **errp) 247f4ede81eSAmarnath Valluri { 248f4ede81eSAmarnath Valluri TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 249f4ede81eSAmarnath Valluri 2509d9dcd96SStefan Berger trace_tpm_emulator_handle_request(); 251f4ede81eSAmarnath Valluri 2526a8a2354SMarc-André Lureau if (tpm_emulator_set_locality(tpm_emu, cmd->locty, errp) < 0 || 2536a8a2354SMarc-André Lureau tpm_emulator_unix_tx_bufs(tpm_emu, cmd->in, cmd->in_len, 2540e43b7e6SMarc-André Lureau cmd->out, cmd->out_len, 2556a8a2354SMarc-André Lureau &cmd->selftest_done, errp) < 0) { 2560e43b7e6SMarc-André Lureau tpm_util_write_fatal_error_response(cmd->out, cmd->out_len); 2576a8a2354SMarc-André Lureau } 258f4ede81eSAmarnath Valluri } 259f4ede81eSAmarnath Valluri 260f4ede81eSAmarnath Valluri static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu) 261f4ede81eSAmarnath Valluri { 262312c5404SStefan Berger ptm_cap_n cap_n; 263312c5404SStefan Berger 264d2bcaaccSStefan Berger if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_CAPABILITY, &cap_n, 0, 265d2bcaaccSStefan Berger sizeof(cap_n.u.resp.tpm_result), 266d2bcaaccSStefan Berger sizeof(cap_n)) < 0) { 267f4ede81eSAmarnath Valluri error_report("tpm-emulator: probing failed : %s", strerror(errno)); 268f4ede81eSAmarnath Valluri return -1; 269f4ede81eSAmarnath Valluri } 270f4ede81eSAmarnath Valluri 271312c5404SStefan Berger tpm_emu->caps = be32_to_cpu(cap_n.u.resp.caps); 272f4ede81eSAmarnath Valluri 2739d9dcd96SStefan Berger trace_tpm_emulator_probe_caps(tpm_emu->caps); 274f4ede81eSAmarnath Valluri 275f4ede81eSAmarnath Valluri return 0; 276f4ede81eSAmarnath Valluri } 277f4ede81eSAmarnath Valluri 278f4ede81eSAmarnath Valluri static int tpm_emulator_check_caps(TPMEmulator *tpm_emu) 279f4ede81eSAmarnath Valluri { 280312c5404SStefan Berger uint32_t caps = 0; 281f4ede81eSAmarnath Valluri const char *tpm = NULL; 282f4ede81eSAmarnath Valluri 283f4ede81eSAmarnath Valluri /* check for min. required capabilities */ 284f4ede81eSAmarnath Valluri switch (tpm_emu->tpm_version) { 285f4ede81eSAmarnath Valluri case TPM_VERSION_1_2: 286f4ede81eSAmarnath Valluri caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | 2879375c44fSStefan Berger PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP | 2889375c44fSStefan Berger PTM_CAP_SET_BUFFERSIZE; 289f4ede81eSAmarnath Valluri tpm = "1.2"; 290f4ede81eSAmarnath Valluri break; 291f4ede81eSAmarnath Valluri case TPM_VERSION_2_0: 292f4ede81eSAmarnath Valluri caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | 293f4ede81eSAmarnath Valluri PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED | 2949375c44fSStefan Berger PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE; 295f4ede81eSAmarnath Valluri tpm = "2"; 296f4ede81eSAmarnath Valluri break; 297f4ede81eSAmarnath Valluri case TPM_VERSION_UNSPEC: 298f4ede81eSAmarnath Valluri error_report("tpm-emulator: TPM version has not been set"); 299f4ede81eSAmarnath Valluri return -1; 300f4ede81eSAmarnath Valluri } 301f4ede81eSAmarnath Valluri 302f4ede81eSAmarnath Valluri if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) { 303f4ede81eSAmarnath Valluri error_report("tpm-emulator: TPM does not implement minimum set of " 304f4ede81eSAmarnath Valluri "required capabilities for TPM %s (0x%x)", tpm, (int)caps); 305f4ede81eSAmarnath Valluri return -1; 306f4ede81eSAmarnath Valluri } 307f4ede81eSAmarnath Valluri 308f4ede81eSAmarnath Valluri return 0; 309f4ede81eSAmarnath Valluri } 310f4ede81eSAmarnath Valluri 3119375c44fSStefan Berger static int tpm_emulator_stop_tpm(TPMBackend *tb) 3129375c44fSStefan Berger { 3139375c44fSStefan Berger TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 3149375c44fSStefan Berger ptm_res res; 3159375c44fSStefan Berger 316d2bcaaccSStefan Berger if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, 317d2bcaaccSStefan Berger sizeof(ptm_res), sizeof(res)) < 0) { 3189375c44fSStefan Berger error_report("tpm-emulator: Could not stop TPM: %s", 3199375c44fSStefan Berger strerror(errno)); 3209375c44fSStefan Berger return -1; 3219375c44fSStefan Berger } 3229375c44fSStefan Berger 3239375c44fSStefan Berger res = be32_to_cpu(res); 3249375c44fSStefan Berger if (res) { 3257e095e84SStefan Berger error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x %s", res, 3267e095e84SStefan Berger tpm_emulator_strerror(res)); 3279375c44fSStefan Berger return -1; 3289375c44fSStefan Berger } 3299375c44fSStefan Berger 3309375c44fSStefan Berger return 0; 3319375c44fSStefan Berger } 3329375c44fSStefan Berger 33399bdcd2cSStefan Berger static int tpm_emulator_lock_storage(TPMEmulator *tpm_emu) 33499bdcd2cSStefan Berger { 33599bdcd2cSStefan Berger ptm_lockstorage pls; 33699bdcd2cSStefan Berger 33799bdcd2cSStefan Berger if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_LOCK_STORAGE)) { 33899bdcd2cSStefan Berger trace_tpm_emulator_lock_storage_cmd_not_supt(); 33999bdcd2cSStefan Berger return 0; 34099bdcd2cSStefan Berger } 34199bdcd2cSStefan Berger 34299bdcd2cSStefan Berger /* give failing side 300 * 10ms time to release lock */ 34399bdcd2cSStefan Berger pls.u.req.retries = cpu_to_be32(300); 344d2bcaaccSStefan Berger if (tpm_emulator_ctrlcmd(tpm_emu, CMD_LOCK_STORAGE, &pls, sizeof(pls.u.req), 345d2bcaaccSStefan Berger sizeof(pls.u.resp.tpm_result), 346d2bcaaccSStefan Berger sizeof(pls.u.resp)) < 0) { 34799bdcd2cSStefan Berger error_report("tpm-emulator: Could not lock storage within 3 seconds: " 34899bdcd2cSStefan Berger "%s", strerror(errno)); 34999bdcd2cSStefan Berger return -1; 35099bdcd2cSStefan Berger } 35199bdcd2cSStefan Berger 35299bdcd2cSStefan Berger pls.u.resp.tpm_result = be32_to_cpu(pls.u.resp.tpm_result); 35399bdcd2cSStefan Berger if (pls.u.resp.tpm_result != 0) { 35499bdcd2cSStefan Berger error_report("tpm-emulator: TPM result for CMD_LOCK_STORAGE: 0x%x %s", 35599bdcd2cSStefan Berger pls.u.resp.tpm_result, 35699bdcd2cSStefan Berger tpm_emulator_strerror(pls.u.resp.tpm_result)); 35799bdcd2cSStefan Berger return -1; 35899bdcd2cSStefan Berger } 35999bdcd2cSStefan Berger 36099bdcd2cSStefan Berger return 0; 36199bdcd2cSStefan Berger } 36299bdcd2cSStefan Berger 3639375c44fSStefan Berger static int tpm_emulator_set_buffer_size(TPMBackend *tb, 3649375c44fSStefan Berger size_t wanted_size, 3659375c44fSStefan Berger size_t *actual_size) 3669375c44fSStefan Berger { 3679375c44fSStefan Berger TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 3689375c44fSStefan Berger ptm_setbuffersize psbs; 3699375c44fSStefan Berger 3709375c44fSStefan Berger if (tpm_emulator_stop_tpm(tb) < 0) { 3719375c44fSStefan Berger return -1; 3729375c44fSStefan Berger } 3739375c44fSStefan Berger 3749375c44fSStefan Berger psbs.u.req.buffersize = cpu_to_be32(wanted_size); 3759375c44fSStefan Berger 3769375c44fSStefan Berger if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs, 377d2bcaaccSStefan Berger sizeof(psbs.u.req), sizeof(psbs.u.resp.tpm_result), 378d2bcaaccSStefan Berger sizeof(psbs.u.resp)) < 0) { 3799375c44fSStefan Berger error_report("tpm-emulator: Could not set buffer size: %s", 3809375c44fSStefan Berger strerror(errno)); 3819375c44fSStefan Berger return -1; 3829375c44fSStefan Berger } 3839375c44fSStefan Berger 3849375c44fSStefan Berger psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result); 3859375c44fSStefan Berger if (psbs.u.resp.tpm_result != 0) { 3867e095e84SStefan Berger error_report("tpm-emulator: TPM result for set buffer size : 0x%x %s", 3877e095e84SStefan Berger psbs.u.resp.tpm_result, 3887e095e84SStefan Berger tpm_emulator_strerror(psbs.u.resp.tpm_result)); 3899375c44fSStefan Berger return -1; 3909375c44fSStefan Berger } 3919375c44fSStefan Berger 3929375c44fSStefan Berger if (actual_size) { 3939375c44fSStefan Berger *actual_size = be32_to_cpu(psbs.u.resp.buffersize); 3949375c44fSStefan Berger } 3959375c44fSStefan Berger 3969d9dcd96SStefan Berger trace_tpm_emulator_set_buffer_size( 3979375c44fSStefan Berger be32_to_cpu(psbs.u.resp.buffersize), 3989375c44fSStefan Berger be32_to_cpu(psbs.u.resp.minsize), 3999375c44fSStefan Berger be32_to_cpu(psbs.u.resp.maxsize)); 4009375c44fSStefan Berger 4019375c44fSStefan Berger return 0; 4029375c44fSStefan Berger } 4039375c44fSStefan Berger 40438ab74e7SStefan Berger static int tpm_emulator_startup_tpm_resume(TPMBackend *tb, size_t buffersize, 40538ab74e7SStefan Berger bool is_resume) 406f4ede81eSAmarnath Valluri { 407f4ede81eSAmarnath Valluri TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 40830270587SStefan Berger ptm_init init = { 40930270587SStefan Berger .u.req.init_flags = 0, 41030270587SStefan Berger }; 411f4ede81eSAmarnath Valluri ptm_res res; 412f4ede81eSAmarnath Valluri 41338ab74e7SStefan Berger trace_tpm_emulator_startup_tpm_resume(is_resume, buffersize); 41438ab74e7SStefan Berger 4159375c44fSStefan Berger if (buffersize != 0 && 4169375c44fSStefan Berger tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) { 4179375c44fSStefan Berger goto err_exit; 4189375c44fSStefan Berger } 4199375c44fSStefan Berger 42038ab74e7SStefan Berger if (is_resume) { 42138ab74e7SStefan Berger init.u.req.init_flags |= cpu_to_be32(PTM_INIT_FLAG_DELETE_VOLATILE); 42238ab74e7SStefan Berger } 42338ab74e7SStefan Berger 42417b1af77SMarc-André Lureau if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init), 425d2bcaaccSStefan Berger sizeof(init.u.resp.tpm_result), 426f4ede81eSAmarnath Valluri sizeof(init)) < 0) { 427f4ede81eSAmarnath Valluri error_report("tpm-emulator: could not send INIT: %s", 428f4ede81eSAmarnath Valluri strerror(errno)); 429f4ede81eSAmarnath Valluri goto err_exit; 430f4ede81eSAmarnath Valluri } 431f4ede81eSAmarnath Valluri 432f4ede81eSAmarnath Valluri res = be32_to_cpu(init.u.resp.tpm_result); 433f4ede81eSAmarnath Valluri if (res) { 4347e095e84SStefan Berger error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x %s", res, 4357e095e84SStefan Berger tpm_emulator_strerror(res)); 436f4ede81eSAmarnath Valluri goto err_exit; 437f4ede81eSAmarnath Valluri } 438f4ede81eSAmarnath Valluri return 0; 439f4ede81eSAmarnath Valluri 440f4ede81eSAmarnath Valluri err_exit: 441f4ede81eSAmarnath Valluri return -1; 442f4ede81eSAmarnath Valluri } 443f4ede81eSAmarnath Valluri 44438ab74e7SStefan Berger static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize) 44538ab74e7SStefan Berger { 446a0bcec03SRoss Lagerwall /* TPM startup will be done from post_load hook */ 447a0bcec03SRoss Lagerwall if (runstate_check(RUN_STATE_INMIGRATE)) { 448a0bcec03SRoss Lagerwall if (buffersize != 0) { 449a0bcec03SRoss Lagerwall return tpm_emulator_set_buffer_size(tb, buffersize, NULL); 450a0bcec03SRoss Lagerwall } 451a0bcec03SRoss Lagerwall 452a0bcec03SRoss Lagerwall return 0; 453a0bcec03SRoss Lagerwall } 454a0bcec03SRoss Lagerwall 45538ab74e7SStefan Berger return tpm_emulator_startup_tpm_resume(tb, buffersize, false); 45638ab74e7SStefan Berger } 45738ab74e7SStefan Berger 458f4ede81eSAmarnath Valluri static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb) 459f4ede81eSAmarnath Valluri { 460f4ede81eSAmarnath Valluri TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 461f4ede81eSAmarnath Valluri ptm_est est; 462f4ede81eSAmarnath Valluri 4630b4c7c65SStefan Berger if (tpm_emu->established_flag_cached) { 4640b4c7c65SStefan Berger return tpm_emu->established_flag; 4650b4c7c65SStefan Berger } 4660b4c7c65SStefan Berger 467d2bcaaccSStefan Berger if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est, 0, 468d2bcaaccSStefan Berger sizeof(est) /* always returns resp.bit */, 469d2bcaaccSStefan Berger sizeof(est)) < 0) { 470f4ede81eSAmarnath Valluri error_report("tpm-emulator: Could not get the TPM established flag: %s", 471f4ede81eSAmarnath Valluri strerror(errno)); 472f4ede81eSAmarnath Valluri return false; 473f4ede81eSAmarnath Valluri } 4749d9dcd96SStefan Berger trace_tpm_emulator_get_tpm_established_flag(est.u.resp.bit); 475f4ede81eSAmarnath Valluri 4760b4c7c65SStefan Berger tpm_emu->established_flag_cached = 1; 4770b4c7c65SStefan Berger tpm_emu->established_flag = (est.u.resp.bit != 0); 4780b4c7c65SStefan Berger 4790b4c7c65SStefan Berger return tpm_emu->established_flag; 480f4ede81eSAmarnath Valluri } 481f4ede81eSAmarnath Valluri 482f4ede81eSAmarnath Valluri static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb, 483f4ede81eSAmarnath Valluri uint8_t locty) 484f4ede81eSAmarnath Valluri { 485f4ede81eSAmarnath Valluri TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 486f4ede81eSAmarnath Valluri ptm_reset_est reset_est; 487f4ede81eSAmarnath Valluri ptm_res res; 488f4ede81eSAmarnath Valluri 489f4ede81eSAmarnath Valluri /* only a TPM 2.0 will support this */ 490f4ede81eSAmarnath Valluri if (tpm_emu->tpm_version != TPM_VERSION_2_0) { 491f4ede81eSAmarnath Valluri return 0; 492f4ede81eSAmarnath Valluri } 493f4ede81eSAmarnath Valluri 494f4ede81eSAmarnath Valluri reset_est.u.req.loc = tpm_emu->cur_locty_number; 49517b1af77SMarc-André Lureau if (tpm_emulator_ctrlcmd(tpm_emu, CMD_RESET_TPMESTABLISHED, 496f4ede81eSAmarnath Valluri &reset_est, sizeof(reset_est), 497d2bcaaccSStefan Berger sizeof(reset_est.u.resp.tpm_result), 498f4ede81eSAmarnath Valluri sizeof(reset_est)) < 0) { 499f4ede81eSAmarnath Valluri error_report("tpm-emulator: Could not reset the establishment bit: %s", 500f4ede81eSAmarnath Valluri strerror(errno)); 501f4ede81eSAmarnath Valluri return -1; 502f4ede81eSAmarnath Valluri } 503f4ede81eSAmarnath Valluri 504f4ede81eSAmarnath Valluri res = be32_to_cpu(reset_est.u.resp.tpm_result); 505f4ede81eSAmarnath Valluri if (res) { 5067e095e84SStefan Berger error_report( 5077e095e84SStefan Berger "tpm-emulator: TPM result for rest established flag: 0x%x %s", 5087e095e84SStefan Berger res, tpm_emulator_strerror(res)); 509f4ede81eSAmarnath Valluri return -1; 510f4ede81eSAmarnath Valluri } 511f4ede81eSAmarnath Valluri 5120b4c7c65SStefan Berger tpm_emu->established_flag_cached = 0; 5130b4c7c65SStefan Berger 514f4ede81eSAmarnath Valluri return 0; 515f4ede81eSAmarnath Valluri } 516f4ede81eSAmarnath Valluri 517f4ede81eSAmarnath Valluri static void tpm_emulator_cancel_cmd(TPMBackend *tb) 518f4ede81eSAmarnath Valluri { 519f4ede81eSAmarnath Valluri TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 520f4ede81eSAmarnath Valluri ptm_res res; 521f4ede81eSAmarnath Valluri 522f4ede81eSAmarnath Valluri if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) { 5239d9dcd96SStefan Berger trace_tpm_emulator_cancel_cmd_not_supt(); 524f4ede81eSAmarnath Valluri return; 525f4ede81eSAmarnath Valluri } 526f4ede81eSAmarnath Valluri 5273d011411SMarc-André Lureau /* FIXME: make the function non-blocking, or it may block a VCPU */ 52817b1af77SMarc-André Lureau if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0, 529d2bcaaccSStefan Berger sizeof(ptm_res), sizeof(res)) < 0) { 530f4ede81eSAmarnath Valluri error_report("tpm-emulator: Could not cancel command: %s", 531f4ede81eSAmarnath Valluri strerror(errno)); 532f4ede81eSAmarnath Valluri } else if (res != 0) { 533f4ede81eSAmarnath Valluri error_report("tpm-emulator: Failed to cancel TPM: 0x%x", 534f4ede81eSAmarnath Valluri be32_to_cpu(res)); 535f4ede81eSAmarnath Valluri } 536f4ede81eSAmarnath Valluri } 537f4ede81eSAmarnath Valluri 538f4ede81eSAmarnath Valluri static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb) 539f4ede81eSAmarnath Valluri { 540f4ede81eSAmarnath Valluri TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 541f4ede81eSAmarnath Valluri 542f4ede81eSAmarnath Valluri return tpm_emu->tpm_version; 543f4ede81eSAmarnath Valluri } 544f4ede81eSAmarnath Valluri 545b21e6aafSStefan Berger static size_t tpm_emulator_get_buffer_size(TPMBackend *tb) 546b21e6aafSStefan Berger { 5479375c44fSStefan Berger size_t actual_size; 5489375c44fSStefan Berger 5499375c44fSStefan Berger if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) { 550b21e6aafSStefan Berger return 4096; 551b21e6aafSStefan Berger } 552b21e6aafSStefan Berger 5539375c44fSStefan Berger return actual_size; 5549375c44fSStefan Berger } 5559375c44fSStefan Berger 556f4ede81eSAmarnath Valluri static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) 557f4ede81eSAmarnath Valluri { 558f4ede81eSAmarnath Valluri Error *err = NULL; 559312c5404SStefan Berger uint32_t caps = PTM_CAP_GET_STATEBLOB | PTM_CAP_SET_STATEBLOB | 56038ab74e7SStefan Berger PTM_CAP_STOP; 561f4ede81eSAmarnath Valluri 56238ab74e7SStefan Berger if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) { 563f4ede81eSAmarnath Valluri error_setg(&tpm_emu->migration_blocker, 56438ab74e7SStefan Berger "Migration disabled: TPM emulator does not support " 56538ab74e7SStefan Berger "migration"); 566c8a7fc51SSteve Sistare if (migrate_add_blocker(&tpm_emu->migration_blocker, &err) < 0) { 567f4ede81eSAmarnath Valluri error_report_err(err); 568f4ede81eSAmarnath Valluri return -1; 569f4ede81eSAmarnath Valluri } 57038ab74e7SStefan Berger } 571f4ede81eSAmarnath Valluri 572f4ede81eSAmarnath Valluri return 0; 573f4ede81eSAmarnath Valluri } 574f4ede81eSAmarnath Valluri 575f4ede81eSAmarnath Valluri static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu) 576f4ede81eSAmarnath Valluri { 577f4ede81eSAmarnath Valluri ptm_res res; 578f4ede81eSAmarnath Valluri Error *err = NULL; 579f4ede81eSAmarnath Valluri int fds[2] = { -1, -1 }; 580f4ede81eSAmarnath Valluri 5810038e9a2SGuoyi Tu if (qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { 582f4ede81eSAmarnath Valluri error_report("tpm-emulator: Failed to create socketpair"); 583f4ede81eSAmarnath Valluri return -1; 584f4ede81eSAmarnath Valluri } 585f4ede81eSAmarnath Valluri 586f4ede81eSAmarnath Valluri qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1); 587f4ede81eSAmarnath Valluri 58817b1af77SMarc-André Lureau if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_DATAFD, &res, 0, 589d2bcaaccSStefan Berger sizeof(ptm_res), sizeof(res)) < 0 || res != 0) { 590f4ede81eSAmarnath Valluri error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s", 591f4ede81eSAmarnath Valluri strerror(errno)); 592f4ede81eSAmarnath Valluri goto err_exit; 593f4ede81eSAmarnath Valluri } 594f4ede81eSAmarnath Valluri 595f4ede81eSAmarnath Valluri tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err)); 596f4ede81eSAmarnath Valluri if (err) { 597f4ede81eSAmarnath Valluri error_prepend(&err, "tpm-emulator: Failed to create io channel: "); 598f4ede81eSAmarnath Valluri error_report_err(err); 599f4ede81eSAmarnath Valluri goto err_exit; 600f4ede81eSAmarnath Valluri } 601f4ede81eSAmarnath Valluri 60225657fc6SMarc-André Lureau close(fds[1]); 603f4ede81eSAmarnath Valluri 604f4ede81eSAmarnath Valluri return 0; 605f4ede81eSAmarnath Valluri 606f4ede81eSAmarnath Valluri err_exit: 60725657fc6SMarc-André Lureau close(fds[0]); 60825657fc6SMarc-André Lureau close(fds[1]); 609f4ede81eSAmarnath Valluri return -1; 610f4ede81eSAmarnath Valluri } 611f4ede81eSAmarnath Valluri 612f4ede81eSAmarnath Valluri static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts) 613f4ede81eSAmarnath Valluri { 614f4ede81eSAmarnath Valluri const char *value; 61588f83074SStefan Berger Error *err = NULL; 61688f83074SStefan Berger Chardev *dev; 617f4ede81eSAmarnath Valluri 618f4ede81eSAmarnath Valluri value = qemu_opt_get(opts, "chardev"); 61988f83074SStefan Berger if (!value) { 62088f83074SStefan Berger error_report("tpm-emulator: parameter 'chardev' is missing"); 62188f83074SStefan Berger goto err; 62288f83074SStefan Berger } 623f4ede81eSAmarnath Valluri 62488f83074SStefan Berger dev = qemu_chr_find(value); 625f4ede81eSAmarnath Valluri if (!dev) { 62688f83074SStefan Berger error_report("tpm-emulator: tpm chardev '%s' not found", value); 627f4ede81eSAmarnath Valluri goto err; 628f4ede81eSAmarnath Valluri } 629f4ede81eSAmarnath Valluri 630f4ede81eSAmarnath Valluri if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) { 631f4ede81eSAmarnath Valluri error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':", 632f4ede81eSAmarnath Valluri value); 633f4ede81eSAmarnath Valluri error_report_err(err); 634f4ede81eSAmarnath Valluri goto err; 635f4ede81eSAmarnath Valluri } 636f4ede81eSAmarnath Valluri 637f4ede81eSAmarnath Valluri tpm_emu->options->chardev = g_strdup(value); 638f4ede81eSAmarnath Valluri 639f4ede81eSAmarnath Valluri if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) { 640f4ede81eSAmarnath Valluri goto err; 641f4ede81eSAmarnath Valluri } 642f4ede81eSAmarnath Valluri 643f4ede81eSAmarnath Valluri /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used 644f4ede81eSAmarnath Valluri * by passthrough driver, which not yet using GIOChannel. 645f4ede81eSAmarnath Valluri */ 646f4ede81eSAmarnath Valluri if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd, 647f4ede81eSAmarnath Valluri &tpm_emu->tpm_version)) { 648f4ede81eSAmarnath Valluri error_report("'%s' is not emulating TPM device. Error: %s", 649f4ede81eSAmarnath Valluri tpm_emu->options->chardev, strerror(errno)); 650f4ede81eSAmarnath Valluri goto err; 651f4ede81eSAmarnath Valluri } 652f4ede81eSAmarnath Valluri 6539d9dcd96SStefan Berger switch (tpm_emu->tpm_version) { 6549d9dcd96SStefan Berger case TPM_VERSION_1_2: 6559d9dcd96SStefan Berger trace_tpm_emulator_handle_device_opts_tpm12(); 6569d9dcd96SStefan Berger break; 6579d9dcd96SStefan Berger case TPM_VERSION_2_0: 6589d9dcd96SStefan Berger trace_tpm_emulator_handle_device_opts_tpm2(); 6599d9dcd96SStefan Berger break; 6609d9dcd96SStefan Berger default: 6619d9dcd96SStefan Berger trace_tpm_emulator_handle_device_opts_unspec(); 6629d9dcd96SStefan Berger } 663f4ede81eSAmarnath Valluri 664f4ede81eSAmarnath Valluri if (tpm_emulator_probe_caps(tpm_emu) || 665f4ede81eSAmarnath Valluri tpm_emulator_check_caps(tpm_emu)) { 666f4ede81eSAmarnath Valluri goto err; 667f4ede81eSAmarnath Valluri } 668f4ede81eSAmarnath Valluri 669f4ede81eSAmarnath Valluri return tpm_emulator_block_migration(tpm_emu); 670f4ede81eSAmarnath Valluri 671f4ede81eSAmarnath Valluri err: 6729d9dcd96SStefan Berger trace_tpm_emulator_handle_device_opts_startup_error(); 6739d9dcd96SStefan Berger 674f4ede81eSAmarnath Valluri return -1; 675f4ede81eSAmarnath Valluri } 676f4ede81eSAmarnath Valluri 6779f7c0ef2SMarc-André Lureau static TPMBackend *tpm_emulator_create(QemuOpts *opts) 678f4ede81eSAmarnath Valluri { 679f4ede81eSAmarnath Valluri TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR)); 680f4ede81eSAmarnath Valluri 681f4ede81eSAmarnath Valluri if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) { 6829f7c0ef2SMarc-André Lureau object_unref(OBJECT(tb)); 6839f7c0ef2SMarc-André Lureau return NULL; 684f4ede81eSAmarnath Valluri } 685f4ede81eSAmarnath Valluri 686f4ede81eSAmarnath Valluri return tb; 687f4ede81eSAmarnath Valluri } 688f4ede81eSAmarnath Valluri 689f4ede81eSAmarnath Valluri static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb) 690f4ede81eSAmarnath Valluri { 691f4ede81eSAmarnath Valluri TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 692f4ede81eSAmarnath Valluri TpmTypeOptions *options = g_new0(TpmTypeOptions, 1); 693f4ede81eSAmarnath Valluri 69439dc3e4aSMarkus Armbruster options->type = TPM_TYPE_EMULATOR; 695f4ede81eSAmarnath Valluri options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options); 696f4ede81eSAmarnath Valluri 697f4ede81eSAmarnath Valluri return options; 698f4ede81eSAmarnath Valluri } 699f4ede81eSAmarnath Valluri 700f4ede81eSAmarnath Valluri static const QemuOptDesc tpm_emulator_cmdline_opts[] = { 701f4ede81eSAmarnath Valluri TPM_STANDARD_CMDLINE_OPTS, 702f4ede81eSAmarnath Valluri { 703f4ede81eSAmarnath Valluri .name = "chardev", 704f4ede81eSAmarnath Valluri .type = QEMU_OPT_STRING, 705f4ede81eSAmarnath Valluri .help = "Character device to use for out-of-band control messages", 706f4ede81eSAmarnath Valluri }, 707f4ede81eSAmarnath Valluri { /* end of list */ }, 708f4ede81eSAmarnath Valluri }; 709f4ede81eSAmarnath Valluri 71038ab74e7SStefan Berger /* 71138ab74e7SStefan Berger * Transfer a TPM state blob from the TPM into a provided buffer. 71238ab74e7SStefan Berger * 71338ab74e7SStefan Berger * @tpm_emu: TPMEmulator 71438ab74e7SStefan Berger * @type: the type of blob to transfer 71538ab74e7SStefan Berger * @tsb: the TPMSizeBuffer to fill with the blob 71638ab74e7SStefan Berger * @flags: the flags to return to the caller 71738ab74e7SStefan Berger */ 71838ab74e7SStefan Berger static int tpm_emulator_get_state_blob(TPMEmulator *tpm_emu, 71938ab74e7SStefan Berger uint8_t type, 72038ab74e7SStefan Berger TPMSizedBuffer *tsb, 72138ab74e7SStefan Berger uint32_t *flags) 72238ab74e7SStefan Berger { 72338ab74e7SStefan Berger ptm_getstate pgs; 72438ab74e7SStefan Berger ptm_res res; 72538ab74e7SStefan Berger ssize_t n; 72638ab74e7SStefan Berger uint32_t totlength, length; 72738ab74e7SStefan Berger 72838ab74e7SStefan Berger tpm_sized_buffer_reset(tsb); 72938ab74e7SStefan Berger 73038ab74e7SStefan Berger pgs.u.req.state_flags = cpu_to_be32(PTM_STATE_FLAG_DECRYPTED); 73138ab74e7SStefan Berger pgs.u.req.type = cpu_to_be32(type); 73238ab74e7SStefan Berger pgs.u.req.offset = 0; 73338ab74e7SStefan Berger 73438ab74e7SStefan Berger if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_STATEBLOB, 73538ab74e7SStefan Berger &pgs, sizeof(pgs.u.req), 736d2bcaaccSStefan Berger /* always returns up to resp.data */ 737d2bcaaccSStefan Berger offsetof(ptm_getstate, u.resp.data), 73838ab74e7SStefan Berger offsetof(ptm_getstate, u.resp.data)) < 0) { 73938ab74e7SStefan Berger error_report("tpm-emulator: could not get state blob type %d : %s", 74038ab74e7SStefan Berger type, strerror(errno)); 74138ab74e7SStefan Berger return -1; 74238ab74e7SStefan Berger } 74338ab74e7SStefan Berger 74438ab74e7SStefan Berger res = be32_to_cpu(pgs.u.resp.tpm_result); 74538ab74e7SStefan Berger if (res != 0 && (res & 0x800) == 0) { 74638ab74e7SStefan Berger error_report("tpm-emulator: Getting the stateblob (type %d) failed " 7477e095e84SStefan Berger "with a TPM error 0x%x %s", type, res, 7487e095e84SStefan Berger tpm_emulator_strerror(res)); 74938ab74e7SStefan Berger return -1; 75038ab74e7SStefan Berger } 75138ab74e7SStefan Berger 75238ab74e7SStefan Berger totlength = be32_to_cpu(pgs.u.resp.totlength); 75338ab74e7SStefan Berger length = be32_to_cpu(pgs.u.resp.length); 75438ab74e7SStefan Berger if (totlength != length) { 75538ab74e7SStefan Berger error_report("tpm-emulator: Expecting to read %u bytes " 75638ab74e7SStefan Berger "but would get %u", totlength, length); 75738ab74e7SStefan Berger return -1; 75838ab74e7SStefan Berger } 75938ab74e7SStefan Berger 76038ab74e7SStefan Berger *flags = be32_to_cpu(pgs.u.resp.state_flags); 76138ab74e7SStefan Berger 76238ab74e7SStefan Berger if (totlength > 0) { 76338ab74e7SStefan Berger tsb->buffer = g_try_malloc(totlength); 76438ab74e7SStefan Berger if (!tsb->buffer) { 76538ab74e7SStefan Berger error_report("tpm-emulator: Out of memory allocating %u bytes", 76638ab74e7SStefan Berger totlength); 76738ab74e7SStefan Berger return -1; 76838ab74e7SStefan Berger } 76938ab74e7SStefan Berger 77038ab74e7SStefan Berger n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr, tsb->buffer, totlength); 77138ab74e7SStefan Berger if (n != totlength) { 77238ab74e7SStefan Berger error_report("tpm-emulator: Could not read stateblob (type %d); " 77338ab74e7SStefan Berger "expected %u bytes, got %zd", 77438ab74e7SStefan Berger type, totlength, n); 77538ab74e7SStefan Berger return -1; 77638ab74e7SStefan Berger } 77738ab74e7SStefan Berger } 77838ab74e7SStefan Berger tsb->size = totlength; 77938ab74e7SStefan Berger 78038ab74e7SStefan Berger trace_tpm_emulator_get_state_blob(type, tsb->size, *flags); 78138ab74e7SStefan Berger 78238ab74e7SStefan Berger return 0; 78338ab74e7SStefan Berger } 78438ab74e7SStefan Berger 78538ab74e7SStefan Berger static int tpm_emulator_get_state_blobs(TPMEmulator *tpm_emu) 78638ab74e7SStefan Berger { 78738ab74e7SStefan Berger TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs; 78838ab74e7SStefan Berger 78938ab74e7SStefan Berger if (tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT, 79038ab74e7SStefan Berger &state_blobs->permanent, 79138ab74e7SStefan Berger &state_blobs->permanent_flags) < 0 || 79238ab74e7SStefan Berger tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE, 79338ab74e7SStefan Berger &state_blobs->volatil, 79438ab74e7SStefan Berger &state_blobs->volatil_flags) < 0 || 79538ab74e7SStefan Berger tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE, 79638ab74e7SStefan Berger &state_blobs->savestate, 79738ab74e7SStefan Berger &state_blobs->savestate_flags) < 0) { 79838ab74e7SStefan Berger goto err_exit; 79938ab74e7SStefan Berger } 80038ab74e7SStefan Berger 80138ab74e7SStefan Berger return 0; 80238ab74e7SStefan Berger 80338ab74e7SStefan Berger err_exit: 80438ab74e7SStefan Berger tpm_sized_buffer_reset(&state_blobs->volatil); 80538ab74e7SStefan Berger tpm_sized_buffer_reset(&state_blobs->permanent); 80638ab74e7SStefan Berger tpm_sized_buffer_reset(&state_blobs->savestate); 80738ab74e7SStefan Berger 80838ab74e7SStefan Berger return -1; 80938ab74e7SStefan Berger } 81038ab74e7SStefan Berger 81138ab74e7SStefan Berger /* 81238ab74e7SStefan Berger * Transfer a TPM state blob to the TPM emulator. 81338ab74e7SStefan Berger * 81438ab74e7SStefan Berger * @tpm_emu: TPMEmulator 81538ab74e7SStefan Berger * @type: the type of TPM state blob to transfer 81638ab74e7SStefan Berger * @tsb: TPMSizedBuffer containing the TPM state blob 81738ab74e7SStefan Berger * @flags: Flags describing the (encryption) state of the TPM state blob 81838ab74e7SStefan Berger */ 81938ab74e7SStefan Berger static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu, 82038ab74e7SStefan Berger uint32_t type, 82138ab74e7SStefan Berger TPMSizedBuffer *tsb, 82238ab74e7SStefan Berger uint32_t flags) 82338ab74e7SStefan Berger { 82438ab74e7SStefan Berger ssize_t n; 82538ab74e7SStefan Berger ptm_setstate pss; 82638ab74e7SStefan Berger ptm_res tpm_result; 82738ab74e7SStefan Berger 82838ab74e7SStefan Berger if (tsb->size == 0) { 82938ab74e7SStefan Berger return 0; 83038ab74e7SStefan Berger } 83138ab74e7SStefan Berger 83238ab74e7SStefan Berger pss = (ptm_setstate) { 83338ab74e7SStefan Berger .u.req.state_flags = cpu_to_be32(flags), 83438ab74e7SStefan Berger .u.req.type = cpu_to_be32(type), 83538ab74e7SStefan Berger .u.req.length = cpu_to_be32(tsb->size), 83638ab74e7SStefan Berger }; 83738ab74e7SStefan Berger 83838ab74e7SStefan Berger /* write the header only */ 83938ab74e7SStefan Berger if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_STATEBLOB, &pss, 840d2bcaaccSStefan Berger offsetof(ptm_setstate, u.req.data), 0, 0) < 0) { 84138ab74e7SStefan Berger error_report("tpm-emulator: could not set state blob type %d : %s", 84238ab74e7SStefan Berger type, strerror(errno)); 84338ab74e7SStefan Berger return -1; 84438ab74e7SStefan Berger } 84538ab74e7SStefan Berger 84638ab74e7SStefan Berger /* now the body */ 84738ab74e7SStefan Berger n = qemu_chr_fe_write_all(&tpm_emu->ctrl_chr, tsb->buffer, tsb->size); 84838ab74e7SStefan Berger if (n != tsb->size) { 84938ab74e7SStefan Berger error_report("tpm-emulator: Writing the stateblob (type %d) " 85038ab74e7SStefan Berger "failed; could not write %u bytes, but only %zd", 85138ab74e7SStefan Berger type, tsb->size, n); 85238ab74e7SStefan Berger return -1; 85338ab74e7SStefan Berger } 85438ab74e7SStefan Berger 85538ab74e7SStefan Berger /* now get the result */ 85638ab74e7SStefan Berger n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr, 85738ab74e7SStefan Berger (uint8_t *)&pss, sizeof(pss.u.resp)); 85838ab74e7SStefan Berger if (n != sizeof(pss.u.resp)) { 85938ab74e7SStefan Berger error_report("tpm-emulator: Reading response from writing stateblob " 86038ab74e7SStefan Berger "(type %d) failed; expected %zu bytes, got %zd", type, 86138ab74e7SStefan Berger sizeof(pss.u.resp), n); 86238ab74e7SStefan Berger return -1; 86338ab74e7SStefan Berger } 86438ab74e7SStefan Berger 86538ab74e7SStefan Berger tpm_result = be32_to_cpu(pss.u.resp.tpm_result); 86638ab74e7SStefan Berger if (tpm_result != 0) { 86738ab74e7SStefan Berger error_report("tpm-emulator: Setting the stateblob (type %d) failed " 8687e095e84SStefan Berger "with a TPM error 0x%x %s", type, tpm_result, 8697e095e84SStefan Berger tpm_emulator_strerror(tpm_result)); 87038ab74e7SStefan Berger return -1; 87138ab74e7SStefan Berger } 87238ab74e7SStefan Berger 87338ab74e7SStefan Berger trace_tpm_emulator_set_state_blob(type, tsb->size, flags); 87438ab74e7SStefan Berger 87538ab74e7SStefan Berger return 0; 87638ab74e7SStefan Berger } 87738ab74e7SStefan Berger 87838ab74e7SStefan Berger /* 87938ab74e7SStefan Berger * Set all the TPM state blobs. 88038ab74e7SStefan Berger * 88138ab74e7SStefan Berger * Returns a negative errno code in case of error. 88238ab74e7SStefan Berger */ 88338ab74e7SStefan Berger static int tpm_emulator_set_state_blobs(TPMBackend *tb) 88438ab74e7SStefan Berger { 88538ab74e7SStefan Berger TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 88638ab74e7SStefan Berger TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs; 88738ab74e7SStefan Berger 88838ab74e7SStefan Berger trace_tpm_emulator_set_state_blobs(); 88938ab74e7SStefan Berger 89038ab74e7SStefan Berger if (tpm_emulator_stop_tpm(tb) < 0) { 89138ab74e7SStefan Berger trace_tpm_emulator_set_state_blobs_error("Could not stop TPM"); 89238ab74e7SStefan Berger return -EIO; 89338ab74e7SStefan Berger } 89438ab74e7SStefan Berger 89538ab74e7SStefan Berger if (tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT, 89638ab74e7SStefan Berger &state_blobs->permanent, 89738ab74e7SStefan Berger state_blobs->permanent_flags) < 0 || 89838ab74e7SStefan Berger tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE, 89938ab74e7SStefan Berger &state_blobs->volatil, 90038ab74e7SStefan Berger state_blobs->volatil_flags) < 0 || 90138ab74e7SStefan Berger tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE, 90238ab74e7SStefan Berger &state_blobs->savestate, 90338ab74e7SStefan Berger state_blobs->savestate_flags) < 0) { 90438ab74e7SStefan Berger return -EIO; 90538ab74e7SStefan Berger } 90638ab74e7SStefan Berger 90738ab74e7SStefan Berger trace_tpm_emulator_set_state_blobs_done(); 90838ab74e7SStefan Berger 90938ab74e7SStefan Berger return 0; 91038ab74e7SStefan Berger } 91138ab74e7SStefan Berger 91238ab74e7SStefan Berger static int tpm_emulator_pre_save(void *opaque) 91338ab74e7SStefan Berger { 91438ab74e7SStefan Berger TPMBackend *tb = opaque; 91538ab74e7SStefan Berger TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 91699bdcd2cSStefan Berger int ret; 91738ab74e7SStefan Berger 91838ab74e7SStefan Berger trace_tpm_emulator_pre_save(); 91938ab74e7SStefan Berger 92038ab74e7SStefan Berger tpm_backend_finish_sync(tb); 92138ab74e7SStefan Berger 92238ab74e7SStefan Berger /* get the state blobs from the TPM */ 92399bdcd2cSStefan Berger ret = tpm_emulator_get_state_blobs(tpm_emu); 92499bdcd2cSStefan Berger 92599bdcd2cSStefan Berger tpm_emu->relock_storage = ret == 0; 92699bdcd2cSStefan Berger 92799bdcd2cSStefan Berger return ret; 92899bdcd2cSStefan Berger } 92999bdcd2cSStefan Berger 93099bdcd2cSStefan Berger static void tpm_emulator_vm_state_change(void *opaque, bool running, 93199bdcd2cSStefan Berger RunState state) 93299bdcd2cSStefan Berger { 93399bdcd2cSStefan Berger TPMBackend *tb = opaque; 93499bdcd2cSStefan Berger TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 93599bdcd2cSStefan Berger 93699bdcd2cSStefan Berger trace_tpm_emulator_vm_state_change(running, state); 93799bdcd2cSStefan Berger 9380f1db069SSteve Sistare if (!running || !tpm_emu->relock_storage) { 93999bdcd2cSStefan Berger return; 94099bdcd2cSStefan Berger } 94199bdcd2cSStefan Berger 94299bdcd2cSStefan Berger /* lock storage after migration fall-back */ 94399bdcd2cSStefan Berger tpm_emulator_lock_storage(tpm_emu); 94438ab74e7SStefan Berger } 94538ab74e7SStefan Berger 94638ab74e7SStefan Berger /* 94738ab74e7SStefan Berger * Load the TPM state blobs into the TPM. 94838ab74e7SStefan Berger * 94938ab74e7SStefan Berger * Returns negative errno codes in case of error. 95038ab74e7SStefan Berger */ 95138ab74e7SStefan Berger static int tpm_emulator_post_load(void *opaque, int version_id) 95238ab74e7SStefan Berger { 95338ab74e7SStefan Berger TPMBackend *tb = opaque; 95438ab74e7SStefan Berger int ret; 95538ab74e7SStefan Berger 95638ab74e7SStefan Berger ret = tpm_emulator_set_state_blobs(tb); 95738ab74e7SStefan Berger if (ret < 0) { 95838ab74e7SStefan Berger return ret; 95938ab74e7SStefan Berger } 96038ab74e7SStefan Berger 96138ab74e7SStefan Berger if (tpm_emulator_startup_tpm_resume(tb, 0, true) < 0) { 96238ab74e7SStefan Berger return -EIO; 96338ab74e7SStefan Berger } 96438ab74e7SStefan Berger 96538ab74e7SStefan Berger return 0; 96638ab74e7SStefan Berger } 96738ab74e7SStefan Berger 96838ab74e7SStefan Berger static const VMStateDescription vmstate_tpm_emulator = { 96938ab74e7SStefan Berger .name = "tpm-emulator", 97038ab74e7SStefan Berger .version_id = 0, 97138ab74e7SStefan Berger .pre_save = tpm_emulator_pre_save, 97238ab74e7SStefan Berger .post_load = tpm_emulator_post_load, 973d349d5abSRichard Henderson .fields = (const VMStateField[]) { 97438ab74e7SStefan Berger VMSTATE_UINT32(state_blobs.permanent_flags, TPMEmulator), 97538ab74e7SStefan Berger VMSTATE_UINT32(state_blobs.permanent.size, TPMEmulator), 97638ab74e7SStefan Berger VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.permanent.buffer, 97738ab74e7SStefan Berger TPMEmulator, 0, 0, 97838ab74e7SStefan Berger state_blobs.permanent.size), 97938ab74e7SStefan Berger 98038ab74e7SStefan Berger VMSTATE_UINT32(state_blobs.volatil_flags, TPMEmulator), 98138ab74e7SStefan Berger VMSTATE_UINT32(state_blobs.volatil.size, TPMEmulator), 98238ab74e7SStefan Berger VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.volatil.buffer, 98338ab74e7SStefan Berger TPMEmulator, 0, 0, 98438ab74e7SStefan Berger state_blobs.volatil.size), 98538ab74e7SStefan Berger 98638ab74e7SStefan Berger VMSTATE_UINT32(state_blobs.savestate_flags, TPMEmulator), 98738ab74e7SStefan Berger VMSTATE_UINT32(state_blobs.savestate.size, TPMEmulator), 98838ab74e7SStefan Berger VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.savestate.buffer, 98938ab74e7SStefan Berger TPMEmulator, 0, 0, 99038ab74e7SStefan Berger state_blobs.savestate.size), 99138ab74e7SStefan Berger 99238ab74e7SStefan Berger VMSTATE_END_OF_LIST() 99338ab74e7SStefan Berger } 99438ab74e7SStefan Berger }; 99538ab74e7SStefan Berger 996f4ede81eSAmarnath Valluri static void tpm_emulator_inst_init(Object *obj) 997f4ede81eSAmarnath Valluri { 998f4ede81eSAmarnath Valluri TPMEmulator *tpm_emu = TPM_EMULATOR(obj); 999f4ede81eSAmarnath Valluri 10009d9dcd96SStefan Berger trace_tpm_emulator_inst_init(); 10019d9dcd96SStefan Berger 1002f4ede81eSAmarnath Valluri tpm_emu->options = g_new0(TPMEmulatorOptions, 1); 1003f4ede81eSAmarnath Valluri tpm_emu->cur_locty_number = ~0; 100417b1af77SMarc-André Lureau qemu_mutex_init(&tpm_emu->mutex); 100599bdcd2cSStefan Berger tpm_emu->vmstate = 100699bdcd2cSStefan Berger qemu_add_vm_change_state_handler(tpm_emulator_vm_state_change, 100799bdcd2cSStefan Berger tpm_emu); 100838ab74e7SStefan Berger 100999b16e8eSJuan Quintela vmstate_register_any(NULL, &vmstate_tpm_emulator, obj); 1010f4ede81eSAmarnath Valluri } 1011f4ede81eSAmarnath Valluri 1012f4ede81eSAmarnath Valluri /* 1013f4ede81eSAmarnath Valluri * Gracefully shut down the external TPM 1014f4ede81eSAmarnath Valluri */ 1015f4ede81eSAmarnath Valluri static void tpm_emulator_shutdown(TPMEmulator *tpm_emu) 1016f4ede81eSAmarnath Valluri { 1017f4ede81eSAmarnath Valluri ptm_res res; 1018f4ede81eSAmarnath Valluri 101988f83074SStefan Berger if (!tpm_emu->options->chardev) { 102088f83074SStefan Berger /* was never properly initialized */ 102188f83074SStefan Berger return; 102288f83074SStefan Berger } 102388f83074SStefan Berger 1024d2bcaaccSStefan Berger if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, 1025d2bcaaccSStefan Berger sizeof(ptm_res), sizeof(res)) < 0) { 1026f4ede81eSAmarnath Valluri error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s", 1027f4ede81eSAmarnath Valluri strerror(errno)); 1028f4ede81eSAmarnath Valluri } else if (res != 0) { 10297e095e84SStefan Berger error_report("tpm-emulator: TPM result for shutdown: 0x%x %s", 10307e095e84SStefan Berger be32_to_cpu(res), tpm_emulator_strerror(be32_to_cpu(res))); 1031f4ede81eSAmarnath Valluri } 1032f4ede81eSAmarnath Valluri } 1033f4ede81eSAmarnath Valluri 1034f4ede81eSAmarnath Valluri static void tpm_emulator_inst_finalize(Object *obj) 1035f4ede81eSAmarnath Valluri { 1036f4ede81eSAmarnath Valluri TPMEmulator *tpm_emu = TPM_EMULATOR(obj); 103738ab74e7SStefan Berger TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs; 1038f4ede81eSAmarnath Valluri 1039f4ede81eSAmarnath Valluri tpm_emulator_shutdown(tpm_emu); 1040f4ede81eSAmarnath Valluri 1041f4ede81eSAmarnath Valluri object_unref(OBJECT(tpm_emu->data_ioc)); 1042f4ede81eSAmarnath Valluri 1043f4ede81eSAmarnath Valluri qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false); 1044f4ede81eSAmarnath Valluri 1045f4ede81eSAmarnath Valluri qapi_free_TPMEmulatorOptions(tpm_emu->options); 1046f4ede81eSAmarnath Valluri 1047c8a7fc51SSteve Sistare migrate_del_blocker(&tpm_emu->migration_blocker); 104817b1af77SMarc-André Lureau 104938ab74e7SStefan Berger tpm_sized_buffer_reset(&state_blobs->volatil); 105038ab74e7SStefan Berger tpm_sized_buffer_reset(&state_blobs->permanent); 105138ab74e7SStefan Berger tpm_sized_buffer_reset(&state_blobs->savestate); 105238ab74e7SStefan Berger 105317b1af77SMarc-André Lureau qemu_mutex_destroy(&tpm_emu->mutex); 105499bdcd2cSStefan Berger qemu_del_vm_change_state_handler(tpm_emu->vmstate); 105538ab74e7SStefan Berger 105638ab74e7SStefan Berger vmstate_unregister(NULL, &vmstate_tpm_emulator, obj); 1057f4ede81eSAmarnath Valluri } 1058f4ede81eSAmarnath Valluri 1059*12d1a768SPhilippe Mathieu-Daudé static void tpm_emulator_class_init(ObjectClass *klass, const void *data) 1060f4ede81eSAmarnath Valluri { 1061f4ede81eSAmarnath Valluri TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); 1062d31076baSMarc-André Lureau 1063d31076baSMarc-André Lureau tbc->type = TPM_TYPE_EMULATOR; 1064d31076baSMarc-André Lureau tbc->opts = tpm_emulator_cmdline_opts; 1065d31076baSMarc-André Lureau tbc->desc = "TPM emulator backend driver"; 1066d31076baSMarc-André Lureau tbc->create = tpm_emulator_create; 1067d31076baSMarc-André Lureau tbc->startup_tpm = tpm_emulator_startup_tpm; 1068d31076baSMarc-André Lureau tbc->cancel_cmd = tpm_emulator_cancel_cmd; 1069d31076baSMarc-André Lureau tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag; 1070d31076baSMarc-André Lureau tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag; 1071d31076baSMarc-André Lureau tbc->get_tpm_version = tpm_emulator_get_tpm_version; 1072b21e6aafSStefan Berger tbc->get_buffer_size = tpm_emulator_get_buffer_size; 1073d31076baSMarc-André Lureau tbc->get_tpm_options = tpm_emulator_get_tpm_options; 1074d31076baSMarc-André Lureau 1075f4ede81eSAmarnath Valluri tbc->handle_request = tpm_emulator_handle_request; 1076f4ede81eSAmarnath Valluri } 1077f4ede81eSAmarnath Valluri 1078f4ede81eSAmarnath Valluri static const TypeInfo tpm_emulator_info = { 1079f4ede81eSAmarnath Valluri .name = TYPE_TPM_EMULATOR, 1080f4ede81eSAmarnath Valluri .parent = TYPE_TPM_BACKEND, 1081f4ede81eSAmarnath Valluri .instance_size = sizeof(TPMEmulator), 1082f4ede81eSAmarnath Valluri .class_init = tpm_emulator_class_init, 1083f4ede81eSAmarnath Valluri .instance_init = tpm_emulator_inst_init, 1084f4ede81eSAmarnath Valluri .instance_finalize = tpm_emulator_inst_finalize, 1085f4ede81eSAmarnath Valluri }; 1086f4ede81eSAmarnath Valluri 1087f4ede81eSAmarnath Valluri static void tpm_emulator_register(void) 1088f4ede81eSAmarnath Valluri { 1089f4ede81eSAmarnath Valluri type_register_static(&tpm_emulator_info); 1090f4ede81eSAmarnath Valluri } 1091f4ede81eSAmarnath Valluri 1092f4ede81eSAmarnath Valluri type_init(tpm_emulator_register) 1093