summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/qemu/qemu/0010-tpm-Added-support-for-TPM-emulator.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/qemu/qemu/0010-tpm-Added-support-for-TPM-emulator.patch')
-rw-r--r--meta/recipes-devtools/qemu/qemu/0010-tpm-Added-support-for-TPM-emulator.patch1059
1 files changed, 0 insertions, 1059 deletions
diff --git a/meta/recipes-devtools/qemu/qemu/0010-tpm-Added-support-for-TPM-emulator.patch b/meta/recipes-devtools/qemu/qemu/0010-tpm-Added-support-for-TPM-emulator.patch
deleted file mode 100644
index 968e12e88a..0000000000
--- a/meta/recipes-devtools/qemu/qemu/0010-tpm-Added-support-for-TPM-emulator.patch
+++ /dev/null
@@ -1,1059 +0,0 @@
1From 70e73b7c6c7cf982d645db9c81c74588e6b10a2b Mon Sep 17 00:00:00 2001
2From: Amarnath Valluri <amarnath.valluri@intel.com>
3Date: Wed, 29 Mar 2017 15:39:41 +0300
4Subject: [PATCH 10/12] tpm: Added support for TPM emulator
5
6This change introduces a new TPM backend driver that can communicate with
7swtpm(software TPM emulator) using unix domain socket interface. QEMU talks to
8TPM emulator using QEMU's socket-based chardev backend device.
9
10Swtpm uses two Unix sockets for communications, one for plain TPM commands and
11responses, and one for out-of-band control messages. QEMU passes data socket to
12be used over the control channel.
13
14The swtpm and associated tools can be found here:
15 https://github.com/stefanberger/swtpm
16
17The swtpm's control channel protocol specification can be found here:
18 https://github.com/stefanberger/swtpm/wiki/Control-Channel-Specification
19
20Usage:
21 # setup TPM state directory
22 mkdir /tmp/mytpm
23 chown -R tss:root /tmp/mytpm
24 /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek
25
26 # Ask qemu to use TPM emulator with given tpm state directory
27 qemu-system-x86_64 \
28 [...] \
29 -chardev socket,id=chrtpm,path=/tmp/swtpm-sock \
30 -tpmdev emulator,id=tpm0,chardev=chrtpm \
31 -device tpm-tis,tpmdev=tpm0 \
32 [...]
33
34Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
35
36Upstream-Status: Backport [f4ede81eed29e6140374177d1f2808248c5b5650]
37---
38 configure | 13 +-
39 hmp.c | 5 +
40 hw/tpm/Makefile.objs | 1 +
41 hw/tpm/tpm_emulator.c | 583 ++++++++++++++++++++++++++++++++++++++++++++++++++
42 hw/tpm/tpm_ioctl.h | 246 +++++++++++++++++++++
43 qapi-schema.json | 18 +-
44 qemu-options.hx | 22 +-
45 7 files changed, 882 insertions(+), 6 deletions(-)
46 create mode 100644 hw/tpm/tpm_emulator.c
47 create mode 100644 hw/tpm/tpm_ioctl.h
48
49diff --git a/configure b/configure
50index dd73cce62f..9a25537096 100755
51--- a/configure
52+++ b/configure
53@@ -3503,6 +3503,12 @@ else
54 tpm_passthrough=no
55 fi
56
57+# TPM emulator is for all posix systems
58+if test "$mingw32" != "yes"; then
59+ tpm_emulator=$tpm
60+else
61+ tpm_emulator=no
62+fi
63 ##########################################
64 # attr probe
65
66@@ -5396,6 +5402,7 @@ echo "gcov enabled $gcov"
67 echo "TPM support $tpm"
68 echo "libssh2 support $libssh2"
69 echo "TPM passthrough $tpm_passthrough"
70+echo "TPM emulator $tpm_emulator"
71 echo "QOM debugging $qom_cast_debug"
72 echo "Live block migration $live_block_migration"
73 echo "lzo support $lzo"
74@@ -5983,12 +5990,16 @@ else
75 echo "HOST_USB=stub" >> $config_host_mak
76 fi
77
78-# TPM passthrough support?
79 if test "$tpm" = "yes"; then
80 echo 'CONFIG_TPM=$(CONFIG_SOFTMMU)' >> $config_host_mak
81+ # TPM passthrough support?
82 if test "$tpm_passthrough" = "yes"; then
83 echo "CONFIG_TPM_PASSTHROUGH=y" >> $config_host_mak
84 fi
85+ # TPM emulator support?
86+ if test "$tpm_emulator" = "yes"; then
87+ echo "CONFIG_TPM_EMULATOR=y" >> $config_host_mak
88+ fi
89 fi
90
91 echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak
92diff --git a/hmp.c b/hmp.c
93index fd80dce758..820aa8f002 100644
94--- a/hmp.c
95+++ b/hmp.c
96@@ -995,6 +995,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
97 Error *err = NULL;
98 unsigned int c = 0;
99 TPMPassthroughOptions *tpo;
100+ TPMEmulatorOptions *teo;
101
102 info_list = qmp_query_tpm(&err);
103 if (err) {
104@@ -1024,6 +1025,10 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
105 tpo->has_cancel_path ? ",cancel-path=" : "",
106 tpo->has_cancel_path ? tpo->cancel_path : "");
107 break;
108+ case TPM_TYPE_OPTIONS_KIND_EMULATOR:
109+ teo = ti->options->u.emulator.data;
110+ monitor_printf(mon, ",chardev=%s", teo->chardev);
111+ break;
112 case TPM_TYPE_OPTIONS_KIND__MAX:
113 break;
114 }
115diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
116index 64cecc3b67..41f0b7a590 100644
117--- a/hw/tpm/Makefile.objs
118+++ b/hw/tpm/Makefile.objs
119@@ -1,2 +1,3 @@
120 common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
121 common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o
122+common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o
123diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
124new file mode 100644
125index 0000000000..433bc4fa8a
126--- /dev/null
127+++ b/hw/tpm/tpm_emulator.c
128@@ -0,0 +1,583 @@
129+/*
130+ * Emulator TPM driver
131+ *
132+ * Copyright (c) 2017 Intel Corporation
133+ * Author: Amarnath Valluri <amarnath.valluri@intel.com>
134+ *
135+ * Copyright (c) 2010 - 2013 IBM Corporation
136+ * Authors:
137+ * Stefan Berger <stefanb@us.ibm.com>
138+ *
139+ * Copyright (C) 2011 IAIK, Graz University of Technology
140+ * Author: Andreas Niederl
141+ *
142+ * This library is free software; you can redistribute it and/or
143+ * modify it under the terms of the GNU Lesser General Public
144+ * License as published by the Free Software Foundation; either
145+ * version 2 of the License, or (at your option) any later version.
146+ *
147+ * This library is distributed in the hope that it will be useful,
148+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
149+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
150+ * Lesser General Public License for more details.
151+ *
152+ * You should have received a copy of the GNU Lesser General Public
153+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
154+ *
155+ */
156+
157+#include "qemu/osdep.h"
158+#include "qemu/error-report.h"
159+#include "qemu/sockets.h"
160+#include "io/channel-socket.h"
161+#include "sysemu/tpm_backend.h"
162+#include "tpm_int.h"
163+#include "hw/hw.h"
164+#include "hw/i386/pc.h"
165+#include "tpm_util.h"
166+#include "tpm_ioctl.h"
167+#include "migration/blocker.h"
168+#include "qapi/error.h"
169+#include "qapi/clone-visitor.h"
170+#include "chardev/char-fe.h"
171+
172+#include <fcntl.h>
173+#include <sys/types.h>
174+#include <sys/stat.h>
175+#include <stdio.h>
176+
177+#define DEBUG_TPM 0
178+
179+#define DPRINTF(fmt, ...) do { \
180+ if (DEBUG_TPM) { \
181+ fprintf(stderr, "tpm-emulator:"fmt"\n", ## __VA_ARGS__); \
182+ } \
183+} while (0)
184+
185+#define TYPE_TPM_EMULATOR "tpm-emulator"
186+#define TPM_EMULATOR(obj) \
187+ OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)
188+
189+#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))
190+
191+static const TPMDriverOps tpm_emulator_driver;
192+
193+/* data structures */
194+typedef struct TPMEmulator {
195+ TPMBackend parent;
196+
197+ TPMEmulatorOptions *options;
198+ CharBackend ctrl_chr;
199+ QIOChannel *data_ioc;
200+ TPMVersion tpm_version;
201+ ptm_cap caps; /* capabilities of the TPM */
202+ uint8_t cur_locty_number; /* last set locality */
203+ Error *migration_blocker;
204+} TPMEmulator;
205+
206+
207+static int tpm_emulator_ctrlcmd(CharBackend *dev, unsigned long cmd, void *msg,
208+ size_t msg_len_in, size_t msg_len_out)
209+{
210+ uint32_t cmd_no = cpu_to_be32(cmd);
211+ ssize_t n = sizeof(uint32_t) + msg_len_in;
212+ uint8_t *buf = NULL;
213+
214+ buf = g_alloca(n);
215+ memcpy(buf, &cmd_no, sizeof(cmd_no));
216+ memcpy(buf + sizeof(cmd_no), msg, msg_len_in);
217+
218+ n = qemu_chr_fe_write_all(dev, buf, n);
219+ if (n <= 0) {
220+ return -1;
221+ }
222+
223+ if (msg_len_out != 0) {
224+ n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
225+ if (n <= 0) {
226+ return -1;
227+ }
228+ }
229+
230+ return 0;
231+}
232+
233+static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu,
234+ const uint8_t *in, uint32_t in_len,
235+ uint8_t *out, uint32_t out_len,
236+ bool *selftest_done,
237+ Error **err)
238+{
239+ ssize_t ret;
240+ bool is_selftest = false;
241+ const struct tpm_resp_hdr *hdr = NULL;
242+
243+ if (selftest_done) {
244+ *selftest_done = false;
245+ is_selftest = tpm_util_is_selftest(in, in_len);
246+ }
247+
248+ ret = qio_channel_write(tpm_emu->data_ioc, (char *)in, in_len, err);
249+ if (ret != in_len) {
250+ return -1;
251+ }
252+
253+ ret = qio_channel_read(tpm_emu->data_ioc, (char *)out, out_len, err);
254+ if (ret <= 0 || ret < sizeof(*hdr)) {
255+ return -1;
256+ }
257+
258+ hdr = (struct tpm_resp_hdr *)out;
259+ if (be32_to_cpu(hdr->len) != ret) {
260+ return -1;
261+ }
262+
263+ if (is_selftest) {
264+ *selftest_done = (be32_to_cpu(hdr->errcode) == 0);
265+ }
266+
267+ return 0;
268+}
269+
270+static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number)
271+{
272+ ptm_loc loc;
273+
274+ DPRINTF("%s : locality: 0x%x", __func__, locty_number);
275+
276+ if (tpm_emu->cur_locty_number == locty_number) {
277+ return 0;
278+ }
279+
280+ DPRINTF("setting locality : 0x%x", locty_number);
281+ loc.u.req.loc = locty_number;
282+ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_SET_LOCALITY, &loc,
283+ sizeof(loc), sizeof(loc)) < 0) {
284+ error_report("tpm-emulator: could not set locality : %s",
285+ strerror(errno));
286+ return -1;
287+ }
288+
289+ loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);
290+ if (loc.u.resp.tpm_result != 0) {
291+ error_report("tpm-emulator: TPM result for set locality : 0x%x",
292+ loc.u.resp.tpm_result);
293+ return -1;
294+ }
295+
296+ tpm_emu->cur_locty_number = locty_number;
297+
298+ return 0;
299+}
300+
301+static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd cmd)
302+{
303+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
304+ TPMLocality *locty = NULL;
305+ bool selftest_done = false;
306+ Error *err = NULL;
307+
308+ DPRINTF("processing command type %d", cmd);
309+
310+ switch (cmd) {
311+ case TPM_BACKEND_CMD_PROCESS_CMD:
312+ locty = tb->tpm_state->locty_data;
313+ if (tpm_emulator_set_locality(tpm_emu,
314+ tb->tpm_state->locty_number) < 0 ||
315+ tpm_emulator_unix_tx_bufs(tpm_emu, locty->w_buffer.buffer,
316+ locty->w_offset, locty->r_buffer.buffer,
317+ locty->r_buffer.size, &selftest_done,
318+ &err) < 0) {
319+ tpm_util_write_fatal_error_response(locty->r_buffer.buffer,
320+ locty->r_buffer.size);
321+ error_report_err(err);
322+ }
323+
324+ tb->recv_data_callback(tb->tpm_state, tb->tpm_state->locty_number,
325+ selftest_done);
326+
327+ break;
328+ case TPM_BACKEND_CMD_INIT:
329+ case TPM_BACKEND_CMD_END:
330+ case TPM_BACKEND_CMD_TPM_RESET:
331+ /* nothing to do */
332+ break;
333+ }
334+}
335+
336+static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu)
337+{
338+ DPRINTF("%s", __func__);
339+ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_GET_CAPABILITY,
340+ &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) {
341+ error_report("tpm-emulator: probing failed : %s", strerror(errno));
342+ return -1;
343+ }
344+
345+ tpm_emu->caps = be64_to_cpu(tpm_emu->caps);
346+
347+ DPRINTF("capbilities : 0x%lx", tpm_emu->caps);
348+
349+ return 0;
350+}
351+
352+static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
353+{
354+ ptm_cap caps = 0;
355+ const char *tpm = NULL;
356+
357+ /* check for min. required capabilities */
358+ switch (tpm_emu->tpm_version) {
359+ case TPM_VERSION_1_2:
360+ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
361+ PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD;
362+ tpm = "1.2";
363+ break;
364+ case TPM_VERSION_2_0:
365+ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
366+ PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED |
367+ PTM_CAP_SET_DATAFD;
368+ tpm = "2";
369+ break;
370+ case TPM_VERSION_UNSPEC:
371+ error_report("tpm-emulator: TPM version has not been set");
372+ return -1;
373+ }
374+
375+ if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
376+ error_report("tpm-emulator: TPM does not implement minimum set of "
377+ "required capabilities for TPM %s (0x%x)", tpm, (int)caps);
378+ return -1;
379+ }
380+
381+ return 0;
382+}
383+
384+static int tpm_emulator_startup_tpm(TPMBackend *tb)
385+{
386+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
387+ ptm_init init;
388+ ptm_res res;
389+
390+ DPRINTF("%s", __func__);
391+ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_INIT, &init, sizeof(init),
392+ sizeof(init)) < 0) {
393+ error_report("tpm-emulator: could not send INIT: %s",
394+ strerror(errno));
395+ goto err_exit;
396+ }
397+
398+ res = be32_to_cpu(init.u.resp.tpm_result);
399+ if (res) {
400+ error_report("tpm-emulator: TPM result for CMD_INIT: 0x%x", res);
401+ goto err_exit;
402+ }
403+ return 0;
404+
405+err_exit:
406+ return -1;
407+}
408+
409+static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
410+{
411+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
412+ ptm_est est;
413+
414+ DPRINTF("%s", __func__);
415+ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_GET_TPMESTABLISHED, &est,
416+ 0, sizeof(est)) < 0) {
417+ error_report("tpm-emulator: Could not get the TPM established flag: %s",
418+ strerror(errno));
419+ return false;
420+ }
421+ DPRINTF("established flag: %0x", est.u.resp.bit);
422+
423+ return (est.u.resp.bit != 0);
424+}
425+
426+static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
427+ uint8_t locty)
428+{
429+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
430+ ptm_reset_est reset_est;
431+ ptm_res res;
432+
433+ /* only a TPM 2.0 will support this */
434+ if (tpm_emu->tpm_version != TPM_VERSION_2_0) {
435+ return 0;
436+ }
437+
438+ reset_est.u.req.loc = tpm_emu->cur_locty_number;
439+ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_RESET_TPMESTABLISHED,
440+ &reset_est, sizeof(reset_est),
441+ sizeof(reset_est)) < 0) {
442+ error_report("tpm-emulator: Could not reset the establishment bit: %s",
443+ strerror(errno));
444+ return -1;
445+ }
446+
447+ res = be32_to_cpu(reset_est.u.resp.tpm_result);
448+ if (res) {
449+ error_report("tpm-emulator: TPM result for rest establixhed flag: 0x%x",
450+ res);
451+ return -1;
452+ }
453+
454+ return 0;
455+}
456+
457+static void tpm_emulator_cancel_cmd(TPMBackend *tb)
458+{
459+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
460+ ptm_res res;
461+
462+ if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, PTM_CAP_CANCEL_TPM_CMD)) {
463+ DPRINTF("Backend does not support CANCEL_TPM_CMD");
464+ return;
465+ }
466+
467+ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_CANCEL_TPM_CMD, &res, 0,
468+ sizeof(res)) < 0) {
469+ error_report("tpm-emulator: Could not cancel command: %s",
470+ strerror(errno));
471+ } else if (res != 0) {
472+ error_report("tpm-emulator: Failed to cancel TPM: 0x%x",
473+ be32_to_cpu(res));
474+ }
475+}
476+
477+static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
478+{
479+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
480+
481+ return tpm_emu->tpm_version;
482+}
483+
484+static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
485+{
486+ Error *err = NULL;
487+
488+ error_setg(&tpm_emu->migration_blocker,
489+ "Migration disabled: TPM emulator not yet migratable");
490+ migrate_add_blocker(tpm_emu->migration_blocker, &err);
491+ if (err) {
492+ error_report_err(err);
493+ error_free(tpm_emu->migration_blocker);
494+ tpm_emu->migration_blocker = NULL;
495+
496+ return -1;
497+ }
498+
499+ return 0;
500+}
501+
502+static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
503+{
504+ ptm_res res;
505+ Error *err = NULL;
506+ int fds[2] = { -1, -1 };
507+
508+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
509+ error_report("tpm-emulator: Failed to create socketpair");
510+ return -1;
511+ }
512+
513+ qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1);
514+
515+ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_SET_DATAFD, &res, 0,
516+ sizeof(res)) || res != 0) {
517+ error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s",
518+ strerror(errno));
519+ goto err_exit;
520+ }
521+
522+ tpm_emu->data_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fds[0], &err));
523+ if (err) {
524+ error_prepend(&err, "tpm-emulator: Failed to create io channel: ");
525+ error_report_err(err);
526+ goto err_exit;
527+ }
528+
529+ closesocket(fds[1]);
530+
531+ return 0;
532+
533+err_exit:
534+ closesocket(fds[0]);
535+ closesocket(fds[1]);
536+ return -1;
537+}
538+
539+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts)
540+{
541+ const char *value;
542+
543+ value = qemu_opt_get(opts, "chardev");
544+ if (value) {
545+ Error *err = NULL;
546+ Chardev *dev = qemu_chr_find(value);
547+
548+ if (!dev) {
549+ error_report("tpm-emulator: tpm chardev '%s' not found.", value);
550+ goto err;
551+ }
552+
553+ if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) {
554+ error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':",
555+ value);
556+ error_report_err(err);
557+ goto err;
558+ }
559+
560+ tpm_emu->options->chardev = g_strdup(value);
561+ }
562+
563+ if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
564+ goto err;
565+ }
566+
567+ /* FIXME: tpm_util_test_tpmdev() accepts only on socket fd, as it also used
568+ * by passthrough driver, which not yet using GIOChannel.
569+ */
570+ if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd,
571+ &tpm_emu->tpm_version)) {
572+ error_report("'%s' is not emulating TPM device. Error: %s",
573+ tpm_emu->options->chardev, strerror(errno));
574+ goto err;
575+ }
576+
577+ DPRINTF("TPM Version %s", tpm_emu->tpm_version == TPM_VERSION_1_2 ? "1.2" :
578+ (tpm_emu->tpm_version == TPM_VERSION_2_0 ? "2.0" : "Unspecified"));
579+
580+ if (tpm_emulator_probe_caps(tpm_emu) ||
581+ tpm_emulator_check_caps(tpm_emu)) {
582+ goto err;
583+ }
584+
585+ return tpm_emulator_block_migration(tpm_emu);
586+
587+err:
588+ DPRINTF("Startup error");
589+ return -1;
590+}
591+
592+static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)
593+{
594+ TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
595+
596+ tb->id = g_strdup(id);
597+
598+ if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
599+ goto err_exit;
600+ }
601+
602+ return tb;
603+
604+err_exit:
605+ object_unref(OBJECT(tb));
606+
607+ return NULL;
608+}
609+
610+static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
611+{
612+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
613+ TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
614+
615+ options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
616+ options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options);
617+
618+ return options;
619+}
620+
621+static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
622+ TPM_STANDARD_CMDLINE_OPTS,
623+ {
624+ .name = "chardev",
625+ .type = QEMU_OPT_STRING,
626+ .help = "Character device to use for out-of-band control messages",
627+ },
628+ { /* end of list */ },
629+};
630+
631+static const TPMDriverOps tpm_emulator_driver = {
632+ .type = TPM_TYPE_EMULATOR,
633+ .opts = tpm_emulator_cmdline_opts,
634+ .desc = "TPM emulator backend driver",
635+
636+ .create = tpm_emulator_create,
637+ .startup_tpm = tpm_emulator_startup_tpm,
638+ .cancel_cmd = tpm_emulator_cancel_cmd,
639+ .get_tpm_established_flag = tpm_emulator_get_tpm_established_flag,
640+ .reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag,
641+ .get_tpm_version = tpm_emulator_get_tpm_version,
642+ .get_tpm_options = tpm_emulator_get_tpm_options,
643+};
644+
645+static void tpm_emulator_inst_init(Object *obj)
646+{
647+ TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
648+
649+ DPRINTF("%s", __func__);
650+ tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
651+ tpm_emu->cur_locty_number = ~0;
652+}
653+
654+/*
655+ * Gracefully shut down the external TPM
656+ */
657+static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
658+{
659+ ptm_res res;
660+
661+ if (tpm_emulator_ctrlcmd(&tpm_emu->ctrl_chr, CMD_SHUTDOWN, &res, 0,
662+ sizeof(res)) < 0) {
663+ error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
664+ strerror(errno));
665+ } else if (res != 0) {
666+ error_report("tpm-emulator: TPM result for sutdown: 0x%x",
667+ be32_to_cpu(res));
668+ }
669+}
670+
671+static void tpm_emulator_inst_finalize(Object *obj)
672+{
673+ TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
674+
675+ tpm_emulator_shutdown(tpm_emu);
676+
677+ object_unref(OBJECT(tpm_emu->data_ioc));
678+
679+ qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false);
680+
681+ qapi_free_TPMEmulatorOptions(tpm_emu->options);
682+
683+ if (tpm_emu->migration_blocker) {
684+ migrate_del_blocker(tpm_emu->migration_blocker);
685+ error_free(tpm_emu->migration_blocker);
686+ }
687+}
688+
689+static void tpm_emulator_class_init(ObjectClass *klass, void *data)
690+{
691+ TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
692+ tbc->ops = &tpm_emulator_driver;
693+ tbc->handle_request = tpm_emulator_handle_request;
694+}
695+
696+static const TypeInfo tpm_emulator_info = {
697+ .name = TYPE_TPM_EMULATOR,
698+ .parent = TYPE_TPM_BACKEND,
699+ .instance_size = sizeof(TPMEmulator),
700+ .class_init = tpm_emulator_class_init,
701+ .instance_init = tpm_emulator_inst_init,
702+ .instance_finalize = tpm_emulator_inst_finalize,
703+};
704+
705+static void tpm_emulator_register(void)
706+{
707+ type_register_static(&tpm_emulator_info);
708+ tpm_register_driver(&tpm_emulator_driver);
709+}
710+
711+type_init(tpm_emulator_register)
712diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h
713new file mode 100644
714index 0000000000..33564b11de
715--- /dev/null
716+++ b/hw/tpm/tpm_ioctl.h
717@@ -0,0 +1,246 @@
718+/*
719+ * tpm_ioctl.h
720+ *
721+ * (c) Copyright IBM Corporation 2014, 2015.
722+ *
723+ * This file is licensed under the terms of the 3-clause BSD license
724+ */
725+#ifndef _TPM_IOCTL_H_
726+#define _TPM_IOCTL_H_
727+
728+#include <stdint.h>
729+#include <sys/uio.h>
730+#include <sys/types.h>
731+#include <sys/ioctl.h>
732+
733+/*
734+ * Every response from a command involving a TPM command execution must hold
735+ * the ptm_res as the first element.
736+ * ptm_res corresponds to the error code of a command executed by the TPM.
737+ */
738+
739+typedef uint32_t ptm_res;
740+
741+/* PTM_GET_TPMESTABLISHED: get the establishment bit */
742+struct ptm_est {
743+ union {
744+ struct {
745+ ptm_res tpm_result;
746+ unsigned char bit; /* TPM established bit */
747+ } resp; /* response */
748+ } u;
749+};
750+
751+/* PTM_RESET_TPMESTABLISHED: reset establishment bit */
752+struct ptm_reset_est {
753+ union {
754+ struct {
755+ uint8_t loc; /* locality to use */
756+ } req; /* request */
757+ struct {
758+ ptm_res tpm_result;
759+ } resp; /* response */
760+ } u;
761+};
762+
763+/* PTM_INIT */
764+struct ptm_init {
765+ union {
766+ struct {
767+ uint32_t init_flags; /* see definitions below */
768+ } req; /* request */
769+ struct {
770+ ptm_res tpm_result;
771+ } resp; /* response */
772+ } u;
773+};
774+
775+/* above init_flags */
776+#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)
777+ /* delete volatile state file after reading it */
778+
779+/* PTM_SET_LOCALITY */
780+struct ptm_loc {
781+ union {
782+ struct {
783+ uint8_t loc; /* locality to set */
784+ } req; /* request */
785+ struct {
786+ ptm_res tpm_result;
787+ } resp; /* response */
788+ } u;
789+};
790+
791+/* PTM_HASH_DATA: hash given data */
792+struct ptm_hdata {
793+ union {
794+ struct {
795+ uint32_t length;
796+ uint8_t data[4096];
797+ } req; /* request */
798+ struct {
799+ ptm_res tpm_result;
800+ } resp; /* response */
801+ } u;
802+};
803+
804+/*
805+ * size of the TPM state blob to transfer; x86_64 can handle 8k,
806+ * ppc64le only ~7k; keep the response below a 4k page size
807+ */
808+#define PTM_STATE_BLOB_SIZE (3 * 1024)
809+
810+/*
811+ * The following is the data structure to get state blobs from the TPM.
812+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple reads
813+ * with this ioctl and with adjusted offset are necessary. All bytes
814+ * must be transferred and the transfer is done once the last byte has been
815+ * returned.
816+ * It is possible to use the read() interface for reading the data; however, the
817+ * first bytes of the state blob will be part of the response to the ioctl(); a
818+ * subsequent read() is only necessary if the total length (totlength) exceeds
819+ * the number of received bytes. seek() is not supported.
820+ */
821+struct ptm_getstate {
822+ union {
823+ struct {
824+ uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */
825+ uint32_t type; /* which blob to pull */
826+ uint32_t offset; /* offset from where to read */
827+ } req; /* request */
828+ struct {
829+ ptm_res tpm_result;
830+ uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */
831+ uint32_t totlength; /* total length that will be transferred */
832+ uint32_t length; /* number of bytes in following buffer */
833+ uint8_t data[PTM_STATE_BLOB_SIZE];
834+ } resp; /* response */
835+ } u;
836+};
837+
838+/* TPM state blob types */
839+#define PTM_BLOB_TYPE_PERMANENT 1
840+#define PTM_BLOB_TYPE_VOLATILE 2
841+#define PTM_BLOB_TYPE_SAVESTATE 3
842+
843+/* state_flags above : */
844+#define PTM_STATE_FLAG_DECRYPTED 1 /* on input: get decrypted state */
845+#define PTM_STATE_FLAG_ENCRYPTED 2 /* on output: state is encrypted */
846+
847+/*
848+ * The following is the data structure to set state blobs in the TPM.
849+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple
850+ * 'writes' using this ioctl are necessary. The last packet is indicated
851+ * by the length being smaller than the PTM_STATE_BLOB_SIZE.
852+ * The very first packet may have a length indicator of '0' enabling
853+ * a write() with all the bytes from a buffer. If the write() interface
854+ * is used, a final ioctl with a non-full buffer must be made to indicate
855+ * that all data were transferred (a write with 0 bytes would not work).
856+ */
857+struct ptm_setstate {
858+ union {
859+ struct {
860+ uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */
861+ uint32_t type; /* which blob to set */
862+ uint32_t length; /* length of the data;
863+ use 0 on the first packet to
864+ transfer using write() */
865+ uint8_t data[PTM_STATE_BLOB_SIZE];
866+ } req; /* request */
867+ struct {
868+ ptm_res tpm_result;
869+ } resp; /* response */
870+ } u;
871+};
872+
873+/*
874+ * PTM_GET_CONFIG: Data structure to get runtime configuration information
875+ * such as which keys are applied.
876+ */
877+struct ptm_getconfig {
878+ union {
879+ struct {
880+ ptm_res tpm_result;
881+ uint32_t flags;
882+ } resp; /* response */
883+ } u;
884+};
885+
886+#define PTM_CONFIG_FLAG_FILE_KEY 0x1
887+#define PTM_CONFIG_FLAG_MIGRATION_KEY 0x2
888+
889+
890+typedef uint64_t ptm_cap;
891+typedef struct ptm_est ptm_est;
892+typedef struct ptm_reset_est ptm_reset_est;
893+typedef struct ptm_loc ptm_loc;
894+typedef struct ptm_hdata ptm_hdata;
895+typedef struct ptm_init ptm_init;
896+typedef struct ptm_getstate ptm_getstate;
897+typedef struct ptm_setstate ptm_setstate;
898+typedef struct ptm_getconfig ptm_getconfig;
899+
900+/* capability flags returned by PTM_GET_CAPABILITY */
901+#define PTM_CAP_INIT (1)
902+#define PTM_CAP_SHUTDOWN (1 << 1)
903+#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)
904+#define PTM_CAP_SET_LOCALITY (1 << 3)
905+#define PTM_CAP_HASHING (1 << 4)
906+#define PTM_CAP_CANCEL_TPM_CMD (1 << 5)
907+#define PTM_CAP_STORE_VOLATILE (1 << 6)
908+#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)
909+#define PTM_CAP_GET_STATEBLOB (1 << 8)
910+#define PTM_CAP_SET_STATEBLOB (1 << 9)
911+#define PTM_CAP_STOP (1 << 10)
912+#define PTM_CAP_GET_CONFIG (1 << 11)
913+#define PTM_CAP_SET_DATAFD (1 << 12)
914+
915+enum {
916+ PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap),
917+ PTM_INIT = _IOWR('P', 1, ptm_init),
918+ PTM_SHUTDOWN = _IOR('P', 2, ptm_res),
919+ PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),
920+ PTM_SET_LOCALITY = _IOWR('P', 4, ptm_loc),
921+ PTM_HASH_START = _IOR('P', 5, ptm_res),
922+ PTM_HASH_DATA = _IOWR('P', 6, ptm_hdata),
923+ PTM_HASH_END = _IOR('P', 7, ptm_res),
924+ PTM_CANCEL_TPM_CMD = _IOR('P', 8, ptm_res),
925+ PTM_STORE_VOLATILE = _IOR('P', 9, ptm_res),
926+ PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),
927+ PTM_GET_STATEBLOB = _IOWR('P', 11, ptm_getstate),
928+ PTM_SET_STATEBLOB = _IOWR('P', 12, ptm_setstate),
929+ PTM_STOP = _IOR('P', 13, ptm_res),
930+ PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig),
931+ PTM_SET_DATAFD = _IOR('P', 15, ptm_res),
932+};
933+
934+/*
935+ * Commands used by the non-CUSE TPMs
936+ *
937+ * All messages container big-endian data.
938+ *
939+ * The return messages only contain the 'resp' part of the unions
940+ * in the data structures above. Besides that the limits in the
941+ * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data
942+ * and ptm_set_state:u.req.data) are 0xffffffff.
943+ */
944+enum {
945+ CMD_GET_CAPABILITY = 1,
946+ CMD_INIT,
947+ CMD_SHUTDOWN,
948+ CMD_GET_TPMESTABLISHED,
949+ CMD_SET_LOCALITY,
950+ CMD_HASH_START,
951+ CMD_HASH_DATA,
952+ CMD_HASH_END,
953+ CMD_CANCEL_TPM_CMD,
954+ CMD_STORE_VOLATILE,
955+ CMD_RESET_TPMESTABLISHED,
956+ CMD_GET_STATEBLOB,
957+ CMD_SET_STATEBLOB,
958+ CMD_STOP,
959+ CMD_GET_CONFIG,
960+ CMD_SET_DATAFD
961+};
962+
963+#endif /* _TPM_IOCTL_H */
964diff --git a/qapi-schema.json b/qapi-schema.json
965index 802ea53d00..78a00bc868 100644
966--- a/qapi-schema.json
967+++ b/qapi-schema.json
968@@ -5314,10 +5314,12 @@
969 # An enumeration of TPM types
970 #
971 # @passthrough: TPM passthrough type
972+# @emulator: Software Emulator TPM type
973+# Since: 2.11
974 #
975 # Since: 1.5
976 ##
977-{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }
978+{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] }
979
980 ##
981 # @query-tpm-types:
982@@ -5352,6 +5354,17 @@
983 '*cancel-path' : 'str'} }
984
985 ##
986+# @TPMEmulatorOptions:
987+#
988+# Information about the TPM emulator type
989+#
990+# @chardev: Name of a unix socket chardev
991+#
992+# Since: 2.11
993+##
994+{ 'struct': 'TPMEmulatorOptions', 'data': { 'chardev' : 'str' } }
995+
996+##
997 # @TpmTypeOptions:
998 #
999 # A union referencing different TPM backend types' configuration options
1000@@ -5361,7 +5374,8 @@
1001 # Since: 1.5
1002 ##
1003 { 'union': 'TpmTypeOptions',
1004- 'data': { 'passthrough' : 'TPMPassthroughOptions' } }
1005+ 'data': { 'passthrough' : 'TPMPassthroughOptions',
1006+ 'emulator': 'TPMEmulatorOptions'} }
1007
1008 ##
1009 # @TPMInfo:
1010diff --git a/qemu-options.hx b/qemu-options.hx
1011index 9f6e2adfff..60eb193c23 100644
1012--- a/qemu-options.hx
1013+++ b/qemu-options.hx
1014@@ -3121,7 +3121,9 @@ DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
1015 "-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n"
1016 " use path to provide path to a character device; default is /dev/tpm0\n"
1017 " use cancel-path to provide path to TPM's cancel sysfs entry; if\n"
1018- " not provided it will be searched for in /sys/class/misc/tpm?/device\n",
1019+ " not provided it will be searched for in /sys/class/misc/tpm?/device\n"
1020+ "-tpmdev emulator,id=id,chardev=dev\n"
1021+ " configure the TPM device using chardev backend\n",
1022 QEMU_ARCH_ALL)
1023 STEXI
1024
1025@@ -3130,8 +3132,8 @@ The general form of a TPM device option is:
1026
1027 @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]
1028 @findex -tpmdev
1029-Backend type must be:
1030-@option{passthrough}.
1031+Backend type must be either one of the following:
1032+@option{passthrough}, @option{emulator}.
1033
1034 The specific backend type will determine the applicable options.
1035 The @code{-tpmdev} option creates the TPM backend and requires a
1036@@ -3181,6 +3183,20 @@ To create a passthrough TPM use the following two options:
1037 Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
1038 @code{tpmdev=tpm0} in the device option.
1039
1040+@item -tpmdev emulator, id=@var{id}, chardev=@var{dev}
1041+
1042+(Linux-host only) Enable access to a TPM emulator using Unix domain socket based
1043+chardev backend.
1044+
1045+@option{chardev} specifies the unique ID of a character device backend that provides connection to the software TPM server.
1046+
1047+To create a TPM emulator backend device with chardev socket backend:
1048+@example
1049+
1050+-chardev socket,id=chrtpm,path=/tmp/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0
1051+
1052+@end example
1053+
1054 @end table
1055
1056 ETEXI
1057--
10582.11.0
1059