qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

tests: Move common TPM test code into tpm-emu.c

Move threads and other common TPM test code into tpm-emu.c.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

+209 -172
+1 -1
tests/Makefile.include
··· 714 714 tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y) 715 715 tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \ 716 716 tests/io-channel-helpers.o $(test-io-obj-y) 717 - tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o $(test-io-obj-y) 717 + tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y) 718 718 tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ 719 719 tests/io-channel-helpers.o $(test-io-obj-y) 720 720 tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \
+3 -171
tests/tpm-crb-test.c
··· 14 14 #include <glib/gstdio.h> 15 15 16 16 #include "hw/acpi/tpm.h" 17 - #include "hw/tpm/tpm_ioctl.h" 18 17 #include "io/channel-socket.h" 19 18 #include "libqtest.h" 20 - #include "qapi/error.h" 21 - 22 - #define TPM_RC_FAILURE 0x101 23 - #define TPM2_ST_NO_SESSIONS 0x8001 24 - 25 - struct tpm_hdr { 26 - uint16_t tag; 27 - uint32_t len; 28 - uint32_t code; /*ordinal/error */ 29 - char buffer[]; 30 - } QEMU_PACKED; 31 - 32 - typedef struct TestState { 33 - CompatGMutex data_mutex; 34 - CompatGCond data_cond; 35 - SocketAddress *addr; 36 - QIOChannel *tpm_ioc; 37 - GThread *emu_tpm_thread; 38 - struct tpm_hdr *tpm_msg; 39 - } TestState; 40 - 41 - static void test_wait_cond(TestState *s) 42 - { 43 - gint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; 44 - 45 - g_mutex_lock(&s->data_mutex); 46 - if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) { 47 - g_assert_not_reached(); 48 - } 49 - g_mutex_unlock(&s->data_mutex); 50 - } 51 - 52 - static void *emu_tpm_thread(void *data) 53 - { 54 - TestState *s = data; 55 - QIOChannel *ioc = s->tpm_ioc; 56 - 57 - s->tpm_msg = g_new(struct tpm_hdr, 1); 58 - while (true) { 59 - int minhlen = sizeof(s->tpm_msg->tag) + sizeof(s->tpm_msg->len); 60 - 61 - if (!qio_channel_read(ioc, (char *)s->tpm_msg, minhlen, &error_abort)) { 62 - break; 63 - } 64 - s->tpm_msg->tag = be16_to_cpu(s->tpm_msg->tag); 65 - s->tpm_msg->len = be32_to_cpu(s->tpm_msg->len); 66 - g_assert_cmpint(s->tpm_msg->len, >=, minhlen); 67 - g_assert_cmpint(s->tpm_msg->tag, ==, TPM2_ST_NO_SESSIONS); 68 - 69 - s->tpm_msg = g_realloc(s->tpm_msg, s->tpm_msg->len); 70 - qio_channel_read(ioc, (char *)&s->tpm_msg->code, 71 - s->tpm_msg->len - minhlen, &error_abort); 72 - s->tpm_msg->code = be32_to_cpu(s->tpm_msg->code); 73 - 74 - /* reply error */ 75 - s->tpm_msg->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); 76 - s->tpm_msg->len = cpu_to_be32(sizeof(struct tpm_hdr)); 77 - s->tpm_msg->code = cpu_to_be32(TPM_RC_FAILURE); 78 - qio_channel_write(ioc, (char *)s->tpm_msg, be32_to_cpu(s->tpm_msg->len), 79 - &error_abort); 80 - } 81 - 82 - g_free(s->tpm_msg); 83 - s->tpm_msg = NULL; 84 - object_unref(OBJECT(s->tpm_ioc)); 85 - return NULL; 86 - } 87 - 88 - static void *emu_ctrl_thread(void *data) 89 - { 90 - TestState *s = data; 91 - QIOChannelSocket *lioc = qio_channel_socket_new(); 92 - QIOChannel *ioc; 93 - 94 - qio_channel_socket_listen_sync(lioc, s->addr, &error_abort); 95 - g_cond_signal(&s->data_cond); 96 - 97 - qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); 98 - ioc = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); 99 - g_assert(ioc); 100 - 101 - { 102 - uint32_t cmd = 0; 103 - struct iovec iov = { .iov_base = &cmd, .iov_len = sizeof(cmd) }; 104 - int *pfd = NULL; 105 - size_t nfd = 0; 106 - 107 - qio_channel_readv_full(ioc, &iov, 1, &pfd, &nfd, &error_abort); 108 - cmd = be32_to_cpu(cmd); 109 - g_assert_cmpint(cmd, ==, CMD_SET_DATAFD); 110 - g_assert_cmpint(nfd, ==, 1); 111 - s->tpm_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(*pfd, &error_abort)); 112 - g_free(pfd); 113 - 114 - cmd = 0; 115 - qio_channel_write(ioc, (char *)&cmd, sizeof(cmd), &error_abort); 116 - 117 - s->emu_tpm_thread = g_thread_new(NULL, emu_tpm_thread, s); 118 - } 119 - 120 - while (true) { 121 - uint32_t cmd; 122 - ssize_t ret; 123 - 124 - ret = qio_channel_read(ioc, (char *)&cmd, sizeof(cmd), NULL); 125 - if (ret <= 0) { 126 - break; 127 - } 128 - 129 - cmd = be32_to_cpu(cmd); 130 - switch (cmd) { 131 - case CMD_GET_CAPABILITY: { 132 - ptm_cap cap = cpu_to_be64(0x3fff); 133 - qio_channel_write(ioc, (char *)&cap, sizeof(cap), &error_abort); 134 - break; 135 - } 136 - case CMD_INIT: { 137 - ptm_init init; 138 - qio_channel_read(ioc, (char *)&init.u.req, sizeof(init.u.req), 139 - &error_abort); 140 - init.u.resp.tpm_result = 0; 141 - qio_channel_write(ioc, (char *)&init.u.resp, sizeof(init.u.resp), 142 - &error_abort); 143 - break; 144 - } 145 - case CMD_SHUTDOWN: { 146 - ptm_res res = 0; 147 - qio_channel_write(ioc, (char *)&res, sizeof(res), &error_abort); 148 - qio_channel_close(s->tpm_ioc, &error_abort); 149 - g_thread_join(s->emu_tpm_thread); 150 - break; 151 - } 152 - case CMD_STOP: { 153 - ptm_res res = 0; 154 - qio_channel_write(ioc, (char *)&res, sizeof(res), &error_abort); 155 - break; 156 - } 157 - case CMD_SET_BUFFERSIZE: { 158 - ptm_setbuffersize sbs; 159 - qio_channel_read(ioc, (char *)&sbs.u.req, sizeof(sbs.u.req), 160 - &error_abort); 161 - sbs.u.resp.buffersize = sbs.u.req.buffersize ?: cpu_to_be32(4096); 162 - sbs.u.resp.tpm_result = 0; 163 - sbs.u.resp.minsize = cpu_to_be32(128); 164 - sbs.u.resp.maxsize = cpu_to_be32(4096); 165 - qio_channel_write(ioc, (char *)&sbs.u.resp, sizeof(sbs.u.resp), 166 - &error_abort); 167 - break; 168 - } 169 - case CMD_SET_LOCALITY: { 170 - ptm_loc loc; 171 - /* Note: this time it's not u.req / u.resp... */ 172 - qio_channel_read(ioc, (char *)&loc, sizeof(loc), &error_abort); 173 - g_assert_cmpint(loc.u.req.loc, ==, 0); 174 - loc.u.resp.tpm_result = 0; 175 - qio_channel_write(ioc, (char *)&loc, sizeof(loc), &error_abort); 176 - break; 177 - } 178 - default: 179 - g_debug("unimplemented %u", cmd); 180 - g_assert_not_reached(); 181 - } 182 - } 183 - 184 - object_unref(OBJECT(ioc)); 185 - object_unref(OBJECT(lioc)); 186 - return NULL; 187 - } 19 + #include "tpm-emu.h" 188 20 189 21 #define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00" 190 22 ··· 250 82 g_mutex_init(&test.data_mutex); 251 83 g_cond_init(&test.data_cond); 252 84 253 - thread = g_thread_new(NULL, emu_ctrl_thread, &test); 254 - test_wait_cond(&test); 85 + thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test); 86 + tpm_emu_test_wait_cond(&test); 255 87 256 88 args = g_strdup_printf( 257 89 "-chardev socket,id=chr,path=%s "
+167
tests/tpm-emu.c
··· 1 + /* 2 + * Minimal TPM emulator for TPM test cases 3 + * 4 + * Copyright (c) 2018 Red Hat, Inc. 5 + * 6 + * Authors: 7 + * Marc-André Lureau <marcandre.lureau@redhat.com> 8 + * 9 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 + * See the COPYING file in the top-level directory. 11 + */ 12 + 13 + #include "qemu/osdep.h" 14 + #include <glib/gstdio.h> 15 + 16 + #include "hw/tpm/tpm_ioctl.h" 17 + #include "io/channel-socket.h" 18 + #include "qapi/error.h" 19 + #include "tpm-emu.h" 20 + 21 + void tpm_emu_test_wait_cond(TestState *s) 22 + { 23 + gint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; 24 + 25 + g_mutex_lock(&s->data_mutex); 26 + if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) { 27 + g_assert_not_reached(); 28 + } 29 + g_mutex_unlock(&s->data_mutex); 30 + } 31 + 32 + static void *tpm_emu_tpm_thread(void *data) 33 + { 34 + TestState *s = data; 35 + QIOChannel *ioc = s->tpm_ioc; 36 + 37 + s->tpm_msg = g_new(struct tpm_hdr, 1); 38 + while (true) { 39 + int minhlen = sizeof(s->tpm_msg->tag) + sizeof(s->tpm_msg->len); 40 + 41 + if (!qio_channel_read(ioc, (char *)s->tpm_msg, minhlen, &error_abort)) { 42 + break; 43 + } 44 + s->tpm_msg->tag = be16_to_cpu(s->tpm_msg->tag); 45 + s->tpm_msg->len = be32_to_cpu(s->tpm_msg->len); 46 + g_assert_cmpint(s->tpm_msg->len, >=, minhlen); 47 + g_assert_cmpint(s->tpm_msg->tag, ==, TPM2_ST_NO_SESSIONS); 48 + 49 + s->tpm_msg = g_realloc(s->tpm_msg, s->tpm_msg->len); 50 + qio_channel_read(ioc, (char *)&s->tpm_msg->code, 51 + s->tpm_msg->len - minhlen, &error_abort); 52 + s->tpm_msg->code = be32_to_cpu(s->tpm_msg->code); 53 + 54 + /* reply error */ 55 + s->tpm_msg->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); 56 + s->tpm_msg->len = cpu_to_be32(sizeof(struct tpm_hdr)); 57 + s->tpm_msg->code = cpu_to_be32(TPM_RC_FAILURE); 58 + qio_channel_write(ioc, (char *)s->tpm_msg, be32_to_cpu(s->tpm_msg->len), 59 + &error_abort); 60 + } 61 + 62 + g_free(s->tpm_msg); 63 + s->tpm_msg = NULL; 64 + object_unref(OBJECT(s->tpm_ioc)); 65 + return NULL; 66 + } 67 + 68 + void *tpm_emu_ctrl_thread(void *data) 69 + { 70 + TestState *s = data; 71 + QIOChannelSocket *lioc = qio_channel_socket_new(); 72 + QIOChannel *ioc; 73 + 74 + qio_channel_socket_listen_sync(lioc, s->addr, &error_abort); 75 + g_cond_signal(&s->data_cond); 76 + 77 + qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); 78 + ioc = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); 79 + g_assert(ioc); 80 + 81 + { 82 + uint32_t cmd = 0; 83 + struct iovec iov = { .iov_base = &cmd, .iov_len = sizeof(cmd) }; 84 + int *pfd = NULL; 85 + size_t nfd = 0; 86 + 87 + qio_channel_readv_full(ioc, &iov, 1, &pfd, &nfd, &error_abort); 88 + cmd = be32_to_cpu(cmd); 89 + g_assert_cmpint(cmd, ==, CMD_SET_DATAFD); 90 + g_assert_cmpint(nfd, ==, 1); 91 + s->tpm_ioc = QIO_CHANNEL(qio_channel_socket_new_fd(*pfd, &error_abort)); 92 + g_free(pfd); 93 + 94 + cmd = 0; 95 + qio_channel_write(ioc, (char *)&cmd, sizeof(cmd), &error_abort); 96 + 97 + s->emu_tpm_thread = g_thread_new(NULL, tpm_emu_tpm_thread, s); 98 + } 99 + 100 + while (true) { 101 + uint32_t cmd; 102 + ssize_t ret; 103 + 104 + ret = qio_channel_read(ioc, (char *)&cmd, sizeof(cmd), NULL); 105 + if (ret <= 0) { 106 + break; 107 + } 108 + 109 + cmd = be32_to_cpu(cmd); 110 + switch (cmd) { 111 + case CMD_GET_CAPABILITY: { 112 + ptm_cap cap = cpu_to_be64(0x3fff); 113 + qio_channel_write(ioc, (char *)&cap, sizeof(cap), &error_abort); 114 + break; 115 + } 116 + case CMD_INIT: { 117 + ptm_init init; 118 + qio_channel_read(ioc, (char *)&init.u.req, sizeof(init.u.req), 119 + &error_abort); 120 + init.u.resp.tpm_result = 0; 121 + qio_channel_write(ioc, (char *)&init.u.resp, sizeof(init.u.resp), 122 + &error_abort); 123 + break; 124 + } 125 + case CMD_SHUTDOWN: { 126 + ptm_res res = 0; 127 + qio_channel_write(ioc, (char *)&res, sizeof(res), &error_abort); 128 + qio_channel_close(s->tpm_ioc, &error_abort); 129 + g_thread_join(s->emu_tpm_thread); 130 + break; 131 + } 132 + case CMD_STOP: { 133 + ptm_res res = 0; 134 + qio_channel_write(ioc, (char *)&res, sizeof(res), &error_abort); 135 + break; 136 + } 137 + case CMD_SET_BUFFERSIZE: { 138 + ptm_setbuffersize sbs; 139 + qio_channel_read(ioc, (char *)&sbs.u.req, sizeof(sbs.u.req), 140 + &error_abort); 141 + sbs.u.resp.buffersize = sbs.u.req.buffersize ?: cpu_to_be32(4096); 142 + sbs.u.resp.tpm_result = 0; 143 + sbs.u.resp.minsize = cpu_to_be32(128); 144 + sbs.u.resp.maxsize = cpu_to_be32(4096); 145 + qio_channel_write(ioc, (char *)&sbs.u.resp, sizeof(sbs.u.resp), 146 + &error_abort); 147 + break; 148 + } 149 + case CMD_SET_LOCALITY: { 150 + ptm_loc loc; 151 + /* Note: this time it's not u.req / u.resp... */ 152 + qio_channel_read(ioc, (char *)&loc, sizeof(loc), &error_abort); 153 + g_assert_cmpint(loc.u.req.loc, ==, 0); 154 + loc.u.resp.tpm_result = 0; 155 + qio_channel_write(ioc, (char *)&loc, sizeof(loc), &error_abort); 156 + break; 157 + } 158 + default: 159 + g_debug("unimplemented %u", cmd); 160 + g_assert_not_reached(); 161 + } 162 + } 163 + 164 + object_unref(OBJECT(ioc)); 165 + object_unref(OBJECT(lioc)); 166 + return NULL; 167 + }
+38
tests/tpm-emu.h
··· 1 + /* 2 + * Minimal TPM emulator for TPM test cases 3 + * 4 + * Copyright (c) 2018 Red Hat, Inc. 5 + * 6 + * Authors: 7 + * Marc-André Lureau <marcandre.lureau@redhat.com> 8 + * 9 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 + * See the COPYING file in the top-level directory. 11 + */ 12 + 13 + #ifndef TESTS_TPM_EMU_H 14 + #define TESTS_TPM_EMU_H 15 + 16 + #define TPM_RC_FAILURE 0x101 17 + #define TPM2_ST_NO_SESSIONS 0x8001 18 + 19 + struct tpm_hdr { 20 + uint16_t tag; 21 + uint32_t len; 22 + uint32_t code; /*ordinal/error */ 23 + char buffer[]; 24 + } QEMU_PACKED; 25 + 26 + typedef struct TestState { 27 + CompatGMutex data_mutex; 28 + CompatGCond data_cond; 29 + SocketAddress *addr; 30 + QIOChannel *tpm_ioc; 31 + GThread *emu_tpm_thread; 32 + struct tpm_hdr *tpm_msg; 33 + } TestState; 34 + 35 + void tpm_emu_test_wait_cond(TestState *s); 36 + void *tpm_emu_ctrl_thread(void *data); 37 + 38 + #endif /* TEST_TPM_EMU_H */