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