This source file includes following definitions.
- lofn_probe
- lofn_attach
- lofn_intr
- lofn_read_reg
- lofn_write_reg
- lofn_zero_reg
- lofn_dump_reg
- lofn_kfind
- lofn_kprocess
- lofn_modexp_start
- lofn_modexp_finish
- lofn_norm_sigbits
- lofn_feed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/proc.h>
41 #include <sys/errno.h>
42 #include <sys/malloc.h>
43 #include <sys/kernel.h>
44 #include <sys/mbuf.h>
45 #include <sys/device.h>
46
47 #include <crypto/cryptodev.h>
48 #include <dev/rndvar.h>
49
50 #include <dev/pci/pcireg.h>
51 #include <dev/pci/pcivar.h>
52 #include <dev/pci/pcidevs.h>
53
54 #include <dev/pci/lofnreg.h>
55 #include <dev/pci/lofnvar.h>
56
57
58
59
60 int lofn_probe(struct device *, void *, void *);
61 void lofn_attach(struct device *, struct device *, void *);
62
63 struct cfattach lofn_ca = {
64 sizeof(struct lofn_softc), lofn_probe, lofn_attach,
65 };
66
67 struct cfdriver lofn_cd = {
68 0, "lofn", DV_DULL
69 };
70
71 int lofn_intr(void *);
72 int lofn_norm_sigbits(const u_int8_t *, u_int);
73 void lofn_dump_reg(struct lofn_softc *, int);
74 void lofn_zero_reg(struct lofn_softc *, int);
75 void lofn_read_reg(struct lofn_softc *, int, union lofn_reg *);
76 void lofn_write_reg(struct lofn_softc *, int, union lofn_reg *);
77 int lofn_kprocess(struct cryptkop *);
78 struct lofn_softc *lofn_kfind(struct cryptkop *);
79 int lofn_modexp_start(struct lofn_softc *, struct lofn_q *);
80 void lofn_modexp_finish(struct lofn_softc *, struct lofn_q *);
81
82 void lofn_feed(struct lofn_softc *);
83
84 int
85 lofn_probe(parent, match, aux)
86 struct device *parent;
87 void *match;
88 void *aux;
89 {
90 struct pci_attach_args *pa = (struct pci_attach_args *) aux;
91
92 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_HIFN &&
93 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_HIFN_6500)
94 return (1);
95 return (0);
96 }
97
98 void
99 lofn_attach(parent, self, aux)
100 struct device *parent, *self;
101 void *aux;
102 {
103 struct lofn_softc *sc = (struct lofn_softc *)self;
104 struct pci_attach_args *pa = aux;
105 pci_chipset_tag_t pc = pa->pa_pc;
106 pci_intr_handle_t ih;
107 const char *intrstr = NULL;
108 bus_size_t iosize;
109 int algs[CRK_ALGORITHM_MAX + 1];
110
111 if (pci_mapreg_map(pa, LOFN_BAR0, PCI_MAPREG_TYPE_MEM, 0,
112 &sc->sc_st, &sc->sc_sh, NULL, &iosize, 0)) {
113 printf(": can't map mem space\n");
114 return;
115 }
116
117 sc->sc_dmat = pa->pa_dmat;
118
119 if (pci_intr_map(pa, &ih)) {
120 printf(": couldn't map interrupt\n");
121 goto fail;
122 }
123 intrstr = pci_intr_string(pc, ih);
124 sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, lofn_intr, sc,
125 self->dv_xname);
126 if (sc->sc_ih == NULL) {
127 printf(": couldn't establish interrupt");
128 if (intrstr != NULL)
129 printf(" at %s", intrstr);
130 printf("\n");
131 goto fail;
132 }
133
134 WRITE_REG_0(sc, LOFN_REL_RNC, LOFN_RNG_SCALAR);
135
136
137 WRITE_REG_0(sc, LOFN_REL_CFG2,
138 READ_REG_0(sc, LOFN_REL_CFG2) | LOFN_CFG2_RNGENA);
139 sc->sc_ier |= LOFN_IER_RDY;
140 WRITE_REG(sc, LOFN_REL_IER, sc->sc_ier);
141
142
143 WRITE_REG_0(sc, LOFN_REL_CFG2,
144 READ_REG_0(sc, LOFN_REL_CFG2) | LOFN_CFG2_PRCENA);
145
146 SIMPLEQ_INIT(&sc->sc_queue);
147
148 sc->sc_cid = crypto_get_driverid(0);
149 if (sc->sc_cid < 0) {
150 printf(": failed to register cid\n");
151 return;
152 }
153
154 bzero(algs, sizeof(algs));
155 algs[CRK_MOD_EXP] = CRYPTO_ALG_FLAG_SUPPORTED;
156
157 crypto_kregister(sc->sc_cid, algs, lofn_kprocess);
158
159 printf(": PK, %s\n", intrstr);
160
161 return;
162
163 fail:
164 bus_space_unmap(sc->sc_st, sc->sc_sh, iosize);
165 }
166
167 int
168 lofn_intr(vsc)
169 void *vsc;
170 {
171 struct lofn_softc *sc = vsc;
172 struct lofn_q *q;
173 u_int32_t sr;
174 int r = 0, i;
175
176 sr = READ_REG_0(sc, LOFN_REL_SR);
177
178 if (sc->sc_ier & LOFN_IER_RDY) {
179 if (sr & LOFN_SR_RNG_UF) {
180 r = 1;
181 printf("%s: rng underflow (disabling)\n",
182 sc->sc_dv.dv_xname);
183 WRITE_REG_0(sc, LOFN_REL_CFG2,
184 READ_REG_0(sc, LOFN_REL_CFG2) &
185 (~LOFN_CFG2_RNGENA));
186 sc->sc_ier &= ~LOFN_IER_RDY;
187 WRITE_REG_0(sc, LOFN_REL_IER, sc->sc_ier);
188 } else if (sr & LOFN_SR_RNG_RDY) {
189 r = 1;
190
191 bus_space_read_region_4(sc->sc_st, sc->sc_sh,
192 LOFN_REL_RNG, sc->sc_rngbuf, LOFN_RNGBUF_SIZE);
193 for (i = 0; i < LOFN_RNGBUF_SIZE; i++)
194 add_true_randomness(sc->sc_rngbuf[i]);
195 }
196 }
197
198 if (sc->sc_ier & LOFN_IER_DONE) {
199 r = 1;
200 if (sr & LOFN_SR_DONE && sc->sc_current != NULL) {
201 q = sc->sc_current;
202 sc->sc_current = NULL;
203 q->q_finish(sc, q);
204 free(q, M_DEVBUF);
205 lofn_feed(sc);
206 }
207 }
208
209 return (r);
210 }
211
212 void
213 lofn_read_reg(sc, ridx, rp)
214 struct lofn_softc *sc;
215 int ridx;
216 union lofn_reg *rp;
217 {
218 #if BYTE_ORDER == BIG_ENDIAN
219 bus_space_read_region_4(sc->sc_st, sc->sc_sh,
220 LOFN_REGADDR(LOFN_WIN_0, ridx, 0), rp->w, 1024/32);
221 #else
222 bus_space_read_region_4(sc->sc_st, sc->sc_sh,
223 LOFN_REGADDR(LOFN_WIN_2, ridx, 0), rp->w, 1024/32);
224 #endif
225 }
226
227 void
228 lofn_write_reg(sc, ridx, rp)
229 struct lofn_softc *sc;
230 int ridx;
231 union lofn_reg *rp;
232 {
233 #if BYTE_ORDER == BIG_ENDIAN
234 bus_space_write_region_4(sc->sc_st, sc->sc_sh,
235 LOFN_REGADDR(LOFN_WIN_0, ridx, 0), rp->w, 1024/32);
236 #else
237 bus_space_write_region_4(sc->sc_st, sc->sc_sh,
238 LOFN_REGADDR(LOFN_WIN_2, ridx, 0), rp->w, 1024/32);
239 #endif
240 }
241
242 void
243 lofn_zero_reg(sc, ridx)
244 struct lofn_softc *sc;
245 int ridx;
246 {
247 lofn_write_reg(sc, ridx, &sc->sc_zero);
248 }
249
250 void
251 lofn_dump_reg(sc, ridx)
252 struct lofn_softc *sc;
253 int ridx;
254 {
255 int i;
256
257 printf("reg %d bits %4u ", ridx,
258 READ_REG(sc, LOFN_LENADDR(LOFN_WIN_2, ridx)) & LOFN_LENMASK);
259
260 for (i = 0; i < 1024/32; i++) {
261 printf("%08X", READ_REG(sc, LOFN_REGADDR(LOFN_WIN_3, ridx, i)));
262 }
263 printf("\n");
264 }
265
266 struct lofn_softc *
267 lofn_kfind(krp)
268 struct cryptkop *krp;
269 {
270 struct lofn_softc *sc;
271 int i;
272
273 for (i = 0; i < lofn_cd.cd_ndevs; i++) {
274 sc = lofn_cd.cd_devs[i];
275 if (sc == NULL)
276 continue;
277 if (sc->sc_cid == krp->krp_hid)
278 return (sc);
279 }
280 return (NULL);
281 }
282
283 int
284 lofn_kprocess(krp)
285 struct cryptkop *krp;
286 {
287 struct lofn_softc *sc;
288 struct lofn_q *q;
289 int s;
290
291 if (krp == NULL || krp->krp_callback == NULL)
292 return (EINVAL);
293 if ((sc = lofn_kfind(krp)) == NULL) {
294 krp->krp_status = EINVAL;
295 crypto_kdone(krp);
296 return (0);
297 }
298
299 q = (struct lofn_q *)malloc(sizeof(*q), M_DEVBUF, M_NOWAIT);
300 if (q == NULL) {
301 krp->krp_status = ENOMEM;
302 crypto_kdone(krp);
303 return (0);
304 }
305
306 switch (krp->krp_op) {
307 case CRK_MOD_EXP:
308 q->q_start = lofn_modexp_start;
309 q->q_finish = lofn_modexp_finish;
310 q->q_krp = krp;
311 s = splnet();
312 SIMPLEQ_INSERT_TAIL(&sc->sc_queue, q, q_next);
313 lofn_feed(sc);
314 splx(s);
315 return (0);
316 default:
317 printf("%s: kprocess: invalid op 0x%x\n",
318 sc->sc_dv.dv_xname, krp->krp_op);
319 krp->krp_status = EOPNOTSUPP;
320 crypto_kdone(krp);
321 free(q, M_DEVBUF);
322 return (0);
323 }
324 }
325
326 int
327 lofn_modexp_start(sc, q)
328 struct lofn_softc *sc;
329 struct lofn_q *q;
330 {
331 struct cryptkop *krp = q->q_krp;
332 int ip = 0, err = 0;
333 int mshift, eshift, nshift;
334 int mbits, ebits, nbits;
335
336 if (krp->krp_param[LOFN_MODEXP_PAR_M].crp_nbits > 1024) {
337 err = ERANGE;
338 goto errout;
339 }
340
341
342 lofn_zero_reg(sc, 0);
343 lofn_zero_reg(sc, 1);
344 lofn_zero_reg(sc, 2);
345 lofn_zero_reg(sc, 3);
346
347
348 nbits = lofn_norm_sigbits(krp->krp_param[LOFN_MODEXP_PAR_N].crp_p,
349 krp->krp_param[LOFN_MODEXP_PAR_N].crp_nbits);
350 if (nbits > 1024) {
351 err = E2BIG;
352 goto errout;
353 }
354 if (nbits < 5) {
355 err = ERANGE;
356 goto errout;
357 }
358 bzero(&sc->sc_tmp, sizeof(sc->sc_tmp));
359 bcopy(krp->krp_param[LOFN_MODEXP_PAR_N].crp_p, &sc->sc_tmp,
360 (nbits + 7) / 8);
361 lofn_write_reg(sc, 2, &sc->sc_tmp);
362
363 nshift = 1024 - nbits;
364 WRITE_REG(sc, LOFN_LENADDR(LOFN_WIN_2, 2), 1024);
365 if (nshift != 0) {
366 WRITE_REG(sc, LOFN_REL_INSTR + ip,
367 LOFN_INSTR2(0, OP_CODE_SL, 2, 2, nshift));
368 ip += 4;
369
370 WRITE_REG(sc, LOFN_REL_INSTR + ip,
371 LOFN_INSTR2(0, OP_CODE_TAG, 2, 2, nbits));
372 ip += 4;
373 }
374
375
376 mbits = lofn_norm_sigbits(krp->krp_param[LOFN_MODEXP_PAR_M].crp_p,
377 krp->krp_param[LOFN_MODEXP_PAR_M].crp_nbits);
378 if (mbits > 1024 || mbits > nbits) {
379 err = E2BIG;
380 goto errout;
381 }
382 bzero(&sc->sc_tmp, sizeof(sc->sc_tmp));
383 bcopy(krp->krp_param[LOFN_MODEXP_PAR_M].crp_p, &sc->sc_tmp,
384 (mbits + 7) / 8);
385 lofn_write_reg(sc, 0, &sc->sc_tmp);
386
387 mshift = 1024 - nbits;
388 WRITE_REG(sc, LOFN_LENADDR(LOFN_WIN_2, 0), 1024);
389 if (mshift != 0) {
390 WRITE_REG(sc, LOFN_REL_INSTR + ip,
391 LOFN_INSTR2(0, OP_CODE_SL, 0, 0, mshift));
392 ip += 4;
393
394 WRITE_REG(sc, LOFN_REL_INSTR + ip,
395 LOFN_INSTR2(0, OP_CODE_TAG, 0, 0, nbits));
396 ip += 4;
397 }
398
399
400 ebits = lofn_norm_sigbits(krp->krp_param[LOFN_MODEXP_PAR_E].crp_p,
401 krp->krp_param[LOFN_MODEXP_PAR_E].crp_nbits);
402 if (ebits > 1024 || ebits > nbits) {
403 err = E2BIG;
404 goto errout;
405 }
406 if (ebits < 1) {
407 err = ERANGE;
408 goto errout;
409 }
410 bzero(&sc->sc_tmp, sizeof(sc->sc_tmp));
411 bcopy(krp->krp_param[LOFN_MODEXP_PAR_E].crp_p, &sc->sc_tmp,
412 (ebits + 7) / 8);
413 lofn_write_reg(sc, 1, &sc->sc_tmp);
414
415 eshift = 1024 - nbits;
416 WRITE_REG(sc, LOFN_LENADDR(LOFN_WIN_2, 1), 1024);
417 if (eshift != 0) {
418 WRITE_REG(sc, LOFN_REL_INSTR + ip,
419 LOFN_INSTR2(0, OP_CODE_SL, 1, 1, eshift));
420 ip += 4;
421
422 WRITE_REG(sc, LOFN_REL_INSTR + ip,
423 LOFN_INSTR2(0, OP_CODE_TAG, 1, 1, nbits));
424 ip += 4;
425 }
426
427 if (nshift == 0) {
428 WRITE_REG(sc, LOFN_REL_INSTR + ip,
429 LOFN_INSTR(OP_DONE, OP_CODE_MODEXP, 3, 0, 1, 2));
430 ip += 4;
431 } else {
432 WRITE_REG(sc, LOFN_REL_INSTR + ip,
433 LOFN_INSTR(0, OP_CODE_MODEXP, 3, 0, 1, 2));
434 ip += 4;
435
436 WRITE_REG(sc, LOFN_REL_INSTR + ip,
437 LOFN_INSTR2(0, OP_CODE_SR, 3, 3, nshift));
438 ip += 4;
439
440 WRITE_REG(sc, LOFN_REL_INSTR + ip,
441 LOFN_INSTR2(OP_DONE, OP_CODE_TAG, 3, 3, nbits));
442 ip += 4;
443 }
444
445
446 WRITE_REG(sc, LOFN_REL_CR, 0);
447
448 return (0);
449
450 errout:
451 bzero(&sc->sc_tmp, sizeof(sc->sc_tmp));
452 lofn_zero_reg(sc, 0);
453 lofn_zero_reg(sc, 1);
454 lofn_zero_reg(sc, 2);
455 lofn_zero_reg(sc, 3);
456 krp->krp_status = err;
457 crypto_kdone(krp);
458 return (1);
459 }
460
461 void
462 lofn_modexp_finish(sc, q)
463 struct lofn_softc *sc;
464 struct lofn_q *q;
465 {
466 struct cryptkop *krp = q->q_krp;
467 int reglen, crplen;
468
469 lofn_read_reg(sc, 3, &sc->sc_tmp);
470
471 reglen = ((READ_REG(sc, LOFN_LENADDR(LOFN_WIN_2, 3)) & LOFN_LENMASK) +
472 7) / 8;
473 crplen = (krp->krp_param[krp->krp_iparams].crp_nbits + 7) / 8;
474
475 if (crplen <= reglen)
476 bcopy(sc->sc_tmp.b, krp->krp_param[krp->krp_iparams].crp_p,
477 reglen);
478 else {
479 bcopy(sc->sc_tmp.b, krp->krp_param[krp->krp_iparams].crp_p,
480 reglen);
481 bzero(krp->krp_param[krp->krp_iparams].crp_p + reglen,
482 crplen - reglen);
483 }
484 bzero(&sc->sc_tmp, sizeof(sc->sc_tmp));
485 lofn_zero_reg(sc, 0);
486 lofn_zero_reg(sc, 1);
487 lofn_zero_reg(sc, 2);
488 lofn_zero_reg(sc, 3);
489 crypto_kdone(krp);
490 }
491
492
493
494
495 int
496 lofn_norm_sigbits(const u_int8_t *p, u_int pbits)
497 {
498 u_int plen = (pbits + 7) / 8;
499 int i, sig = plen * 8;
500 u_int8_t c;
501
502 for (i = plen - 1; i >= 0; i--) {
503 c = p[i];
504 if (c != 0) {
505 while ((c & 0x80) == 0) {
506 sig--;
507 c <<= 1;
508 }
509 break;
510 }
511 sig -= 8;
512 }
513 return (sig);
514 }
515
516 void
517 lofn_feed(sc)
518 struct lofn_softc *sc;
519 {
520 struct lofn_q *q;
521
522
523 if (SIMPLEQ_EMPTY(&sc->sc_queue) &&
524 sc->sc_current == NULL) {
525 sc->sc_ier &= ~LOFN_IER_DONE;
526 WRITE_REG(sc, LOFN_REL_IER, sc->sc_ier);
527 return;
528 }
529
530
531 if (sc->sc_current != NULL)
532 return;
533
534 while (!SIMPLEQ_EMPTY(&sc->sc_queue)) {
535 q = SIMPLEQ_FIRST(&sc->sc_queue);
536 if (q->q_start(sc, q) == 0) {
537 sc->sc_current = q;
538 SIMPLEQ_REMOVE_HEAD(&sc->sc_queue, q_next);
539 sc->sc_ier |= LOFN_IER_DONE;
540 WRITE_REG(sc, LOFN_REL_IER, sc->sc_ier);
541 break;
542 } else {
543 SIMPLEQ_REMOVE_HEAD(&sc->sc_queue, q_next);
544 free(q, M_DEVBUF);
545 }
546 }
547 }