| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: tpm.c,v 1.15 2019/10/09 07:30:58 maxv Exp $ */ | | 1 | /* $NetBSD: tpm.c,v 1.16 2019/10/09 14:03:58 maxv Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2019 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2019 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Maxime Villard. | | 8 | * by Maxime Villard. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -38,27 +38,27 @@ | | | @@ -38,27 +38,27 @@ |
38 | * purpose with or without fee is hereby granted, provided that the above | | 38 | * purpose with or without fee is hereby granted, provided that the above |
39 | * copyright notice and this permission notice appear in all copies. | | 39 | * copyright notice and this permission notice appear in all copies. |
40 | * | | 40 | * |
41 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 41 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
42 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 42 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
43 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 43 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
44 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 44 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
45 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN | | 45 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN |
46 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | | 46 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
47 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 47 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
48 | */ | | 48 | */ |
49 | | | 49 | |
50 | #include <sys/cdefs.h> | | 50 | #include <sys/cdefs.h> |
51 | __KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.15 2019/10/09 07:30:58 maxv Exp $"); | | 51 | __KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.16 2019/10/09 14:03:58 maxv Exp $"); |
52 | | | 52 | |
53 | #include <sys/param.h> | | 53 | #include <sys/param.h> |
54 | #include <sys/systm.h> | | 54 | #include <sys/systm.h> |
55 | #include <sys/kernel.h> | | 55 | #include <sys/kernel.h> |
56 | #include <sys/malloc.h> | | 56 | #include <sys/malloc.h> |
57 | #include <sys/proc.h> | | 57 | #include <sys/proc.h> |
58 | #include <sys/device.h> | | 58 | #include <sys/device.h> |
59 | #include <sys/conf.h> | | 59 | #include <sys/conf.h> |
60 | #include <sys/bus.h> | | 60 | #include <sys/bus.h> |
61 | #include <sys/pmf.h> | | 61 | #include <sys/pmf.h> |
62 | | | 62 | |
63 | #include <dev/ic/tpmreg.h> | | 63 | #include <dev/ic/tpmreg.h> |
64 | #include <dev/ic/tpmvar.h> | | 64 | #include <dev/ic/tpmvar.h> |
| @@ -83,62 +83,26 @@ CTASSERT(sizeof(struct tpm_header) == 10 | | | @@ -83,62 +83,26 @@ CTASSERT(sizeof(struct tpm_header) == 10 |
83 | | | 83 | |
84 | static inline int | | 84 | static inline int |
85 | tpm_tmotohz(int tmo) | | 85 | tpm_tmotohz(int tmo) |
86 | { | | 86 | { |
87 | struct timeval tv; | | 87 | struct timeval tv; |
88 | | | 88 | |
89 | tv.tv_sec = tmo / 1000; | | 89 | tv.tv_sec = tmo / 1000; |
90 | tv.tv_usec = 1000 * (tmo % 1000); | | 90 | tv.tv_usec = 1000 * (tmo % 1000); |
91 | | | 91 | |
92 | return tvtohz(&tv); | | 92 | return tvtohz(&tv); |
93 | } | | 93 | } |
94 | | | 94 | |
95 | static int | | 95 | static int |
96 | tpm_request_locality(struct tpm_softc *sc, int l) | | | |
97 | { | | | |
98 | uint32_t r; | | | |
99 | int to, rv; | | | |
100 | | | | |
101 | if (l != 0) | | | |
102 | return EINVAL; | | | |
103 | | | | |
104 | if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) & | | | |
105 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) == | | | |
106 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) | | | |
107 | return 0; | | | |
108 | | | | |
109 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS, | | | |
110 | TPM_ACCESS_REQUEST_USE); | | | |
111 | | | | |
112 | to = tpm_tmotohz(TPM_ACCESS_TMO); | | | |
113 | | | | |
114 | while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) & | | | |
115 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != | | | |
116 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) { | | | |
117 | rv = tsleep(sc->sc_init, PCATCH, "tpm_locality", 1); | | | |
118 | if (rv && rv != EWOULDBLOCK) { | | | |
119 | return rv; | | | |
120 | } | | | |
121 | } | | | |
122 | | | | |
123 | if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != | | | |
124 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { | | | |
125 | return EBUSY; | | | |
126 | } | | | |
127 | | | | |
128 | return 0; | | | |
129 | } | | | |
130 | | | | |
131 | static int | | | |
132 | tpm_getburst(struct tpm_softc *sc) | | 96 | tpm_getburst(struct tpm_softc *sc) |
133 | { | | 97 | { |
134 | int burst, to, rv; | | 98 | int burst, to, rv; |
135 | | | 99 | |
136 | to = tpm_tmotohz(TPM_BURST_TMO); | | 100 | to = tpm_tmotohz(TPM_BURST_TMO); |
137 | | | 101 | |
138 | while (to--) { | | 102 | while (to--) { |
139 | /* | | 103 | /* |
140 | * Burst count is in bits 23:8, so read the two higher bytes. | | 104 | * Burst count is in bits 23:8, so read the two higher bytes. |
141 | */ | | 105 | */ |
142 | burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1); | | 106 | burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1); |
143 | burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2) | | 107 | burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2) |
144 | << 8; | | 108 | << 8; |
| @@ -164,50 +128,50 @@ tpm_status(struct tpm_softc *sc) | | | @@ -164,50 +128,50 @@ tpm_status(struct tpm_softc *sc) |
164 | | | 128 | |
165 | /* -------------------------------------------------------------------------- */ | | 129 | /* -------------------------------------------------------------------------- */ |
166 | | | 130 | |
167 | static bool | | 131 | static bool |
168 | tpm12_suspend(struct tpm_softc *sc) | | 132 | tpm12_suspend(struct tpm_softc *sc) |
169 | { | | 133 | { |
170 | static const uint8_t command[10] = { | | 134 | static const uint8_t command[10] = { |
171 | 0x00, 0xC1, /* TPM_TAG_RQU_COMMAND */ | | 135 | 0x00, 0xC1, /* TPM_TAG_RQU_COMMAND */ |
172 | 0x00, 0x00, 0x00, 10, /* Length in bytes */ | | 136 | 0x00, 0x00, 0x00, 10, /* Length in bytes */ |
173 | 0x00, 0x00, 0x00, 0x98 /* TPM_ORD_SaveState */ | | 137 | 0x00, 0x00, 0x00, 0x98 /* TPM_ORD_SaveState */ |
174 | }; | | 138 | }; |
175 | struct tpm_header response; | | 139 | struct tpm_header response; |
176 | | | 140 | |
177 | if ((*sc->sc_write)(sc, &command, sizeof(command)) != 0) | | 141 | if ((*sc->sc_intf->write)(sc, &command, sizeof(command)) != 0) |
178 | return false; | | 142 | return false; |
179 | if ((*sc->sc_read)(sc, &response, sizeof(response), NULL, 0) != 0) | | 143 | if ((*sc->sc_intf->read)(sc, &response, sizeof(response), NULL, 0) != 0) |
180 | return false; | | 144 | return false; |
181 | if (TPM_BE32(response.code) != 0) | | 145 | if (TPM_BE32(response.code) != 0) |
182 | return false; | | 146 | return false; |
183 | | | 147 | |
184 | return true; | | 148 | return true; |
185 | } | | 149 | } |
186 | | | 150 | |
187 | static bool | | 151 | static bool |
188 | tpm20_suspend(struct tpm_softc *sc) | | 152 | tpm20_suspend(struct tpm_softc *sc) |
189 | { | | 153 | { |
190 | static const uint8_t command[12] = { | | 154 | static const uint8_t command[12] = { |
191 | 0x80, 0x01, /* TPM_ST_NO_SESSIONS */ | | 155 | 0x80, 0x01, /* TPM_ST_NO_SESSIONS */ |
192 | 0x00, 0x00, 0x00, 12, /* Length in bytes */ | | 156 | 0x00, 0x00, 0x00, 12, /* Length in bytes */ |
193 | 0x00, 0x00, 0x01, 0x45, /* TPM_CC_Shutdown */ | | 157 | 0x00, 0x00, 0x01, 0x45, /* TPM_CC_Shutdown */ |
194 | 0x00, 0x01 /* TPM_SU_STATE */ | | 158 | 0x00, 0x01 /* TPM_SU_STATE */ |
195 | }; | | 159 | }; |
196 | struct tpm_header response; | | 160 | struct tpm_header response; |
197 | | | 161 | |
198 | if ((*sc->sc_write)(sc, &command, sizeof(command)) != 0) | | 162 | if ((*sc->sc_intf->write)(sc, &command, sizeof(command)) != 0) |
199 | return false; | | 163 | return false; |
200 | if ((*sc->sc_read)(sc, &response, sizeof(response), NULL, 0) != 0) | | 164 | if ((*sc->sc_intf->read)(sc, &response, sizeof(response), NULL, 0) != 0) |
201 | return false; | | 165 | return false; |
202 | if (TPM_BE32(response.code) != 0) | | 166 | if (TPM_BE32(response.code) != 0) |
203 | return false; | | 167 | return false; |
204 | | | 168 | |
205 | return true; | | 169 | return true; |
206 | } | | 170 | } |
207 | | | 171 | |
208 | bool | | 172 | bool |
209 | tpm_suspend(device_t dev, const pmf_qual_t *qual) | | 173 | tpm_suspend(device_t dev, const pmf_qual_t *qual) |
210 | { | | 174 | { |
211 | struct tpm_softc *sc = device_private(dev); | | 175 | struct tpm_softc *sc = device_private(dev); |
212 | | | 176 | |
213 | switch (sc->sc_ver) { | | 177 | switch (sc->sc_ver) { |
| @@ -276,154 +240,192 @@ restart: | | | @@ -276,154 +240,192 @@ restart: |
276 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, | | 240 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, |
277 | TPM_STS_RESP_RETRY); | | 241 | TPM_STS_RESP_RETRY); |
278 | goto restart; | | 242 | goto restart; |
279 | } | | 243 | } |
280 | return EIO; | | 244 | return EIO; |
281 | } | | 245 | } |
282 | | | 246 | |
283 | return 0; | | 247 | return 0; |
284 | } | | 248 | } |
285 | | | 249 | |
286 | /* -------------------------------------------------------------------------- */ | | 250 | /* -------------------------------------------------------------------------- */ |
287 | | | 251 | |
288 | /* | | 252 | /* |
289 | * TPM using TIS 1.2 interface. | | 253 | * TPM using the TIS 1.2 interface. |
290 | */ | | 254 | */ |
291 | | | 255 | |
292 | int | | 256 | static int |
| | | 257 | tpm12_request_locality(struct tpm_softc *sc, int l) |
| | | 258 | { |
| | | 259 | uint32_t r; |
| | | 260 | int to, rv; |
| | | 261 | |
| | | 262 | if (l != 0) |
| | | 263 | return EINVAL; |
| | | 264 | |
| | | 265 | if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) & |
| | | 266 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) == |
| | | 267 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) |
| | | 268 | return 0; |
| | | 269 | |
| | | 270 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS, |
| | | 271 | TPM_ACCESS_REQUEST_USE); |
| | | 272 | |
| | | 273 | to = tpm_tmotohz(TPM_ACCESS_TMO); |
| | | 274 | |
| | | 275 | while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) & |
| | | 276 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != |
| | | 277 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) { |
| | | 278 | rv = tsleep(sc->sc_intf->init, PCATCH, "tpm_locality", 1); |
| | | 279 | if (rv && rv != EWOULDBLOCK) { |
| | | 280 | return rv; |
| | | 281 | } |
| | | 282 | } |
| | | 283 | |
| | | 284 | if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != |
| | | 285 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { |
| | | 286 | return EBUSY; |
| | | 287 | } |
| | | 288 | |
| | | 289 | return 0; |
| | | 290 | } |
| | | 291 | |
| | | 292 | static int |
293 | tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh) | | 293 | tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh) |
294 | { | | 294 | { |
295 | uint32_t cap; | | 295 | uint32_t cap; |
296 | uint8_t reg; | | 296 | uint8_t reg; |
297 | int tmo; | | 297 | int tmo; |
298 | | | 298 | |
299 | cap = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITY); | | 299 | cap = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITY); |
300 | if (cap == 0xffffffff) | | 300 | if (cap == 0xffffffff) |
301 | return 0; | | 301 | return EINVAL; |
302 | if ((cap & TPM_CAPS_REQUIRED) != TPM_CAPS_REQUIRED) | | 302 | if ((cap & TPM_CAPS_REQUIRED) != TPM_CAPS_REQUIRED) |
303 | return 0; | | 303 | return ENOTSUP; |
304 | | | 304 | |
305 | /* Request locality 0. */ | | 305 | /* Request locality 0. */ |
306 | bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE); | | 306 | bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE); |
307 | | | 307 | |
308 | /* Wait for it to become active. */ | | 308 | /* Wait for it to become active. */ |
309 | tmo = TPM_ACCESS_TMO; /* Milliseconds. */ | | 309 | tmo = TPM_ACCESS_TMO; /* Milliseconds. */ |
310 | while ((reg = bus_space_read_1(bt, bh, TPM_ACCESS) & | | 310 | while ((reg = bus_space_read_1(bt, bh, TPM_ACCESS) & |
311 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != | | 311 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != |
312 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && tmo--) { | | 312 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && tmo--) { |
313 | DELAY(1000); /* 1 millisecond. */ | | 313 | DELAY(1000); /* 1 millisecond. */ |
314 | } | | 314 | } |
315 | if ((reg & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != | | 315 | if ((reg & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != |
316 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { | | 316 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { |
317 | return 0; | | 317 | return ETIMEDOUT; |
318 | } | | 318 | } |
319 | | | 319 | |
320 | if (bus_space_read_4(bt, bh, TPM_ID) == 0xffffffff) | | 320 | if (bus_space_read_4(bt, bh, TPM_ID) == 0xffffffff) |
321 | return 0; | | 321 | return EINVAL; |
322 | | | 322 | |
323 | return 1; | | 323 | return 0; |
324 | } | | 324 | } |
325 | | | 325 | |
326 | int | | 326 | static int |
327 | tpm_tis12_init(struct tpm_softc *sc) | | 327 | tpm_tis12_init(struct tpm_softc *sc) |
328 | { | | 328 | { |
| | | 329 | int rv; |
| | | 330 | |
329 | sc->sc_caps = bus_space_read_4(sc->sc_bt, sc->sc_bh, | | 331 | sc->sc_caps = bus_space_read_4(sc->sc_bt, sc->sc_bh, |
330 | TPM_INTF_CAPABILITY); | | 332 | TPM_INTF_CAPABILITY); |
331 | sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID); | | 333 | sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID); |
332 | sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV); | | 334 | sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV); |
333 | | | 335 | |
334 | aprint_normal_dev(sc->sc_dev, "device 0x%08x rev 0x%x\n", | | 336 | aprint_normal_dev(sc->sc_dev, "device 0x%08x rev 0x%x\n", |
335 | sc->sc_devid, sc->sc_rev); | | 337 | sc->sc_devid, sc->sc_rev); |
336 | | | 338 | |
337 | if (tpm_request_locality(sc, 0)) | | 339 | if ((rv = tpm12_request_locality(sc, 0)) != 0) |
338 | return 1; | | 340 | return rv; |
339 | | | 341 | |
340 | /* Abort whatever it thought it was doing. */ | | 342 | /* Abort whatever it thought it was doing. */ |
341 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); | | 343 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); |
342 | | | 344 | |
343 | return 0; | | 345 | return 0; |
344 | } | | 346 | } |
345 | | | 347 | |
346 | int | | 348 | static int |
347 | tpm_tis12_start(struct tpm_softc *sc, int rw) | | 349 | tpm_tis12_start(struct tpm_softc *sc, int rw) |
348 | { | | 350 | { |
349 | int rv; | | 351 | int rv; |
350 | | | 352 | |
351 | if (rw == UIO_READ) { | | 353 | if (rw == UIO_READ) { |
352 | rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, | | 354 | rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
353 | TPM_READ_TMO, sc->sc_read); | | 355 | TPM_READ_TMO, sc->sc_intf->read); |
354 | return rv; | | 356 | return rv; |
355 | } | | 357 | } |
356 | | | 358 | |
357 | /* Request the 0th locality. */ | | 359 | /* Request the 0th locality. */ |
358 | if ((rv = tpm_request_locality(sc, 0)) != 0) | | 360 | if ((rv = tpm12_request_locality(sc, 0)) != 0) |
359 | return rv; | | 361 | return rv; |
360 | | | 362 | |
361 | sc->sc_status = tpm_status(sc); | | 363 | sc->sc_status = tpm_status(sc); |
362 | if (sc->sc_status & TPM_STS_CMD_READY) | | 364 | if (sc->sc_status & TPM_STS_CMD_READY) |
363 | return 0; | | 365 | return 0; |
364 | | | 366 | |
365 | /* Abort previous and restart. */ | | 367 | /* Abort previous and restart. */ |
366 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); | | 368 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); |
367 | rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO, sc->sc_write); | | 369 | rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO, sc->sc_intf->write); |
368 | if (rv) | | 370 | if (rv) |
369 | return rv; | | 371 | return rv; |
370 | | | 372 | |
371 | return 0; | | 373 | return 0; |
372 | } | | 374 | } |
373 | | | 375 | |
374 | int | | 376 | static int |
375 | tpm_tis12_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count, | | 377 | tpm_tis12_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count, |
376 | int flags) | | 378 | int flags) |
377 | { | | 379 | { |
378 | uint8_t *p = buf; | | 380 | uint8_t *p = buf; |
379 | size_t cnt; | | 381 | size_t cnt; |
380 | int rv, n; | | 382 | int rv, n; |
381 | | | 383 | |
382 | cnt = 0; | | 384 | cnt = 0; |
383 | while (len > 0) { | | 385 | while (len > 0) { |
384 | rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, | | 386 | rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
385 | TPM_READ_TMO, sc->sc_read); | | 387 | TPM_READ_TMO, sc->sc_intf->read); |
386 | if (rv) | | 388 | if (rv) |
387 | return rv; | | 389 | return rv; |
388 | | | 390 | |
389 | n = MIN(len, tpm_getburst(sc)); | | 391 | n = MIN(len, tpm_getburst(sc)); |
390 | while (n > 0) { | | 392 | while (n > 0) { |
391 | *p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA); | | 393 | *p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA); |
392 | cnt++; | | 394 | cnt++; |
393 | len--; | | 395 | len--; |
394 | n--; | | 396 | n--; |
395 | } | | 397 | } |
396 | | | 398 | |
397 | if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6) | | 399 | if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6) |
398 | break; | | 400 | break; |
399 | } | | 401 | } |
400 | | | 402 | |
401 | if (count) | | 403 | if (count) |
402 | *count = cnt; | | 404 | *count = cnt; |
403 | | | 405 | |
404 | return 0; | | 406 | return 0; |
405 | } | | 407 | } |
406 | | | 408 | |
407 | int | | 409 | static int |
408 | tpm_tis12_write(struct tpm_softc *sc, const void *buf, size_t len) | | 410 | tpm_tis12_write(struct tpm_softc *sc, const void *buf, size_t len) |
409 | { | | 411 | { |
410 | const uint8_t *p = buf; | | 412 | const uint8_t *p = buf; |
411 | size_t cnt; | | 413 | size_t cnt; |
412 | int rv, r; | | 414 | int rv, r; |
413 | | | 415 | |
414 | if (len == 0) | | 416 | if (len == 0) |
415 | return 0; | | 417 | return 0; |
416 | if ((rv = tpm_request_locality(sc, 0)) != 0) | | 418 | if ((rv = tpm12_request_locality(sc, 0)) != 0) |
417 | return rv; | | 419 | return rv; |
418 | | | 420 | |
419 | cnt = 0; | | 421 | cnt = 0; |
420 | while (cnt < len - 1) { | | 422 | while (cnt < len - 1) { |
421 | for (r = tpm_getburst(sc); r > 0 && cnt < len - 1; r--) { | | 423 | for (r = tpm_getburst(sc); r > 0 && cnt < len - 1; r--) { |
422 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++); | | 424 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++); |
423 | cnt++; | | 425 | cnt++; |
424 | } | | 426 | } |
425 | if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { | | 427 | if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { |
426 | return rv; | | 428 | return rv; |
427 | } | | 429 | } |
428 | sc->sc_status = tpm_status(sc); | | 430 | sc->sc_status = tpm_status(sc); |
429 | if (!(sc->sc_status & TPM_STS_DATA_EXPECT)) { | | 431 | if (!(sc->sc_status & TPM_STS_DATA_EXPECT)) { |
| @@ -434,33 +436,33 @@ tpm_tis12_write(struct tpm_softc *sc, co | | | @@ -434,33 +436,33 @@ tpm_tis12_write(struct tpm_softc *sc, co |
434 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++); | | 436 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++); |
435 | cnt++; | | 437 | cnt++; |
436 | | | 438 | |
437 | if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { | | 439 | if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { |
438 | return rv; | | 440 | return rv; |
439 | } | | 441 | } |
440 | if ((sc->sc_status & TPM_STS_DATA_EXPECT) != 0) { | | 442 | if ((sc->sc_status & TPM_STS_DATA_EXPECT) != 0) { |
441 | return EIO; | | 443 | return EIO; |
442 | } | | 444 | } |
443 | | | 445 | |
444 | return 0; | | 446 | return 0; |
445 | } | | 447 | } |
446 | | | 448 | |
447 | int | | 449 | static int |
448 | tpm_tis12_end(struct tpm_softc *sc, int rw, int err) | | 450 | tpm_tis12_end(struct tpm_softc *sc, int rw, int err) |
449 | { | | 451 | { |
450 | int rv = 0; | | 452 | int rv = 0; |
451 | | | 453 | |
452 | if (rw == UIO_READ) { | | 454 | if (rw == UIO_READ) { |
453 | rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc->sc_read); | | 455 | rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc->sc_intf->read); |
454 | if (rv) | | 456 | if (rv) |
455 | return rv; | | 457 | return rv; |
456 | | | 458 | |
457 | /* Still more data? */ | | 459 | /* Still more data? */ |
458 | sc->sc_status = tpm_status(sc); | | 460 | sc->sc_status = tpm_status(sc); |
459 | if (!err && (sc->sc_status & TPM_STS_DATA_AVAIL)) { | | 461 | if (!err && (sc->sc_status & TPM_STS_DATA_AVAIL)) { |
460 | rv = EIO; | | 462 | rv = EIO; |
461 | } | | 463 | } |
462 | | | 464 | |
463 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, | | 465 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, |
464 | TPM_STS_CMD_READY); | | 466 | TPM_STS_CMD_READY); |
465 | | | 467 | |
466 | /* Release the 0th locality. */ | | 468 | /* Release the 0th locality. */ |
| @@ -470,26 +472,36 @@ tpm_tis12_end(struct tpm_softc *sc, int | | | @@ -470,26 +472,36 @@ tpm_tis12_end(struct tpm_softc *sc, int |
470 | /* Hungry for more? */ | | 472 | /* Hungry for more? */ |
471 | sc->sc_status = tpm_status(sc); | | 473 | sc->sc_status = tpm_status(sc); |
472 | if (!err && (sc->sc_status & TPM_STS_DATA_EXPECT)) { | | 474 | if (!err && (sc->sc_status & TPM_STS_DATA_EXPECT)) { |
473 | rv = EIO; | | 475 | rv = EIO; |
474 | } | | 476 | } |
475 | | | 477 | |
476 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, | | 478 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, |
477 | err ? TPM_STS_CMD_READY : TPM_STS_GO); | | 479 | err ? TPM_STS_CMD_READY : TPM_STS_GO); |
478 | } | | 480 | } |
479 | | | 481 | |
480 | return rv; | | 482 | return rv; |
481 | } | | 483 | } |
482 | | | 484 | |
| | | 485 | const struct tpm_intf tpm_intf_tis12 = { |
| | | 486 | .version = TIS_1_2, |
| | | 487 | .probe = tpm_tis12_probe, |
| | | 488 | .init = tpm_tis12_init, |
| | | 489 | .start = tpm_tis12_start, |
| | | 490 | .read = tpm_tis12_read, |
| | | 491 | .write = tpm_tis12_write, |
| | | 492 | .end = tpm_tis12_end |
| | | 493 | }; |
| | | 494 | |
483 | /* -------------------------------------------------------------------------- */ | | 495 | /* -------------------------------------------------------------------------- */ |
484 | | | 496 | |
485 | static dev_type_open(tpmopen); | | 497 | static dev_type_open(tpmopen); |
486 | static dev_type_close(tpmclose); | | 498 | static dev_type_close(tpmclose); |
487 | static dev_type_read(tpmread); | | 499 | static dev_type_read(tpmread); |
488 | static dev_type_write(tpmwrite); | | 500 | static dev_type_write(tpmwrite); |
489 | static dev_type_ioctl(tpmioctl); | | 501 | static dev_type_ioctl(tpmioctl); |
490 | | | 502 | |
491 | const struct cdevsw tpm_cdevsw = { | | 503 | const struct cdevsw tpm_cdevsw = { |
492 | .d_open = tpmopen, | | 504 | .d_open = tpmopen, |
493 | .d_close = tpmclose, | | 505 | .d_close = tpmclose, |
494 | .d_read = tpmread, | | 506 | .d_read = tpmread, |
495 | .d_write = tpmwrite, | | 507 | .d_write = tpmwrite, |
| @@ -545,104 +557,100 @@ tpmclose(dev_t dev, int flag, int mode, | | | @@ -545,104 +557,100 @@ tpmclose(dev_t dev, int flag, int mode, |
545 | | | 557 | |
546 | static int | | 558 | static int |
547 | tpmread(dev_t dev, struct uio *uio, int flags) | | 559 | tpmread(dev_t dev, struct uio *uio, int flags) |
548 | { | | 560 | { |
549 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); | | 561 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); |
550 | struct tpm_header hdr; | | 562 | struct tpm_header hdr; |
551 | uint8_t buf[TPM_BUFSIZ]; | | 563 | uint8_t buf[TPM_BUFSIZ]; |
552 | size_t cnt, len, n; | | 564 | size_t cnt, len, n; |
553 | int rv; | | 565 | int rv; |
554 | | | 566 | |
555 | if (sc == NULL) | | 567 | if (sc == NULL) |
556 | return ENXIO; | | 568 | return ENXIO; |
557 | | | 569 | |
558 | if ((rv = (*sc->sc_start)(sc, UIO_READ))) | | 570 | if ((rv = (*sc->sc_intf->start)(sc, UIO_READ))) |
559 | goto out; | | 571 | return rv; |
560 | | | 572 | |
561 | /* Get the header. */ | | 573 | /* Get the header. */ |
562 | if ((rv = (*sc->sc_read)(sc, &hdr, sizeof(hdr), &cnt, 0))) { | | 574 | if ((rv = (*sc->sc_intf->read)(sc, &hdr, sizeof(hdr), &cnt, 0))) { |
563 | (*sc->sc_end)(sc, UIO_READ, rv); | | | |
564 | goto out; | | 575 | goto out; |
565 | } | | 576 | } |
566 | len = TPM_BE32(hdr.length); | | 577 | len = TPM_BE32(hdr.length); |
567 | if (len > uio->uio_resid || len < cnt) { | | 578 | if (len > uio->uio_resid || len < cnt) { |
568 | rv = EIO; | | 579 | rv = EIO; |
569 | (*sc->sc_end)(sc, UIO_READ, rv); | | | |
570 | goto out; | | 580 | goto out; |
571 | } | | 581 | } |
572 | | | 582 | |
573 | /* Copy out the header. */ | | 583 | /* Copy out the header. */ |
574 | if ((rv = uiomove(&hdr, cnt, uio))) { | | 584 | if ((rv = uiomove(&hdr, cnt, uio))) { |
575 | (*sc->sc_end)(sc, UIO_READ, rv); | | | |
576 | goto out; | | 585 | goto out; |
577 | } | | 586 | } |
578 | | | 587 | |
579 | /* Process the rest. */ | | 588 | /* Process the rest. */ |
580 | len -= cnt; | | 589 | len -= cnt; |
581 | while (len > 0) { | | 590 | while (len > 0) { |
582 | n = MIN(sizeof(buf), len); | | 591 | n = MIN(sizeof(buf), len); |
583 | if ((rv = (*sc->sc_read)(sc, buf, n, NULL, TPM_PARAM_SIZE))) { | | 592 | if ((rv = (*sc->sc_intf->read)(sc, buf, n, NULL, TPM_PARAM_SIZE))) { |
584 | (*sc->sc_end)(sc, UIO_READ, rv); | | | |
585 | goto out; | | 593 | goto out; |
586 | } | | 594 | } |
587 | if ((rv = uiomove(buf, n, uio))) { | | 595 | if ((rv = uiomove(buf, n, uio))) { |
588 | (*sc->sc_end)(sc, UIO_READ, rv); | | | |
589 | goto out; | | 596 | goto out; |
590 | } | | 597 | } |
591 | len -= n; | | 598 | len -= n; |
592 | } | | 599 | } |
593 | | | 600 | |
594 | rv = (*sc->sc_end)(sc, UIO_READ, rv); | | | |
595 | out: | | 601 | out: |
| | | 602 | rv = (*sc->sc_intf->end)(sc, UIO_READ, rv); |
596 | return rv; | | 603 | return rv; |
597 | } | | 604 | } |
598 | | | 605 | |
599 | static int | | 606 | static int |
600 | tpmwrite(dev_t dev, struct uio *uio, int flags) | | 607 | tpmwrite(dev_t dev, struct uio *uio, int flags) |
601 | { | | 608 | { |
602 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); | | 609 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); |
603 | uint8_t buf[TPM_BUFSIZ]; | | 610 | uint8_t buf[TPM_BUFSIZ]; |
604 | int n, rv; | | 611 | int n, rv; |
605 | | | 612 | |
606 | if (sc == NULL) | | 613 | if (sc == NULL) |
607 | return ENXIO; | | 614 | return ENXIO; |
608 | | | 615 | |
609 | n = MIN(sizeof(buf), uio->uio_resid); | | 616 | n = MIN(sizeof(buf), uio->uio_resid); |
610 | if ((rv = uiomove(buf, n, uio))) { | | 617 | if ((rv = uiomove(buf, n, uio))) { |
611 | goto out; | | 618 | goto out; |
612 | } | | 619 | } |
613 | if ((rv = (*sc->sc_start)(sc, UIO_WRITE))) { | | 620 | if ((rv = (*sc->sc_intf->start)(sc, UIO_WRITE))) { |
614 | goto out; | | 621 | goto out; |
615 | } | | 622 | } |
616 | if ((rv = (*sc->sc_write)(sc, buf, n))) { | | 623 | if ((rv = (*sc->sc_intf->write)(sc, buf, n))) { |
617 | goto out; | | 624 | goto out; |
618 | } | | 625 | } |
619 | | | 626 | |
620 | rv = (*sc->sc_end)(sc, UIO_WRITE, rv); | | 627 | rv = (*sc->sc_intf->end)(sc, UIO_WRITE, rv); |
621 | out: | | 628 | out: |
622 | return rv; | | 629 | return rv; |
623 | } | | 630 | } |
624 | | | 631 | |
625 | static int | | 632 | static int |
626 | tpmioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) | | 633 | tpmioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) |
627 | { | | 634 | { |
628 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); | | 635 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); |
629 | struct tpm_ioc_getinfo *info; | | 636 | struct tpm_ioc_getinfo *info; |
630 | | | 637 | |
631 | if (sc == NULL) | | 638 | if (sc == NULL) |
632 | return ENXIO; | | 639 | return ENXIO; |
633 | | | 640 | |
634 | switch (cmd) { | | 641 | switch (cmd) { |
635 | case TPM_IOC_GETINFO: | | 642 | case TPM_IOC_GETINFO: |
636 | info = addr; | | 643 | info = addr; |
637 | info->api_version = TPM_API_VERSION; | | 644 | info->api_version = TPM_API_VERSION; |
638 | info->tpm_version = sc->sc_ver; | | 645 | info->tpm_version = sc->sc_ver; |
| | | 646 | info->itf_version = sc->sc_intf->version; |
639 | info->device_id = sc->sc_devid; | | 647 | info->device_id = sc->sc_devid; |
640 | info->device_rev = sc->sc_rev; | | 648 | info->device_rev = sc->sc_rev; |
641 | info->device_caps = sc->sc_caps; | | 649 | info->device_caps = sc->sc_caps; |
642 | return 0; | | 650 | return 0; |
643 | default: | | 651 | default: |
644 | break; | | 652 | break; |
645 | } | | 653 | } |
646 | | | 654 | |
647 | return ENOTTY; | | 655 | return ENOTTY; |
648 | } | | 656 | } |