summaryrefslogtreecommitdiff
path: root/sys/arch/i386
diff options
context:
space:
mode:
authorTom Cosgrove <tom@cvs.openbsd.org>2006-11-19 13:41:28 +0000
committerTom Cosgrove <tom@cvs.openbsd.org>2006-11-19 13:41:28 +0000
commitd7b48500242d68067ddc8584bfe53243eed21f49 (patch)
tree93c0a1198e4ec5f94e86ba71c1e61d7f03b7a7b5 /sys/arch/i386
parente55ed29b03c21de48fe1451997556e213487a80f (diff)
Handle operations larger than will fit in the buffer we allocate,
by processing in a loop. And bump the size of this buffer (32KB taken by the driver shouldn't be a problem). Also reduce the places we hard-code the AES block size of 16. Still disabled (doing more testing), but I want to commit before the aged hard disk I have in the system here dies. (This commit from the Geode system with the AES enabled.)
Diffstat (limited to 'sys/arch/i386')
-rw-r--r--sys/arch/i386/pci/glxsb.c129
1 files changed, 76 insertions, 53 deletions
diff --git a/sys/arch/i386/pci/glxsb.c b/sys/arch/i386/pci/glxsb.c
index 3615ba97ea5..4c458e11c58 100644
--- a/sys/arch/i386/pci/glxsb.c
+++ b/sys/arch/i386/pci/glxsb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: glxsb.c,v 1.3 2006/11/19 02:08:10 tom Exp $ */
+/* $OpenBSD: glxsb.c,v 1.4 2006/11/19 13:41:27 tom Exp $ */
/*
* Copyright (c) 2006 Tom Cosgrove <tom@openbsd.org>
@@ -125,6 +125,7 @@
#define SB_AES_ALIGN 0x0010 /* Source and dest buffers */
/* must be 16-byte aligned */
+#define SB_AES_BLOCK_SIZE 0x0010
/*
* The Geode LX security block AES acceleration doesn't perform scatter-
@@ -135,7 +136,7 @@
* buffer (buffer is twice the size of the max length, as it has both input
* and output) then we have to perform multiple encryptions/decryptions.
*/
-#define GLXSB_MAX_AES_LEN 8192
+#define GLXSB_MAX_AES_LEN 16384
#ifdef CRYPTO
struct glxsb_dma_map {
@@ -148,7 +149,7 @@ struct glxsb_dma_map {
};
struct glxsb_session {
uint32_t ses_key[4];
- uint8_t ses_iv[16];
+ uint8_t ses_iv[SB_AES_BLOCK_SIZE];
int ses_klen;
int ses_used;
};
@@ -486,8 +487,10 @@ glxsb_crypto_process(struct cryptop *crp)
struct cryptodesc *crd;
char *op_src, *op_dst;
uint32_t op_psrc, op_pdst;
- uint8_t op_iv[16];
+ uint8_t op_iv[SB_AES_BLOCK_SIZE], *piv;
int sesn, err = 0;
+ int len, tlen, xlen;
+ int offset;
uint32_t control;
int s;
@@ -500,19 +503,11 @@ glxsb_crypto_process(struct cryptop *crp)
crd = crp->crp_desc;
if (crd == NULL || crd->crd_next != NULL ||
crd->crd_alg != CRYPTO_AES_CBC ||
- (crd->crd_len % 16) != 0) {
+ (crd->crd_len % SB_AES_BLOCK_SIZE) != 0) {
err = EINVAL;
goto out;
}
- /* XXX TEMP TEMP TEMP need to handle this properly */
- if (crd->crd_len > GLXSB_MAX_AES_LEN) {
- printf("%s: operation too big: %d > %d\n",
- sc->sc_dev.dv_xname, crd->crd_len, GLXSB_MAX_AES_LEN);
- err = ENOMEM;
- goto out;
- }
-
sesn = GLXSB_SESSION(crp->crp_sid);
if (sesn >= sc->sc_nsessions) {
err = EINVAL;
@@ -520,91 +515,119 @@ glxsb_crypto_process(struct cryptop *crp)
}
ses = &sc->sc_sessions[sesn];
+ /* How much of our buffer will we need to use? */
+ xlen = crd->crd_len > GLXSB_MAX_AES_LEN ?
+ GLXSB_MAX_AES_LEN : crd->crd_len;
+
/*
* XXX Check if we can have input == output on Geode LX.
* XXX In the meantime, use two separate (adjacent) buffers.
*/
op_src = sc->sc_dma.dma_vaddr;
- op_dst = sc->sc_dma.dma_vaddr + crd->crd_len;
+ op_dst = sc->sc_dma.dma_vaddr + xlen;
op_psrc = sc->sc_dma.dma_paddr;
- op_pdst = sc->sc_dma.dma_paddr + crd->crd_len;
+ op_pdst = sc->sc_dma.dma_paddr + xlen;
if (crd->crd_flags & CRD_F_ENCRYPT) {
control = SB_CTL_ENC;
if (crd->crd_flags & CRD_F_IV_EXPLICIT)
- bcopy(crd->crd_iv, op_iv, 16);
+ bcopy(crd->crd_iv, op_iv, sizeof(op_iv));
else
- bcopy(ses->ses_iv, op_iv, 16);
+ bcopy(ses->ses_iv, op_iv, sizeof(op_iv));
if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
if (crp->crp_flags & CRYPTO_F_IMBUF)
m_copyback((struct mbuf *)crp->crp_buf,
- crd->crd_inject, 16, op_iv);
+ crd->crd_inject, sizeof(op_iv), op_iv);
else if (crp->crp_flags & CRYPTO_F_IOV)
cuio_copyback((struct uio *)crp->crp_buf,
- crd->crd_inject, 16, op_iv);
+ crd->crd_inject, sizeof(op_iv), op_iv);
else
bcopy(op_iv,
- crp->crp_buf + crd->crd_inject, 16);
+ crp->crp_buf + crd->crd_inject, sizeof(op_iv));
}
} else {
control = SB_CTL_DEC;
if (crd->crd_flags & CRD_F_IV_EXPLICIT)
- bcopy(crd->crd_iv, op_iv, 16);
+ bcopy(crd->crd_iv, op_iv, sizeof(op_iv));
else {
if (crp->crp_flags & CRYPTO_F_IMBUF)
m_copydata((struct mbuf *)crp->crp_buf,
- crd->crd_inject, 16, op_iv);
+ crd->crd_inject, sizeof(op_iv), op_iv);
else if (crp->crp_flags & CRYPTO_F_IOV)
cuio_copydata((struct uio *)crp->crp_buf,
- crd->crd_inject, 16, op_iv);
+ crd->crd_inject, sizeof(op_iv), op_iv);
else
bcopy(crp->crp_buf + crd->crd_inject,
- op_iv, 16);
+ op_iv, sizeof(op_iv));
}
}
- if (crp->crp_flags & CRYPTO_F_IMBUF)
- m_copydata((struct mbuf *)crp->crp_buf,
- crd->crd_skip, crd->crd_len, op_src);
- else if (crp->crp_flags & CRYPTO_F_IOV)
- cuio_copydata((struct uio *)crp->crp_buf,
- crd->crd_skip, crd->crd_len, op_src);
- else
- bcopy(crp->crp_buf + crd->crd_skip, op_src, crd->crd_len);
+ offset = 0;
+ tlen = crd->crd_len;
+ piv = op_iv;
- glxsb_dma_pre_op(sc, &sc->sc_dma);
+ /* Process the data in GLXSB_MAX_AES_LEN chunks */
+ while (tlen > 0) {
+ len = (tlen > GLXSB_MAX_AES_LEN) ? GLXSB_MAX_AES_LEN : tlen;
- glxsb_aes(sc, control, op_psrc, op_pdst, ses->ses_key,
- crd->crd_len, op_iv);
+ if (crp->crp_flags & CRYPTO_F_IMBUF)
+ m_copydata((struct mbuf *)crp->crp_buf,
+ crd->crd_skip + offset, len, op_src);
+ else if (crp->crp_flags & CRYPTO_F_IOV)
+ cuio_copydata((struct uio *)crp->crp_buf,
+ crd->crd_skip + offset, len, op_src);
+ else
+ bcopy(crp->crp_buf + crd->crd_skip + offset, op_src,
+ len);
- glxsb_dma_post_op(sc, &sc->sc_dma);
+ glxsb_dma_pre_op(sc, &sc->sc_dma);
- if (crp->crp_flags & CRYPTO_F_IMBUF)
- m_copyback((struct mbuf *)crp->crp_buf,
- crd->crd_skip, crd->crd_len, op_dst);
- else if (crp->crp_flags & CRYPTO_F_IOV)
- cuio_copyback((struct uio *)crp->crp_buf,
- crd->crd_skip, crd->crd_len, op_dst);
- else
- bcopy(op_dst, crp->crp_buf + crd->crd_skip, crd->crd_len);
+ glxsb_aes(sc, control, op_psrc, op_pdst, ses->ses_key,
+ len, op_iv);
+
+ glxsb_dma_post_op(sc, &sc->sc_dma);
- /* copy out last block for use as next session IV */
- if (crd->crd_flags & CRD_F_ENCRYPT) {
if (crp->crp_flags & CRYPTO_F_IMBUF)
- m_copydata((struct mbuf *)crp->crp_buf,
- crd->crd_skip + crd->crd_len - 16, 16, ses->ses_iv);
+ m_copyback((struct mbuf *)crp->crp_buf,
+ crd->crd_skip + offset, len, op_dst);
else if (crp->crp_flags & CRYPTO_F_IOV)
- cuio_copydata((struct uio *)crp->crp_buf,
- crd->crd_skip + crd->crd_len - 16, 16, ses->ses_iv);
+ cuio_copyback((struct uio *)crp->crp_buf,
+ crd->crd_skip + offset, len, op_dst);
else
- bcopy(crp->crp_buf + crd->crd_skip + crd->crd_len - 16,
- ses->ses_iv, 16);
+ bcopy(op_dst, crp->crp_buf + crd->crd_skip + offset,
+ len);
+
+ offset += len;
+ tlen -= len;
+
+ if (tlen <= 0) { /* Ideally, just == 0 */
+ /* Finished - put the IV in session IV */
+ piv = ses->ses_iv;
+ }
+
+ /*
+ * Copy out last block for use as next iteration/session IV.
+ *
+ * piv is set to op_iv[] before the loop starts, but is
+ * set to ses->ses_iv if we're going to exit the loop this
+ * time.
+ */
+ if (crd->crd_flags & CRD_F_ENCRYPT) {
+ bcopy(op_dst + len - sizeof(op_iv), piv, sizeof(op_iv));
+ } else {
+ /* Decryption, only need this if another iteration */
+ if (tlen > 0) {
+ bcopy(op_src + len - sizeof(op_iv), piv,
+ sizeof(op_iv));
+ }
+ }
}
- bzero(sc->sc_dma.dma_vaddr, crd->crd_len * 2);
+ /* All AES processing has now been done. */
+ bzero(sc->sc_dma.dma_vaddr, xlen * 2);
out:
crp->crp_etype = err;
crypto_done(crp);