4 * Copyright (c) 2018 IBM Corporation
5 * Copyright (c) 2018 Red Hat, Inc.
8 * Stefan Berger <stefanb@linux.vnet.ibm.com>
9 * Marc-André Lureau <marcandre.lureau@redhat.com>
11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
12 * See the COPYING file in the top-level directory.
15 #include "qemu/osdep.h"
17 #include "hw/acpi/tpm.h"
20 #include "qapi/qmp/qdict.h"
22 #define TIS_REG(LOCTY, REG) \
23 (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
27 void tpm_util_crb_transfer(QTestState *s,
28 const unsigned char *req, size_t req_size,
29 unsigned char *rsp, size_t rsp_size)
31 uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
32 uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
34 qtest_writeb(s, TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
36 qtest_memwrite(s, caddr, req, req_size);
38 uint32_t sts, start = 1;
39 uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
40 qtest_writel(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
42 start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
43 if ((start & 1) == 0) {
46 if (g_get_monotonic_time() >= end_time) {
50 start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
51 g_assert_cmpint(start & 1, ==, 0);
52 sts = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
53 g_assert_cmpint(sts & 1, ==, 0);
55 qtest_memread(s, raddr, rsp, rsp_size);
58 void tpm_util_tis_transfer(QTestState *s,
59 const unsigned char *req, size_t req_size,
60 unsigned char *rsp, size_t rsp_size)
66 /* request use of locality 0 */
67 qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
68 qtest_writel(s, TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY);
70 sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
71 bcount = (sts >> 8) & 0xffff;
72 g_assert_cmpint(bcount, >=, req_size);
74 /* transmit command */
75 for (i = 0; i < req_size; i++) {
76 qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_DATA_FIFO), req[i]);
79 /* start processing */
80 qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO);
82 uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
84 sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
85 if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
88 } while (g_get_monotonic_time() < end_time);
90 sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
91 bcount = (sts >> 8) & 0xffff;
93 memset(rsp, 0, rsp_size);
94 for (i = 0; i < bcount; i++) {
95 rsp[i] = qtest_readb(s, TIS_REG(0, TPM_TIS_REG_DATA_FIFO));
98 /* relinquish use of locality 0 */
99 qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_ACCESS),
100 TPM_TIS_ACCESS_ACTIVE_LOCALITY);
103 void tpm_util_startup(QTestState *s, tx_func *tx)
105 unsigned char buffer[1024];
106 unsigned char tpm_startup[] =
107 "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
108 unsigned char tpm_startup_resp[] =
109 "\x80\x01\x00\x00\x00\x0a\x00\x00\x00\x00";
111 tx(s, tpm_startup, sizeof(tpm_startup), buffer, sizeof(buffer));
113 g_assert_cmpmem(buffer, sizeof(tpm_startup_resp),
114 tpm_startup_resp, sizeof(tpm_startup_resp));
117 void tpm_util_pcrextend(QTestState *s, tx_func *tx)
119 unsigned char buffer[1024];
120 unsigned char tpm_pcrextend[] =
121 "\x80\x02\x00\x00\x00\x41\x00\x00\x01\x82\x00\x00\x00\x0a\x00\x00"
122 "\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00"
123 "\x0b\x74\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
124 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
127 unsigned char tpm_pcrextend_resp[] =
128 "\x80\x02\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
131 tx(s, tpm_pcrextend, sizeof(tpm_pcrextend), buffer, sizeof(buffer));
133 g_assert_cmpmem(buffer, sizeof(tpm_pcrextend_resp),
134 tpm_pcrextend_resp, sizeof(tpm_pcrextend_resp));
137 void tpm_util_pcrread(QTestState *s, tx_func *tx,
138 const unsigned char *exp_resp, size_t exp_resp_size)
140 unsigned char buffer[1024];
141 unsigned char tpm_pcrread[] =
142 "\x80\x01\x00\x00\x00\x14\x00\x00\x01\x7e\x00\x00\x00\x01\x00\x0b"
145 tx(s, tpm_pcrread, sizeof(tpm_pcrread), buffer, sizeof(buffer));
147 g_assert_cmpmem(buffer, exp_resp_size, exp_resp, exp_resp_size);
150 static gboolean tpm_util_swtpm_has_tpm2(void)
157 gchar *swtpm_argv[] = {
158 g_strdup("swtpm"), g_strdup("socket"), g_strdup("--help"), NULL
161 succ = g_spawn_async_with_pipes(NULL, swtpm_argv, NULL,
162 G_SPAWN_SEARCH_PATH, NULL, NULL, NULL,
163 NULL, &mystdout, NULL, NULL);
168 n = read(mystdout, buffer, sizeof(buffer) - 1);
173 if (!strstr(buffer, "--tpm2")) {
178 for (i = 0; swtpm_argv[i]; i++) {
179 g_free(swtpm_argv[i]);
185 gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
186 SocketAddress **addr, GError **error)
188 char *swtpm_argv_tpmstate = g_strdup_printf("dir=%s", path);
189 char *swtpm_argv_ctrl = g_strdup_printf("type=unixio,path=%s/sock",
191 gchar *swtpm_argv[] = {
192 g_strdup("swtpm"), g_strdup("socket"),
193 g_strdup("--tpmstate"), swtpm_argv_tpmstate,
194 g_strdup("--ctrl"), swtpm_argv_ctrl,
201 succ = tpm_util_swtpm_has_tpm2();
206 *addr = g_new0(SocketAddress, 1);
207 (*addr)->type = SOCKET_ADDRESS_TYPE_UNIX;
208 (*addr)->u.q_unix.path = g_build_filename(path, "sock", NULL);
210 succ = g_spawn_async(NULL, swtpm_argv, NULL, G_SPAWN_SEARCH_PATH,
211 NULL, NULL, pid, error);
214 for (i = 0; swtpm_argv[i]; i++) {
215 g_free(swtpm_argv[i]);
221 void tpm_util_swtpm_kill(GPid pid)
229 g_spawn_close_pid(pid);
239 void tpm_util_migrate(QTestState *who, const char *uri)
244 cmd = g_strdup_printf("{ 'execute': 'migrate',"
245 "'arguments': { 'uri': '%s' } }",
247 rsp = qtest_qmp(who, cmd);
249 g_assert(qdict_haskey(rsp, "return"));
254 * Events can get in the way of responses we are actually waiting for.
256 static QDict *tpm_util_wait_command(QTestState *who, const char *command)
258 const char *event_string;
261 response = qtest_qmp(who, command);
263 while (qdict_haskey(response, "event")) {
264 /* OK, it was an event */
265 event_string = qdict_get_str(response, "event");
266 if (!strcmp(event_string, "STOP")) {
269 qobject_unref(response);
270 response = qtest_qmp_receive(who);
275 void tpm_util_wait_for_migration_complete(QTestState *who)
278 QDict *rsp, *rsp_return;
282 rsp = tpm_util_wait_command(who, "{ 'execute': 'query-migrate' }");
283 rsp_return = qdict_get_qdict(rsp, "return");
284 status = qdict_get_str(rsp_return, "status");
285 completed = strcmp(status, "completed") == 0;
286 g_assert_cmpstr(status, !=, "failed");
295 void tpm_util_migration_start_qemu(QTestState **src_qemu,
296 QTestState **dst_qemu,
297 SocketAddress *src_tpm_addr,
298 SocketAddress *dst_tpm_addr,
302 char *src_qemu_args, *dst_qemu_args;
304 src_qemu_args = g_strdup_printf(
305 "-chardev socket,id=chr,path=%s "
306 "-tpmdev emulator,id=dev,chardev=chr "
307 "-device %s,tpmdev=dev ",
308 src_tpm_addr->u.q_unix.path, ifmodel);
310 *src_qemu = qtest_init(src_qemu_args);
312 dst_qemu_args = g_strdup_printf(
313 "-chardev socket,id=chr,path=%s "
314 "-tpmdev emulator,id=dev,chardev=chr "
315 "-device %s,tpmdev=dev "
317 dst_tpm_addr->u.q_unix.path,
320 *dst_qemu = qtest_init(dst_qemu_args);