root/dev/pci/lofn.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lofn_probe
  2. lofn_attach
  3. lofn_intr
  4. lofn_read_reg
  5. lofn_write_reg
  6. lofn_zero_reg
  7. lofn_dump_reg
  8. lofn_kfind
  9. lofn_kprocess
  10. lofn_modexp_start
  11. lofn_modexp_finish
  12. lofn_norm_sigbits
  13. lofn_feed

    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 }

/* [<][>][^][v][top][bottom][index][help] */