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
tpm_emulator_strerror(uint32_t tpm_result)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
tpm_emulator_ctrlcmd(TPMEmulator * tpm,unsigned long cmd,void * msg,size_t msg_len_in,size_t msg_len_out_err,size_t msg_len_out_total)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
tpm_emulator_unix_tx_bufs(TPMEmulator * tpm_emu,const uint8_t * in,uint32_t in_len,uint8_t * out,uint32_t out_len,bool * selftest_done,Error ** errp)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
tpm_emulator_set_locality(TPMEmulator * tpm_emu,uint8_t locty_number,Error ** errp)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
tpm_emulator_handle_request(TPMBackend * tb,TPMBackendCmd * cmd,Error ** errp)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
tpm_emulator_probe_caps(TPMEmulator * tpm_emu)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
tpm_emulator_check_caps(TPMEmulator * tpm_emu)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
tpm_emulator_stop_tpm(TPMBackend * tb)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
tpm_emulator_lock_storage(TPMEmulator * tpm_emu)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
tpm_emulator_set_buffer_size(TPMBackend * tb,size_t wanted_size,size_t * actual_size)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
tpm_emulator_startup_tpm_resume(TPMBackend * tb,size_t buffersize,bool is_resume)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
tpm_emulator_startup_tpm(TPMBackend * tb,size_t buffersize)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
tpm_emulator_get_tpm_established_flag(TPMBackend * tb)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
tpm_emulator_reset_tpm_established_flag(TPMBackend * tb,uint8_t locty)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
tpm_emulator_cancel_cmd(TPMBackend * tb)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
tpm_emulator_get_tpm_version(TPMBackend * tb)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
tpm_emulator_get_buffer_size(TPMBackend * tb)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
tpm_emulator_block_migration(TPMEmulator * tpm_emu)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
tpm_emulator_prepare_data_fd(TPMEmulator * tpm_emu)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
tpm_emulator_handle_device_opts(TPMEmulator * tpm_emu,QemuOpts * opts)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
tpm_emulator_create(QemuOpts * opts)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
tpm_emulator_get_tpm_options(TPMBackend * tb)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 */
tpm_emulator_get_state_blob(TPMEmulator * tpm_emu,uint8_t type,TPMSizedBuffer * tsb,uint32_t * flags)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
tpm_emulator_get_state_blobs(TPMEmulator * tpm_emu)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 */
tpm_emulator_set_state_blob(TPMEmulator * tpm_emu,uint32_t type,TPMSizedBuffer * tsb,uint32_t flags)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 */
tpm_emulator_set_state_blobs(TPMBackend * tb)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
tpm_emulator_pre_save(void * opaque)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
tpm_emulator_vm_state_change(void * opaque,bool running,RunState state)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 */
tpm_emulator_post_load(void * opaque,int version_id)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
tpm_emulator_inst_init(Object * obj)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 */
tpm_emulator_shutdown(TPMEmulator * tpm_emu)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
tpm_emulator_inst_finalize(Object * obj)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
tpm_emulator_class_init(ObjectClass * klass,const void * data)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
tpm_emulator_register(void)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