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