Annotation of sys/dev/pci/lofn.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: lofn.c,v 1.27 2006/06/29 21:34:51 deraadt Exp $ */
2:
3: /*
4: * Copyright (c) 2001-2002 Jason L. Wright (jason@thought.net)
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26: * POSSIBILITY OF SUCH DAMAGE.
27: *
28: * Effort sponsored in part by the Defense Advanced Research Projects
29: * Agency (DARPA) and Air Force Research Laboratory, Air Force
30: * Materiel Command, USAF, under agreement number F30602-01-2-0537.
31: *
32: */
33:
34: /*
35: * Driver for the Hifn 6500 assymmetric encryption processor.
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: * Prototypes and count for the pci_device structure
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: /* Enable RNG */
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: /* Enable ALU */
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: /* Zero out registers. */
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: /* Write out N... */
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: /* Write out M... */
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: /* Write out E... */
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: /* Start microprogram */
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: * Return the number of significant bits of a big number.
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: /* Queue is empty and nothing being processed, turn off interrupt */
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: /* Operation already pending, wait. */
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: }
CVSweb