1 /* $MirOS: src/sys/dev/ic/tpm.c,v 1.5 2010/07/25 16:36:18 tg Exp $ */
2
3 /*-
4 * Copyright (c) 2009, 2010
5 * Thorsten Glaser <tg@mirbsd.org>
6 * Copyright (c) 2003
7 * Rick Wash <rwash@citi.umich.edu>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 /*
23 * TCPA TPM driver, bus independent code
24 */
25
26 #include <sys/param.h>
27 #include <sys/device.h>
28 #include <sys/conf.h>
29 #include <sys/errno.h>
30 #include <sys/systm.h>
31 #include <sys/proc.h>
32 #include <sys/kernel.h>
33 #include <sys/timeout.h>
34 #include <machine/bus.h>
35 #include <machine/intr.h>
36 #include <machine/param.h>
37 #include <dev/pci/pcivar.h>
38 #include <dev/pci/pcireg.h>
39 #include <dev/pci/pcidevs.h>
40
41 #include <dev/ic/tpm.h>
42
43 /* #define TPM_DEBUG */
44
45 /* TPM addresses */
46 #define TPM_ADDR 0x4E
47 #define TPM_DATA 0x4F
48
49 /* write status bits */
50 #define STATUS_BIT_ABORT 0x01
51 #define STATUS_BIT_LASTBYTE 0x04
52
53 /* read status bits */
54 #define STATUS_BIT_BUSY 0x01
55 #define STATUS_BIT_DATA_AVAIL 0x02
56 #define STATUS_BIT_REWRITE 0x04
57
58 /* Timeout Numbers */
59 #define TPM_DELAY 50 /* in milliseconds */
60 #define TPM_TIMEOUT ((2*2*60*60) / TPM_DELAY)
61 #define TPM_TSLEEP_TIMEOUT (2*60*hz)
62 #define TPM_CALLOUT_TIMEOUT TPM_DELAY
63
64 int tpm_init(struct tpm_softc *sc, pci_chipset_tag_t pa_pc, pcitag_t pa_tag);
65 int tpm_recv(struct tpm_softc *sc, int count);
66 int tpm_send(struct tpm_softc *sc, int count);
67
68 void tpm_intr(void *data);
69 void tpm_read_data(struct tpm_softc *sc);
70 void tpm_send_data(struct tpm_softc *sc);
71
72 struct cfdriver tpm_cd = {
73 NULL, "tpm", DV_DULL
74 };
75
76 struct tpm_softc *tpm_sc;
77
78 #ifndef SMALL_KERNEL
79 /* must match enum tpm_chip_type */
80 static const char *tpm_chip_names[] = {
81 "<invalid>",
82 "Intel ICH2 LPC",
83 "Intel ICH3 LPC-M",
84 "Intel ICH4 LPC",
85 "Intel ICH4 LPC-M"
86 };
87 #endif
88
89
90 int
tpmopen(dev_t dev,int flag,int mode,struct proc * p)91 tpmopen(dev_t dev, int flag, int mode, struct proc *p)
92 {
93 #ifdef TPM_DEBUG
94 printf("in tpmopen\n");
95 #endif /* TPM_DEBUG */
96
97 /* Make sure it has been initialised */
98 if (!tpm_sc || !tpm_sc->initialised)
99 return (ENODEV);
100
101 /* Only can be opened by one process at a time */
102 /* XXX: concurrency hack */
103 if (tpm_sc->open != 0)
104 return (EBUSY);
105
106 tpm_sc->open = 1;
107 return (0);
108 }
109
110 int
tpmclose(dev_t dev,int flag,int mode,struct proc * p)111 tpmclose(dev_t dev, int flag, int mode, struct proc *p)
112 {
113 #ifdef TPM_DEBUG
114 printf("in tpmclose\n");
115 #endif /* TPM_DEBUG */
116
117 tpm_sc->open = 0;
118
119 return (0);
120 }
121
122 int
tpmwrite(dev_t dev,struct uio * uio,int flags)123 tpmwrite(dev_t dev, struct uio *uio, int flags)
124 {
125 size_t len;
126 int rv;
127
128 if (!tpm_sc || !tpm_sc->initialised)
129 return (ENODEV);
130 else if (!tpm_sc->open)
131 return (EPERM);
132 else if (tpm_sc->state != TPM_STATE_READY)
133 return (EBUSY);
134
135 len = min(uio->uio_resid, TPM_BUFFER_LEN);
136
137 uiomove(tpm_sc->buffer, len, uio);
138
139 tpm_sc->len = len;
140 tpm_sc->state = TPM_STATE_WRITE_START;
141 timeout_add(&tpm_sc->tmo, 1);
142 while ((tpm_sc->state != TPM_STATE_WRITE_DONE) &&
143 (tpm_sc->state != TPM_STATE_ERROR))
144 tsleep(tpm_sc->buffer, PRIBIO, "tpmwrite", TPM_TSLEEP_TIMEOUT);
145
146 rv = tpm_sc->retval;
147 tpm_sc->retval = 0;
148
149 tpm_sc->state = TPM_STATE_READY;
150
151 #ifdef TPM_DEBUG
152 printf("in tpmwrite\n");
153 #endif /* TPM_DEBUG */
154
155 return (rv);
156 }
157
158 int
tpmread(dev_t dev,struct uio * uio,int flags)159 tpmread(dev_t dev, struct uio *uio, int flags)
160 {
161 size_t len;
162 int rv;
163
164 if (!tpm_sc || !tpm_sc->initialised)
165 return (ENODEV);
166 else if (!tpm_sc->open)
167 return (EPERM);
168 else if (tpm_sc->state != TPM_STATE_READY)
169 return (EBUSY);
170
171 #ifdef TPM_DEBUG
172 printf("in tpmread\n");
173 #endif /* TPM_DEBUG */
174
175 len = min(uio->uio_resid, TPM_BUFFER_LEN);
176
177 if (len < 6)
178 return (EIO);
179
180 tpm_sc->len = len;
181 tpm_sc->state = TPM_STATE_READ_START;
182 timeout_add(&tpm_sc->tmo, 1);
183 while ((tpm_sc->state != TPM_STATE_READ_DONE) &&
184 (tpm_sc->state != TPM_STATE_ERROR))
185 tsleep(tpm_sc->buffer, PRIBIO, "tpmread", TPM_TSLEEP_TIMEOUT);
186
187 rv = tpm_sc->retval;
188 tpm_sc->retval = 0;
189
190 if (tpm_sc->len > 0)
191 uiomove(tpm_sc->buffer, tpm_sc->len, uio);
192
193 tpm_sc->state = TPM_STATE_READY;
194
195 return (rv);
196 }
197
198 int
tpmioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)199 tpmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
200 {
201 return (ENODEV);
202 }
203
204
205 int
tpm_match(struct device * parent,void * match,void * aux)206 tpm_match(struct device *parent, void *match, void *aux)
207 {
208 struct tpm_attach_args *ta = aux;
209
210 if (ta == NULL || strcmp(ta->busname, "tpm") ||
211 ta->chiptype == TPM_INVALID_CHIP)
212 return (0);
213 if (tpm_sc && tpm_sc->initialised) {
214 printf("tpm: second %sch ignored\n", "mat");
215 return (0);
216 }
217 return (1);
218 }
219
220 void
tpm_attach(struct device * parent,struct device * self,void * aux)221 tpm_attach(struct device *parent, struct device *self, void *aux)
222 {
223 struct tpm_attach_args *ta = aux;
224 int notattach;
225
226 if (tpm_sc && tpm_sc->initialised) {
227 printf("tpm: second %sch ignored\n", "atta");
228 return;
229 }
230
231 tpm_sc = (void *)self;
232 tpm_sc->type = ta->chiptype;
233
234 outb(TPM_ADDR, 0x08); /* base addr lo */
235 tpm_sc->base = inb(TPM_DATA);
236 outb(TPM_ADDR, 0x09); /* base addr hi */
237 tpm_sc->base |= inb(TPM_DATA) << 8;
238
239 /* Query the chip for its version */
240 outb(TPM_ADDR, 0x00);
241 tpm_sc->version[0] = inb(TPM_DATA);
242 outb(TPM_ADDR, 0x01);
243 tpm_sc->version[1] = inb(TPM_DATA);
244 outb(TPM_ADDR, 0x02);
245 tpm_sc->version[2] = inb(TPM_DATA);
246 outb(TPM_ADDR, 0x03);
247 tpm_sc->version[3] = inb(TPM_DATA);
248
249 /* Query the chip for its vendor */
250 outb(TPM_ADDR, 0x04);
251 tpm_sc->vendor[0] = inb(TPM_DATA);
252 outb(TPM_ADDR, 0x05);
253 tpm_sc->vendor[1] = inb(TPM_DATA);
254 outb(TPM_ADDR, 0x06);
255 tpm_sc->vendor[2] = inb(TPM_DATA);
256 outb(TPM_ADDR, 0x07);
257 tpm_sc->vendor[3] = inb(TPM_DATA);
258 tpm_sc->vendor[4] = '\0';
259
260 notattach = (tpm_sc->vendor[0] == 0xFF) ? 1 : 0;
261 printf(" port 0x%X (%s), version ", tpm_sc->base,
262 tpm_chip_names[tpm_sc->type]);
263 if (tpm_sc->version[0] == 0xFF) {
264 notattach |= 2;
265 printf("failed");
266 } else
267 printf("%d.%d.%d.%d", tpm_sc->version[0], tpm_sc->version[1],
268 tpm_sc->version[2], tpm_sc->version[3]);
269 printf(", vendor %s, %sattached\n",
270 (notattach & 1) ? "failed" : (const char *)tpm_sc->vendor,
271 notattach ? "not " : "");
272
273 if (notattach)
274 return;
275
276 timeout_set(&tpm_sc->tmo, tpm_intr, tpm_sc);
277 timeout_add(&tpm_sc->tmo, 1);
278
279 tpm_sc->initialised = 1;
280 }
281
282 /* Lower half of the device driver. This does the actual polling of the device
283 * Uses NetBSD's callout to delay, so the kernel stays useful while polling
284 */
285 void
tpm_intr(void * data)286 tpm_intr(void *data)
287 {
288 struct tpm_softc *sc = data;
289 int status;
290 #ifdef __OpenBSD__
291 int s;
292
293 s = splnet();
294 #endif
295
296 switch (sc->state) {
297 case TPM_STATE_READY:
298 /* XXX: Should this be here? */
299 #ifdef TPM_DEBUG
300 printf("tpm: state ready\n");
301 #endif /* TPM_DEBUG */
302 timeout_add(&sc->tmo, TPM_CALLOUT_TIMEOUT);
303 break;
304 case TPM_STATE_READ_START: /* Wait till the chip is not busy */
305 #ifdef TPM_DEBUG
306 printf("tpm: state read start\n");
307 #endif /* TPM_DEBUG */
308 sc->wait_timeout++;
309 if (sc->wait_timeout > TPM_TIMEOUT) {
310 printf("tpm: timeout on read\n");
311 sc->state = TPM_STATE_ERROR;
312 sc->retval = EIO;
313 wakeup(sc->buffer);
314 break;
315 }
316 status = inb(sc->base + 1);
317 if ((status & STATUS_BIT_BUSY) != 0) {
318 timeout_add(&sc->tmo, TPM_CALLOUT_TIMEOUT);
319 break;
320 }
321 sc->state = TPM_STATE_WAIT_FOR_DATA;
322 sc->wait_timeout = 0;
323 /* fallthrough */
324 case TPM_STATE_WAIT_FOR_DATA: /* Wait till there is data available */
325 #ifdef TPM_DEBUG
326 printf("tpm: state wait for data\n");
327 #endif /* TPM_DEBUG */
328 sc->wait_timeout++;
329 if (sc->wait_timeout > TPM_TIMEOUT) {
330 printf("tpm: timeout waiting for data\n");
331 sc->state = TPM_STATE_ERROR;
332 sc->retval = EIO;
333 wakeup(sc->buffer);
334 break;
335 }
336 status = inb(sc->base + 1);
337 status &= (STATUS_BIT_BUSY | STATUS_BIT_DATA_AVAIL);
338 if ( status != STATUS_BIT_DATA_AVAIL ) {
339 timeout_add(&sc->tmo, TPM_CALLOUT_TIMEOUT);
340 break;
341 }
342
343 /* Read Data */
344 sc->wait_timeout = 0;
345 sc->retval = 0;
346 sc->state = TPM_STATE_READ_DONE;
347 tpm_read_data(sc);
348 wakeup(sc->buffer);
349 break;
350 case TPM_STATE_WRITE_START: /* Wait till the chip is not busy */
351 outb(sc->base+1, STATUS_BIT_ABORT);
352 #ifdef TPM_DEBUG
353 printf("tpm: state write start\n");
354 #endif /* TPM_DEBUG */
355 sc->state = TPM_STATE_WRITE_BUSY;
356 case TPM_STATE_WRITE_BUSY:
357 sc->wait_timeout++;
358 #ifdef TPM_DEBUG
359 printf("tpm:state write busy\n");
360 #endif /* TPM_DEBUG */
361 if (sc->wait_timeout > TPM_TIMEOUT) {
362 printf("tpm: timeout waiting to write\n");
363 sc->state = TPM_STATE_ERROR;
364 sc->retval = EIO;
365 wakeup(sc->buffer);
366 break;
367 }
368 status = 0;
369 status = inb(sc->base + 1);
370 #ifdef TPM_DEBUG
371 printf("tpm: base: %08x, status bit: %08x\n", sc->base, status);
372 #endif /* TPM_DEBUG */
373 if ( (status & STATUS_BIT_BUSY) != 0) {
374 timeout_add(&sc->tmo, TPM_CALLOUT_TIMEOUT);
375 break;
376 }
377 sc->wait_timeout = 0;
378 sc->retval = 0;
379 sc->state = TPM_STATE_WRITE_WORKING;
380
381 /* Send Data */
382 tpm_send_data(sc);
383 /* fallthrough */
384 case TPM_STATE_WRITE_WORKING: /* Wait till the chip is working, done, or an error */
385 #ifdef TPM_DEBUG
386 printf("tpm: state write working\n");
387 #endif /* TPM_DEBUG */
388 sc->wait_timeout++;
389 if (sc->wait_timeout > TPM_TIMEOUT) {
390 printf("tpm: timeout after writing\n");
391 sc->state = TPM_STATE_ERROR;
392 sc->retval = EIO;
393 wakeup(sc->buffer);
394 break;
395 }
396 status = inb(sc->base + 1);
397 if ( (status & (STATUS_BIT_BUSY | STATUS_BIT_DATA_AVAIL | STATUS_BIT_REWRITE)) == 0) {
398 timeout_add(&sc->tmo, TPM_CALLOUT_TIMEOUT);
399 break;
400 }
401 sc->state = TPM_STATE_WRITE_DONE;
402
403 if ( (status & STATUS_BIT_REWRITE) != 0) {
404 sc->retval = EIO;
405 sc->state = TPM_STATE_ERROR;
406 }
407 wakeup(sc->buffer);
408 break;
409 default:
410 printf("tpm: error in interrupt\n");
411 sc->state = TPM_STATE_ERROR;
412 sc->retval = EIO;
413 wakeup(sc->buffer);
414 }
415
416 #ifdef __OpenBSD__
417 splx(s);
418 #endif
419 }
420
421 void
tpm_read_data(struct tpm_softc * sc)422 tpm_read_data(struct tpm_softc *sc)
423 {
424 int i;
425 int status;
426 char *buffer = sc->buffer;
427 u_int32_t size;
428
429 for (i=0; i<6; i++) {
430 status = inb(sc->base+1);
431 if ( (status & STATUS_BIT_DATA_AVAIL) == 0) {
432 printf("tpm: error reading header\n");
433 sc->len = 0;
434 sc->retval = EIO;
435 sc->state = TPM_STATE_ERROR;;
436 return;
437 }
438 *buffer++ = inb(sc->base);
439 }
440
441 #ifdef __OpenBSD__
442 size = betoh32(*(u_int32_t *)(sc->buffer + 2));
443 #else
444 size = be32toh(*(u_int32_t *)(sc->buffer + 2));
445 #endif
446 if (sc->len < size) {
447 sc->len = 0;
448 sc->retval = EIO;
449 sc->state = TPM_STATE_ERROR;
450 return;
451 }
452
453 for (; i < size; i++) {
454 status = inb(sc->base+1);
455 if ( (status & STATUS_BIT_DATA_AVAIL) == 0) {
456 printf("tpm: error reading data\n");
457 sc->len = 0;
458 sc->retval = EIO;
459 sc->state = TPM_STATE_ERROR;
460 return;
461 }
462 *buffer++ = inb(sc->base);
463 }
464
465 /* Make sure data available is gone */
466 status = inb(sc->base+1);
467 if ( (status & STATUS_BIT_DATA_AVAIL) != 0) {
468 printf("tpm: data avail is stuck\n");
469 sc->len = 0;
470 sc->retval = EIO;
471 sc->state = TPM_STATE_ERROR;
472 return;
473 }
474
475 /* Send an abort */
476 outb(sc->base+1, STATUS_BIT_ABORT);
477
478 sc->len = size;
479 /* TODO: crc check? */
480 }
481
482 void
tpm_send_data(struct tpm_softc * sc)483 tpm_send_data(struct tpm_softc *sc)
484 {
485 int i;
486
487 /* Write everything but the last byte */
488 for (i = 0; i < sc->len; i++) {
489 outb(sc->base, sc->buffer[i]);
490 }
491
492 /* Send last byte */
493 outb(sc->base+1, STATUS_BIT_LASTBYTE);
494
495 /* Send last byte */
496 outb(sc->base, sc->buffer[i]);
497 }
498