diff options
author | Hakan Olsson <ho@cvs.openbsd.org> | 2001-06-04 13:07:21 +0000 |
---|---|---|
committer | Hakan Olsson <ho@cvs.openbsd.org> | 2001-06-04 13:07:21 +0000 |
commit | def0a55bccd5d217c525df2164ff92a51088f7db (patch) | |
tree | d9e61ec474a36ad62d50952560fbebf3b49fd615 /sys/dev | |
parent | e56790115cb821304411a9e82a148d366d5369fa (diff) |
Some further work. No crypto yet.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/ises.c | 739 | ||||
-rw-r--r-- | sys/dev/pci/isesreg.h | 25 | ||||
-rw-r--r-- | sys/dev/pci/isesvar.h | 43 |
3 files changed, 705 insertions, 102 deletions
diff --git a/sys/dev/pci/ises.c b/sys/dev/pci/ises.c index 3288e67881e..89d70b1e8b0 100644 --- a/sys/dev/pci/ises.c +++ b/sys/dev/pci/ises.c @@ -1,7 +1,7 @@ -/* $OpenBSD: ises.c,v 1.4 2001/03/28 20:02:59 angelos Exp $ */ +/* $OpenBSD: ises.c,v 1.5 2001/06/04 13:07:19 ho Exp $ */ /* - * Copyright (c) 2000 Håkan Olsson (ho@crt.se) + * Copyright (c) 2000, 2001 Håkan Olsson (ho@crt.se) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,10 +40,6 @@ #include <sys/kernel.h> #include <sys/mbuf.h> #include <sys/timeout.h> -#include <vm/vm.h> -#include <vm/vm_extern.h> -#include <vm/pmap.h> -#include <machine/pmap.h> #include <sys/device.h> #include <sys/queue.h> @@ -71,7 +67,9 @@ void ises_initstate __P((void *)); void ises_hrng_init __P((struct ises_softc *)); void ises_hrng __P((void *)); void ises_process_oqueue __P((struct ises_softc *)); -int ises_queue_cmd __P((struct ises_softc *, u_int32_t, u_int32_t *)); +int ises_queue_cmd __P((struct ises_softc *, u_int32_t, u_int32_t *, + u_int32_t (*)(struct ises_softc *, + struct ises_cmd *))); u_int32_t ises_get_fwversion __P((struct ises_softc *)); int ises_assert_cmd_mode __P((struct ises_softc *)); @@ -81,6 +79,8 @@ int ises_freesession __P((u_int64_t)); int ises_process __P((struct cryptop *)); void ises_callback __P((struct ises_q *)); int ises_feed __P((struct ises_softc *)); +void ises_bchu_switch_session __P((struct ises_softc *, + struct ises_bchu_session *)); /* XXX for now... */ void ubsec_mcopy __P((struct mbuf *, struct mbuf *, int, int)); @@ -91,6 +91,7 @@ void ubsec_mcopy __P((struct mbuf *, struct mbuf *, int, int)); #define WRITE_REG(sc,reg,val) \ bus_space_write_4((sc)->sc_memt, (sc)->sc_memh, reg, val) +/* XXX This should probably be (x) = htole32((x)) */ #define SWAP32(x) ((x) = swap32((x))) #ifdef ISESDEBUG @@ -99,6 +100,18 @@ void ubsec_mcopy __P((struct mbuf *, struct mbuf *, int, int)); # define DPRINTF(x) #endif +#ifdef ISESDEBUG +void ises_debug_init __P((struct ises_softc *)); +void ises_debug_2 __P((void)); +void ises_debug_loop __P((void *)); +void ises_showreg __P((void)); +void ises_debug_parse_omr __P((struct ises_softc *)); +void ises_debug_simple_cmd __P((struct ises_softc *, u_int32_t, u_int32_t)); +struct ises_softc *ises_sc; +struct timeout ises_db_timeout; +int ises_db; +#endif + /* For HRNG entropy collection, these values gather 1600 bytes/s */ #ifndef ISESRNGBITS #define ISESRNGBITS 128 /* Bits per iteration (mult. of 32) */ @@ -113,6 +126,15 @@ struct cfdriver ises_cd = { 0, "ises", DV_DULL }; +struct ises_stats { + u_int64_t ibytes; + u_int64_t obytes; + u_int32_t ipkts; + u_int32_t opkts; + u_int32_t invalid; + u_int32_t nomem; +} isesstats; + int ises_match(struct device *parent, void *match, void *aux) { @@ -142,6 +164,7 @@ ises_attach(struct device *parent, struct device *self, void *aux) SIMPLEQ_INIT(&sc->sc_queue); SIMPLEQ_INIT(&sc->sc_qchip); + SIMPLEQ_INIT(&sc->sc_cmdq); state = 0; /* Verify PCI space */ @@ -216,6 +239,8 @@ ises_attach(struct device *parent, struct device *self, void *aux) printf(": %s\n", intrstr); + memset (&isesstats, 0, sizeof(isesstats)); + sc->sc_cid = crypto_get_driverid(); if (sc->sc_cid < 0) @@ -230,7 +255,9 @@ ises_attach(struct device *parent, struct device *self, void *aux) sc->sc_initstate = 0; timeout_set(&sc->sc_timeout, ises_initstate, sc); ises_initstate(sc); - +#ifdef ISESDEBUG + ises_debug_init(sc); +#endif return; fail: @@ -420,7 +447,9 @@ ises_initstate(void *v) /* Set the interrupt mask */ sc->sc_intrmask = ISES_STAT_BCHU_OAF | ISES_STAT_BCHU_ERR | - ISES_STAT_BCHU_OFHF | ISES_STAT_SW_OQSINC; + ISES_STAT_BCHU_OFHF | ISES_STAT_SW_OQSINC | + ISES_STAT_LNAU_BUSY_1 | ISES_STAT_LNAU_ERR_1 | + ISES_STAT_LNAU_BUSY_2 | ISES_STAT_LNAU_ERR_2; #if 0 ISES_STAT_BCHU_ERR | ISES_STAT_BCHU_OAF | ISES_STAT_BCHU_IFE | ISES_STAT_BCHU_IFHE | @@ -465,12 +494,15 @@ ises_initstate(void *v) /* Put a command on the A-interface queue. */ int -ises_queue_cmd(struct ises_softc *sc, u_int32_t cmd, u_int32_t *data) +ises_queue_cmd(struct ises_softc *sc, u_int32_t cmd, u_int32_t *data, + u_int32_t (*callback)(struct ises_softc *, struct ises_cmd *)) { - int p, len, s; + struct ises_cmd *cq; + int p, len, s, code; len = cmd >> 24; - + code = (cmd >> 16) & 0xFF; + s = splimp(); if (len > READ_REG(sc, ISES_A_IQF)) { @@ -478,10 +510,28 @@ ises_queue_cmd(struct ises_softc *sc, u_int32_t cmd, u_int32_t *data) return (EAGAIN); /* XXX ENOMEM ? */ } + cq = (struct ises_cmd *) + malloc(sizeof (struct ises_cmd), M_DEVBUF, M_NOWAIT); + if (cq == NULL) { + splx(s); + isesstats.nomem++; + return (ENOMEM); + } + memset(cq, 0, sizeof (struct ises_cmd)); + cq->cmd_code = code; + cq->cmd_cb = callback; + SIMPLEQ_INSERT_TAIL(&sc->sc_cmdq, cq, cmd_next); + WRITE_REG(sc, ISES_A_IQD, cmd); - for (p = 0; p < len; p++) - WRITE_REG(sc, ISES_A_IQD, *(data + p)); + /* LNAU register data should be written in reverse order */ + if ((code >= ISES_CMD_LW_A_1 && code <= ISES_CMD_LW_U_1) || /* LNAU1 */ + (code >= ISES_CMD_LW_A_2 && code <= ISES_CMD_LW_U_2)) /* LNAU2 */ + for (p = len - 1; p >= 0; p--) + WRITE_REG(sc, ISES_A_IQD, *(data + p)); + else + for (p = 0; p < len; p++) + WRITE_REG(sc, ISES_A_IQD, *(data + p)); WRITE_REG(sc, ISES_A_IQS, 0); @@ -496,8 +546,13 @@ ises_process_oqueue(struct ises_softc *sc) #ifdef ISESDEBUG char *dv = sc->sc_dv.dv_xname; #endif + struct ises_cmd *cq; u_int32_t oqs, r, d; - int cmd, len; + int cmd, len, c; + + r = READ_REG(sc, ISES_A_OQS); + if (r > 1) + DPRINTF(("%s:process_oqueue: OQS=%d\n", dv, r)); /* OQS gives us the number of responses we have to process. */ while ((oqs = READ_REG(sc, ISES_A_OQS)) > 0) { @@ -507,12 +562,37 @@ ises_process_oqueue(struct ises_softc *sc) cmd = (r >> 16) & 0xff; r = r & 0xffff; + if (!SIMPLEQ_EMPTY(&sc->sc_cmdq)) { + cq = SIMPLEQ_FIRST(&sc->sc_cmdq); + SIMPLEQ_REMOVE_HEAD(&sc->sc_cmdq, cq, cmd_next); + cq->cmd_rlen = len; + } else { + cq = NULL; + DPRINTF(("%s:process_oqueue: cmd queue empty!\n", dv)); + } + if (r) { /* This command generated an error */ - DPRINTF(("%s: cmd %d error %d\n", dv, cmd, + DPRINTF(("%s:process_oqueue: cmd %d err %d\n", dv, cmd, (r & ISES_RC_MASK))); - } else + } else { + /* Use specified callback, if any */ + if (cq && cq->cmd_cb) { + if (cmd == cq->cmd_code) { + cq->cmd_cb(sc, cq); + cmd = ISES_CMD_NONE; + } else { + DPRINTF(("%s:process_oqueue: expected" + " cmd %d, got %d\n", dv, + cq->cmd_code, cmd)); + /* XXX Some error handling here? */ + } + } + switch (cmd) { + case ISES_CMD_NONE: + break; + case ISES_CMD_HBITS: /* XXX How about increasing the pool size? */ /* XXX Use add_entropy_words instead? */ @@ -524,22 +604,67 @@ ises_process_oqueue(struct ises_softc *sc) } break; + case ISES_CMD_LUPLOAD_1: + /* Get result of LNAU 1 operation. */ + DPRINTF(("%s:process_oqueue: LNAU 1 result " + "upload (len=%d)\n", dv, len)); + sc->sc_lnau1_rlen = len; + memset (sc->sc_lnau1_r, 0, 2048 / 8); + while (len--) { + /* first word is LSW */ + sc->sc_lnau1_r[len] = + READ_REG(sc, ISES_A_OQD); + } + break; + + case ISES_CMD_LUPLOAD_2: + /* Get result of LNAU 1 operation. */ + DPRINTF(("%s:process_oqueue: LNAU 2 result " + "upload (len=%d)\n", dv, len)); + sc->sc_lnau2_rlen = len; + memset (sc->sc_lnau1_r, 0, 2048 / 8); + while (len--) { + /* first word is LSW */ + sc->sc_lnau2_r[len] = + READ_REG(sc, ISES_A_OQD); + } + break; + case ISES_CMD_BR_OMR: - sc->sc_omr = READ_REG(sc, ISES_A_OQD); - DPRINTF(("%s: read sc->sc_omr [%08x]\n", dv, - sc->sc_omr)); + sc->sc_bsession.omr = READ_REG(sc, ISES_A_OQD); + DPRINTF(("%s:process_oqueue: read OMR[%08x]\n", + dv, sc->sc_bsession.omr)); +#ifdef ISESDEBUG + ises_debug_parse_omr(sc); +#endif + break; + + case ISES_CMD_BSWITCH: + DPRINTF(("%s:process_oqueue: BCHU_SWITCH\n")); + /* Put switched BCHU session in sc_bsession. */ + for(c = 0; len > 0; len--, c++) + *((u_int32_t *)&sc->sc_bsession + c) = + READ_REG(sc, ISES_A_OQD); break; default: /* All other are ok (no response data) */ + DPRINTF(("%s:process_oqueue [cmd %d len %d]\n", + dv, cmd, len)); + if (cq && cq->cmd_cb) + len -= cq->cmd_cb(sc, cq); } + } - /* This will drain any remaining data and ACK this reponse. */ - while (len-- > 0) - d = READ_REG(sc, ISES_A_OQD); - WRITE_REG(sc, ISES_A_OQS, 0); - if (oqs > 1) - DELAY(1); /* Wait for firmware to decrement OQS (8 clocks) */ + if (cq) + free(cq, M_DEVBUF); + + /* This will drain any remaining data and ACK this reponse. */ + while (len-- > 0) + d = READ_REG(sc, ISES_A_OQD); + WRITE_REG(sc, ISES_A_OQS, 0); + if (oqs > 1) + DELAY(1); /* Wait for fw to decrement OQS (8 clocks) */ } } @@ -548,6 +673,10 @@ ises_intr(void *arg) { struct ises_softc *sc = arg; volatile u_int32_t ints; + u_int32_t cmd; +#ifdef ISESDEBUG + char *dv = sc->sc_dv.dv_xname; +#endif ints = READ_REG(sc, ISES_A_INTS); if (!(ints & sc->sc_intrmask)) @@ -566,18 +695,42 @@ ises_intr(void *arg) ises_process_oqueue(sc); } + if (ints & ISES_STAT_LNAU_BUSY_1) { + DPRINTF(("%s:ises_intr: LNAU 1 job complete\n", dv)); + /* upload LNAU 1 result (into sc->sc_lnau1_r) */ + cmd = ISES_MKCMD(ISES_CMD_LUPLOAD_1, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); + } + + if (ints & ISES_STAT_LNAU_BUSY_2) { + DPRINTF(("%s:ises_intr: LNAU 2 job complete\n", dv)); + /* upload LNAU 2 result (into sc->sc_lnau2_r) */ + cmd = ISES_MKCMD(ISES_CMD_LUPLOAD_2, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); + } + + if (ints & ISES_STAT_LNAU_ERR_1) { + DPRINTF(("%s:ises_intr: LNAU 1 error\n", dv)); + sc->sc_lnau1_rlen = -1; + } + + if (ints & ISES_STAT_LNAU_ERR_2) { + DPRINTF(("%s:ises_intr: LNAU 2 error\n", dv)); + sc->sc_lnau2_rlen = -1; + } + if (ints & ISES_STAT_BCHU_OAF) { /* output data available */ - DPRINTF(("ises_intr: BCHU_OAF bit set\n")); + DPRINTF(("%s:ises_intr: BCHU_OAF bit set\n", dv)); /* ises_process_oqueue(sc); */ } if (ints & ISES_STAT_BCHU_ERR) { /* We got a BCHU error */ - DPRINTF(("ises_intr: BCHU error\n")); + DPRINTF(("%s:ises_intr: BCHU error\n", dv)); /* XXX Error handling */ } if (ints & ISES_STAT_BCHU_OFHF) { /* Output is half full */ - DPRINTF(("ises_intr: BCHU output FIFO half full\n")); + DPRINTF(("%s:ises_intr: BCHU output FIFO half full\n", dv)); /* XXX drain data? */ } @@ -621,7 +774,7 @@ ises_newsession(u_int32_t *sidp, struct cryptoini *cri) { struct cryptoini *c, *mac = NULL, *enc = NULL; struct ises_softc *sc = NULL; - struct ises_session *ses = NULL; + struct ises_session *ses; MD5_CTX md5ctx; SHA1_CTX sha1ctx; RMD160_CTX rmd160ctx; @@ -656,27 +809,33 @@ ises_newsession(u_int32_t *sidp, struct cryptoini *cri) if (mac == 0 && enc == 0) return (EINVAL); + /* Allocate a new session */ if (sc->sc_sessions == NULL) { ses = sc->sc_sessions = (struct ises_session *) malloc(sizeof(struct ises_session), M_DEVBUF, M_NOWAIT); - if (ses == NULL) + if (ses == NULL) { + isesstats.nomem++; return (ENOMEM); + } sesn = 0; sc->sc_nsessions = 1; } else { + ses = NULL; for (sesn = 0; sesn < sc->sc_nsessions; sesn++) if (sc->sc_sessions[sesn].ses_used == 0) { ses = &sc->sc_sessions[sesn]; break; } - if (ses == NULL) { + if (ses == NULL) { i = sc->sc_nsessions * sizeof(struct ises_session); ses = (struct ises_session *) malloc(i + sizeof(struct ises_session), M_DEVBUF, M_NOWAIT); - if (ses == NULL) + if (ses == NULL) { + isesstats.nomem++; return (ENOMEM); + } memcpy(ses, sc->sc_sessions, i); memset(sc->sc_sessions, 0, i); @@ -715,21 +874,25 @@ ises_newsession(u_int32_t *sidp, struct cryptoini *cri) for (i = 0; i < mac->cri_klen / 8; i++) mac->cri_key[i] ^= HMAC_IPAD_VAL; - if (mac->cri_alg == CRYPTO_MD5_HMAC) { + switch (mac->cri_alg) { + case CRYPTO_MD5_HMAC: MD5Init(&md5ctx); MD5Update(&md5ctx, mac->cri_key, mac->cri_klen / 8); MD5Update(&md5ctx, hmac_ipad_buffer, HMAC_BLOCK_LEN - (mac->cri_klen / 8)); memcpy(ses->ses_hminner, md5ctx.state, sizeof(md5ctx.state)); - } else if (mac->cri_alg == CRYPTO_SHA1_HMAC) { + break; + case CRYPTO_SHA1_HMAC: SHA1Init(&sha1ctx); SHA1Update(&sha1ctx, mac->cri_key, mac->cri_klen / 8); SHA1Update(&sha1ctx, hmac_ipad_buffer, HMAC_BLOCK_LEN - (mac->cri_klen / 8)); memcpy(ses->ses_hminner, sha1ctx.state, sizeof(sha1ctx.state)); - } else { + break; + case CRYPTO_RIPEMD160_HMAC: + default: RMD160Init(&rmd160ctx); RMD160Update(&rmd160ctx, mac->cri_key, mac->cri_klen / 8); @@ -737,26 +900,31 @@ ises_newsession(u_int32_t *sidp, struct cryptoini *cri) HMAC_BLOCK_LEN - (mac->cri_klen / 8)); memcpy(ses->ses_hminner, rmd160ctx.state, sizeof(rmd160ctx.state)); + break; } for (i = 0; i < mac->cri_klen / 8; i++) mac->cri_key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL); - if (mac->cri_alg == CRYPTO_MD5_HMAC) { + switch (mac->cri_alg) { + case CRYPTO_MD5_HMAC: MD5Init(&md5ctx); MD5Update(&md5ctx, mac->cri_key, mac->cri_klen / 8); MD5Update(&md5ctx, hmac_ipad_buffer, HMAC_BLOCK_LEN - (mac->cri_klen / 8)); memcpy(ses->ses_hmouter, md5ctx.state, sizeof(md5ctx.state)); - } else if (mac->cri_alg == CRYPTO_SHA1_HMAC) { + break; + case CRYPTO_SHA1_HMAC: SHA1Init(&sha1ctx); SHA1Update(&sha1ctx, mac->cri_key, mac->cri_klen / 8); SHA1Update(&sha1ctx, hmac_ipad_buffer, HMAC_BLOCK_LEN - (mac->cri_klen / 8)); memcpy(ses->ses_hmouter, sha1ctx.state, sizeof(sha1ctx.state)); - } else { + break; + case CRYPTO_RIPEMD160_HMAC: + default: RMD160Init(&rmd160ctx); RMD160Update(&rmd160ctx, mac->cri_key, mac->cri_klen / 8); @@ -764,6 +932,7 @@ ises_newsession(u_int32_t *sidp, struct cryptoini *cri) HMAC_BLOCK_LEN - (mac->cri_klen / 8)); memcpy(ses->ses_hmouter, rmd160ctx.state, sizeof(rmd160ctx.state)); + break; } for (i = 0; i < mac->cri_klen / 8; i++) @@ -892,43 +1061,43 @@ ises_process(struct cryptop *crp) encoffset = enccrd->crd_skip; if (enccrd->crd_alg == CRYPTO_3DES_CBC) - q->q_ctx.pc_omrflags |= ISES_SOMR_BOMR_3DES; + q->q_bsession.omr |= ISES_SOMR_BOMR_3DES; else - q->q_ctx.pc_omrflags |= ISES_SOMR_BOMR_DES; - q->q_ctx.pc_omrflags |= ISES_SOMR_FMR_CBC; + q->q_bsession.omr |= ISES_SOMR_BOMR_DES; + q->q_bsession.omr |= ISES_SOMR_FMR_CBC; if (enccrd->crd_flags & CRD_F_ENCRYPT) { - q->q_ctx.pc_omrflags |= ISES_SOMR_EDR; /* XXX */ + q->q_bsession.omr |= ISES_SOMR_EDR; /* XXX */ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) - bcopy(enccrd->crd_iv, q->q_ctx.pc_iv, 8); + bcopy(enccrd->crd_iv, q->q_bsession.sccr, 8); else { - q->q_ctx.pc_iv[0] = ses->ses_iv[0]; - q->q_ctx.pc_iv[1] = ses->ses_iv[1]; + q->q_bsession.sccr[0] = ses->ses_iv[0]; + q->q_bsession.sccr[1] = ses->ses_iv[1]; } if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) m_copyback(q->q_src_m, enccrd->crd_inject, - 8, (caddr_t)q->q_ctx.pc_iv); + 8, (caddr_t)q->q_bsession.sccr); } else { - q->q_ctx.pc_omrflags &= ~ISES_SOMR_EDR; /* XXX */ + q->q_bsession.omr &= ~ISES_SOMR_EDR; /* XXX */ if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) - bcopy(enccrd->crd_iv, q->q_ctx.pc_iv, 8); + bcopy(enccrd->crd_iv, q->q_bsession.sccr, 8); else m_copyback(q->q_src_m, enccrd->crd_inject, - 8, (caddr_t)q->q_ctx.pc_iv); + 8, (caddr_t)q->q_bsession.sccr); } - q->q_ctx.pc_deskey[0] = ses->ses_deskey[0]; - q->q_ctx.pc_deskey[1] = ses->ses_deskey[1]; - q->q_ctx.pc_deskey[2] = ses->ses_deskey[2]; - q->q_ctx.pc_deskey[3] = ses->ses_deskey[3]; - q->q_ctx.pc_deskey[4] = ses->ses_deskey[4]; - q->q_ctx.pc_deskey[5] = ses->ses_deskey[5]; + q->q_bsession.kr[0] = ses->ses_deskey[0]; + q->q_bsession.kr[1] = ses->ses_deskey[1]; + q->q_bsession.kr[2] = ses->ses_deskey[2]; + q->q_bsession.kr[3] = ses->ses_deskey[3]; + q->q_bsession.kr[4] = ses->ses_deskey[4]; + q->q_bsession.kr[5] = ses->ses_deskey[5]; - SWAP32(q->q_ctx.pc_iv[0]); - SWAP32(q->q_ctx.pc_iv[1]); + SWAP32(q->q_bsession.sccr[0]); + SWAP32(q->q_bsession.sccr[1]); } if (maccrd) { @@ -936,30 +1105,30 @@ ises_process(struct cryptop *crp) switch (crd->crd_alg) { case CRYPTO_MD5_HMAC: - q->q_ctx.pc_omrflags |= ISES_HOMR_HFR_MD5; + q->q_bsession.omr |= ISES_HOMR_HFR_MD5; break; case CRYPTO_SHA1_HMAC: - q->q_ctx.pc_omrflags |= ISES_HOMR_HFR_SHA1; + q->q_bsession.omr |= ISES_HOMR_HFR_SHA1; break; case CRYPTO_RIPEMD160_HMAC: default: - q->q_ctx.pc_omrflags |= ISES_HOMR_HFR_RMD160; + q->q_bsession.omr |= ISES_HOMR_HFR_RMD160; break; } - q->q_ctx.pc_hminner[0] = ses->ses_hminner[0]; - q->q_ctx.pc_hminner[1] = ses->ses_hminner[1]; - q->q_ctx.pc_hminner[2] = ses->ses_hminner[2]; - q->q_ctx.pc_hminner[3] = ses->ses_hminner[3]; - q->q_ctx.pc_hminner[4] = ses->ses_hminner[4]; - q->q_ctx.pc_hminner[5] = ses->ses_hminner[5]; - - q->q_ctx.pc_hmouter[0] = ses->ses_hmouter[0]; - q->q_ctx.pc_hmouter[1] = ses->ses_hmouter[1]; - q->q_ctx.pc_hmouter[2] = ses->ses_hmouter[2]; - q->q_ctx.pc_hmouter[3] = ses->ses_hmouter[3]; - q->q_ctx.pc_hmouter[4] = ses->ses_hmouter[4]; - q->q_ctx.pc_hmouter[5] = ses->ses_hmouter[5]; + q->q_hminner[0] = ses->ses_hminner[0]; + q->q_hminner[1] = ses->ses_hminner[1]; + q->q_hminner[2] = ses->ses_hminner[2]; + q->q_hminner[3] = ses->ses_hminner[3]; + q->q_hminner[4] = ses->ses_hminner[4]; + q->q_hminner[5] = ses->ses_hminner[5]; + + q->q_hmouter[0] = ses->ses_hmouter[0]; + q->q_hmouter[1] = ses->ses_hmouter[1]; + q->q_hmouter[2] = ses->ses_hmouter[2]; + q->q_hmouter[3] = ses->ses_hmouter[3]; + q->q_hmouter[4] = ses->ses_hmouter[4]; + q->q_hmouter[5] = ses->ses_hmouter[5]; } if (enccrd && maccrd) { @@ -986,7 +1155,7 @@ ises_process(struct cryptop *crp) cpoffset = cpskip + dtheend; coffset = 0; } - q->q_ctx.pc_offset = coffset >> 2; + q->q_offset = coffset >> 2; q->q_src_l = mbuf2pages(q->q_src_m, &q->q_src_npa, &q->q_src_packp, &q->q_src_packl, 1, &nicealign); @@ -1149,6 +1318,11 @@ ises_process(struct cryptop *crp) return (0); errout: + if (err == ENOMEM) + isesstats.nomem++; + else if (err == EINVAL) + isesstats.invalid++; + if (q) { if (q->q_src_m != q->q_dst_m) m_freem(q->q_dst_m); @@ -1198,7 +1372,7 @@ ises_hrng_init(struct ises_softc *sc) cmd = ISES_MKCMD(ISES_CMD_HBITS, 1); r = 8; /* 8 * 32 = 256 bits */ - if (ises_queue_cmd(sc, cmd, &r)) + if (ises_queue_cmd(sc, cmd, &r, NULL)) return; /* Wait until response arrives. */ @@ -1235,7 +1409,7 @@ ises_hrng_init(struct ises_softc *sc) /* Queue 100 cmds; each generate 250 32-bit words of rnd data. */ microtime(&tv1); for (i = 0; i < ISES_ROUNDS; i++) - ises_queue_cmd(sc, cmd, &r); + ises_queue_cmd(sc, cmd, &r, NULL); for (i = 0; i < ISES_ROUNDS; i++) { while (READ_REG(sc, ISES_A_OQS) == 0) ; /* Wait for response */ @@ -1253,7 +1427,6 @@ ises_hrng_init(struct ises_softc *sc) ISES_WPR * ISES_ROUNDS * 32 / 1024 * 1000000 / tv1.tv_usec); #endif - printf("\n"); timeout_set(&sc->sc_timeout, ises_hrng, sc); ises_hrng(sc); /* Call first update */ } @@ -1278,7 +1451,7 @@ ises_hrng(void *v) cmd = ISES_MKCMD(ISES_CMD_HBITS, 1); n = (ISESRNGBITS >> 5) & 0xff; /* ask for N 32 bit words */ - ises_queue_cmd(sc, cmd, &n); + ises_queue_cmd(sc, cmd, &n, NULL); } u_int32_t @@ -1351,3 +1524,411 @@ ises_assert_cmd_mode(struct ises_softc *sc) return (-1); /* Unknown mode */ } } + +#ifdef ISESDEBUG +/* + * Development code section below here. + */ + +void +ises_debug_init (struct ises_softc *sc) +{ + ises_sc = sc; + ises_db = 0; + timeout_set (&ises_db_timeout, ises_debug_loop, sc); + timeout_add (&ises_db_timeout, 100); + printf ("ises0: ISESDEBUG active (ises_sc = %p)\n", ises_sc); +} + +void +ises_debug_2 (void) +{ + timeout_set (&ises_db_timeout, ises_debug_loop, ises_sc); + timeout_add (&ises_db_timeout, 100); + printf ("ises0: another debug timeout scheduled!\n"); +} + +void +ises_debug_simple_cmd (struct ises_softc *sc, u_int32_t code, u_int32_t d) +{ + u_int32_t cmd, data; + + cmd = ISES_MKCMD(code, (d ? 1 : 0)); + data = d; + ises_queue_cmd(sc, cmd, &d, NULL); +} + +void +ises_bchu_switch_session (struct ises_softc *sc, struct ises_bchu_session *ss) +{ + /* It appears that the BCHU_SWITCH_SESSION command is broken. */ + /* We have to work around it. */ + + u_int32_t cmd; + + cmd = ISES_MKCMD(ISES_CMD_BR_KR0, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); + cmd = ISES_MKCMD(ISES_CMD_BR_KR1, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); + cmd = ISES_MKCMD(ISES_CMD_BR_KR2, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); + + cmd = ISES_MKCMD(ISES_CMD_BR_OMR, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); + cmd = ISES_MKCMD(ISES_CMD_BR_SCCR, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); + cmd = ISES_MKCMD(ISES_CMD_BR_DBCR, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); + cmd = ISES_MKCMD(ISES_CMD_BR_HMLR, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); + cmd = ISES_MKCMD(ISES_CMD_BR_CVR, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); +} + +void +ises_debug_loop (void *v) +{ + struct ises_softc *sc = (struct ises_softc *)v; + struct ises_bchu_session bses; + u_int32_t cmd, stat; + int i; + + if (ises_db) + printf ("ises0: ises_db = %d sc = %p\n", ises_db, sc); + + timeout_add (&ises_db_timeout, 300); /* Every 3 secs */ + + stat = READ_REG(sc, ISES_A_OQS); + cmd = READ_REG(sc, ISES_A_IQS); + if (stat || cmd) + printf ("ises0: IQS=%d OQS=%d / IQF=%d OQF=%d\n", + cmd, stat, READ_REG(sc, ISES_A_IQF), + READ_REG(sc, ISES_A_OQF)); + + switch (ises_db) { + default: + /* 0 - do nothing (just loop) */ + break; + case 1: + /* Just dump register info */ + ises_showreg(); + break; + case 2: + /* Reset LNAU 1 registers */ + ises_debug_simple_cmd(sc, ISES_CMD_LRESET_1, 0); + + /* Compute R = (141 * 5623) % 117 (R should be 51 (0x33)) */ + ises_debug_simple_cmd(sc, ISES_CMD_LW_A_1, 141); + ises_debug_simple_cmd(sc, ISES_CMD_LW_B_1, 5623); + ises_debug_simple_cmd(sc, ISES_CMD_LW_N_1, 117); + + /* Launch LNAU operation. */ + ises_debug_simple_cmd(sc, ISES_CMD_LMULMOD_1, 0); + break; + case 3: + /* Read result LNAU_1 R register (should not be necessary) */ + ises_debug_simple_cmd(sc, ISES_CMD_LUPLOAD_1, 0); + break; + case 4: + /* Print result */ + printf ("LNAU_1 R length = %d\n", sc->sc_lnau1_rlen); + for (i = 0; i < sc->sc_lnau1_rlen; i++) + printf ("W%02d-[%08x]-(%u)\t%s", i, sc->sc_lnau1_r[i], + sc->sc_lnau1_r[i], (i%4)==3 ? "\n" : ""); + printf ("%s", (i%4) ? "\n" : ""); + break; + case 5: + /* Crypto. */ + + /* Load BCHU session data */ + memset(&bses, 0, sizeof bses); + bses.kr[0] = 0xD0; + bses.kr[1] = 0xD1; + bses.kr[2] = 0xD2; + bses.kr[3] = 0xD3; + bses.kr[4] = 0xD4; + bses.kr[5] = 0xD5; + + /* cipher data out is hash in, SHA1, 3DES, encrypt, ECB */ + bses.omr = ISES_SELR_BCHU_HISOF | ISES_HOMR_HFR_SHA1 | + ISES_SOMR_BOMR_3DES | ISES_SOMR_EDR | ISES_SOMR_FMR_ECB; + + printf ("Queueing OMR write\n"); + cmd = ISES_MKCMD(ISES_CMD_BW_OMR, 1); + ises_queue_cmd(sc, cmd, &bses.omr, NULL); + + printf ("Queueing KR0, KR1, KR2 writes\n"); + cmd = ISES_MKCMD(ISES_CMD_BW_KR0, 2); + ises_queue_cmd(sc, cmd, &bses.kr[4], NULL); + cmd = ISES_MKCMD(ISES_CMD_BW_KR1, 2); + ises_queue_cmd(sc, cmd, &bses.kr[2], NULL); + cmd = ISES_MKCMD(ISES_CMD_BW_KR2, 2); + ises_queue_cmd(sc, cmd, &bses.kr[0], NULL); + +#if 0 /* switch session does not appear to work - it never returns */ + printf ("Queueing BCHU session switch\n"); + cmd = ISES_MKCMD(ISES_CMD_BSWITCH, sizeof bses / 4); + printf ("session is %d 32bit words (== 18 ?), cmd = [%08x]\n", + sizeof bses / 4, cmd); + ises_queue_cmd(sc, cmd, (u_int32_t *)&bses, NULL); +#endif + + break; + case 96: + printf ("Stopping HRNG data collection\n"); + timeout_del(&sc->sc_timeout); + break; + case 97: + printf ("Restarting HRNG data collection\n"); + if (!timeout_pending(&sc->sc_timeout)) + timeout_add(&sc->sc_timeout, hz); + break; + case 98: + printf ("Resetting (wait >1s before cont.)\n"); + stat = ISES_BO_STAT_HWRESET; + WRITE_REG(sc, ISES_BO_STAT, stat); + stat &= ~ISES_BO_STAT_HWRESET; + WRITE_REG(sc, ISES_BO_STAT, stat); + break; + case 99: + printf ("Resetting everything!\n"); + if (timeout_pending(&sc->sc_timeout)) + timeout_del(&sc->sc_timeout); + timeout_set(&sc->sc_timeout, ises_initstate, sc); + sc->sc_initstate = 0; + ises_initstate(sc); + break; + } + + ises_db = 0; +} + +void +ises_showreg (void) +{ + struct ises_softc *sc = ises_sc; + u_int32_t stat, cmd; + + /* Board register */ + + printf ("Board register: "); + stat = READ_REG(sc, ISES_BO_STAT); + + if (stat & ISES_BO_STAT_LOOP) + printf ("LoopMode "); + if (stat & ISES_BO_STAT_TAMPER) + printf ("Tamper "); + if (stat & ISES_BO_STAT_POWERDOWN) + printf ("PowerDown "); + if (stat & ISES_BO_STAT_ACONF) + printf ("16bitA-IF "); + if (stat & ISES_BO_STAT_HWRESET) + printf ("HWReset"); + if (stat & ISES_BO_STAT_AIRQ) + printf ("A-IFintr"); + printf("\n"); + + /* A interface */ + + printf ("A Interface STAT register: \n\tLNAU-["); + stat = READ_REG(sc, ISES_A_STAT); + if (stat & ISES_STAT_LNAU_MASKED) + printf ("masked"); + else { + if (stat & ISES_STAT_LNAU_BUSY_1) + printf ("busy1 "); + if (stat & ISES_STAT_LNAU_ERR_1) + printf ("err1 "); + if (stat & ISES_STAT_LNAU_BUSY_2) + printf ("busy2 "); + if (stat & ISES_STAT_LNAU_ERR_2) + printf ("err2 "); + } + printf ("]\n\tBCHU-["); + + if (stat & ISES_STAT_BCHU_MASKED) + printf ("masked"); + else { + if (stat & ISES_STAT_BCHU_BUSY) + printf ("busy "); + if (stat & ISES_STAT_BCHU_ERR) + printf ("err "); + if (stat & ISES_STAT_BCHU_SCIF) + printf ("cr-inop "); + if (stat & ISES_STAT_BCHU_HIF) + printf ("ha-inop "); + if (stat & ISES_STAT_BCHU_DDB) + printf ("dscd-data "); + if (stat & ISES_STAT_BCHU_IRF) + printf ("inp-req "); + if (stat & ISES_STAT_BCHU_OAF) + printf ("out-avail "); + if (stat & ISES_STAT_BCHU_DIE) + printf ("inp-enabled "); + if (stat & ISES_STAT_BCHU_UE) + printf ("ififo-empty "); + if (stat & ISES_STAT_BCHU_IFE) + printf ("ififo-half "); + if (stat & ISES_STAT_BCHU_IFHE) + printf ("ififo-full "); + if (stat & ISES_STAT_BCHU_OFE) + printf ("ofifo-empty "); + if (stat & ISES_STAT_BCHU_OFHF) + printf ("ofifo-half "); + if (stat & ISES_STAT_BCHU_OFF) + printf ("ofifo-full "); + } + printf ("] \n\tmisc-["); + + if (stat & ISES_STAT_HW_DA) + printf ("downloaded-appl "); + if (stat & ISES_STAT_HW_ACONF) + printf ("A-IF-conf "); + if (stat & ISES_STAT_SW_WFOQ) + printf ("OQ-wait "); + if (stat & ISES_STAT_SW_OQSINC) + printf ("OQS-increased "); + printf ("]\n\t"); + + if (stat & ISES_STAT_HW_DA) + printf ("SW-mode is \"%s\"", + ises_sw_mode[ISES_STAT_SW_MODE(stat)]); + else + printf ("LDP-state is \"%s\"", + ises_idp_state[ISES_STAT_IDP_STATE(stat)]); + printf ("\n"); + + printf ("\tOQS = %d\n\tIQS = %d\n", READ_REG(sc, ISES_A_OQS), + READ_REG(sc, ISES_A_IQS)); + + /* B interface */ + + printf ("B-interface status register contains [%08x]\n", + READ_REG(sc, ISES_B_STAT)); + + /* DMA */ + + printf ("DMA read starts at 0x%x, length %d bytes\n", + READ_REG(sc, ISES_DMA_READ_START), + READ_REG(sc, ISES_DMA_READ_COUNT)); + + printf ("DMA write starts at 0x%x, length %d bytes\n", + READ_REG(sc, ISES_DMA_WRITE_START), + READ_REG(sc, ISES_DMA_WRITE_COUNT)); + + printf ("DMA status register contains [%08x]\n", + READ_REG(sc, ISES_DMA_STATUS)); + + /* OMR / HOMR / SOMR */ + + /* + * All these means throwing a cmd on to the A-interface, and then + * reading the result. + * + * Currently, put debug output in process_oqueue... + */ + + printf ("Queueing Operation Method Register (OMR) READ cmd...\n"); + cmd = ISES_MKCMD(ISES_CMD_BR_OMR, 0); + ises_queue_cmd(sc, cmd, NULL, NULL); +} + +void +ises_debug_parse_omr (struct ises_softc *sc) +{ + u_int32_t omr = sc->sc_bsession.omr; + + printf ("SELR : "); + if (omr & ISES_SELR_BCHU_EH) + printf ("cont-on-error "); + else + printf ("stop-on-error "); + + if (omr & ISES_SELR_BCHU_HISOF) + printf ("HU-input-is-SCU-output "); + + if (omr & ISES_SELR_BCHU_DIS) + printf ("data-interface-select "); + + printf ("\n"); + + printf ("HOMR : "); + if (omr & ISES_HOMR_HMTR) + printf ("expect-padded-hash-msg "); + else + printf ("expect-plaintext-hash-msg "); + + printf ("ER=%d ", (omr & ISES_HOMR_ER) >> 20); /* ick */ + + printf ("HFR="); + switch (omr & ISES_HOMR_HFR) { + case ISES_HOMR_HFR_NOP: + printf ("inactive "); + break; + case ISES_HOMR_HFR_MD5: + printf ("MD5 "); + break; + case ISES_HOMR_HFR_RMD160: + printf ("RMD160 "); + break; + case ISES_HOMR_HFR_RMD128: + printf ("RMD128 "); + break; + case ISES_HOMR_HFR_SHA1: + printf ("SHA-1 "); + break; + default: + printf ("reserved! "); + break; + } + printf ("\nSOMR : "); + + switch (omr & ISES_SOMR_BOMR) { + case ISES_SOMR_BOMR_NOP: + printf ("NOP "); + break; + case ISES_SOMR_BOMR_TRANSPARENT: + printf ("transparent "); + break; + case ISES_SOMR_BOMR_DES: + printf ("DES "); + break; + case ISES_SOMR_BOMR_3DES2: + printf ("3DES-2 "); + break; + case ISES_SOMR_BOMR_3DES: + printf ("3DES-3 "); + break; + default: + if (omr & ISES_SOMR_BOMR_SAFER) + printf ("SAFER "); + else + printf ("reserved! "); + break; + } + + if (omr & ISES_SOMR_EDR) + printf ("mode=encrypt "); + else + printf ("mode=decrypt "); + + switch (omr & ISES_SOMR_FMR) { + case ISES_SOMR_FMR_ECB: + printf ("ECB"); + break; + case ISES_SOMR_FMR_CBC: + printf ("CBC"); + break; + case ISES_SOMR_FMR_CFB64: + printf ("CFB64"); + break; + case ISES_SOMR_FMR_OFB64: + printf ("OFB64"); + break; + default: + /* Nada */ + } + printf ("\n"); +} + +#endif /* ISESDEBUG */ diff --git a/sys/dev/pci/isesreg.h b/sys/dev/pci/isesreg.h index e49bea9a676..70e0dde2f9f 100644 --- a/sys/dev/pci/isesreg.h +++ b/sys/dev/pci/isesreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: isesreg.h,v 1.1 2001/01/29 08:45:58 ho Exp $ $ */ +/* $OpenBSD: isesreg.h,v 1.2 2001/06/04 13:07:19 ho Exp $ $ */ /* * Copyright (c) 2000 Håkan Olsson (ho@crt.se) @@ -225,6 +225,7 @@ static const char *ises_sw_mode[] = * A-interface commands */ #define ISES_MKCMD(cmd,len) (cmd | cmd << 16 | len << 8 | len << 24) +#define ISES_CMD_NONE -1 /* Command name Code Len RLen Desc */ #define ISES_CMD_CHIP_ID 0x00 /* 0 3 Read chipID */ @@ -328,16 +329,18 @@ static const char *ises_sw_mode[] = #define ISES_CARD(sid) (((sid) & 0xf0000000) >> 28) #define ISES_SID(crd,ses) (((crd) << 28) | ((ses) & 0x0fffffff)) -struct ises_pktctx { - u_int32_t pc_deskey[6]; /* 3DES key */ - u_int32_t pc_hminner[5]; /* hmac inner state */ - u_int32_t pc_hmouter[5]; /* hmac outer state */ - u_int32_t pc_iv[2]; /* [3]DES iv */ - u_int32_t pc_omrflags; /* OMR flags, as above */ - u_int32_t pc_paddr; - u_int16_t pc_offset; /* crypto offset */ - u_int8_t pad[16]; -}; +/* Size and layout of ises_bchu_session is firmware dependent. */ +/* This structure should be usable for the SWITCH_SESSION command. */ +struct ises_bchu_session { + u_int32_t kr[6]; /* Key register KR2,KR1,KR0 */ + u_int32_t omr; /* Operation method register */ + + /* The following values (on-chip) are cleared after an OMR write */ + u_int32_t sccr[2]; /* Symm. crypto chaining reg. (IV) */ + u_int32_t cvr[5]; /* Chaining variables reg. */ + u_int32_t dbcr[2]; /* Data block count register */ + u_int32_t hmlr[2]; /* Hash message length reg. */ +} __attribute__((packed)); struct ises_pktbuf { volatile u_int32_t pb_addr; /* address of buffer start */ diff --git a/sys/dev/pci/isesvar.h b/sys/dev/pci/isesvar.h index efe90d7acb2..a8fe7d78d71 100644 --- a/sys/dev/pci/isesvar.h +++ b/sys/dev/pci/isesvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: isesvar.h,v 1.1 2001/01/29 08:45:58 ho Exp $ */ +/* $OpenBSD: isesvar.h,v 1.2 2001/06/04 13:07:20 ho Exp $ */ /* * Copyright (c) 2000 Håkan Olsson (ho@crt.se) @@ -28,7 +28,7 @@ */ struct ises_softc { - struct device sc_dv; /* generic device */ + struct device sc_dv; /* generic device */ void *sc_ih; /* interrupt handler cookie */ bus_space_handle_t sc_memh; /* memory handle */ bus_space_tag_t sc_memt; /* memory tag */ @@ -38,7 +38,6 @@ struct ises_softc { bus_addr_t sc_dmamap_phys; /* bus address of data area */ int32_t sc_cid; /* crypto tag */ u_int32_t sc_intrmask; /* interrupt mask */ - u_int32_t sc_omr; /* OMR */ SIMPLEQ_HEAD(,ises_q) sc_queue; /* packet queue */ int sc_nqueue; /* count enqueued */ SIMPLEQ_HEAD(,ises_q) sc_qchip; /* on chip */ @@ -46,19 +45,31 @@ struct ises_softc { int sc_nsessions; /* nr of sessions */ struct ises_session *sc_sessions; /* sessions */ int sc_initstate; /* card initialization state */ + + SIMPLEQ_HEAD(,ises_cmd) sc_cmdq; /* Commands in A-queue */ + struct ises_bchu_session sc_bsession; /* Current BCHU session */ + u_int32_t sc_lnau1_r[64]; /* LNAU 1 result (2048 bits) */ + int sc_lnau1_rlen; /* LNAU 1 result len (bytes) */ + u_int32_t sc_lnau2_r[64]; /* LNAU 2 result (2048 bits) */ + int sc_lnau2_rlen; /* LNAU 2 result len (bytes) */ }; struct ises_q { SIMPLEQ_ENTRY(ises_q) q_next; struct cryptop *q_crp; - struct ises_pktbuf q_srcpkt; - struct ises_pktbuf q_dstpkt; - struct ises_pktctx q_ctx; - struct ises_softc *q_sc; + struct mbuf *q_src_m, *q_dst_m; + struct ises_pktbuf q_srcpkt, q_dstpkt; + struct ises_bchu_session q_bsession; + u_int32_t q_hminner[5]; /* hmac inner state */ + u_int32_t q_hmouter[5]; /* hmac outer state */ + u_int32_t q_paddr; + u_int16_t q_offset; /* crypto offset */ + u_int8_t q_pad[16]; int q_sesn; + long q_src_packp; int q_src_packl; int q_src_npa, q_src_l; @@ -69,12 +80,20 @@ struct ises_q { u_int32_t q_macbuf[5]; }; +struct ises_cmd { + SIMPLEQ_ENTRY(ises_cmd) cmd_next; + u_int32_t cmd_code; /* Command code */ + u_int32_t cmd_rlen; /* Response length */ + u_int32_t (*cmd_cb)(struct ises_softc *, + struct ises_cmd *); /* Callback */ +}; + struct ises_session { - u_int32_t ses_used; - u_int32_t ses_deskey[6]; /* 3DES key */ - u_int32_t ses_hminner[5]; /* hmac inner state */ - u_int32_t ses_hmouter[5]; /* hmac outer state */ - u_int32_t ses_iv[2]; /* DES/3DES iv */ + u_int32_t ses_used; + u_int32_t ses_deskey[6]; /* 3DES key */ + u_int32_t ses_hminner[5]; /* hmac inner state */ + u_int32_t ses_hmouter[5]; /* hmac outer state */ + u_int32_t ses_iv[2]; /* DES/3DES iv */ }; /* Maximum queue length */ |