summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2002-05-15 21:33:23 +0000
committerJason Wright <jason@cvs.openbsd.org>2002-05-15 21:33:23 +0000
commit491e5c6b0c116bbda1fd014744e96d71caf73738 (patch)
tree0528b6be1a530fca8f2305bbcace72d6921af57e /sys/dev/pci
parent8452c3d8fbf96be6c1011daa6f636c4b56c03ebd (diff)
Driver for the Hifn 7814/7851/7854 HIPP1 processors; currently only supports
the public key engine (very much like the 6500, surprise) and the rng.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/files.pci7
-rw-r--r--sys/dev/pci/nofn.c708
-rw-r--r--sys/dev/pci/nofnreg.h183
-rw-r--r--sys/dev/pci/nofnvar.h80
4 files changed, 977 insertions, 1 deletions
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index c91efd1e8dd..9b0478f93d0 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.133 2002/05/06 16:37:43 mickey Exp $
+# $OpenBSD: files.pci,v 1.134 2002/05/15 21:33:22 jason Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -306,6 +306,11 @@ device hifn: crypto
attach hifn at pci
file dev/pci/hifn7751.c hifn
+# Hi/fn 7814/7851/7854
+device nofn: crypto
+attach nofn at pci
+file dev/pci/nofn.c nofn
+
# Bluesteelnet (Broadcom) 5501/5601
device ubsec: crypto
attach ubsec at pci
diff --git a/sys/dev/pci/nofn.c b/sys/dev/pci/nofn.c
new file mode 100644
index 00000000000..6ccab9c549e
--- /dev/null
+++ b/sys/dev/pci/nofn.c
@@ -0,0 +1,708 @@
+/* $OpenBSD: nofn.c,v 1.3 2002/05/15 21:33:22 jason Exp $ */
+
+/*
+ * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Driver for the Hifn 7814/7851/7854 HIPP1 processor.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/device.h>
+#include <sys/queue.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <crypto/cryptodev.h>
+#include <crypto/cryptosoft.h>
+#include <dev/rndvar.h>
+#include <sys/md5k.h>
+#include <crypto/sha1.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/pci/nofnreg.h>
+#include <dev/pci/nofnvar.h>
+
+int nofn_match(struct device *, void *, void *);
+void nofn_attach(struct device *, struct device *, void *);
+int nofn_intr(void *);
+
+void nofn_rng_enable(struct nofn_softc *);
+void nofn_rng_disable(struct nofn_softc *);
+void nofn_rng_tick(void *);
+int nofn_rng_intr(struct nofn_softc *);
+int nofn_rng_read(struct nofn_softc *);
+
+int nofn_pk_process(struct cryptkop *);
+void nofn_pk_enable(struct nofn_softc *);
+void nofn_pk_feed(struct nofn_softc *);
+struct nofn_softc *nofn_pk_find(struct cryptkop *);
+void nofn_pk_write_reg(struct nofn_softc *, int, union nofn_pk_reg *);
+void nofn_pk_read_reg(struct nofn_softc *, int, union nofn_pk_reg *);
+void nofn_pk_zero_reg(struct nofn_softc *, int);
+int nofn_modexp_start(struct nofn_softc *, struct nofn_pk_q *);
+void nofn_modexp_finish(struct nofn_softc *, struct nofn_pk_q *);
+int nofn_pk_sigbits(const u_int8_t *, u_int);
+
+struct cfattach nofn_ca = {
+ sizeof(struct nofn_softc), nofn_match, nofn_attach
+};
+
+struct cfdriver nofn_cd = {
+ 0, "nofn", DV_DULL
+};
+
+int
+nofn_match(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_HIFN &&
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_HIFN_78XX)
+ return (1);
+ return (0);
+}
+
+void
+nofn_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct nofn_softc *sc = (struct nofn_softc *)self;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+ bus_size_t bar0size = 0, bar3size = 0;
+ u_int32_t cmd;
+
+ sc->sc_dmat = pa->pa_dmat;
+
+ cmd = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+ cmd |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE;
+ pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, cmd);
+ cmd = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+
+ if (!(cmd & PCI_COMMAND_MEM_ENABLE)) {
+ printf(": failed to enable memory mapping\n");
+ goto fail;
+ }
+
+ if (!(cmd & PCI_COMMAND_MASTER_ENABLE)) {
+ printf(": failed to enable bus mastering\n");
+ goto fail;
+ }
+
+ if (pci_mapreg_map(pa, NOFN_BAR0_REGS, PCI_MAPREG_TYPE_MEM, 0,
+ &sc->sc_st, &sc->sc_sh, NULL, &bar0size, 0)) {
+ printf(": can't map bar0 regs\n");
+ goto fail;
+ }
+
+ if (pci_intr_map(pa, &ih)) {
+ printf(": couldn't map interrupt\n");
+ bus_space_unmap(sc->sc_st, sc->sc_sh, bar0size);
+ goto fail;
+ }
+
+ intrstr = pci_intr_string(pc, ih);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, nofn_intr, sc,
+ self->dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf(": couldn't establish interrupt");
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ goto fail;
+ }
+
+ sc->sc_revid = REG_READ_4(sc, NOFN_REVID);
+
+ switch (sc->sc_revid) {
+ case REVID_7814_7854_1:
+ case REVID_8154_1:/* XXX ? */
+ case REVID_8065_1:/* XXX ? */
+ case REVID_8165_1:/* XXX ? */
+ if (pci_mapreg_map(pa, NOFN_BAR3_PK, PCI_MAPREG_TYPE_MEM, 0,
+ &sc->sc_pk_t, &sc->sc_pk_h, NULL, &bar3size, 0)) {
+ printf(": can't map bar3 regs\n");
+ goto fail;
+ }
+ nofn_rng_enable(sc);
+ nofn_pk_enable(sc);
+ break;
+ case REVID_7851_1:
+ case REVID_7851_2:
+ break;
+ default:
+ printf(": unknown revid %x\n", sc->sc_revid);
+ break;
+ }
+
+ printf(": %s", intrstr);
+ if (sc->sc_flags & NOFN_FLAGS_PK)
+ printf(", pk");
+ if (sc->sc_flags & NOFN_FLAGS_RNG)
+ printf(", rng");
+ printf("\n");
+
+ REG_WRITE_4(sc, NOFN_PCI_INT_MASK, sc->sc_intrmask);
+
+ return;
+
+fail:
+ if (bar3size != 0)
+ bus_space_unmap(sc->sc_pk_t, sc->sc_pk_h, bar3size);
+ if (bar0size != 0)
+ bus_space_unmap(sc->sc_st, sc->sc_sh, bar0size);
+}
+
+int
+nofn_intr(vsc)
+ void *vsc;
+{
+ struct nofn_softc *sc = vsc;
+ u_int32_t stat;
+ int r = 0;
+
+ stat = REG_READ_4(sc, NOFN_PCI_INT_STAT) & sc->sc_intrmask;
+
+ if (stat & PCIINTSTAT_RNGRDY)
+ r |= nofn_rng_intr(sc);
+
+ if (stat & PCIINTSTAT_PK) {
+ struct nofn_pk_q *q;
+ u_int32_t sr;
+
+ r = 1;
+ sr = PK_READ_4(sc, NOFN_PK_SR);
+ if (sr & PK_SR_DONE && sc->sc_pk_current != NULL) {
+ q = sc->sc_pk_current;
+ sc->sc_pk_current = NULL;
+ q->q_finish(sc, q);
+ free(q, M_DEVBUF);
+ nofn_pk_feed(sc);
+ }
+ }
+
+ return (r);
+}
+
+int
+nofn_rng_read(sc)
+ struct nofn_softc *sc;
+{
+ u_int32_t buf[8], reg;
+ int ret = 0, i;
+
+ for (;;) {
+ reg = PK_READ_4(sc, NOFN_PK_SR);
+ if (reg & PK_SR_UFLOW) {
+ ret = -1;
+ printf("%s: rng underflow, disabling.\n");
+ nofn_rng_disable(sc);
+ break;
+ }
+
+ if ((reg & PK_SR_RRDY) == 0)
+ break;
+
+ ret = 1;
+ bus_space_read_region_4(sc->sc_pk_t, sc->sc_pk_h,
+ NOFN_PK_RNGFIFO_BEGIN, buf, 8);
+ if (sc->sc_rngskip > 0)
+ sc->sc_rngskip -= 8;
+ else
+ for (i = 0; i < 8; i++)
+ add_true_randomness(buf[i]);
+ }
+
+ return (ret);
+}
+
+int
+nofn_rng_intr(sc)
+ struct nofn_softc *sc;
+{
+ int r;
+
+ r = nofn_rng_read(sc);
+ if (r == 0)
+ return (0);
+ return (1);
+}
+
+void
+nofn_rng_tick(vsc)
+ void *vsc;
+{
+ struct nofn_softc *sc = vsc;
+ int s, r;
+
+ s = splnet();
+ r = nofn_rng_read(sc);
+ if (r != -1)
+ timeout_add(&sc->sc_rngto, sc->sc_rngtick);
+ splx(s);
+}
+
+void
+nofn_rng_disable(sc)
+ struct nofn_softc *sc;
+{
+ u_int32_t r;
+
+ /* disable rng unit */
+ r = PK_READ_4(sc, NOFN_PK_CFG2);
+ r &= PK_CFG2_ALU_ENA; /* preserve */
+ PK_WRITE_4(sc, NOFN_PK_CFG2, r);
+
+ switch (sc->sc_revid) {
+ case REVID_7814_7854_1:
+ if (timeout_pending(&sc->sc_rngto))
+ timeout_del(&sc->sc_rngto);
+ break;
+ case REVID_8154_1:
+ case REVID_8065_1:
+ case REVID_8165_1:
+ /* disable rng interrupts */
+ r = PK_READ_4(sc, NOFN_PK_IER);
+ r &= PK_IER_DONE; /* preserve */
+ PK_WRITE_4(sc, NOFN_PK_IER, r);
+
+ sc->sc_intrmask &= ~PCIINTMASK_RNGRDY;
+ REG_WRITE_4(sc, NOFN_PCI_INT_MASK, sc->sc_intrmask);
+ break;
+ default:
+ printf("%s: nofn_rng_disable: unknown rev %x\n", sc->sc_revid);
+ break;
+ }
+
+ sc->sc_flags &= ~NOFN_FLAGS_RNG;
+}
+
+void
+nofn_rng_enable(sc)
+ struct nofn_softc *sc;
+{
+ u_int32_t r;
+
+ /* setup scalar */
+ PK_WRITE_4(sc, NOFN_PK_RNC, PK_RNC_SCALER);
+
+ /* enable rng unit */
+ r = PK_READ_4(sc, NOFN_PK_CFG2);
+ r &= PK_CFG2_ALU_ENA; /* preserve */
+ r |= PK_CFG2_RNG_ENA;
+ PK_WRITE_4(sc, NOFN_PK_CFG2, r);
+
+ /* 78xx chips cannot use interrupts to gather rng's */
+ switch (sc->sc_revid) {
+ case REVID_7814_7854_1:
+ timeout_set(&sc->sc_rngto, nofn_rng_tick, sc);
+ if (hz < 100)
+ sc->sc_rngtick = 1;
+ else
+ sc->sc_rngtick = hz / 100;
+ timeout_add(&sc->sc_rngto, sc->sc_rngtick);
+ break;
+ case REVID_8154_1:
+ case REVID_8065_1:
+ case REVID_8165_1:
+ /* enable rng interrupts */
+ r = PK_READ_4(sc, NOFN_PK_IER);
+ r &= PK_IER_DONE; /* preserve */
+ r |= PK_IER_RRDY;
+ PK_WRITE_4(sc, NOFN_PK_IER, r);
+ sc->sc_intrmask |= PCIINTMASK_RNGRDY;
+ break;
+ default:
+ printf("%s: nofn_rng_enable: unknown rev %x\n", sc->sc_revid);
+ break;
+ }
+
+ sc->sc_flags |= NOFN_FLAGS_RNG;
+}
+
+void
+nofn_pk_enable(sc)
+ struct nofn_softc *sc;
+{
+ u_int32_t r;
+
+ if ((sc->sc_cid = crypto_get_driverid(0)) < 0) {
+ printf(": failed to register cid\n");
+ return;
+ }
+
+ SIMPLEQ_INIT(&sc->sc_pk_queue);
+ sc->sc_pk_current = NULL;
+
+ crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0, nofn_pk_process);
+
+ /* enable ALU */
+ r = PK_READ_4(sc, NOFN_PK_CFG2);
+ r &= PK_CFG2_RNG_ENA; /* preserve */
+ r |= PK_CFG2_ALU_ENA;
+ PK_WRITE_4(sc, NOFN_PK_CFG2, r);
+
+ sc->sc_intrmask |= PCIINTMASK_PK;
+ sc->sc_flags |= NOFN_FLAGS_PK;
+}
+
+void
+nofn_pk_feed(sc)
+ struct nofn_softc *sc;
+{
+ struct nofn_pk_q *q;
+ u_int32_t r;
+
+ /* Queue is empty and nothing being processed, turn off interrupt */
+ if (SIMPLEQ_EMPTY(&sc->sc_pk_queue) &&
+ sc->sc_pk_current == NULL) {
+ r = PK_READ_4(sc, NOFN_PK_IER);
+ r &= PK_IER_RRDY; /* preserve */
+ PK_WRITE_4(sc, NOFN_PK_IER, r);
+ return;
+ }
+
+ /* Operation already pending, wait. */
+ if (sc->sc_pk_current != NULL)
+ return;
+
+ while (!SIMPLEQ_EMPTY(&sc->sc_pk_queue)) {
+ q = SIMPLEQ_FIRST(&sc->sc_pk_queue);
+ if (q->q_start(sc, q) == 0) {
+ sc->sc_pk_current = q;
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_pk_queue, q, q_next);
+
+ r = PK_READ_4(sc, NOFN_PK_IER);
+ r &= PK_IER_RRDY; /* preserve */
+ r |= PK_IER_DONE;
+ PK_WRITE_4(sc, NOFN_PK_IER, r);
+ break;
+ } else {
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_pk_queue, q, q_next);
+ free(q, M_DEVBUF);
+ }
+ }
+}
+
+int
+nofn_pk_process(krp)
+ struct cryptkop *krp;
+{
+ struct nofn_softc *sc;
+ struct nofn_pk_q *q;
+ int s;
+
+ if (krp == NULL || krp->krp_callback == NULL)
+ return (EINVAL);
+ if ((sc = nofn_pk_find(krp)) == NULL) {
+ krp->krp_status = EINVAL;
+ crypto_kdone(krp);
+ return (0);
+ }
+
+ q = (struct nofn_pk_q *)malloc(sizeof(*q), M_DEVBUF, M_NOWAIT);
+ if (q == NULL) {
+ krp->krp_status = ENOMEM;
+ crypto_kdone(krp);
+ return (0);
+ }
+
+ switch (krp->krp_op) {
+ case CRK_MOD_EXP:
+ q->q_start = nofn_modexp_start;
+ q->q_finish = nofn_modexp_finish;
+ q->q_krp = krp;
+ s = splnet();
+ SIMPLEQ_INSERT_TAIL(&sc->sc_pk_queue, q, q_next);
+ nofn_pk_feed(sc);
+ splx(s);
+ return (0);
+ default:
+ printf("%s: kprocess: invalid op 0x%x\n",
+ sc->sc_dev.dv_xname, krp->krp_op);
+ krp->krp_status = EOPNOTSUPP;
+ crypto_kdone(krp);
+ free(q, M_DEVBUF);
+ return (0);
+ }
+}
+
+struct nofn_softc *
+nofn_pk_find(krp)
+ struct cryptkop *krp;
+{
+ struct nofn_softc *sc;
+ int i;
+
+ for (i = 0; i < nofn_cd.cd_ndevs; i++) {
+ sc = nofn_cd.cd_devs[i];
+ if (sc == NULL)
+ continue;
+ if (sc->sc_cid == krp->krp_hid)
+ return (sc);
+ }
+ return (NULL);
+}
+
+void
+nofn_pk_read_reg(sc, ridx, rp)
+ struct nofn_softc *sc;
+ int ridx;
+ union nofn_pk_reg *rp;
+{
+ bus_space_read_region_4(sc->sc_pk_t, sc->sc_pk_h,
+ NOFN_PK_REGADDR(NOFN_PK_WIN_2, ridx, 0), rp->w, 1024/32);
+}
+
+void
+nofn_pk_write_reg(sc, ridx, rp)
+ struct nofn_softc *sc;
+ int ridx;
+ union nofn_pk_reg *rp;
+{
+ bus_space_write_region_4(sc->sc_pk_t, sc->sc_pk_h,
+ NOFN_PK_REGADDR(NOFN_PK_WIN_2, ridx, 0), rp->w, 1024/32);
+}
+
+void
+nofn_pk_zero_reg(sc, ridx)
+ struct nofn_softc *sc;
+ int ridx;
+{
+ nofn_pk_write_reg(sc, ridx, &sc->sc_pk_zero);
+}
+
+int
+nofn_modexp_start(sc, q)
+ struct nofn_softc *sc;
+ struct nofn_pk_q *q;
+{
+ struct cryptkop *krp = q->q_krp;
+ int ip = 0, err = 0;
+ int mshift, eshift, nshift;
+ int mbits, ebits, nbits;
+
+ if (krp->krp_param[NOFN_MODEXP_PAR_M].crp_nbits > 1024) {
+ err = ERANGE;
+ goto errout;
+ }
+
+ /* Zero out registers. */
+ nofn_pk_zero_reg(sc, 0);
+ nofn_pk_zero_reg(sc, 1);
+ nofn_pk_zero_reg(sc, 2);
+ nofn_pk_zero_reg(sc, 3);
+
+ /* Write out N... */
+ nbits = nofn_pk_sigbits(krp->krp_param[NOFN_MODEXP_PAR_N].crp_p,
+ krp->krp_param[NOFN_MODEXP_PAR_N].crp_nbits);
+ if (nbits > 1024) {
+ err = E2BIG;
+ goto errout;
+ }
+ if (nbits < 5) {
+ err = ERANGE;
+ goto errout;
+ }
+ bzero(&sc->sc_pk_tmp, sizeof(sc->sc_pk_tmp));
+ bcopy(krp->krp_param[NOFN_MODEXP_PAR_N].crp_p, &sc->sc_pk_tmp,
+ (nbits + 7) / 8);
+ nofn_pk_write_reg(sc, 2, &sc->sc_pk_tmp);
+
+ nshift = 1024 - nbits;
+ PK_WRITE_4(sc, NOFN_PK_LENADDR(2), 1024);
+ if (nshift != 0) {
+ PK_WRITE_4(sc, NOFN_PK_INSTR_BEGIN + ip,
+ NOFN_PK_INSTR2(0, PK_OPCODE_SL, 2, 2, nshift));
+ ip += 4;
+
+ PK_WRITE_4(sc, NOFN_PK_INSTR_BEGIN + ip,
+ NOFN_PK_INSTR2(0, PK_OPCODE_TAG, 2, 2, nbits));
+ ip += 4;
+ }
+
+ /* Write out M... */
+ mbits = nofn_pk_sigbits(krp->krp_param[NOFN_MODEXP_PAR_M].crp_p,
+ krp->krp_param[NOFN_MODEXP_PAR_M].crp_nbits);
+ if (mbits > 1024 || mbits > nbits) {
+ err = E2BIG;
+ goto errout;
+ }
+ bzero(&sc->sc_pk_tmp, sizeof(sc->sc_pk_tmp));
+ bcopy(krp->krp_param[NOFN_MODEXP_PAR_M].crp_p, &sc->sc_pk_tmp,
+ (mbits + 7) / 8);
+ nofn_pk_write_reg(sc, 0, &sc->sc_pk_tmp);
+
+ mshift = 1024 - nbits;
+ PK_WRITE_4(sc, NOFN_PK_LENADDR(0), 1024);
+ if (mshift != 0) {
+ PK_WRITE_4(sc, NOFN_PK_INSTR_BEGIN + ip,
+ NOFN_PK_INSTR2(0, PK_OPCODE_SL, 0, 0, mshift));
+ ip += 4;
+
+ PK_WRITE_4(sc, NOFN_PK_INSTR_BEGIN + ip,
+ NOFN_PK_INSTR2(0, PK_OPCODE_TAG, 0, 0, nbits));
+ ip += 4;
+ }
+
+ /* Write out E... */
+ ebits = nofn_pk_sigbits(krp->krp_param[NOFN_MODEXP_PAR_E].crp_p,
+ krp->krp_param[NOFN_MODEXP_PAR_E].crp_nbits);
+ if (ebits > 1024 || ebits > nbits) {
+ err = E2BIG;
+ goto errout;
+ }
+ if (ebits < 1) {
+ err = ERANGE;
+ goto errout;
+ }
+ bzero(&sc->sc_pk_tmp, sizeof(sc->sc_pk_tmp));
+ bcopy(krp->krp_param[NOFN_MODEXP_PAR_E].crp_p, &sc->sc_pk_tmp,
+ (ebits + 7) / 8);
+ nofn_pk_write_reg(sc, 1, &sc->sc_pk_tmp);
+
+ eshift = 1024 - nbits;
+ PK_WRITE_4(sc, NOFN_PK_LENADDR(1), 1024);
+ if (eshift != 0) {
+ PK_WRITE_4(sc, NOFN_PK_INSTR_BEGIN + ip,
+ NOFN_PK_INSTR2(0, PK_OPCODE_SL, 1, 1, eshift));
+ ip += 4;
+
+ PK_WRITE_4(sc, NOFN_PK_INSTR_BEGIN + ip,
+ NOFN_PK_INSTR2(0, PK_OPCODE_TAG, 1, 1, nbits));
+ ip += 4;
+ }
+
+ if (nshift == 0) {
+ PK_WRITE_4(sc, NOFN_PK_INSTR_BEGIN + ip,
+ NOFN_PK_INSTR(PK_OP_DONE, PK_OPCODE_MODEXP, 3, 0, 1, 2));
+ ip += 4;
+ } else {
+ PK_WRITE_4(sc, NOFN_PK_INSTR_BEGIN + ip,
+ NOFN_PK_INSTR(0, PK_OPCODE_MODEXP, 3, 0, 1, 2));
+ ip += 4;
+
+ PK_WRITE_4(sc, NOFN_PK_INSTR_BEGIN + ip,
+ NOFN_PK_INSTR2(0, PK_OPCODE_SR, 3, 3, nshift));
+ ip += 4;
+
+ PK_WRITE_4(sc, NOFN_PK_INSTR_BEGIN + ip,
+ NOFN_PK_INSTR2(PK_OP_DONE, PK_OPCODE_TAG, 3, 3, nbits));
+ ip += 4;
+ }
+
+ /* Start microprogram */
+ PK_WRITE_4(sc, NOFN_PK_CR, 0 << PK_CR_OFFSET_S);
+
+ return (0);
+
+errout:
+ bzero(&sc->sc_pk_tmp, sizeof(sc->sc_pk_tmp));
+ nofn_pk_zero_reg(sc, 0);
+ nofn_pk_zero_reg(sc, 1);
+ nofn_pk_zero_reg(sc, 2);
+ nofn_pk_zero_reg(sc, 3);
+ krp->krp_status = err;
+ crypto_kdone(krp);
+ return (1);
+}
+
+void
+nofn_modexp_finish(sc, q)
+ struct nofn_softc *sc;
+ struct nofn_pk_q *q;
+{
+ struct cryptkop *krp = q->q_krp;
+ int reglen, crplen;
+
+ nofn_pk_read_reg(sc, 3, &sc->sc_pk_tmp);
+
+ reglen = ((PK_READ_4(sc, NOFN_PK_LENADDR(3)) & NOFN_PK_LENMASK) + 7)
+ / 8;
+ crplen = (krp->krp_param[NOFN_MODEXP_PAR_C].crp_nbits + 7) / 8;
+
+ if (crplen <= reglen)
+ bcopy(sc->sc_pk_tmp.b, krp->krp_param[NOFN_MODEXP_PAR_C].crp_p,
+ reglen);
+ else {
+ bcopy(sc->sc_pk_tmp.b, krp->krp_param[NOFN_MODEXP_PAR_C].crp_p,
+ reglen);
+ bzero(krp->krp_param[NOFN_MODEXP_PAR_C].crp_p + reglen,
+ crplen - reglen);
+ }
+ bzero(&sc->sc_pk_tmp, sizeof(sc->sc_pk_tmp));
+ nofn_pk_zero_reg(sc, 0);
+ nofn_pk_zero_reg(sc, 1);
+ nofn_pk_zero_reg(sc, 2);
+ nofn_pk_zero_reg(sc, 3);
+ crypto_kdone(krp);
+}
+
+/*
+ * Return the number of significant bits of a little endian big number.
+ */
+int
+nofn_pk_sigbits(p, pbits)
+ const u_int8_t *p;
+ u_int pbits;
+{
+ u_int plen = (pbits + 7) / 8;
+ int i, sig = plen * 8;
+ u_int8_t c;
+
+ for (i = plen - 1; i >= 0; i--) {
+ c = p[i];
+ if (c != 0) {
+ while ((c & 0x80) == 0) {
+ sig--;
+ c <<= 1;
+ }
+ break;
+ }
+ sig -= 8;
+ }
+ return (sig);
+}
diff --git a/sys/dev/pci/nofnreg.h b/sys/dev/pci/nofnreg.h
new file mode 100644
index 00000000000..339136d87f2
--- /dev/null
+++ b/sys/dev/pci/nofnreg.h
@@ -0,0 +1,183 @@
+/* $OpenBSD: nofnreg.h,v 1.3 2002/05/15 21:33:22 jason Exp $ */
+
+/*
+ * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define NOFN_BAR0_REGS 0x10 /* main register set */
+#define NOFN_BAR1 0x14 /* memory space 1 */
+#define NOFN_BAR2 0x18 /* memory space 2 */
+#define NOFN_BAR3_PK 0x1c /* public key unit */
+
+#define NOFN_REVID 0x0098 /* revision id */
+#define NOFN_SPINLOCK_0 0x0118 /* spinlock 0 */
+#define NOFN_SPINLOCK_1 0x0120 /* spinlock 1 */
+#define NOFN_PCI_INT 0x0130 /* generate a pci intr */
+#define NOFN_PCI_INT_STAT 0x0138 /* pci interrupt status */
+#define NOFN_PCI_INT_MASK 0x0140 /* pci interrupt mask */
+
+#define REVID_7851_1 0x00140000 /* 7851, first silicon */
+#define REVID_7851_2 0x00140001 /* 7851, second silicon */
+#define REVID_7814_7854_1 0x00140002 /* 7814/7854, first silicon */
+#define REVID_8154_1 0x00180000 /* 8154, first silicon */
+#define REVID_8065_1 0x00160000 /* 8065, first silicon */
+#define REVID_8165_1 0x00170000 /* 8165, first silicon */
+
+#define PCIINTMASK_PK 0x80000000 /* pk processor idle */
+#define PCIINTMASK_RNGRDY 0x40000000 /* pk rng has 8 32bit words */
+#define PCIINTMASK_MIPSINT 0x00080000 /* mips interrupt */
+#define PCIINTMASK_ERR_OUT 0x00010000 /* err: outbound dma */
+#define PCIINTMASK_ERR_FREE 0x00008000 /* err: free descriptor */
+#define PCIINTMASK_ERR_DEST 0x00004000 /* err: dest descriptor */
+#define PCIINTMASK_ERR_RES 0x00002000 /* err: result cycle */
+#define PCIINTMASK_ERR_RESP 0x00001000 /* err: post address cycle */
+#define PCIINTMASK_DESCOVF 0x00000800 /* descriptor overflow */
+#define PCIINTMASK_RESDONE 0x00000400 /* result done */
+#define PCIINTMASK_DESTINV 0x00000200 /* destination invalidated */
+#define PCIINTMASK_POOLINV 0x00000100 /* free desc invalidated */
+#define PCIINTMASK_ERR_CMD 0x00000080 /* pci error fetching cmd */
+#define PCIINTMASK_ERR_SRC 0x00000040 /* pci error fetching src */
+#define PCIINTMASK_ERR_IN 0x00000020 /* pci error during input */
+#define PCIINTMASK_ERR_MULTI 0x00000010 /* multibit ecc error */
+#define PCIINTMASK_MIPSPAR 0x00000004 /* mips parity error */
+#define PCIINTMASK_MIPSPCI 0x00000002 /* write to pciint register */
+#define PCIINTMASK_FREE_E 0x00000001 /* free-pool empty */
+
+#define PCIINTSTAT_PK 0x80000000 /* pk processor idle */
+#define PCIINTSTAT_RNGRDY 0x40000000 /* pk rng has 8 32bit words */
+#define PCIINTSTAT_MIPSINT 0x00080000 /* mips interrupt */
+#define PCIINTSTAT_ERR_OUT 0x00010000 /* err: outbound dma */
+#define PCIINTSTAT_ERR_FREE 0x00008000 /* err: free descriptor */
+#define PCIINTSTAT_ERR_DEST 0x00004000 /* err: dest descriptor */
+#define PCIINTSTAT_ERR_RES 0x00002000 /* err: result cycle */
+#define PCIINTSTAT_ERR_RESP 0x00001000 /* err: post address cycle */
+#define PCIINTSTAT_DESCOVF 0x00000800 /* descriptor overflow */
+#define PCIINTSTAT_RESDONE 0x00000400 /* result done */
+#define PCIINTSTAT_DESTINV 0x00000200 /* destination invalidated */
+#define PCIINTSTAT_POOLINV 0x00000100 /* free desc invalidated */
+#define PCIINTSTAT_ERR_CMD 0x00000080 /* pci error fetching cmd */
+#define PCIINTSTAT_ERR_SRC 0x00000040 /* pci error fetching src */
+#define PCIINTSTAT_ERR_IN 0x00000020 /* pci error during input */
+#define PCIINTSTAT_ERR_MULTI 0x00000010 /* multibit ecc error */
+#define PCIINTSTAT_MIPSPAR 0x00000004 /* mips parity error */
+#define PCIINTSTAT_MIPSPCI 0x00000002 /* write to pciint register */
+#define PCIINTSTAT_FREE_E 0x00000001 /* free-pool empty */
+
+#define NOFN_PK_WIN_0 0x0000 /* big endian byte and words */
+#define NOFN_PK_WIN_1 0x2000 /* big endian byte, little endian words */
+#define NOFN_PK_WIN_2 0x4000 /* little endian byte and words */
+#define NOFN_PK_WIN_3 0x6000 /* little endian byte, big endian words */
+
+#define NOFN_PK_REGADDR(win,r,i) \
+ ((win) | (((r) & 0xf) << 7) | (((i) & 0x1f) << 2))
+
+#define NOFN_PK_LENADDR(r) (0x1000 + ((r) << 2))
+#define NOFN_PK_LENMASK 0x000007ff /* mask of length bits */
+
+#define NOFN_PK_RNGFIFO_BEGIN 0x1080
+#define NOFN_PK_RNGFIFO_END 0x10bc
+#define NOFN_PK_INSTR_BEGIN 0x1100
+#define NOFN_PK_INSTR_END 0x12fc
+
+#define NOFN_PK_CR 0x1fd4 /* command */
+#define NOFN_PK_SR 0x1fd8 /* status */
+#define NOFN_PK_IER 0x1fdc /* interrupt enable */
+#define NOFN_PK_RNC 0x1fe0 /* random number config */
+#define NOFN_PK_CFG1 0x1fe4 /* config1 */
+#define NOFN_PK_CFG2 0x1fe8 /* config2 */
+#define NOFN_PK_CHIPID 0x1fec /* chipid */
+#define NOFN_PK_SCR 0x1ff0 /* stack content */
+
+#define PK_CR_OFFSET_M 0x000001fc /* instruction offset mask */
+#define PK_CR_OFFSET_S 2 /* instruction offset shift */
+
+#define PK_SR_DONE 0x00008000 /* proc is idle */
+#define PK_SR_RRDY 0x00004000 /* random number ready */
+#define PK_SR_UFLOW 0x00001000 /* random number underflow */
+#define PK_SR_CARRY 0x00000008 /* alu carry bit */
+
+#define PK_IER_DONE 0x00008000 /* intr when alu is idle */
+#define PK_IER_RRDY 0x00004000 /* intr when rng ready */
+
+#define PK_RNC_FST_SCALER 0x00000f00 /* first prescaler */
+#define PK_RNC_OUT_SCALER 0x00000080 /* output prescaler */
+
+#define PK_CFG1_RESET 0x00000001 /* reset pk unit */
+
+#define PK_CFG2_ALU_ENA 0x00000002 /* enable alu */
+#define PK_CFG2_RNG_ENA 0x00000001 /* enable rng */
+
+/* alu registers are 1024 bits wide, but must be addressed by word. */
+union nofn_pk_reg {
+ u_int8_t b[128];
+ u_int32_t w[32];
+};
+
+#define PK_OP_DONE 0x80000000 /* end of program */
+#define PK_OPCODE_MASK 0x7c000000 /* opcode mask */
+#define PK_OPCODE_MODEXP 0x00000000 /* modular exponentiation */
+#define PK_OPCODE_MODMUL 0x04000000 /* modular multiplication */
+#define PK_OPCODE_MODRED 0x08000000 /* modular reduction */
+#define PK_OPCODE_MODADD 0x0c000000 /* modular addition */
+#define PK_OPCODE_MODSUB 0x10000000 /* modular subtraction */
+#define PK_OPCODE_ADD 0x14000000 /* addition */
+#define PK_OPCODE_SUB 0x18000000 /* subtraction */
+#define PK_OPCODE_ADDC 0x1c000000 /* addition with carry */
+#define PK_OPCODE_SUBC 0x20000000 /* subtraction with carry */
+#define PK_OPCODE_MULT 0x24000000 /* 2048bit multiplication */
+#define PK_OPCODE_SR 0x28000000 /* shift right */
+#define PK_OPCODE_SL 0x2c000000 /* shift left */
+#define PK_OPCODE_INC 0x30000000 /* increment */
+#define PK_OPCODE_DEC 0x34000000 /* decrement */
+#define PK_OPCODE_TAG 0x38000000 /* set length tag */
+#define PK_OPCODE_BRANCH 0x3c000000 /* jump to insn */
+#define PK_OPCODE_CALL 0x40000000 /* push addr and jump */
+#define PK_OPCODE_RETURN 0x44000000 /* pop addr and return */
+
+#define PK_OP_RD_SHIFT 21
+#define PK_OP_RA_SHIFT 16
+#define PK_OP_RB_SHIFT 11
+#define PK_OP_RM_SHIFT 6
+#define PK_OP_R_MASK 0x1f
+#define PK_OP_LEN_MASK 0xffff
+
+#define NOFN_PK_INSTR(done,op,rd,ra,rb,rm) \
+ ((done) | (op) | \
+ (((rd) & PK_OP_R_MASK) << PK_OP_RD_SHIFT) | \
+ (((ra) & PK_OP_R_MASK) << PK_OP_RA_SHIFT) | \
+ (((rb) & PK_OP_R_MASK) << PK_OP_RB_SHIFT) | \
+ (((rm) & PK_OP_R_MASK) << PK_OP_RM_SHIFT))
+
+/* shift left, shift right, tag */
+#define NOFN_PK_INSTR2(done,op,rd,ra,len) \
+ ((done) | (op) | \
+ (((rd) & PK_OP_R_MASK) << PK_OP_RD_SHIFT) | \
+ (((ra) & PK_OP_R_MASK) << PK_OP_RA_SHIFT) | \
+ ((len) & PK_OP_LEN_MASK))
diff --git a/sys/dev/pci/nofnvar.h b/sys/dev/pci/nofnvar.h
new file mode 100644
index 00000000000..2e2dd6e11ae
--- /dev/null
+++ b/sys/dev/pci/nofnvar.h
@@ -0,0 +1,80 @@
+/* $OpenBSD: nofnvar.h,v 1.3 2002/05/15 21:33:22 jason Exp $ */
+
+/*
+ * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct nofn_softc {
+ struct device sc_dev;
+ void *sc_ih;
+ bus_space_handle_t sc_sh;
+ bus_space_tag_t sc_st;
+ bus_space_handle_t sc_pk_h;
+ bus_space_tag_t sc_pk_t;
+ bus_dma_tag_t sc_dmat;
+ int32_t sc_cid;
+ int sc_flags;
+ int sc_rngskip, sc_rngtick;
+ struct timeout sc_rngto;
+ u_int32_t sc_intrmask, sc_revid;
+ SIMPLEQ_HEAD(,nofn_pk_q) sc_pk_queue;
+ struct nofn_pk_q *sc_pk_current;
+ union nofn_pk_reg sc_pk_tmp, sc_pk_zero;
+};
+
+struct nofn_pk_q {
+ SIMPLEQ_ENTRY(nofn_pk_q) q_next;
+ int (*q_start)(struct nofn_softc *, struct nofn_pk_q *);
+ void (*q_finish)(struct nofn_softc *, struct nofn_pk_q *);
+ struct cryptkop *q_krp;
+};
+
+#define NOFN_FLAGS_RNG 0x01
+#define NOFN_FLAGS_PK 0x02
+
+#define REG_WRITE_4(sc,r,v) \
+ bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (r), (v))
+#define REG_READ_4(sc,r) \
+ bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (r))
+
+#define PK_WRITE_4(sc,r,v) \
+ bus_space_write_4((sc)->sc_pk_t, (sc)->sc_pk_h, (r), (v))
+#define PK_READ_4(sc,r) \
+ bus_space_read_4((sc)->sc_pk_t, (sc)->sc_pk_h, (r))
+
+#ifndef PK_RNC_SCALER
+#define PK_RNC_SCALER 0x00000700
+#endif
+
+/* C = M ^ E mod N */
+#define NOFN_MODEXP_PAR_M 0
+#define NOFN_MODEXP_PAR_E 1
+#define NOFN_MODEXP_PAR_N 2
+#define NOFN_MODEXP_PAR_C 3