1 /* 2 * QTest testcase for TPM CRB 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/acpi/tpm.h" 17 #include "io/channel-socket.h" 18 #include "libqtest-single.h" 19 #include "qemu/module.h" 20 #include "tpm-emu.h" 21 22 /* Not used but needed for linking */ 23 uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; 24 25 #define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00" 26 27 static void tpm_crb_test(const void *data) 28 { 29 const TestState *s = data; 30 uint32_t intfid = readl(TPM_CRB_ADDR_BASE + A_CRB_INTF_ID); 31 uint32_t csize = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_SIZE); 32 uint64_t caddr = readq(TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR); 33 uint32_t rsize = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_SIZE); 34 uint64_t raddr = readq(TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR); 35 uint8_t locstate = readb(TPM_CRB_ADDR_BASE + A_CRB_LOC_STATE); 36 uint32_t locctrl = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL); 37 uint32_t locsts = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_STS); 38 uint32_t sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS); 39 40 g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceType), ==, 1); 41 g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceVersion), ==, 1); 42 g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapLocality), ==, 0); 43 g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapCRBIdleBypass), ==, 0); 44 g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapDataXferSizeSupport), 45 ==, 3); 46 g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapFIFO), ==, 0); 47 g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapCRB), ==, 1); 48 g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceSelector), ==, 1); 49 g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, RID), ==, 0); 50 51 g_assert_cmpint(csize, >=, 128); 52 g_assert_cmpint(rsize, >=, 128); 53 g_assert_cmpint(caddr, >, TPM_CRB_ADDR_BASE); 54 g_assert_cmpint(raddr, >, TPM_CRB_ADDR_BASE); 55 56 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmEstablished), ==, 1); 57 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, locAssigned), ==, 0); 58 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, activeLocality), ==, 0); 59 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, reserved), ==, 0); 60 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmRegValidSts), ==, 1); 61 62 g_assert_cmpint(locctrl, ==, 0); 63 64 g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, Granted), ==, 0); 65 g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, beenSeized), ==, 0); 66 67 g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 1); 68 g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0); 69 70 /* request access to locality 0 */ 71 writeb(TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1); 72 73 /* granted bit must be set now */ 74 locsts = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_STS); 75 g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, Granted), ==, 1); 76 g_assert_cmpint(FIELD_EX32(locsts, CRB_LOC_STS, beenSeized), ==, 0); 77 78 /* we must have an assigned locality */ 79 locstate = readb(TPM_CRB_ADDR_BASE + A_CRB_LOC_STATE); 80 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmEstablished), ==, 1); 81 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, locAssigned), ==, 1); 82 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, activeLocality), ==, 0); 83 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, reserved), ==, 0); 84 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmRegValidSts), ==, 1); 85 86 /* set into ready state */ 87 writel(TPM_CRB_ADDR_BASE + A_CRB_CTRL_REQ, 1); 88 89 /* TPM must not be in the idle state */ 90 sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS); 91 g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 0); 92 g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0); 93 94 memwrite(caddr, TPM_CMD, sizeof(TPM_CMD)); 95 96 uint32_t start = 1; 97 uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; 98 writel(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start); 99 do { 100 start = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START); 101 if ((start & 1) == 0) { 102 break; 103 } 104 } while (g_get_monotonic_time() < end_time); 105 start = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START); 106 g_assert_cmpint(start & 1, ==, 0); 107 108 /* TPM must still not be in the idle state */ 109 sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS); 110 g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 0); 111 g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0); 112 113 struct tpm_hdr tpm_msg; 114 memread(raddr, &tpm_msg, sizeof(tpm_msg)); 115 g_assert_cmpmem(&tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); 116 117 /* set TPM into idle state */ 118 writel(TPM_CRB_ADDR_BASE + A_CRB_CTRL_REQ, 2); 119 120 /* idle state must be indicated now */ 121 sts = readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS); 122 g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmIdle), ==, 1); 123 g_assert_cmpint(FIELD_EX32(sts, CRB_CTRL_STS, tpmSts), ==, 0); 124 125 /* relinquish locality */ 126 writel(TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 2); 127 128 /* Granted flag must be cleared */ 129 sts = readl(TPM_CRB_ADDR_BASE + A_CRB_LOC_STS); 130 g_assert_cmpint(FIELD_EX32(sts, CRB_LOC_STS, Granted), ==, 0); 131 g_assert_cmpint(FIELD_EX32(sts, CRB_LOC_STS, beenSeized), ==, 0); 132 133 /* no locality may be assigned */ 134 locstate = readb(TPM_CRB_ADDR_BASE + A_CRB_LOC_STATE); 135 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmEstablished), ==, 1); 136 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, locAssigned), ==, 0); 137 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, activeLocality), ==, 0); 138 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, reserved), ==, 0); 139 g_assert_cmpint(FIELD_EX32(locstate, CRB_LOC_STATE, tpmRegValidSts), ==, 1); 140 141 } 142 143 int main(int argc, char **argv) 144 { 145 int ret; 146 char *args, *tmp_path = g_dir_make_tmp("qemu-tpm-crb-test.XXXXXX", NULL); 147 GThread *thread; 148 TestState test; 149 150 module_call_init(MODULE_INIT_QOM); 151 g_test_init(&argc, &argv, NULL); 152 153 test.addr = g_new0(SocketAddress, 1); 154 test.addr->type = SOCKET_ADDRESS_TYPE_UNIX; 155 test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL); 156 g_mutex_init(&test.data_mutex); 157 g_cond_init(&test.data_cond); 158 test.data_cond_signal = false; 159 160 thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test); 161 tpm_emu_test_wait_cond(&test); 162 163 args = g_strdup_printf( 164 "-chardev socket,id=chr,path=%s " 165 "-tpmdev emulator,id=dev,chardev=chr " 166 "-device tpm-crb,tpmdev=dev", 167 test.addr->u.q_unix.path); 168 qtest_start(args); 169 170 qtest_add_data_func("/tpm-crb/test", &test, tpm_crb_test); 171 ret = g_test_run(); 172 173 qtest_end(); 174 175 g_thread_join(thread); 176 g_unlink(test.addr->u.q_unix.path); 177 qapi_free_SocketAddress(test.addr); 178 g_rmdir(tmp_path); 179 g_free(tmp_path); 180 g_free(args); 181 return ret; 182 } 183