Line data Source code
1 : /* $OpenBSD: tpm.c,v 1.3 2018/07/01 19:40:49 mlarkin Exp $ */
2 :
3 : /*
4 : * Minimal interface to Trusted Platform Module chips implementing the
5 : * TPM Interface Spec 1.2, just enough to tell the TPM to save state before
6 : * a system suspend.
7 : *
8 : * Copyright (c) 2008, 2009 Michael Shalayeff
9 : * Copyright (c) 2009, 2010 Hans-Joerg Hoexer
10 : * Copyright (c) 2016 joshua stein <jcs@openbsd.org>
11 : * All rights reserved.
12 : *
13 : * Permission to use, copy, modify, and distribute this software for any
14 : * purpose with or without fee is hereby granted, provided that the above
15 : * copyright notice and this permission notice appear in all copies.
16 : *
17 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
18 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
19 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
20 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21 : * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
22 : * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
23 : * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 : */
25 :
26 : #include <sys/param.h>
27 : #include <sys/systm.h>
28 : #include <sys/device.h>
29 : #include <sys/malloc.h>
30 :
31 : #include <machine/bus.h>
32 : #include <machine/apmvar.h>
33 :
34 : #include <dev/acpi/acpireg.h>
35 : #include <dev/acpi/acpivar.h>
36 : #include <dev/acpi/acpidev.h>
37 : #include <dev/acpi/amltypes.h>
38 : #include <dev/acpi/dsdt.h>
39 :
40 : /* #define TPM_DEBUG */
41 :
42 : #ifdef TPM_DEBUG
43 : #define DPRINTF(x) printf x
44 : #else
45 : #define DPRINTF(x)
46 : #endif
47 :
48 : #define TPM_BUFSIZ 1024
49 : #define TPM_HDRSIZE 10
50 : #define TPM_PARAM_SIZE 0x0001
51 :
52 : #define TPM_ACCESS 0x0000 /* access register */
53 : #define TPM_ACCESS_ESTABLISHMENT 0x01 /* establishment */
54 : #define TPM_ACCESS_REQUEST_USE 0x02 /* request using locality */
55 : #define TPM_ACCESS_REQUEST_PENDING 0x04 /* pending request */
56 : #define TPM_ACCESS_SEIZE 0x08 /* request locality seize */
57 : #define TPM_ACCESS_SEIZED 0x10 /* locality has been seized */
58 : #define TPM_ACCESS_ACTIVE_LOCALITY 0x20 /* locality is active */
59 : #define TPM_ACCESS_VALID 0x80 /* bits are valid */
60 : #define TPM_ACCESS_BITS \
61 : "\020\01EST\02REQ\03PEND\04SEIZE\05SEIZED\06ACT\010VALID"
62 :
63 : #define TPM_INTERRUPT_ENABLE 0x0008
64 : #define TPM_GLOBAL_INT_ENABLE 0x80000000 /* enable ints */
65 : #define TPM_CMD_READY_INT 0x00000080 /* cmd ready enable */
66 : #define TPM_INT_EDGE_FALLING 0x00000018
67 : #define TPM_INT_EDGE_RISING 0x00000010
68 : #define TPM_INT_LEVEL_LOW 0x00000008
69 : #define TPM_INT_LEVEL_HIGH 0x00000000
70 : #define TPM_LOCALITY_CHANGE_INT 0x00000004 /* locality change enable */
71 : #define TPM_STS_VALID_INT 0x00000002 /* int on TPM_STS_VALID is set */
72 : #define TPM_DATA_AVAIL_INT 0x00000001 /* int on TPM_STS_DATA_AVAIL is set */
73 : #define TPM_INTERRUPT_ENABLE_BITS \
74 : "\020\040ENA\010RDY\03LOCH\02STSV\01DRDY"
75 :
76 : #define TPM_INT_VECTOR 0x000c /* 8 bit reg for 4 bit irq vector */
77 : #define TPM_INT_STATUS 0x0010 /* bits are & 0x87 from TPM_INTERRUPT_ENABLE */
78 :
79 : #define TPM_INTF_CAPABILITIES 0x0014 /* capability register */
80 : #define TPM_INTF_BURST_COUNT_STATIC 0x0100 /* TPM_STS_BMASK static */
81 : #define TPM_INTF_CMD_READY_INT 0x0080 /* int on ready supported */
82 : #define TPM_INTF_INT_EDGE_FALLING 0x0040 /* falling edge ints supported */
83 : #define TPM_INTF_INT_EDGE_RISING 0x0020 /* rising edge ints supported */
84 : #define TPM_INTF_INT_LEVEL_LOW 0x0010 /* level-low ints supported */
85 : #define TPM_INTF_INT_LEVEL_HIGH 0x0008 /* level-high ints supported */
86 : #define TPM_INTF_LOCALITY_CHANGE_INT 0x0004 /* locality-change int (mb 1) */
87 : #define TPM_INTF_STS_VALID_INT 0x0002 /* TPM_STS_VALID int supported */
88 : #define TPM_INTF_DATA_AVAIL_INT 0x0001 /* TPM_STS_DATA_AVAIL int supported (mb 1) */
89 : #define TPM_CAPSREQ \
90 : (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT|TPM_INTF_INT_LEVEL_LOW)
91 : #define TPM_CAPBITS \
92 : "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IEDGE\07IFALL\010IRDY\011BCST"
93 :
94 : #define TPM_STS 0x0018 /* status register */
95 : #define TPM_STS_MASK 0x000000ff /* status bits */
96 : #define TPM_STS_BMASK 0x00ffff00 /* ro io burst size */
97 : #define TPM_STS_VALID 0x00000080 /* ro other bits are valid */
98 : #define TPM_STS_CMD_READY 0x00000040 /* rw chip/signal ready */
99 : #define TPM_STS_GO 0x00000020 /* wo start the command */
100 : #define TPM_STS_DATA_AVAIL 0x00000010 /* ro data available */
101 : #define TPM_STS_DATA_EXPECT 0x00000008 /* ro more data to be written */
102 : #define TPM_STS_RESP_RETRY 0x00000002 /* wo resend the response */
103 : #define TPM_STS_BITS "\020\010VALID\07RDY\06GO\05DRDY\04EXPECT\02RETRY"
104 :
105 : #define TPM_DATA 0x0024
106 : #define TPM_ID 0x0f00
107 : #define TPM_REV 0x0f04
108 : #define TPM_SIZE 0x5000 /* five pages of the above */
109 :
110 : #define TPM_ACCESS_TMO 2000 /* 2sec */
111 : #define TPM_READY_TMO 2000 /* 2sec */
112 : #define TPM_READ_TMO 120000 /* 2 minutes */
113 : #define TPM_BURST_TMO 2000 /* 2sec */
114 :
115 : struct tpm_softc {
116 : struct device sc_dev;
117 :
118 : bus_space_tag_t sc_bt;
119 : bus_space_handle_t sc_bh;
120 :
121 : struct acpi_softc *sc_acpi;
122 : struct aml_node *sc_devnode;
123 :
124 : uint32_t sc_devid;
125 : uint32_t sc_rev;
126 :
127 : int sc_enabled;
128 : };
129 :
130 : struct tpm_crs {
131 : int irq_int;
132 : uint8_t irq_flags;
133 : uint32_t addr_min;
134 : uint32_t addr_bas;
135 : uint32_t addr_len;
136 : uint16_t i2c_addr;
137 : struct aml_node *devnode;
138 : struct aml_node *gpio_int_node;
139 : uint16_t gpio_int_pin;
140 : uint16_t gpio_int_flags;
141 : };
142 :
143 : const struct {
144 : uint32_t devid;
145 : char name[32];
146 : } tpm_devs[] = {
147 : { 0x000615d1, "Infineon SLD9630 1.1" },
148 : { 0x000b15d1, "Infineon SLB9635 1.2" },
149 : { 0x100214e4, "Broadcom BCM0102" },
150 : { 0x00fe1050, "WEC WPCT200" },
151 : { 0x687119fa, "SNS SSX35" },
152 : { 0x2e4d5453, "STM ST19WP18" },
153 : { 0x32021114, "Atmel 97SC3203" },
154 : { 0x10408086, "Intel INTC0102" },
155 : { 0, "" },
156 : };
157 :
158 : int tpm_match(struct device *, void *, void *);
159 : void tpm_attach(struct device *, struct device *, void *);
160 : int tpm_activate(struct device *, int);
161 : int tpm_parse_crs(int, union acpi_resource *, void *);
162 :
163 : int tpm_probe(bus_space_tag_t, bus_space_handle_t);
164 : int tpm_init(struct tpm_softc *);
165 : int tpm_read(struct tpm_softc *, void *, int, size_t *, int);
166 : int tpm_write(struct tpm_softc *, void *, int);
167 : int tpm_suspend(struct tpm_softc *);
168 : int tpm_resume(struct tpm_softc *);
169 :
170 : int tpm_waitfor(struct tpm_softc *, uint8_t, int);
171 : int tpm_request_locality(struct tpm_softc *, int);
172 : void tpm_release_locality(struct tpm_softc *);
173 : int tpm_getburst(struct tpm_softc *);
174 : uint8_t tpm_status(struct tpm_softc *);
175 : int tpm_tmotohz(int);
176 :
177 : struct cfattach tpm_ca = {
178 : sizeof(struct tpm_softc),
179 : tpm_match,
180 : tpm_attach,
181 : NULL,
182 : tpm_activate
183 : };
184 :
185 : struct cfdriver tpm_cd = {
186 : NULL, "tpm", DV_DULL
187 : };
188 :
189 : const char *tpm_hids[] = {
190 : "PNP0C31",
191 : "ATM1200",
192 : "IFX0102",
193 : "BCM0101",
194 : "BCM0102",
195 : "NSC1200",
196 : "ICO0102",
197 : NULL
198 : };
199 :
200 : int
201 0 : tpm_match(struct device *parent, void *match, void *aux)
202 : {
203 0 : struct acpi_attach_args *aa = aux;
204 0 : struct cfdata *cf = match;
205 :
206 0 : return (acpi_matchhids(aa, tpm_hids, cf->cf_driver->cd_name));
207 : }
208 :
209 : void
210 0 : tpm_attach(struct device *parent, struct device *self, void *aux)
211 : {
212 0 : struct tpm_softc *sc = (struct tpm_softc *)self;
213 0 : struct acpi_attach_args *aa = aux;
214 0 : struct tpm_crs crs;
215 0 : struct aml_value res;
216 0 : int64_t st;
217 :
218 0 : sc->sc_acpi = (struct acpi_softc *)parent;
219 0 : sc->sc_devnode = aa->aaa_node;
220 0 : sc->sc_enabled = 0;
221 :
222 0 : printf(": %s", sc->sc_devnode->name);
223 :
224 0 : if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &st))
225 0 : st = STA_PRESENT | STA_ENABLED | STA_DEV_OK;
226 0 : if ((st & (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) !=
227 : (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) {
228 0 : printf(", not enabled\n");
229 0 : return;
230 : }
231 :
232 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
233 0 : printf(", no _CRS method\n");
234 0 : return;
235 : }
236 0 : if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
237 0 : printf(", invalid _CRS object (type %d len %d)\n",
238 0 : res.type, res.length);
239 0 : aml_freevalue(&res);
240 0 : return;
241 : }
242 0 : memset(&crs, 0, sizeof(crs));
243 0 : crs.devnode = sc->sc_devnode;
244 0 : aml_parse_resource(&res, tpm_parse_crs, &crs);
245 0 : aml_freevalue(&res);
246 :
247 0 : if (crs.addr_bas == 0) {
248 0 : printf(", can't find address\n");
249 0 : return;
250 : }
251 :
252 0 : printf(" addr 0x%x/0x%x", crs.addr_bas, crs.addr_len);
253 :
254 0 : sc->sc_bt = aa->aaa_memt;
255 0 : if (bus_space_map(sc->sc_bt, crs.addr_bas, crs.addr_len, 0,
256 0 : &sc->sc_bh)) {
257 0 : printf(", failed mapping at 0x%x\n", crs.addr_bas);
258 0 : return;
259 : }
260 :
261 0 : if (!tpm_probe(sc->sc_bt, sc->sc_bh)) {
262 0 : printf(", probe failed\n");
263 0 : return;
264 : }
265 :
266 0 : if (tpm_init(sc) != 0) {
267 0 : printf(", init failed\n");
268 0 : return;
269 : }
270 :
271 0 : sc->sc_enabled = 1;
272 0 : }
273 :
274 : int
275 0 : tpm_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
276 : {
277 0 : struct tpm_crs *sc_crs = arg;
278 :
279 0 : switch (AML_CRSTYPE(crs)) {
280 : case LR_MEM32:
281 0 : sc_crs->addr_min = letoh32(crs->lr_m32._min);
282 0 : sc_crs->addr_len = letoh32(crs->lr_m32._len);
283 0 : break;
284 :
285 : case LR_MEM32FIXED:
286 0 : sc_crs->addr_bas = letoh32(crs->lr_m32fixed._bas);
287 0 : sc_crs->addr_len = letoh32(crs->lr_m32fixed._len);
288 0 : break;
289 :
290 : case SR_IOPORT:
291 : case SR_IRQ:
292 : case LR_EXTIRQ:
293 : case LR_GPIO:
294 : break;
295 :
296 : default:
297 : DPRINTF(("%s: unknown resource type %d\n", __func__,
298 : AML_CRSTYPE(crs)));
299 : }
300 :
301 0 : return 0;
302 : }
303 :
304 : int
305 0 : tpm_activate(struct device *self, int act)
306 : {
307 0 : struct tpm_softc *sc = (struct tpm_softc *)self;
308 :
309 0 : switch (act) {
310 : case DVACT_SUSPEND:
311 0 : if (!sc->sc_enabled) {
312 : DPRINTF(("%s: suspend, but not enabled\n",
313 : sc->sc_dev.dv_xname));
314 0 : return 0;
315 : }
316 0 : tpm_suspend(sc);
317 0 : break;
318 :
319 : case DVACT_WAKEUP:
320 0 : if (!sc->sc_enabled) {
321 : DPRINTF(("%s: wakeup, but not enabled\n",
322 : sc->sc_dev.dv_xname));
323 0 : return 0;
324 : }
325 0 : tpm_resume(sc);
326 0 : break;
327 : }
328 :
329 0 : return 0;
330 0 : }
331 :
332 : int
333 0 : tpm_suspend(struct tpm_softc *sc)
334 : {
335 0 : uint8_t command[] = {
336 : 0, 0xc1, /* TPM_TAG_RQU_COMMAND */
337 : 0, 0, 0, 10, /* Length in bytes */
338 : 0, 0, 0, 0x98 /* TPM_ORD_SaveStates */
339 : };
340 :
341 : DPRINTF(("%s: saving state preparing for suspend\n",
342 : sc->sc_dev.dv_xname));
343 :
344 : /*
345 : * Tell the chip to save its state so the BIOS can then restore it upon
346 : * resume.
347 : */
348 0 : tpm_write(sc, &command, sizeof(command));
349 0 : tpm_read(sc, &command, sizeof(command), NULL, TPM_HDRSIZE);
350 :
351 0 : return 0;
352 0 : }
353 :
354 : int
355 0 : tpm_resume(struct tpm_softc *sc)
356 : {
357 : /*
358 : * TODO: The BIOS should have restored the chip's state for us already,
359 : * but we should tell the chip to do a self-test here (according to the
360 : * Linux driver).
361 : */
362 :
363 : DPRINTF(("%s: resume\n", sc->sc_dev.dv_xname));
364 0 : return 0;
365 : }
366 :
367 : int
368 0 : tpm_probe(bus_space_tag_t bt, bus_space_handle_t bh)
369 : {
370 : uint32_t r;
371 : int tries = 10000;
372 :
373 : /* wait for chip to settle */
374 0 : while (tries--) {
375 0 : if (bus_space_read_1(bt, bh, TPM_ACCESS) & TPM_ACCESS_VALID)
376 : break;
377 0 : else if (!tries) {
378 0 : printf(": timed out waiting for validity\n");
379 0 : return 1;
380 : }
381 :
382 0 : DELAY(10);
383 : }
384 :
385 0 : r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES);
386 0 : if (r == 0xffffffff)
387 0 : return 0;
388 :
389 0 : return 1;
390 0 : }
391 :
392 : int
393 0 : tpm_init(struct tpm_softc *sc)
394 : {
395 : uint32_t r, intmask;
396 : int i;
397 :
398 0 : r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTF_CAPABILITIES);
399 0 : if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
400 0 : !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
401 : DPRINTF((": caps too low (caps=%b)\n", r, TPM_CAPBITS));
402 0 : return 0;
403 : }
404 :
405 : /* ack and disable all interrupts, we'll be using polling only */
406 0 : intmask = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE);
407 0 : intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
408 : TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
409 0 : intmask &= ~TPM_GLOBAL_INT_ENABLE;
410 0 : bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, intmask);
411 :
412 0 : if (tpm_request_locality(sc, 0)) {
413 0 : printf(", requesting locality failed\n");
414 0 : return 1;
415 : }
416 :
417 0 : sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
418 0 : sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
419 :
420 0 : for (i = 0; tpm_devs[i].devid; i++)
421 0 : if (tpm_devs[i].devid == sc->sc_devid)
422 : break;
423 :
424 0 : if (tpm_devs[i].devid)
425 0 : printf(": %s rev 0x%x\n", tpm_devs[i].name, sc->sc_rev);
426 : else
427 0 : printf(": device 0x%08x rev 0x%x\n", sc->sc_devid, sc->sc_rev);
428 :
429 0 : return 0;
430 0 : }
431 :
432 : int
433 0 : tpm_request_locality(struct tpm_softc *sc, int l)
434 : {
435 : uint32_t r;
436 : int to;
437 :
438 0 : if (l != 0)
439 0 : return EINVAL;
440 :
441 0 : if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
442 0 : (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) ==
443 : (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
444 0 : return 0;
445 :
446 0 : bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
447 : TPM_ACCESS_REQUEST_USE);
448 :
449 0 : to = tpm_tmotohz(TPM_ACCESS_TMO);
450 :
451 0 : while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
452 0 : (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
453 0 : (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
454 0 : DELAY(10);
455 : }
456 :
457 0 : if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
458 : (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
459 : DPRINTF(("%s: %s: access %b\n", sc->sc_dev.dv_xname, __func__,
460 : r, TPM_ACCESS_BITS));
461 0 : return EBUSY;
462 : }
463 :
464 0 : return 0;
465 0 : }
466 :
467 : void
468 0 : tpm_release_locality(struct tpm_softc *sc)
469 : {
470 0 : if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
471 0 : (TPM_ACCESS_REQUEST_PENDING|TPM_ACCESS_VALID)) ==
472 : (TPM_ACCESS_REQUEST_PENDING|TPM_ACCESS_VALID)) {
473 : DPRINTF(("%s: releasing locality\n", sc->sc_dev.dv_xname));
474 0 : bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
475 : TPM_ACCESS_ACTIVE_LOCALITY);
476 0 : }
477 0 : }
478 :
479 : int
480 0 : tpm_getburst(struct tpm_softc *sc)
481 : {
482 : int burst, burst2, to;
483 :
484 0 : to = tpm_tmotohz(TPM_BURST_TMO);
485 :
486 : burst = 0;
487 0 : while (burst == 0 && to--) {
488 : /*
489 : * Burst count has to be read from bits 8 to 23 without
490 : * touching any other bits, eg. the actual status bits 0 to 7.
491 : */
492 0 : burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1);
493 : DPRINTF(("%s: %s: read1(0x%x): 0x%x\n", sc->sc_dev.dv_xname,
494 : __func__, TPM_STS + 1, burst));
495 0 : burst2 = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2);
496 : DPRINTF(("%s: %s: read1(0x%x): 0x%x\n", sc->sc_dev.dv_xname,
497 : __func__, TPM_STS + 2, burst2));
498 0 : burst |= burst2 << 8;
499 0 : if (burst)
500 0 : return burst;
501 :
502 0 : DELAY(10);
503 : }
504 :
505 : DPRINTF(("%s: getburst timed out\n", sc->sc_dev.dv_xname));
506 :
507 0 : return 0;
508 0 : }
509 :
510 : uint8_t
511 0 : tpm_status(struct tpm_softc *sc)
512 : {
513 0 : return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & TPM_STS_MASK;
514 : }
515 :
516 : int
517 0 : tpm_tmotohz(int tmo)
518 : {
519 0 : struct timeval tv;
520 :
521 0 : tv.tv_sec = tmo / 1000;
522 0 : tv.tv_usec = 1000 * (tmo % 1000);
523 :
524 0 : return tvtohz(&tv);
525 0 : }
526 :
527 : int
528 0 : tpm_waitfor(struct tpm_softc *sc, uint8_t mask, int tries)
529 : {
530 : uint8_t status;
531 :
532 0 : while (((status = tpm_status(sc)) & mask) != mask) {
533 0 : if (tries == 0) {
534 : DPRINTF(("%s: %s: timed out, status 0x%x != 0x%x\n",
535 : sc->sc_dev.dv_xname, __func__, status, mask));
536 0 : return status;
537 : }
538 :
539 0 : tries--;
540 0 : DELAY(1);
541 : }
542 :
543 0 : return 0;
544 0 : }
545 :
546 : int
547 0 : tpm_read(struct tpm_softc *sc, void *buf, int len, size_t *count,
548 : int flags)
549 : {
550 : uint8_t *p = buf;
551 : uint8_t c;
552 : size_t cnt;
553 : int rv, n, bcnt;
554 :
555 : DPRINTF(("%s: %s %d:", sc->sc_dev.dv_xname, __func__, len));
556 :
557 : cnt = 0;
558 0 : while (len > 0) {
559 0 : if ((rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
560 : TPM_READ_TMO)))
561 0 : return rv;
562 :
563 0 : bcnt = tpm_getburst(sc);
564 0 : n = MIN(len, bcnt);
565 :
566 0 : for (; n--; len--) {
567 0 : c = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA);
568 : DPRINTF((" %02x", c));
569 0 : *p++ = c;
570 0 : cnt++;
571 : }
572 :
573 0 : if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6)
574 : break;
575 : }
576 :
577 : DPRINTF(("\n"));
578 :
579 0 : if (count)
580 0 : *count = cnt;
581 :
582 0 : return 0;
583 0 : }
584 :
585 : int
586 0 : tpm_write(struct tpm_softc *sc, void *buf, int len)
587 : {
588 : uint8_t *p = buf;
589 : uint8_t status;
590 : size_t count = 0;
591 : int rv, r;
592 :
593 0 : if ((rv = tpm_request_locality(sc, 0)) != 0)
594 0 : return rv;
595 :
596 : DPRINTF(("%s: %s %d:", sc->sc_dev.dv_xname, __func__, len));
597 0 : for (r = 0; r < len; r++)
598 : DPRINTF((" %02x", (uint8_t)(*(p + r))));
599 : DPRINTF(("\n"));
600 :
601 : /* read status */
602 0 : status = tpm_status(sc);
603 0 : if ((status & TPM_STS_CMD_READY) == 0) {
604 : /* abort! */
605 0 : bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
606 : TPM_STS_CMD_READY);
607 0 : if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READ_TMO))) {
608 : DPRINTF(("%s: failed waiting for ready after abort "
609 : "(0x%x)\n", sc->sc_dev.dv_xname, rv));
610 0 : return rv;
611 : }
612 : }
613 :
614 0 : while (count < len - 1) {
615 0 : for (r = tpm_getburst(sc); r > 0 && count < len - 1; r--) {
616 : DPRINTF(("%s: %s: write1(0x%x, 0x%x)\n",
617 : sc->sc_dev.dv_xname, __func__, TPM_DATA, *p));
618 0 : bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++);
619 0 : count++;
620 : }
621 0 : if ((rv = tpm_waitfor(sc, TPM_STS_VALID | TPM_STS_DATA_EXPECT,
622 : TPM_READ_TMO))) {
623 : DPRINTF(("%s: %s: failed waiting for next byte (%d)\n",
624 : sc->sc_dev.dv_xname, __func__, rv));
625 0 : return rv;
626 : }
627 : }
628 :
629 : DPRINTF(("%s: %s: write1(0x%x, 0x%x)\n", sc->sc_dev.dv_xname, __func__,
630 : TPM_DATA, *p));
631 0 : bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p);
632 : count++;
633 :
634 0 : if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO))) {
635 : DPRINTF(("%s: %s: failed after last byte (%d)\n",
636 : sc->sc_dev.dv_xname, __func__, rv));
637 0 : return rv;
638 : }
639 :
640 0 : if ((status = tpm_status(sc)) & TPM_STS_DATA_EXPECT) {
641 : DPRINTF(("%s: %s: final status still expecting data: %b\n",
642 : sc->sc_dev.dv_xname, __func__, status, TPM_STS_BITS));
643 0 : return status;
644 : }
645 :
646 : DPRINTF(("%s: final status after write: %b\n", sc->sc_dev.dv_xname,
647 : status, TPM_STS_BITS));
648 :
649 : /* XXX: are we ever sending non-command data? */
650 0 : bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_GO);
651 :
652 0 : return 0;
653 0 : }
|