xref: /qemu/tests/qtest/tpm-tis-test.c (revision adb0e917e6ee93631e40265ca145bc31cd3b6c9a)
1*adb0e917SStefan Berger /*
2*adb0e917SStefan Berger  * QTest testcase for TPM TIS
3*adb0e917SStefan Berger  *
4*adb0e917SStefan Berger  * Copyright (c) 2018 Red Hat, Inc.
5*adb0e917SStefan Berger  * Copyright (c) 2018 IBM Corporation
6*adb0e917SStefan Berger  *
7*adb0e917SStefan Berger  * Authors:
8*adb0e917SStefan Berger  *   Marc-André Lureau <marcandre.lureau@redhat.com>
9*adb0e917SStefan Berger  *   Stefan Berger <stefanb@linux.vnet.ibm.com>
10*adb0e917SStefan Berger  *
11*adb0e917SStefan Berger  * This work is licensed under the terms of the GNU GPL, version 2 or later.
12*adb0e917SStefan Berger  * See the COPYING file in the top-level directory.
13*adb0e917SStefan Berger  */
14*adb0e917SStefan Berger 
15*adb0e917SStefan Berger #include "qemu/osdep.h"
16*adb0e917SStefan Berger #include <glib/gstdio.h>
17*adb0e917SStefan Berger 
18*adb0e917SStefan Berger #include "hw/acpi/tpm.h"
19*adb0e917SStefan Berger #include "io/channel-socket.h"
20*adb0e917SStefan Berger #include "libqtest.h"
21*adb0e917SStefan Berger #include "tpm-emu.h"
22*adb0e917SStefan Berger 
23*adb0e917SStefan Berger #define TIS_REG(LOCTY, REG) \
24*adb0e917SStefan Berger     (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
25*adb0e917SStefan Berger 
26*adb0e917SStefan Berger #define DEBUG_TIS_TEST 0
27*adb0e917SStefan Berger 
28*adb0e917SStefan Berger #define DPRINTF(fmt, ...) do { \
29*adb0e917SStefan Berger     if (DEBUG_TIS_TEST) { \
30*adb0e917SStefan Berger         printf(fmt, ## __VA_ARGS__); \
31*adb0e917SStefan Berger     } \
32*adb0e917SStefan Berger } while (0)
33*adb0e917SStefan Berger 
34*adb0e917SStefan Berger #define DPRINTF_ACCESS \
35*adb0e917SStefan Berger     DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \
36*adb0e917SStefan Berger             __func__, __LINE__, locty, l, access, pending_request_flag)
37*adb0e917SStefan Berger 
38*adb0e917SStefan Berger #define DPRINTF_STS \
39*adb0e917SStefan Berger     DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts)
40*adb0e917SStefan Berger 
41*adb0e917SStefan Berger static const uint8_t TPM_CMD[12] =
42*adb0e917SStefan Berger     "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
43*adb0e917SStefan Berger 
44*adb0e917SStefan Berger static void tpm_tis_test_check_localities(const void *data)
45*adb0e917SStefan Berger {
46*adb0e917SStefan Berger     uint8_t locty;
47*adb0e917SStefan Berger     uint8_t access;
48*adb0e917SStefan Berger     uint32_t ifaceid;
49*adb0e917SStefan Berger     uint32_t capability;
50*adb0e917SStefan Berger     uint32_t didvid;
51*adb0e917SStefan Berger     uint32_t rid;
52*adb0e917SStefan Berger 
53*adb0e917SStefan Berger     for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) {
54*adb0e917SStefan Berger         access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
55*adb0e917SStefan Berger         g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
56*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
57*adb0e917SStefan Berger 
58*adb0e917SStefan Berger         capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY));
59*adb0e917SStefan Berger         g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0);
60*adb0e917SStefan Berger 
61*adb0e917SStefan Berger         ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID));
62*adb0e917SStefan Berger         g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0);
63*adb0e917SStefan Berger 
64*adb0e917SStefan Berger         didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID));
65*adb0e917SStefan Berger         g_assert_cmpint(didvid, !=, 0);
66*adb0e917SStefan Berger         g_assert_cmpint(didvid, !=, 0xffffffff);
67*adb0e917SStefan Berger 
68*adb0e917SStefan Berger         rid = readl(TIS_REG(locty, TPM_TIS_REG_RID));
69*adb0e917SStefan Berger         g_assert_cmpint(rid, !=, 0);
70*adb0e917SStefan Berger         g_assert_cmpint(rid, !=, 0xffffffff);
71*adb0e917SStefan Berger     }
72*adb0e917SStefan Berger }
73*adb0e917SStefan Berger 
74*adb0e917SStefan Berger static void tpm_tis_test_check_access_reg(const void *data)
75*adb0e917SStefan Berger {
76*adb0e917SStefan Berger     uint8_t locty;
77*adb0e917SStefan Berger     uint8_t access;
78*adb0e917SStefan Berger 
79*adb0e917SStefan Berger     /* do not test locality 4 (hw only) */
80*adb0e917SStefan Berger     for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
81*adb0e917SStefan Berger         access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
82*adb0e917SStefan Berger         g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
83*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
84*adb0e917SStefan Berger 
85*adb0e917SStefan Berger         /* request use of locality */
86*adb0e917SStefan Berger         writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
87*adb0e917SStefan Berger 
88*adb0e917SStefan Berger         access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
89*adb0e917SStefan Berger         g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
90*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_ACTIVE_LOCALITY |
91*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
92*adb0e917SStefan Berger 
93*adb0e917SStefan Berger         /* release access */
94*adb0e917SStefan Berger         writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS),
95*adb0e917SStefan Berger                TPM_TIS_ACCESS_ACTIVE_LOCALITY);
96*adb0e917SStefan Berger         access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
97*adb0e917SStefan Berger         g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
98*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
99*adb0e917SStefan Berger     }
100*adb0e917SStefan Berger }
101*adb0e917SStefan Berger 
102*adb0e917SStefan Berger /*
103*adb0e917SStefan Berger  * Test case for seizing access by a higher number locality
104*adb0e917SStefan Berger  */
105*adb0e917SStefan Berger static void tpm_tis_test_check_access_reg_seize(const void *data)
106*adb0e917SStefan Berger {
107*adb0e917SStefan Berger     int locty, l;
108*adb0e917SStefan Berger     uint8_t access;
109*adb0e917SStefan Berger     uint8_t pending_request_flag;
110*adb0e917SStefan Berger 
111*adb0e917SStefan Berger     /* do not test locality 4 (hw only) */
112*adb0e917SStefan Berger     for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
113*adb0e917SStefan Berger         pending_request_flag = 0;
114*adb0e917SStefan Berger 
115*adb0e917SStefan Berger         access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
116*adb0e917SStefan Berger         g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
117*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
118*adb0e917SStefan Berger 
119*adb0e917SStefan Berger         /* request use of locality */
120*adb0e917SStefan Berger         writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
121*adb0e917SStefan Berger         access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
122*adb0e917SStefan Berger         g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
123*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_ACTIVE_LOCALITY |
124*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
125*adb0e917SStefan Berger 
126*adb0e917SStefan Berger         /* lower localities cannot seize access */
127*adb0e917SStefan Berger         for (l = 0; l < locty; l++) {
128*adb0e917SStefan Berger             /* lower locality is not active */
129*adb0e917SStefan Berger             access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
130*adb0e917SStefan Berger             DPRINTF_ACCESS;
131*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
132*adb0e917SStefan Berger                                         pending_request_flag |
133*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
134*adb0e917SStefan Berger 
135*adb0e917SStefan Berger             /* try to request use from 'l' */
136*adb0e917SStefan Berger             writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
137*adb0e917SStefan Berger 
138*adb0e917SStefan Berger             /* requesting use from 'l' was not possible;
139*adb0e917SStefan Berger                we must see REQUEST_USE and possibly PENDING_REQUEST */
140*adb0e917SStefan Berger             access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
141*adb0e917SStefan Berger             DPRINTF_ACCESS;
142*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
143*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_REQUEST_USE |
144*adb0e917SStefan Berger                                         pending_request_flag |
145*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
146*adb0e917SStefan Berger 
147*adb0e917SStefan Berger             /* locality 'locty' must be unchanged;
148*adb0e917SStefan Berger                we must see PENDING_REQUEST */
149*adb0e917SStefan Berger             access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
150*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
151*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_ACTIVE_LOCALITY |
152*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_PENDING_REQUEST |
153*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
154*adb0e917SStefan Berger 
155*adb0e917SStefan Berger             /* try to seize from 'l' */
156*adb0e917SStefan Berger             writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE);
157*adb0e917SStefan Berger             /* seize from 'l' was not possible */
158*adb0e917SStefan Berger             access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
159*adb0e917SStefan Berger             DPRINTF_ACCESS;
160*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
161*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_REQUEST_USE |
162*adb0e917SStefan Berger                                         pending_request_flag |
163*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
164*adb0e917SStefan Berger 
165*adb0e917SStefan Berger             /* locality 'locty' must be unchanged */
166*adb0e917SStefan Berger             access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
167*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
168*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_ACTIVE_LOCALITY |
169*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_PENDING_REQUEST |
170*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
171*adb0e917SStefan Berger 
172*adb0e917SStefan Berger             /* on the next loop we will have a PENDING_REQUEST flag
173*adb0e917SStefan Berger                set for locality 'l' */
174*adb0e917SStefan Berger             pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
175*adb0e917SStefan Berger         }
176*adb0e917SStefan Berger 
177*adb0e917SStefan Berger         /* higher localities can 'seize' access but not 'request use';
178*adb0e917SStefan Berger            note: this will activate first l+1, then l+2 etc. */
179*adb0e917SStefan Berger         for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
180*adb0e917SStefan Berger             /* try to 'request use' from 'l' */
181*adb0e917SStefan Berger             writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
182*adb0e917SStefan Berger 
183*adb0e917SStefan Berger             /* requesting use from 'l' was not possible; we should see
184*adb0e917SStefan Berger                REQUEST_USE and may see PENDING_REQUEST */
185*adb0e917SStefan Berger             access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
186*adb0e917SStefan Berger             DPRINTF_ACCESS;
187*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
188*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_REQUEST_USE |
189*adb0e917SStefan Berger                                         pending_request_flag |
190*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
191*adb0e917SStefan Berger 
192*adb0e917SStefan Berger             /* locality 'l-1' must be unchanged; we should always
193*adb0e917SStefan Berger                see PENDING_REQUEST from 'l' requesting access */
194*adb0e917SStefan Berger             access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
195*adb0e917SStefan Berger             DPRINTF_ACCESS;
196*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
197*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_ACTIVE_LOCALITY |
198*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_PENDING_REQUEST |
199*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
200*adb0e917SStefan Berger 
201*adb0e917SStefan Berger             /* try to seize from 'l' */
202*adb0e917SStefan Berger             writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE);
203*adb0e917SStefan Berger 
204*adb0e917SStefan Berger             /* seize from 'l' was possible */
205*adb0e917SStefan Berger             access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
206*adb0e917SStefan Berger             DPRINTF_ACCESS;
207*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
208*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_ACTIVE_LOCALITY |
209*adb0e917SStefan Berger                                         pending_request_flag |
210*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
211*adb0e917SStefan Berger 
212*adb0e917SStefan Berger             /* l - 1 should show that it has BEEN_SEIZED */
213*adb0e917SStefan Berger             access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
214*adb0e917SStefan Berger             DPRINTF_ACCESS;
215*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
216*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_BEEN_SEIZED |
217*adb0e917SStefan Berger                                         pending_request_flag |
218*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
219*adb0e917SStefan Berger 
220*adb0e917SStefan Berger             /* clear the BEEN_SEIZED flag and make sure it's gone */
221*adb0e917SStefan Berger             writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS),
222*adb0e917SStefan Berger                    TPM_TIS_ACCESS_BEEN_SEIZED);
223*adb0e917SStefan Berger 
224*adb0e917SStefan Berger             access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
225*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
226*adb0e917SStefan Berger                                         pending_request_flag |
227*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
228*adb0e917SStefan Berger         }
229*adb0e917SStefan Berger 
230*adb0e917SStefan Berger         /* PENDING_REQUEST will not be set if locty = 0 since all localities
231*adb0e917SStefan Berger            were active; in case of locty = 1, locality 0 will be active
232*adb0e917SStefan Berger            but no PENDING_REQUEST anywhere */
233*adb0e917SStefan Berger         if (locty <= 1) {
234*adb0e917SStefan Berger             pending_request_flag = 0;
235*adb0e917SStefan Berger         }
236*adb0e917SStefan Berger 
237*adb0e917SStefan Berger         /* release access from l - 1; this activates locty - 1 */
238*adb0e917SStefan Berger         l--;
239*adb0e917SStefan Berger 
240*adb0e917SStefan Berger         access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
241*adb0e917SStefan Berger         DPRINTF_ACCESS;
242*adb0e917SStefan Berger 
243*adb0e917SStefan Berger         DPRINTF("%s: %d: relinquishing control on l = %d\n",
244*adb0e917SStefan Berger                 __func__, __LINE__, l);
245*adb0e917SStefan Berger         writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
246*adb0e917SStefan Berger                TPM_TIS_ACCESS_ACTIVE_LOCALITY);
247*adb0e917SStefan Berger 
248*adb0e917SStefan Berger         access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
249*adb0e917SStefan Berger         DPRINTF_ACCESS;
250*adb0e917SStefan Berger         g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
251*adb0e917SStefan Berger                                     pending_request_flag |
252*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
253*adb0e917SStefan Berger 
254*adb0e917SStefan Berger         for (l = locty - 1; l >= 0; l--) {
255*adb0e917SStefan Berger             access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
256*adb0e917SStefan Berger             DPRINTF_ACCESS;
257*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
258*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_ACTIVE_LOCALITY |
259*adb0e917SStefan Berger                                         pending_request_flag |
260*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
261*adb0e917SStefan Berger 
262*adb0e917SStefan Berger             /* release this locality */
263*adb0e917SStefan Berger             writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
264*adb0e917SStefan Berger                    TPM_TIS_ACCESS_ACTIVE_LOCALITY);
265*adb0e917SStefan Berger 
266*adb0e917SStefan Berger             if (l == 1) {
267*adb0e917SStefan Berger                 pending_request_flag = 0;
268*adb0e917SStefan Berger             }
269*adb0e917SStefan Berger         }
270*adb0e917SStefan Berger 
271*adb0e917SStefan Berger         /* no locality may be active now */
272*adb0e917SStefan Berger         for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
273*adb0e917SStefan Berger             access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
274*adb0e917SStefan Berger             DPRINTF_ACCESS;
275*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
276*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
277*adb0e917SStefan Berger         }
278*adb0e917SStefan Berger     }
279*adb0e917SStefan Berger }
280*adb0e917SStefan Berger 
281*adb0e917SStefan Berger /*
282*adb0e917SStefan Berger  * Test case for getting access when higher number locality relinquishes access
283*adb0e917SStefan Berger  */
284*adb0e917SStefan Berger static void tpm_tis_test_check_access_reg_release(const void *data)
285*adb0e917SStefan Berger {
286*adb0e917SStefan Berger     int locty, l;
287*adb0e917SStefan Berger     uint8_t access;
288*adb0e917SStefan Berger     uint8_t pending_request_flag;
289*adb0e917SStefan Berger 
290*adb0e917SStefan Berger     /* do not test locality 4 (hw only) */
291*adb0e917SStefan Berger     for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) {
292*adb0e917SStefan Berger         pending_request_flag = 0;
293*adb0e917SStefan Berger 
294*adb0e917SStefan Berger         access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
295*adb0e917SStefan Berger         g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
296*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
297*adb0e917SStefan Berger 
298*adb0e917SStefan Berger         /* request use of locality */
299*adb0e917SStefan Berger         writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
300*adb0e917SStefan Berger         access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
301*adb0e917SStefan Berger         g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
302*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_ACTIVE_LOCALITY |
303*adb0e917SStefan Berger                                     TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
304*adb0e917SStefan Berger 
305*adb0e917SStefan Berger         /* request use of all other localities */
306*adb0e917SStefan Berger         for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
307*adb0e917SStefan Berger             if (l == locty) {
308*adb0e917SStefan Berger                 continue;
309*adb0e917SStefan Berger             }
310*adb0e917SStefan Berger             /* request use of locality 'l' -- we MUST see REQUEST USE and
311*adb0e917SStefan Berger                may see PENDING_REQUEST */
312*adb0e917SStefan Berger             writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
313*adb0e917SStefan Berger             access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
314*adb0e917SStefan Berger             DPRINTF_ACCESS;
315*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
316*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_REQUEST_USE |
317*adb0e917SStefan Berger                                         pending_request_flag |
318*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
319*adb0e917SStefan Berger             pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
320*adb0e917SStefan Berger         }
321*adb0e917SStefan Berger         /* release locality 'locty' */
322*adb0e917SStefan Berger         writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS),
323*adb0e917SStefan Berger                TPM_TIS_ACCESS_ACTIVE_LOCALITY);
324*adb0e917SStefan Berger         /* highest locality should now be active; release it and make sure the
325*adb0e917SStefan Berger            next higest locality is active afterwards */
326*adb0e917SStefan Berger         for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) {
327*adb0e917SStefan Berger             if (l == locty) {
328*adb0e917SStefan Berger                 continue;
329*adb0e917SStefan Berger             }
330*adb0e917SStefan Berger             /* 'l' should be active now */
331*adb0e917SStefan Berger             access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
332*adb0e917SStefan Berger             DPRINTF_ACCESS;
333*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
334*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_ACTIVE_LOCALITY |
335*adb0e917SStefan Berger                                         pending_request_flag |
336*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
337*adb0e917SStefan Berger             /* 'l' relinquishes access */
338*adb0e917SStefan Berger             writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
339*adb0e917SStefan Berger                    TPM_TIS_ACCESS_ACTIVE_LOCALITY);
340*adb0e917SStefan Berger             access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
341*adb0e917SStefan Berger             DPRINTF_ACCESS;
342*adb0e917SStefan Berger             if (l == 1 || (locty <= 1 && l == 2)) {
343*adb0e917SStefan Berger                 pending_request_flag = 0;
344*adb0e917SStefan Berger             }
345*adb0e917SStefan Berger             g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
346*adb0e917SStefan Berger                                         pending_request_flag |
347*adb0e917SStefan Berger                                         TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
348*adb0e917SStefan Berger         }
349*adb0e917SStefan Berger     }
350*adb0e917SStefan Berger }
351*adb0e917SStefan Berger 
352*adb0e917SStefan Berger /*
353*adb0e917SStefan Berger  * Test case for transmitting packets
354*adb0e917SStefan Berger  */
355*adb0e917SStefan Berger static void tpm_tis_test_check_transmit(const void *data)
356*adb0e917SStefan Berger {
357*adb0e917SStefan Berger     const TestState *s = data;
358*adb0e917SStefan Berger     uint8_t access;
359*adb0e917SStefan Berger     uint32_t sts;
360*adb0e917SStefan Berger     uint16_t bcount;
361*adb0e917SStefan Berger     size_t i;
362*adb0e917SStefan Berger 
363*adb0e917SStefan Berger     /* request use of locality 0 */
364*adb0e917SStefan Berger     writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
365*adb0e917SStefan Berger     access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
366*adb0e917SStefan Berger     g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
367*adb0e917SStefan Berger                                 TPM_TIS_ACCESS_ACTIVE_LOCALITY |
368*adb0e917SStefan Berger                                 TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
369*adb0e917SStefan Berger 
370*adb0e917SStefan Berger     sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
371*adb0e917SStefan Berger     DPRINTF_STS;
372*adb0e917SStefan Berger 
373*adb0e917SStefan Berger     g_assert_cmpint(sts & 0xff, ==, 0);
374*adb0e917SStefan Berger     g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==,
375*adb0e917SStefan Berger                     TPM_TIS_STS_TPM_FAMILY2_0);
376*adb0e917SStefan Berger 
377*adb0e917SStefan Berger     bcount = (sts >> 8) & 0xffff;
378*adb0e917SStefan Berger     g_assert_cmpint(bcount, >=, 128);
379*adb0e917SStefan Berger 
380*adb0e917SStefan Berger     writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY);
381*adb0e917SStefan Berger     sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
382*adb0e917SStefan Berger     DPRINTF_STS;
383*adb0e917SStefan Berger     g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY);
384*adb0e917SStefan Berger 
385*adb0e917SStefan Berger     /* transmit command */
386*adb0e917SStefan Berger     for (i = 0; i < sizeof(TPM_CMD); i++) {
387*adb0e917SStefan Berger         writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]);
388*adb0e917SStefan Berger         sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
389*adb0e917SStefan Berger         DPRINTF_STS;
390*adb0e917SStefan Berger         if (i < sizeof(TPM_CMD) - 1) {
391*adb0e917SStefan Berger             g_assert_cmpint(sts & 0xff, ==,
392*adb0e917SStefan Berger                             TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
393*adb0e917SStefan Berger         } else {
394*adb0e917SStefan Berger             g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID);
395*adb0e917SStefan Berger         }
396*adb0e917SStefan Berger         g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
397*adb0e917SStefan Berger     }
398*adb0e917SStefan Berger     /* start processing */
399*adb0e917SStefan Berger     writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO);
400*adb0e917SStefan Berger 
401*adb0e917SStefan Berger     uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
402*adb0e917SStefan Berger     do {
403*adb0e917SStefan Berger         sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
404*adb0e917SStefan Berger         if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
405*adb0e917SStefan Berger             break;
406*adb0e917SStefan Berger         }
407*adb0e917SStefan Berger     } while (g_get_monotonic_time() < end_time);
408*adb0e917SStefan Berger 
409*adb0e917SStefan Berger     sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
410*adb0e917SStefan Berger     DPRINTF_STS;
411*adb0e917SStefan Berger     g_assert_cmpint(sts & 0xff, == ,
412*adb0e917SStefan Berger                     TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
413*adb0e917SStefan Berger     bcount = (sts >> 8) & 0xffff;
414*adb0e917SStefan Berger 
415*adb0e917SStefan Berger     /* read response */
416*adb0e917SStefan Berger     uint8_t tpm_msg[sizeof(struct tpm_hdr)];
417*adb0e917SStefan Berger     g_assert_cmpint(sizeof(tpm_msg), ==, bcount);
418*adb0e917SStefan Berger 
419*adb0e917SStefan Berger     for (i = 0; i < sizeof(tpm_msg); i++) {
420*adb0e917SStefan Berger         tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO));
421*adb0e917SStefan Berger         sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
422*adb0e917SStefan Berger         DPRINTF_STS;
423*adb0e917SStefan Berger         if (sts & TPM_TIS_STS_DATA_AVAILABLE) {
424*adb0e917SStefan Berger             g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
425*adb0e917SStefan Berger         }
426*adb0e917SStefan Berger     }
427*adb0e917SStefan Berger     g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg));
428*adb0e917SStefan Berger 
429*adb0e917SStefan Berger     /* relinquish use of locality 0 */
430*adb0e917SStefan Berger     writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY);
431*adb0e917SStefan Berger     access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
432*adb0e917SStefan Berger }
433*adb0e917SStefan Berger 
434*adb0e917SStefan Berger int main(int argc, char **argv)
435*adb0e917SStefan Berger {
436*adb0e917SStefan Berger     int ret;
437*adb0e917SStefan Berger     char *args, *tmp_path = g_dir_make_tmp("qemu-tpm-tis-test.XXXXXX", NULL);
438*adb0e917SStefan Berger     GThread *thread;
439*adb0e917SStefan Berger     TestState test;
440*adb0e917SStefan Berger 
441*adb0e917SStefan Berger     module_call_init(MODULE_INIT_QOM);
442*adb0e917SStefan Berger     g_test_init(&argc, &argv, NULL);
443*adb0e917SStefan Berger 
444*adb0e917SStefan Berger     test.addr = g_new0(SocketAddress, 1);
445*adb0e917SStefan Berger     test.addr->type = SOCKET_ADDRESS_TYPE_UNIX;
446*adb0e917SStefan Berger     test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL);
447*adb0e917SStefan Berger     g_mutex_init(&test.data_mutex);
448*adb0e917SStefan Berger     g_cond_init(&test.data_cond);
449*adb0e917SStefan Berger 
450*adb0e917SStefan Berger     thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test);
451*adb0e917SStefan Berger     tpm_emu_test_wait_cond(&test);
452*adb0e917SStefan Berger 
453*adb0e917SStefan Berger     args = g_strdup_printf(
454*adb0e917SStefan Berger         "-chardev socket,id=chr,path=%s "
455*adb0e917SStefan Berger         "-tpmdev emulator,id=dev,chardev=chr "
456*adb0e917SStefan Berger         "-device tpm-tis,tpmdev=dev",
457*adb0e917SStefan Berger         test.addr->u.q_unix.path);
458*adb0e917SStefan Berger     qtest_start(args);
459*adb0e917SStefan Berger 
460*adb0e917SStefan Berger     qtest_add_data_func("/tpm-tis/test_check_localities", &test,
461*adb0e917SStefan Berger                         tpm_tis_test_check_localities);
462*adb0e917SStefan Berger 
463*adb0e917SStefan Berger     qtest_add_data_func("/tpm-tis/test_check_access_reg", &test,
464*adb0e917SStefan Berger                         tpm_tis_test_check_access_reg);
465*adb0e917SStefan Berger 
466*adb0e917SStefan Berger     qtest_add_data_func("/tpm-tis/test_check_access_reg_seize", &test,
467*adb0e917SStefan Berger                         tpm_tis_test_check_access_reg_seize);
468*adb0e917SStefan Berger 
469*adb0e917SStefan Berger     qtest_add_data_func("/tpm-tis/test_check_access_reg_release", &test,
470*adb0e917SStefan Berger                         tpm_tis_test_check_access_reg_release);
471*adb0e917SStefan Berger 
472*adb0e917SStefan Berger     qtest_add_data_func("/tpm-tis/test_check_transmit", &test,
473*adb0e917SStefan Berger                         tpm_tis_test_check_transmit);
474*adb0e917SStefan Berger 
475*adb0e917SStefan Berger     ret = g_test_run();
476*adb0e917SStefan Berger 
477*adb0e917SStefan Berger     qtest_end();
478*adb0e917SStefan Berger 
479*adb0e917SStefan Berger     g_thread_join(thread);
480*adb0e917SStefan Berger     g_unlink(test.addr->u.q_unix.path);
481*adb0e917SStefan Berger     qapi_free_SocketAddress(test.addr);
482*adb0e917SStefan Berger     g_rmdir(tmp_path);
483*adb0e917SStefan Berger     g_free(tmp_path);
484*adb0e917SStefan Berger     g_free(args);
485*adb0e917SStefan Berger     return ret;
486*adb0e917SStefan Berger }
487