Annotation of sys/dev/pci/lofn.c, Revision 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