These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / seabios / src / hw / tpm_drivers.c
1 // Implementation of a TPM driver for the TPM TIS interface
2 //
3 // Copyright (C) 2006-2011 IBM Corporation
4 //
5 // Authors:
6 //     Stefan Berger <stefanb@linux.vnet.ibm.com>
7 //
8 // This file may be distributed under the terms of the GNU LGPLv3 license.
9
10 #include "config.h" // CONFIG_TPM_TIS_SHA1THRESHOLD
11 #include "string.h" // memcpy
12 #include "util.h" // msleep
13 #include "x86.h" // readl
14 #include "hw/tpm_drivers.h" // struct tpm_driver
15 #include "tcgbios.h" // TCG_*
16
17 static const u32 tis_default_timeouts[4] = {
18     TIS_DEFAULT_TIMEOUT_A,
19     TIS_DEFAULT_TIMEOUT_B,
20     TIS_DEFAULT_TIMEOUT_C,
21     TIS_DEFAULT_TIMEOUT_D,
22 };
23
24 static const u32 tpm_default_durations[3] = {
25     TPM_DEFAULT_DURATION_SHORT,
26     TPM_DEFAULT_DURATION_MEDIUM,
27     TPM_DEFAULT_DURATION_LONG,
28 };
29
30 /* determined values */
31 static u32 tpm_default_dur[3];
32 static u32 tpm_default_to[4];
33
34
35 /* if device is not there, return '0', '1' otherwise */
36 static u32 tis_probe(void)
37 {
38     if (!CONFIG_TCGBIOS)
39         return 0;
40
41     u32 rc = 0;
42     u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID));
43
44     if ((didvid != 0) && (didvid != 0xffffffff))
45         rc = 1;
46
47     return rc;
48 }
49
50 static u32 tis_init(void)
51 {
52     if (!CONFIG_TCGBIOS)
53         return 1;
54
55     writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0);
56
57     if (tpm_drivers[TIS_DRIVER_IDX].durations == NULL) {
58         u32 *durations = tpm_default_dur;
59         memcpy(durations, tpm_default_durations,
60                sizeof(tpm_default_durations));
61         tpm_drivers[TIS_DRIVER_IDX].durations = durations;
62     }
63
64     if (tpm_drivers[TIS_DRIVER_IDX].timeouts == NULL) {
65         u32 *timeouts = tpm_default_to;
66         memcpy(timeouts, tis_default_timeouts,
67                sizeof(tis_default_timeouts));
68         tpm_drivers[TIS_DRIVER_IDX].timeouts = timeouts;
69     }
70
71     return 1;
72 }
73
74
75 static void set_timeouts(u32 timeouts[4], u32 durations[3])
76 {
77     if (!CONFIG_TCGBIOS)
78         return;
79
80     u32 *tos = tpm_drivers[TIS_DRIVER_IDX].timeouts;
81     u32 *dus = tpm_drivers[TIS_DRIVER_IDX].durations;
82
83     if (tos && tos != tis_default_timeouts && timeouts)
84         memcpy(tos, timeouts, 4 * sizeof(u32));
85     if (dus && dus != tpm_default_durations && durations)
86         memcpy(dus, durations, 3 * sizeof(u32));
87 }
88
89
90 static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect)
91 {
92     if (!CONFIG_TCGBIOS)
93         return 0;
94
95     u32 rc = 1;
96
97     while (time > 0) {
98         u8 sts = readb(TIS_REG(locty, TIS_REG_STS));
99         if ((sts & mask) == expect) {
100             rc = 0;
101             break;
102         }
103         msleep(1);
104         time--;
105     }
106     return rc;
107 }
108
109 static u32 tis_activate(u8 locty)
110 {
111     if (!CONFIG_TCGBIOS)
112         return 0;
113
114     u32 rc = 0;
115     u8 acc;
116     int l;
117     u32 timeout_a = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_A];
118
119     if (!(readb(TIS_REG(locty, TIS_REG_ACCESS)) &
120           TIS_ACCESS_ACTIVE_LOCALITY)) {
121         /* release locality in use top-downwards */
122         for (l = 4; l >= 0; l--)
123             writeb(TIS_REG(l, TIS_REG_ACCESS),
124                    TIS_ACCESS_ACTIVE_LOCALITY);
125     }
126
127     /* request access to locality */
128     writeb(TIS_REG(locty, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE);
129
130     acc = readb(TIS_REG(locty, TIS_REG_ACCESS));
131     if ((acc & TIS_ACCESS_ACTIVE_LOCALITY)) {
132         writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
133         rc = tis_wait_sts(locty, timeout_a,
134                           TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
135     }
136
137     return rc;
138 }
139
140 static u32 tis_find_active_locality(void)
141 {
142     if (!CONFIG_TCGBIOS)
143         return 0;
144
145     u8 locty;
146
147     for (locty = 0; locty <= 4; locty++) {
148         if ((readb(TIS_REG(locty, TIS_REG_ACCESS)) &
149              TIS_ACCESS_ACTIVE_LOCALITY))
150             return locty;
151     }
152
153     tis_activate(0);
154
155     return 0;
156 }
157
158 static u32 tis_ready(void)
159 {
160     if (!CONFIG_TCGBIOS)
161         return 0;
162
163     u32 rc = 0;
164     u8 locty = tis_find_active_locality();
165     u32 timeout_b = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_B];
166
167     writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
168     rc = tis_wait_sts(locty, timeout_b,
169                       TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
170
171     return rc;
172 }
173
174 static u32 tis_senddata(const u8 *const data, u32 len)
175 {
176     if (!CONFIG_TCGBIOS)
177         return 0;
178
179     u32 rc = 0;
180     u32 offset = 0;
181     u32 end = 0;
182     u16 burst = 0;
183     u32 ctr = 0;
184     u8 locty = tis_find_active_locality();
185     u32 timeout_d = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_D];
186
187     do {
188         while (burst == 0 && ctr < timeout_d) {
189                burst = readl(TIS_REG(locty, TIS_REG_STS)) >> 8;
190             if (burst == 0) {
191                 msleep(1);
192                 ctr++;
193             }
194         }
195
196         if (burst == 0) {
197             rc = TCG_RESPONSE_TIMEOUT;
198             break;
199         }
200
201         while (1) {
202             writeb(TIS_REG(locty, TIS_REG_DATA_FIFO), data[offset++]);
203             burst--;
204
205             if (burst == 0 || offset == len)
206                 break;
207         }
208
209         if (offset == len)
210             end = 1;
211     } while (end == 0);
212
213     return rc;
214 }
215
216 static u32 tis_readresp(u8 *buffer, u32 *len)
217 {
218     if (!CONFIG_TCGBIOS)
219         return 0;
220
221     u32 rc = 0;
222     u32 offset = 0;
223     u32 sts;
224     u8 locty = tis_find_active_locality();
225
226     while (offset < *len) {
227         buffer[offset] = readb(TIS_REG(locty, TIS_REG_DATA_FIFO));
228         offset++;
229         sts = readb(TIS_REG(locty, TIS_REG_STS));
230         /* data left ? */
231         if ((sts & TIS_STS_DATA_AVAILABLE) == 0)
232             break;
233     }
234
235     *len = offset;
236
237     return rc;
238 }
239
240
241 static u32 tis_waitdatavalid(void)
242 {
243     if (!CONFIG_TCGBIOS)
244         return 0;
245
246     u32 rc = 0;
247     u8 locty = tis_find_active_locality();
248     u32 timeout_c = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C];
249
250     if (tis_wait_sts(locty, timeout_c, TIS_STS_VALID, TIS_STS_VALID) != 0)
251         rc = TCG_NO_RESPONSE;
252
253     return rc;
254 }
255
256 static u32 tis_waitrespready(enum tpmDurationType to_t)
257 {
258     if (!CONFIG_TCGBIOS)
259         return 0;
260
261     u32 rc = 0;
262     u8 locty = tis_find_active_locality();
263     u32 timeout = tpm_drivers[TIS_DRIVER_IDX].durations[to_t];
264
265     writeb(TIS_REG(locty ,TIS_REG_STS), TIS_STS_TPM_GO);
266
267     if (tis_wait_sts(locty, timeout,
268                      TIS_STS_DATA_AVAILABLE, TIS_STS_DATA_AVAILABLE) != 0)
269         rc = TCG_NO_RESPONSE;
270
271     return rc;
272 }
273
274
275 struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
276     [TIS_DRIVER_IDX] =
277         {
278             .timeouts      = NULL,
279             .durations     = NULL,
280             .set_timeouts  = set_timeouts,
281             .probe         = tis_probe,
282             .init          = tis_init,
283             .activate      = tis_activate,
284             .ready         = tis_ready,
285             .senddata      = tis_senddata,
286             .readresp      = tis_readresp,
287             .waitdatavalid = tis_waitdatavalid,
288             .waitrespready = tis_waitrespready,
289             .sha1threshold = 100 * 1024,
290         },
291 };