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