| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $ */ | | 1 | /* $NetBSD: tpm.c,v 1.14 2019/10/08 18:43:02 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,74 +38,58 @@ | | | @@ -38,74 +38,58 @@ |
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.13 2019/06/22 12:57:41 maxv Exp $"); | | 51 | __KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.14 2019/10/08 18:43:02 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> |
65 | | | 65 | |
66 | #include "ioconf.h" | | 66 | #include "ioconf.h" |
67 | | | 67 | |
68 | #define TPM_BUFSIZ 1024 | | 68 | #define TPM_BUFSIZ 1024 |
69 | #define TPM_HDRSIZE 10 | | 69 | #define TPM_HDRSIZE 10 |
| | | 70 | |
70 | #define TPM_PARAM_SIZE 0x0001 /* that's a flag */ | | 71 | #define TPM_PARAM_SIZE 0x0001 /* that's a flag */ |
71 | | | 72 | |
72 | /* Timeouts. */ | | 73 | /* Timeouts. */ |
73 | #define TPM_ACCESS_TMO 2000 /* 2sec */ | | 74 | #define TPM_ACCESS_TMO 2000 /* 2sec */ |
74 | #define TPM_READY_TMO 2000 /* 2sec */ | | 75 | #define TPM_READY_TMO 2000 /* 2sec */ |
75 | #define TPM_READ_TMO 2000 /* 2sec */ | | 76 | #define TPM_READ_TMO 2000 /* 2sec */ |
76 | #define TPM_BURST_TMO 2000 /* 2sec */ | | 77 | #define TPM_BURST_TMO 2000 /* 2sec */ |
77 | | | 78 | |
78 | #define TPM_CAPS_REQUIRED \ | | 79 | #define TPM_CAPS_REQUIRED \ |
79 | (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT| \ | | 80 | (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT| \ |
80 | TPM_INTF_INT_LEVEL_LOW) | | 81 | TPM_INTF_INT_LEVEL_LOW) |
81 | | | 82 | |
82 | static const struct { | | | |
83 | uint32_t devid; | | | |
84 | const char *name; | | | |
85 | int flags; | | | |
86 | #define TPM_DEV_NOINTS 0x0001 | | | |
87 | } tpm_devs[] = { | | | |
88 | { 0x000615d1, "IFX SLD 9630 TT 1.1", 0 }, | | | |
89 | { 0x000b15d1, "IFX SLB 9635 TT 1.2", 0 }, | | | |
90 | { 0x100214e4, "Broadcom BCM0102", TPM_DEV_NOINTS }, | | | |
91 | { 0x00fe1050, "WEC WPCT200", 0 }, | | | |
92 | { 0x687119fa, "SNS SSX35", 0 }, | | | |
93 | { 0x2e4d5453, "STM ST19WP18", 0 }, | | | |
94 | { 0x32021114, "ATML 97SC3203", TPM_DEV_NOINTS }, | | | |
95 | { 0x10408086, "INTEL INTC0102", 0 }, | | | |
96 | { 0, "", TPM_DEV_NOINTS }, | | | |
97 | }; | | | |
98 | | | | |
99 | static inline int | | 83 | static inline int |
100 | tpm_tmotohz(int tmo) | | 84 | tpm_tmotohz(int tmo) |
101 | { | | 85 | { |
102 | struct timeval tv; | | 86 | struct timeval tv; |
103 | | | 87 | |
104 | tv.tv_sec = tmo / 1000; | | 88 | tv.tv_sec = tmo / 1000; |
105 | tv.tv_usec = 1000 * (tmo % 1000); | | 89 | tv.tv_usec = 1000 * (tmo % 1000); |
106 | | | 90 | |
107 | return tvtohz(&tv); | | 91 | return tvtohz(&tv); |
108 | } | | 92 | } |
109 | | | 93 | |
110 | static int | | 94 | static int |
111 | tpm_request_locality(struct tpm_softc *sc, int l) | | 95 | tpm_request_locality(struct tpm_softc *sc, int l) |
| @@ -119,27 +103,27 @@ tpm_request_locality(struct tpm_softc *s | | | @@ -119,27 +103,27 @@ tpm_request_locality(struct tpm_softc *s |
119 | if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) & | | 103 | if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) & |
120 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) == | | 104 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) == |
121 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) | | 105 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) |
122 | return 0; | | 106 | return 0; |
123 | | | 107 | |
124 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS, | | 108 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS, |
125 | TPM_ACCESS_REQUEST_USE); | | 109 | TPM_ACCESS_REQUEST_USE); |
126 | | | 110 | |
127 | to = tpm_tmotohz(TPM_ACCESS_TMO); | | 111 | to = tpm_tmotohz(TPM_ACCESS_TMO); |
128 | | | 112 | |
129 | while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) & | | 113 | while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) & |
130 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != | | 114 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != |
131 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) { | | 115 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) { |
132 | rv = tsleep(sc->sc_init, PRIBIO | PCATCH, "tpm_locality", 1); | | 116 | rv = tsleep(sc->sc_init, PCATCH, "tpm_locality", 1); |
133 | if (rv && rv != EWOULDBLOCK) { | | 117 | if (rv && rv != EWOULDBLOCK) { |
134 | return rv; | | 118 | return rv; |
135 | } | | 119 | } |
136 | } | | 120 | } |
137 | | | 121 | |
138 | if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != | | 122 | if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != |
139 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { | | 123 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { |
140 | return EBUSY; | | 124 | return EBUSY; |
141 | } | | 125 | } |
142 | | | 126 | |
143 | return 0; | | 127 | return 0; |
144 | } | | 128 | } |
145 | | | 129 | |
| @@ -151,27 +135,27 @@ tpm_getburst(struct tpm_softc *sc) | | | @@ -151,27 +135,27 @@ tpm_getburst(struct tpm_softc *sc) |
151 | to = tpm_tmotohz(TPM_BURST_TMO); | | 135 | to = tpm_tmotohz(TPM_BURST_TMO); |
152 | | | 136 | |
153 | while (to--) { | | 137 | while (to--) { |
154 | /* | | 138 | /* |
155 | * Burst count is in bits 23:8, so read the two higher bytes. | | 139 | * Burst count is in bits 23:8, so read the two higher bytes. |
156 | */ | | 140 | */ |
157 | burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1); | | 141 | burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1); |
158 | burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2) | | 142 | burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2) |
159 | << 8; | | 143 | << 8; |
160 | | | 144 | |
161 | if (burst) | | 145 | if (burst) |
162 | return burst; | | 146 | return burst; |
163 | | | 147 | |
164 | rv = tsleep(sc, PRIBIO | PCATCH, "tpm_getburst", 1); | | 148 | rv = tsleep(sc, PCATCH, "tpm_getburst", 1); |
165 | if (rv && rv != EWOULDBLOCK) { | | 149 | if (rv && rv != EWOULDBLOCK) { |
166 | return 0; | | 150 | return 0; |
167 | } | | 151 | } |
168 | } | | 152 | } |
169 | | | 153 | |
170 | return 0; | | 154 | return 0; |
171 | } | | 155 | } |
172 | | | 156 | |
173 | static inline uint8_t | | 157 | static inline uint8_t |
174 | tpm_status(struct tpm_softc *sc) | | 158 | tpm_status(struct tpm_softc *sc) |
175 | { | | 159 | { |
176 | return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & | | 160 | return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & |
177 | TPM_STS_STATUS_BITS; | | 161 | TPM_STS_STATUS_BITS; |
| @@ -179,353 +163,163 @@ tpm_status(struct tpm_softc *sc) | | | @@ -179,353 +163,163 @@ tpm_status(struct tpm_softc *sc) |
179 | | | 163 | |
180 | /* -------------------------------------------------------------------------- */ | | 164 | /* -------------------------------------------------------------------------- */ |
181 | | | 165 | |
182 | /* | | 166 | /* |
183 | * Save TPM state on suspend. On resume we don't do anything, since the BIOS | | 167 | * Save TPM state on suspend. On resume we don't do anything, since the BIOS |
184 | * is supposed to restore the previously saved state. | | 168 | * is supposed to restore the previously saved state. |
185 | */ | | 169 | */ |
186 | | | 170 | |
187 | bool | | 171 | bool |
188 | tpm12_suspend(device_t dev, const pmf_qual_t *qual) | | 172 | tpm12_suspend(device_t dev, const pmf_qual_t *qual) |
189 | { | | 173 | { |
190 | struct tpm_softc *sc = device_private(dev); | | 174 | struct tpm_softc *sc = device_private(dev); |
191 | static const uint8_t command[] = { | | 175 | static const uint8_t command[] = { |
192 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | | 176 | 0, 0xC1, /* TPM_TAG_RQU_COMMAND */ |
193 | 0, 0, 0, 10, /* Length in bytes */ | | 177 | 0, 0, 0, 10, /* Length in bytes */ |
194 | 0, 0, 0, 156 /* TPM_ORD_SaveStates */ | | 178 | 0, 0, 0, 0x98 /* TPM_ORD_SaveState */ |
195 | }; | | 179 | }; |
196 | uint8_t scratch[sizeof(command)]; | | 180 | uint8_t scratch[sizeof(command)]; |
197 | | | 181 | |
198 | (*sc->sc_write)(sc, &command, sizeof(command)); | | 182 | (*sc->sc_write)(sc, &command, sizeof(command)); |
199 | (*sc->sc_read)(sc, &scratch, sizeof(scratch), NULL, 0); | | 183 | (*sc->sc_read)(sc, &scratch, sizeof(scratch), NULL, 0); |
200 | | | 184 | |
201 | return true; | | 185 | return true; |
202 | } | | 186 | } |
203 | | | 187 | |
204 | bool | | 188 | bool |
205 | tpm12_resume(device_t dev, const pmf_qual_t *qual) | | 189 | tpm12_resume(device_t dev, const pmf_qual_t *qual) |
206 | { | | 190 | { |
207 | return true; | | 191 | return true; |
208 | } | | 192 | } |
209 | | | 193 | |
210 | /* -------------------------------------------------------------------------- */ | | 194 | /* -------------------------------------------------------------------------- */ |
211 | | | 195 | |
212 | /* | | | |
213 | * Wait for given status bits using polling. | | | |
214 | */ | | | |
215 | static int | | 196 | static int |
216 | tpm_waitfor_poll(struct tpm_softc *sc, uint8_t mask, int to, wchan_t chan) | | 197 | tpm_poll(struct tpm_softc *sc, uint8_t mask, int to, wchan_t chan) |
217 | { | | 198 | { |
218 | int rv; | | 199 | int rv; |
219 | | | 200 | |
220 | while (((sc->sc_status = tpm_status(sc)) & mask) != mask && to--) { | | 201 | while (((sc->sc_status = tpm_status(sc)) & mask) != mask && to--) { |
221 | rv = tsleep(chan, PRIBIO | PCATCH, "tpm_poll", 1); | | 202 | rv = tsleep(chan, PCATCH, "tpm_poll", 1); |
222 | if (rv && rv != EWOULDBLOCK) { | | 203 | if (rv && rv != EWOULDBLOCK) { |
223 | return rv; | | 204 | return rv; |
224 | } | | 205 | } |
225 | } | | 206 | } |
226 | | | 207 | |
227 | return 0; | | 208 | return 0; |
228 | } | | 209 | } |
229 | | | 210 | |
230 | /* | | | |
231 | * Wait for given status bits using interrupts. | | | |
232 | */ | | | |
233 | static int | | | |
234 | tpm_waitfor_int(struct tpm_softc *sc, uint8_t mask, int tmo, wchan_t chan, | | | |
235 | int inttype) | | | |
236 | { | | | |
237 | int rv, to; | | | |
238 | | | | |
239 | sc->sc_status = tpm_status(sc); | | | |
240 | if ((sc->sc_status & mask) == mask) | | | |
241 | return 0; | | | |
242 | | | | |
243 | /* | | | |
244 | * Enable interrupt on tpm chip. Note that interrupts on our | | | |
245 | * level (SPL_TTY) are disabled (see tpm{read,write} et al) and | | | |
246 | * will not be delivered to the cpu until we call tsleep(9) below. | | | |
247 | */ | | | |
248 | bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, | | | |
249 | bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) | | | | |
250 | inttype); | | | |
251 | bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, | | | |
252 | bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) | | | | |
253 | TPM_GLOBAL_INT_ENABLE); | | | |
254 | | | | |
255 | sc->sc_status = tpm_status(sc); | | | |
256 | if ((sc->sc_status & mask) == mask) { | | | |
257 | rv = 0; | | | |
258 | goto out; | | | |
259 | } | | | |
260 | | | | |
261 | to = tpm_tmotohz(tmo); | | | |
262 | | | | |
263 | /* | | | |
264 | * tsleep(9) enables interrupts on the cpu and returns after | | | |
265 | * wake up with interrupts disabled again. Note that interrupts | | | |
266 | * generated by the tpm chip while being at SPL_TTY are not lost | | | |
267 | * but held and delivered as soon as the cpu goes below SPL_TTY. | | | |
268 | */ | | | |
269 | rv = tsleep(chan, PRIBIO | PCATCH, "tpm_wait", to); | | | |
270 | | | | |
271 | sc->sc_status = tpm_status(sc); | | | |
272 | if ((sc->sc_status & mask) == mask) | | | |
273 | rv = 0; | | | |
274 | | | | |
275 | out: | | | |
276 | /* Disable interrupts on tpm chip again. */ | | | |
277 | bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, | | | |
278 | bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) & | | | |
279 | ~TPM_GLOBAL_INT_ENABLE); | | | |
280 | bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, | | | |
281 | bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) & | | | |
282 | ~inttype); | | | |
283 | | | | |
284 | return rv; | | | |
285 | } | | | |
286 | | | | |
287 | /* | | | |
288 | * Wait on given status bits, use interrupts where possible, otherwise poll. | | | |
289 | */ | | | |
290 | static int | | 211 | static int |
291 | tpm_waitfor(struct tpm_softc *sc, uint8_t bits, int tmo, wchan_t chan) | | 212 | tpm_waitfor(struct tpm_softc *sc, uint8_t bits, int tmo, wchan_t chan) |
292 | { | | 213 | { |
293 | int retry, to, rv; | | 214 | int retry, to, rv; |
294 | uint8_t todo; | | 215 | uint8_t todo; |
295 | | | 216 | |
296 | /* | | 217 | to = tpm_tmotohz(tmo); |
297 | * We use interrupts for TPM_STS_DATA_AVAIL and TPM_STS_VALID (if the | | | |
298 | * TPM chip supports them) as waiting for those can take really long. | | | |
299 | * The other TPM_STS* are not needed very often so we do not support | | | |
300 | * them. | | | |
301 | */ | | | |
302 | if (sc->sc_vector != -1) { | | | |
303 | todo = bits; | | | |
304 | | | | |
305 | /* | | | |
306 | * Wait for data ready. This interrupt only occurs when both | | | |
307 | * TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted. Thus we | | | |
308 | * don't have to bother with TPM_STS_VALID separately and can | | | |
309 | * just return. | | | |
310 | * | | | |
311 | * This only holds for interrupts! When using polling both | | | |
312 | * flags have to be waited for, see below. | | | |
313 | */ | | | |
314 | if ((bits & TPM_STS_DATA_AVAIL) && | | | |
315 | (sc->sc_capabilities & TPM_INTF_DATA_AVAIL_INT)) | | | |
316 | return tpm_waitfor_int(sc, bits, tmo, chan, | | | |
317 | TPM_DATA_AVAIL_INT); | | | |
318 | | | | |
319 | /* Wait for status valid bit. */ | | | |
320 | if ((bits & TPM_STS_VALID) && | | | |
321 | (sc->sc_capabilities & TPM_INTF_STS_VALID_INT)) { | | | |
322 | rv = tpm_waitfor_int(sc, bits, tmo, chan, | | | |
323 | TPM_STS_VALID_INT); | | | |
324 | if (rv) | | | |
325 | return rv; | | | |
326 | todo = bits & ~TPM_STS_VALID; | | | |
327 | } | | | |
328 | | | | |
329 | /* | | | |
330 | * When all flags have been taken care of, return. Otherwise | | | |
331 | * use polling for eg TPM_STS_CMD_READY. | | | |
332 | */ | | | |
333 | if (todo == 0) | | | |
334 | return 0; | | | |
335 | } | | | |
336 | | | | |
337 | retry = 3; | | 218 | retry = 3; |
338 | | | 219 | |
339 | restart: | | 220 | restart: |
340 | /* | | | |
341 | * If requested, wait for TPM_STS_VALID before dealing with any other | | | |
342 | * flag. Eg when both TPM_STS_DATA_AVAIL and TPM_STS_VALID are | | | |
343 | * requested, wait for the latter first. | | | |
344 | */ | | | |
345 | todo = bits; | | 221 | todo = bits; |
346 | if (bits & TPM_STS_VALID) | | | |
347 | todo = TPM_STS_VALID; | | | |
348 | to = tpm_tmotohz(tmo); | | | |
349 | again: | | | |
350 | if ((rv = tpm_waitfor_poll(sc, todo, to, chan)) != 0) | | | |
351 | return rv; | | | |
352 | | | 222 | |
353 | if ((todo & sc->sc_status) == TPM_STS_VALID) { | | 223 | /* |
354 | /* Now wait for other flags. */ | | 224 | * TPM_STS_VALID has priority over the others. |
355 | todo = bits & ~TPM_STS_VALID; | | 225 | */ |
356 | to++; | | 226 | if (todo & TPM_STS_VALID) { |
357 | goto again; | | 227 | if ((rv = tpm_poll(sc, TPM_STS_VALID, to+1, chan)) != 0) |
| | | 228 | return rv; |
| | | 229 | todo &= ~TPM_STS_VALID; |
358 | } | | 230 | } |
359 | | | 231 | |
| | | 232 | if ((rv = tpm_poll(sc, todo, to, chan)) != 0) |
| | | 233 | return rv; |
| | | 234 | |
360 | if ((todo & sc->sc_status) != todo) { | | 235 | if ((todo & sc->sc_status) != todo) { |
361 | if (retry-- && (bits & TPM_STS_VALID)) { | | 236 | if ((retry-- > 0) && (bits & TPM_STS_VALID)) { |
362 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, | | 237 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, |
363 | TPM_STS_RESP_RETRY); | | 238 | TPM_STS_RESP_RETRY); |
364 | goto restart; | | 239 | goto restart; |
365 | } | | 240 | } |
366 | return EIO; | | 241 | return EIO; |
367 | } | | 242 | } |
368 | | | 243 | |
369 | return 0; | | 244 | return 0; |
370 | } | | 245 | } |
371 | | | 246 | |
372 | int | | | |
373 | tpm_intr(void *v) | | | |
374 | { | | | |
375 | struct tpm_softc *sc = v; | | | |
376 | uint32_t reg; | | | |
377 | | | | |
378 | reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS); | | | |
379 | if (!(reg & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT | | | | |
380 | TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT))) | | | |
381 | return 0; | | | |
382 | | | | |
383 | if (reg & TPM_STS_VALID_INT) | | | |
384 | wakeup(sc); | | | |
385 | if (reg & TPM_CMD_READY_INT) | | | |
386 | wakeup(sc->sc_write); | | | |
387 | if (reg & TPM_DATA_AVAIL_INT) | | | |
388 | wakeup(sc->sc_read); | | | |
389 | if (reg & TPM_LOCALITY_CHANGE_INT) | | | |
390 | wakeup(sc->sc_init); | | | |
391 | | | | |
392 | bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, reg); | | | |
393 | | | | |
394 | return 1; | | | |
395 | } | | | |
396 | | | | |
397 | /* -------------------------------------------------------------------------- */ | | 247 | /* -------------------------------------------------------------------------- */ |
398 | | | 248 | |
399 | /* | | 249 | /* |
400 | * TPM using TIS 1.2 interface. | | 250 | * TPM using TIS 1.2 interface. |
401 | */ | | 251 | */ |
402 | | | 252 | |
403 | int | | 253 | int |
404 | tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh) | | 254 | tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh) |
405 | { | | 255 | { |
406 | uint32_t cap; | | 256 | uint32_t cap; |
407 | uint8_t reg; | | 257 | uint8_t reg; |
408 | int tmo; | | 258 | int tmo; |
409 | | | 259 | |
410 | cap = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITY); | | 260 | cap = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITY); |
411 | if (cap == 0xffffffff) | | 261 | if (cap == 0xffffffff) |
412 | return 0; | | 262 | return 0; |
413 | if ((cap & TPM_CAPS_REQUIRED) != TPM_CAPS_REQUIRED) | | 263 | if ((cap & TPM_CAPS_REQUIRED) != TPM_CAPS_REQUIRED) |
414 | return 0; | | 264 | return 0; |
415 | if (!(cap & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) | | | |
416 | return 0; | | | |
417 | | | 265 | |
418 | /* Request locality 0. */ | | 266 | /* Request locality 0. */ |
419 | bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE); | | 267 | bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE); |
420 | | | 268 | |
421 | /* Wait for it to become active. */ | | 269 | /* Wait for it to become active. */ |
422 | tmo = TPM_ACCESS_TMO; /* Milliseconds. */ | | 270 | tmo = TPM_ACCESS_TMO; /* Milliseconds. */ |
423 | while ((reg = bus_space_read_1(bt, bh, TPM_ACCESS) & | | 271 | while ((reg = bus_space_read_1(bt, bh, TPM_ACCESS) & |
424 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != | | 272 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != |
425 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && tmo--) { | | 273 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && tmo--) { |
426 | DELAY(1000); /* 1 millisecond. */ | | 274 | DELAY(1000); /* 1 millisecond. */ |
427 | } | | 275 | } |
428 | if ((reg & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != | | 276 | if ((reg & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != |
429 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { | | 277 | (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { |
430 | return 0; | | 278 | return 0; |
431 | } | | 279 | } |
432 | | | 280 | |
433 | if (bus_space_read_4(bt, bh, TPM_ID) == 0xffffffff) | | 281 | if (bus_space_read_4(bt, bh, TPM_ID) == 0xffffffff) |
434 | return 0; | | 282 | return 0; |
435 | | | 283 | |
436 | return 1; | | 284 | return 1; |
437 | } | | 285 | } |
438 | | | 286 | |
439 | static int | | | |
440 | tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx) | | | |
441 | { | | | |
442 | uint32_t reg; | | | |
443 | | | | |
444 | if ((irq == -1) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) { | | | |
445 | sc->sc_vector = -1; | | | |
446 | return 0; | | | |
447 | } | | | |
448 | | | | |
449 | /* Ack and disable all interrupts. */ | | | |
450 | reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE); | | | |
451 | bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, | | | |
452 | reg & ~TPM_GLOBAL_INT_ENABLE); | | | |
453 | bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, | | | |
454 | bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS)); | | | |
455 | | | | |
456 | /* Program interrupt vector. */ | | | |
457 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq); | | | |
458 | sc->sc_vector = irq; | | | |
459 | | | | |
460 | /* Program interrupt type. */ | | | |
461 | reg &= ~(TPM_INT_EDGE_RISING|TPM_INT_EDGE_FALLING|TPM_INT_LEVEL_HIGH| | | | |
462 | TPM_INT_LEVEL_LOW); | | | |
463 | reg |= TPM_GLOBAL_INT_ENABLE|TPM_CMD_READY_INT|TPM_LOCALITY_CHANGE_INT| | | | |
464 | TPM_STS_VALID_INT|TPM_DATA_AVAIL_INT; | | | |
465 | if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING) | | | |
466 | reg |= TPM_INT_EDGE_RISING; | | | |
467 | else if (sc->sc_capabilities & TPM_INTF_INT_EDGE_FALLING) | | | |
468 | reg |= TPM_INT_EDGE_FALLING; | | | |
469 | else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH) | | | |
470 | reg |= TPM_INT_LEVEL_HIGH; | | | |
471 | else | | | |
472 | reg |= TPM_INT_LEVEL_LOW; | | | |
473 | | | | |
474 | bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, reg); | | | |
475 | | | | |
476 | return 0; | | | |
477 | } | | | |
478 | | | | |
479 | int | | 287 | int |
480 | tpm_tis12_init(struct tpm_softc *sc, int irq) | | 288 | tpm_tis12_init(struct tpm_softc *sc) |
481 | { | | 289 | { |
482 | int i; | | 290 | sc->sc_caps = bus_space_read_4(sc->sc_bt, sc->sc_bh, |
483 | | | | |
484 | sc->sc_capabilities = bus_space_read_4(sc->sc_bt, sc->sc_bh, | | | |
485 | TPM_INTF_CAPABILITY); | | 291 | TPM_INTF_CAPABILITY); |
486 | sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID); | | 292 | sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID); |
487 | sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV); | | 293 | sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV); |
488 | | | 294 | |
489 | for (i = 0; tpm_devs[i].devid; i++) { | | 295 | aprint_normal_dev(sc->sc_dev, "device 0x%08x rev 0x%x\n", |
490 | if (tpm_devs[i].devid == sc->sc_devid) | | 296 | sc->sc_devid, sc->sc_rev); |
491 | break; | | | |
492 | } | | | |
493 | | | | |
494 | if (tpm_devs[i].devid) | | | |
495 | aprint_normal_dev(sc->sc_dev, "%s rev 0x%x\n", | | | |
496 | tpm_devs[i].name, sc->sc_rev); | | | |
497 | else | | | |
498 | aprint_normal_dev(sc->sc_dev, "device 0x%08x rev 0x%x\n", | | | |
499 | sc->sc_devid, sc->sc_rev); | | | |
500 | | | | |
501 | if (tpm_tis12_irqinit(sc, irq, i)) | | | |
502 | return 1; | | | |
503 | | | 297 | |
504 | if (tpm_request_locality(sc, 0)) | | 298 | if (tpm_request_locality(sc, 0)) |
505 | return 1; | | 299 | return 1; |
506 | | | 300 | |
507 | /* Abort whatever it thought it was doing. */ | | 301 | /* Abort whatever it thought it was doing. */ |
508 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); | | 302 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); |
509 | | | 303 | |
510 | return 0; | | 304 | return 0; |
511 | } | | 305 | } |
512 | | | 306 | |
513 | int | | 307 | int |
514 | tpm_tis12_start(struct tpm_softc *sc, int flag) | | 308 | tpm_tis12_start(struct tpm_softc *sc, int rw) |
515 | { | | 309 | { |
516 | int rv; | | 310 | int rv; |
517 | | | 311 | |
518 | if (flag == UIO_READ) { | | 312 | if (rw == UIO_READ) { |
519 | rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, | | 313 | rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
520 | TPM_READ_TMO, sc->sc_read); | | 314 | TPM_READ_TMO, sc->sc_read); |
521 | return rv; | | 315 | return rv; |
522 | } | | 316 | } |
523 | | | 317 | |
524 | /* Request the 0th locality. */ | | 318 | /* Request the 0th locality. */ |
525 | if ((rv = tpm_request_locality(sc, 0)) != 0) | | 319 | if ((rv = tpm_request_locality(sc, 0)) != 0) |
526 | return rv; | | 320 | return rv; |
527 | | | 321 | |
528 | sc->sc_status = tpm_status(sc); | | 322 | sc->sc_status = tpm_status(sc); |
529 | if (sc->sc_status & TPM_STS_CMD_READY) | | 323 | if (sc->sc_status & TPM_STS_CMD_READY) |
530 | return 0; | | 324 | return 0; |
531 | | | 325 | |
| @@ -534,41 +328,41 @@ tpm_tis12_start(struct tpm_softc *sc, in | | | @@ -534,41 +328,41 @@ tpm_tis12_start(struct tpm_softc *sc, in |
534 | rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO, sc->sc_write); | | 328 | rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO, sc->sc_write); |
535 | if (rv) | | 329 | if (rv) |
536 | return rv; | | 330 | return rv; |
537 | | | 331 | |
538 | return 0; | | 332 | return 0; |
539 | } | | 333 | } |
540 | | | 334 | |
541 | int | | 335 | int |
542 | tpm_tis12_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count, | | 336 | tpm_tis12_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count, |
543 | int flags) | | 337 | int flags) |
544 | { | | 338 | { |
545 | uint8_t *p = buf; | | 339 | uint8_t *p = buf; |
546 | size_t cnt; | | 340 | size_t cnt; |
547 | int rv, n, bcnt; | | 341 | int rv, n; |
548 | | | 342 | |
549 | cnt = 0; | | 343 | cnt = 0; |
550 | while (len > 0) { | | 344 | while (len > 0) { |
551 | rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, | | 345 | rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
552 | TPM_READ_TMO, sc->sc_read); | | 346 | TPM_READ_TMO, sc->sc_read); |
553 | if (rv) | | 347 | if (rv) |
554 | return rv; | | 348 | return rv; |
555 | | | 349 | |
556 | bcnt = tpm_getburst(sc); | | 350 | n = MIN(len, tpm_getburst(sc)); |
557 | n = MIN(len, bcnt); | | 351 | while (n > 0) { |
558 | | | | |
559 | for (; n--; len--) { | | | |
560 | *p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA); | | 352 | *p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA); |
561 | cnt++; | | 353 | cnt++; |
| | | 354 | len--; |
| | | 355 | n--; |
562 | } | | 356 | } |
563 | | | 357 | |
564 | if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6) | | 358 | if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6) |
565 | break; | | 359 | break; |
566 | } | | 360 | } |
567 | | | 361 | |
568 | if (count) | | 362 | if (count) |
569 | *count = cnt; | | 363 | *count = cnt; |
570 | | | 364 | |
571 | return 0; | | 365 | return 0; |
572 | } | | 366 | } |
573 | | | 367 | |
574 | int | | 368 | int |
| @@ -602,39 +396,38 @@ tpm_tis12_write(struct tpm_softc *sc, co | | | @@ -602,39 +396,38 @@ tpm_tis12_write(struct tpm_softc *sc, co |
602 | cnt++; | | 396 | cnt++; |
603 | | | 397 | |
604 | if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { | | 398 | if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { |
605 | return rv; | | 399 | return rv; |
606 | } | | 400 | } |
607 | if ((sc->sc_status & TPM_STS_DATA_EXPECT) != 0) { | | 401 | if ((sc->sc_status & TPM_STS_DATA_EXPECT) != 0) { |
608 | return EIO; | | 402 | return EIO; |
609 | } | | 403 | } |
610 | | | 404 | |
611 | return 0; | | 405 | return 0; |
612 | } | | 406 | } |
613 | | | 407 | |
614 | int | | 408 | int |
615 | tpm_tis12_end(struct tpm_softc *sc, int flag, int err) | | 409 | tpm_tis12_end(struct tpm_softc *sc, int rw, int err) |
616 | { | | 410 | { |
617 | int rv = 0; | | 411 | int rv = 0; |
618 | | | 412 | |
619 | if (flag == UIO_READ) { | | 413 | if (rw == UIO_READ) { |
620 | rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc->sc_read); | | 414 | rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc->sc_read); |
621 | if (rv) | | 415 | if (rv) |
622 | return rv; | | 416 | return rv; |
623 | | | 417 | |
624 | /* Still more data? */ | | 418 | /* Still more data? */ |
625 | sc->sc_status = tpm_status(sc); | | 419 | sc->sc_status = tpm_status(sc); |
626 | if (!err && ((sc->sc_status & TPM_STS_DATA_AVAIL) == | | 420 | if (!err && (sc->sc_status & TPM_STS_DATA_AVAIL)) { |
627 | TPM_STS_DATA_AVAIL)) { | | | |
628 | rv = EIO; | | 421 | rv = EIO; |
629 | } | | 422 | } |
630 | | | 423 | |
631 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, | | 424 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, |
632 | TPM_STS_CMD_READY); | | 425 | TPM_STS_CMD_READY); |
633 | | | 426 | |
634 | /* Release the 0th locality. */ | | 427 | /* Release the 0th locality. */ |
635 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS, | | 428 | bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS, |
636 | TPM_ACCESS_ACTIVE_LOCALITY); | | 429 | TPM_ACCESS_ACTIVE_LOCALITY); |
637 | } else { | | 430 | } else { |
638 | /* Hungry for more? */ | | 431 | /* Hungry for more? */ |
639 | sc->sc_status = tpm_status(sc); | | 432 | sc->sc_status = tpm_status(sc); |
640 | if (!err && (sc->sc_status & TPM_STS_DATA_EXPECT)) { | | 433 | if (!err && (sc->sc_status & TPM_STS_DATA_EXPECT)) { |
| @@ -658,155 +451,158 @@ static dev_type_ioctl(tpmioctl); | | | @@ -658,155 +451,158 @@ static dev_type_ioctl(tpmioctl); |
658 | | | 451 | |
659 | const struct cdevsw tpm_cdevsw = { | | 452 | const struct cdevsw tpm_cdevsw = { |
660 | .d_open = tpmopen, | | 453 | .d_open = tpmopen, |
661 | .d_close = tpmclose, | | 454 | .d_close = tpmclose, |
662 | .d_read = tpmread, | | 455 | .d_read = tpmread, |
663 | .d_write = tpmwrite, | | 456 | .d_write = tpmwrite, |
664 | .d_ioctl = tpmioctl, | | 457 | .d_ioctl = tpmioctl, |
665 | .d_stop = nostop, | | 458 | .d_stop = nostop, |
666 | .d_tty = notty, | | 459 | .d_tty = notty, |
667 | .d_poll = nopoll, | | 460 | .d_poll = nopoll, |
668 | .d_mmap = nommap, | | 461 | .d_mmap = nommap, |
669 | .d_kqfilter = nokqfilter, | | 462 | .d_kqfilter = nokqfilter, |
670 | .d_discard = nodiscard, | | 463 | .d_discard = nodiscard, |
671 | .d_flag = D_OTHER, | | 464 | .d_flag = D_OTHER | D_MPSAFE, |
672 | }; | | 465 | }; |
673 | | | 466 | |
674 | #define TPMUNIT(a) minor(a) | | | |
675 | | | | |
676 | static int | | 467 | static int |
677 | tpmopen(dev_t dev, int flag, int mode, struct lwp *l) | | 468 | tpmopen(dev_t dev, int flag, int mode, struct lwp *l) |
678 | { | | 469 | { |
679 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev)); | | 470 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); |
| | | 471 | int ret = 0; |
680 | | | 472 | |
681 | if (sc == NULL) | | 473 | if (sc == NULL) |
682 | return ENXIO; | | 474 | return ENXIO; |
683 | if (sc->sc_flags & TPM_OPEN) | | | |
684 | return EBUSY; | | | |
685 | | | 475 | |
686 | sc->sc_flags |= TPM_OPEN; | | 476 | mutex_enter(&sc->sc_lock); |
| | | 477 | if (sc->sc_busy) { |
| | | 478 | ret = EBUSY; |
| | | 479 | } else { |
| | | 480 | sc->sc_busy = true; |
| | | 481 | } |
| | | 482 | mutex_exit(&sc->sc_lock); |
687 | | | 483 | |
688 | return 0; | | 484 | return ret; |
689 | } | | 485 | } |
690 | | | 486 | |
691 | static int | | 487 | static int |
692 | tpmclose(dev_t dev, int flag, int mode, struct lwp *l) | | 488 | tpmclose(dev_t dev, int flag, int mode, struct lwp *l) |
693 | { | | 489 | { |
694 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev)); | | 490 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); |
| | | 491 | int ret = 0; |
695 | | | 492 | |
696 | if (sc == NULL) | | 493 | if (sc == NULL) |
697 | return ENXIO; | | 494 | return ENXIO; |
698 | if (!(sc->sc_flags & TPM_OPEN)) | | | |
699 | return EINVAL; | | | |
700 | | | 495 | |
701 | sc->sc_flags &= ~TPM_OPEN; | | 496 | mutex_enter(&sc->sc_lock); |
| | | 497 | if (!sc->sc_busy) { |
| | | 498 | ret = EINVAL; |
| | | 499 | } else { |
| | | 500 | sc->sc_busy = false; |
| | | 501 | } |
| | | 502 | mutex_exit(&sc->sc_lock); |
702 | | | 503 | |
703 | return 0; | | 504 | return ret; |
704 | } | | 505 | } |
705 | | | 506 | |
706 | static int | | 507 | static int |
707 | tpmread(dev_t dev, struct uio *uio, int flags) | | 508 | tpmread(dev_t dev, struct uio *uio, int flags) |
708 | { | | 509 | { |
709 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev)); | | 510 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); |
710 | uint8_t buf[TPM_BUFSIZ], *p; | | 511 | uint8_t buf[TPM_BUFSIZ]; |
711 | size_t cnt, len, n; | | 512 | size_t cnt, len, n; |
712 | int rv, s; | | 513 | int rv; |
713 | | | 514 | |
714 | if (sc == NULL) | | 515 | if (sc == NULL) |
715 | return ENXIO; | | 516 | return ENXIO; |
716 | | | 517 | |
717 | s = spltty(); | | | |
718 | if ((rv = (*sc->sc_start)(sc, UIO_READ))) | | 518 | if ((rv = (*sc->sc_start)(sc, UIO_READ))) |
719 | goto out; | | 519 | goto out; |
720 | | | 520 | |
| | | 521 | /* Get the header. */ |
721 | if ((rv = (*sc->sc_read)(sc, buf, TPM_HDRSIZE, &cnt, 0))) { | | 522 | if ((rv = (*sc->sc_read)(sc, buf, TPM_HDRSIZE, &cnt, 0))) { |
722 | (*sc->sc_end)(sc, UIO_READ, rv); | | 523 | (*sc->sc_end)(sc, UIO_READ, rv); |
723 | goto out; | | 524 | goto out; |
724 | } | | 525 | } |
725 | | | | |
726 | len = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5]; | | 526 | len = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5]; |
727 | if (len > uio->uio_resid) { | | 527 | if (len > uio->uio_resid || len < cnt) { |
728 | rv = EIO; | | 528 | rv = EIO; |
729 | (*sc->sc_end)(sc, UIO_READ, rv); | | 529 | (*sc->sc_end)(sc, UIO_READ, rv); |
730 | goto out; | | 530 | goto out; |
731 | } | | 531 | } |
732 | | | 532 | |
733 | /* Copy out header. */ | | 533 | /* Copy out the header. */ |
734 | if ((rv = uiomove(buf, cnt, uio))) { | | 534 | if ((rv = uiomove(buf, cnt, uio))) { |
735 | (*sc->sc_end)(sc, UIO_READ, rv); | | 535 | (*sc->sc_end)(sc, UIO_READ, rv); |
736 | goto out; | | 536 | goto out; |
737 | } | | 537 | } |
738 | | | 538 | |
739 | /* Get remaining part of the answer (if anything is left). */ | | 539 | /* Process the rest. */ |
740 | for (len -= cnt, p = buf, n = sizeof(buf); len > 0; p = buf, len -= n, | | 540 | len -= cnt; |
741 | n = sizeof(buf)) { | | 541 | while (len > 0) { |
742 | n = MIN(n, len); | | 542 | n = MIN(sizeof(buf), len); |
743 | if ((rv = (*sc->sc_read)(sc, p, n, NULL, TPM_PARAM_SIZE))) { | | 543 | if ((rv = (*sc->sc_read)(sc, buf, n, NULL, TPM_PARAM_SIZE))) { |
744 | (*sc->sc_end)(sc, UIO_READ, rv); | | 544 | (*sc->sc_end)(sc, UIO_READ, rv); |
745 | goto out; | | 545 | goto out; |
746 | } | | 546 | } |
747 | p += n; | | 547 | if ((rv = uiomove(buf, n, uio))) { |
748 | if ((rv = uiomove(buf, p - buf, uio))) { | | | |
749 | (*sc->sc_end)(sc, UIO_READ, rv); | | 548 | (*sc->sc_end)(sc, UIO_READ, rv); |
750 | goto out; | | 549 | goto out; |
751 | } | | 550 | } |
| | | 551 | len -= n; |
752 | } | | 552 | } |
753 | | | 553 | |
754 | rv = (*sc->sc_end)(sc, UIO_READ, rv); | | 554 | rv = (*sc->sc_end)(sc, UIO_READ, rv); |
755 | out: | | 555 | out: |
756 | splx(s); | | | |
757 | return rv; | | 556 | return rv; |
758 | } | | 557 | } |
759 | | | 558 | |
760 | static int | | 559 | static int |
761 | tpmwrite(dev_t dev, struct uio *uio, int flags) | | 560 | tpmwrite(dev_t dev, struct uio *uio, int flags) |
762 | { | | 561 | { |
763 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev)); | | 562 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); |
764 | uint8_t buf[TPM_BUFSIZ]; | | 563 | uint8_t buf[TPM_BUFSIZ]; |
765 | int n, rv, s; | | 564 | int n, rv; |
766 | | | 565 | |
767 | if (sc == NULL) | | 566 | if (sc == NULL) |
768 | return ENXIO; | | 567 | return ENXIO; |
769 | | | 568 | |
770 | s = spltty(); | | | |
771 | | | | |
772 | n = MIN(sizeof(buf), uio->uio_resid); | | 569 | n = MIN(sizeof(buf), uio->uio_resid); |
773 | if ((rv = uiomove(buf, n, uio))) { | | 570 | if ((rv = uiomove(buf, n, uio))) { |
774 | goto out; | | 571 | goto out; |
775 | } | | 572 | } |
776 | if ((rv = (*sc->sc_start)(sc, UIO_WRITE))) { | | 573 | if ((rv = (*sc->sc_start)(sc, UIO_WRITE))) { |
777 | goto out; | | 574 | goto out; |
778 | } | | 575 | } |
779 | if ((rv = (*sc->sc_write)(sc, buf, n))) { | | 576 | if ((rv = (*sc->sc_write)(sc, buf, n))) { |
780 | goto out; | | 577 | goto out; |
781 | } | | 578 | } |
782 | | | 579 | |
783 | rv = (*sc->sc_end)(sc, UIO_WRITE, rv); | | 580 | rv = (*sc->sc_end)(sc, UIO_WRITE, rv); |
784 | out: | | 581 | out: |
785 | splx(s); | | | |
786 | return rv; | | 582 | return rv; |
787 | } | | 583 | } |
788 | | | 584 | |
789 | static int | | 585 | static int |
790 | tpmioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) | | 586 | tpmioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) |
791 | { | | 587 | { |
792 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev)); | | 588 | struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev)); |
793 | struct tpm_ioc_getinfo *info; | | 589 | struct tpm_ioc_getinfo *info; |
794 | | | 590 | |
795 | if (sc == NULL) | | 591 | if (sc == NULL) |
796 | return ENXIO; | | 592 | return ENXIO; |
797 | | | 593 | |
798 | switch (cmd) { | | 594 | switch (cmd) { |
799 | case TPM_IOC_GETINFO: | | 595 | case TPM_IOC_GETINFO: |
800 | info = addr; | | 596 | info = addr; |
801 | info->api_version = TPM_API_VERSION; | | 597 | info->api_version = TPM_API_VERSION; |
802 | info->tpm_version = sc->sc_ver; | | 598 | info->tpm_version = sc->sc_ver; |
803 | info->device_id = sc->sc_devid; | | 599 | info->device_id = sc->sc_devid; |
804 | info->device_rev = sc->sc_rev; | | 600 | info->device_rev = sc->sc_rev; |
805 | info->device_caps = sc->sc_capabilities; | | 601 | info->device_caps = sc->sc_caps; |
806 | return 0; | | 602 | return 0; |
807 | default: | | 603 | default: |
808 | break; | | 604 | break; |
809 | } | | 605 | } |
810 | | | 606 | |
811 | return ENOTTY; | | 607 | return ENOTTY; |
812 | } | | 608 | } |