summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2003-09-11 19:46:23 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2003-09-11 19:46:23 +0000
commit4b4bcaa5feb947e313b5e6748a028ae519ac1ed2 (patch)
tree8ea7a4e0a95525c50483f4ec85bbc888852dff26 /sys
parentecd42c89177afb4c4aa0d1cd3cd759bbb8f3f5bf (diff)
support new via c3 AES instruction; written by jason
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/i386/i386/autoconf.c9
-rw-r--r--sys/arch/i386/i386/machdep.c388
2 files changed, 383 insertions, 14 deletions
diff --git a/sys/arch/i386/i386/autoconf.c b/sys/arch/i386/i386/autoconf.c
index 636c50b7601..67cb620d46f 100644
--- a/sys/arch/i386/i386/autoconf.c
+++ b/sys/arch/i386/i386/autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.c,v 1.48 2003/09/07 04:02:03 krw Exp $ */
+/* $OpenBSD: autoconf.c,v 1.49 2003/09/11 19:46:22 deraadt Exp $ */
/* $NetBSD: autoconf.c,v 1.20 1996/05/03 19:41:56 christos Exp $ */
/*-
@@ -81,6 +81,8 @@ dev_t bootdev = 0; /* bootdevice, initialized in locore.s */
extern struct timeout viac3_rnd_tmo;
extern int viac3_rnd_present;
void viac3_rnd(void *);
+extern int viac3_crypto_present;
+void viac3_crypto_setup(void);
#endif
/*
@@ -125,6 +127,11 @@ cpu_configure()
timeout_set(&viac3_rnd_tmo, viac3_rnd, &viac3_rnd_tmo);
viac3_rnd(&viac3_rnd_tmo);
}
+ /*
+ * Also, if the chip as crypto available, enable it.
+ */
+ if (viac3_crypto_present)
+ viac3_crypto_setup();
#endif
}
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index e0fcaf7d30a..31c82060847 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.242 2003/09/02 17:35:53 grange Exp $ */
+/* $OpenBSD: machdep.c,v 1.243 2003/09/11 19:46:22 deraadt Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -101,6 +101,11 @@
#include <sys/msg.h>
#endif
+#if defined(I686_CPU)
+/* YYY move */
+#include <crypto/cryptodev.h>
+#endif
+
#ifdef KGDB
#include <sys/kgdb.h>
#endif
@@ -1091,6 +1096,350 @@ viac3_rnd(void *v)
timeout_add(tmo, (hz>100)?(hz/100):1);
splx(s);
}
+
+struct viac3_session {
+ u_int8_t ses_iv[16];
+ int ses_klen, ses_used;
+};
+
+struct viac3_softc {
+ int32_t sc_cid;
+ int sc_nsessions;
+ struct viac3_session *sc_sessions;
+};
+
+#define VIAC3_SESSION(sid) ((sid) & 0x0fffffff)
+#define VIAC3_SID(crd,ses) (((crd) << 28) | ((ses) & 0x0fffffff))
+
+#define C3_CRYPT_CWLO_ROUND_M 0x0000000f
+#define C3_CRYPT_CWLO_ALG_M 0x00000070
+#define C3_CRYPT_CWLO_ALG_AES 0x00000000
+#define C3_CRYPT_CWLO_KEYGEN_M 0x00000080
+#define C3_CRYPT_CWLO_KEYGEN_HW 0x00000000
+#define C3_CRYPT_CWLO_KEYGEN_SW 0x00000080
+#define C3_CRYPT_CWLO_NORMAL 0x00000000
+#define C3_CRYPT_CWLO_INTERMEDIATE 0x00000100
+#define C3_CRYPT_CWLO_ENCRYPT 0x00000000
+#define C3_CRYPT_CWLO_DECRYPT 0x00000200
+#define C3_CRYPT_CWLO_KEY128 0x0000000a /* 128bit, 10 rds */
+#define C3_CRYPT_CWLO_KEY192 0x0000040c /* 192bit, 12 rds */
+#define C3_CRYPT_CWLO_KEY256 0x0000080e /* 256bit, 15 rds */
+
+struct viac3_crypto_op {
+ u_int32_t op_cw[4];
+ u_int8_t op_iv[16];
+ u_int8_t op_key[32];
+ void *op_src;
+ void *op_dst;
+ u_int32_t pad[2];
+};
+
+static struct viac3_softc *vc3_sc;
+int viac3_crypto_present;
+
+/* Opcodes */
+#define VIAC3_CRYPTOP_RNG 0xc0 /* rng */
+#define VIAC3_CRYPTOP_ECB 0xc8 /* aes-ecb */
+#define VIAC3_CRYPTOP_CBC 0xd0 /* aes-cbc */
+#define VIAC3_CRYPTOP_CFB 0xe0 /* aes-cfb */
+#define VIAC3_CRYPTOP_OFB 0xe8 /* aes-ofb */
+
+void viac3_crypto_setup(void);
+int viac3_crypto_newsession(u_int32_t *, struct cryptoini *);
+int viac3_crypto_process(struct cryptop *);
+int viac3_crypto_freesession(u_int64_t);
+void viac3_crypto(void *, void *, void *, void *, int, void *, int);
+
+void
+viac3_crypto_setup(void)
+{
+ int algs[CRYPTO_ALGORITHM_MAX + 1];
+
+ if ((vc3_sc = malloc(sizeof(*vc3_sc), M_DEVBUF, M_NOWAIT)) == NULL)
+ return; /* YYY bitch? */
+ bzero(vc3_sc, sizeof(*vc3_sc));
+
+ bzero(algs, sizeof(algs));
+ algs[CRYPTO_AES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
+
+ vc3_sc->sc_cid = crypto_get_driverid(0);
+ if (vc3_sc->sc_cid < 0)
+ return; /* YYY bitch? */
+
+ crypto_register(vc3_sc->sc_cid, algs, viac3_crypto_newsession,
+ viac3_crypto_freesession, viac3_crypto_process);
+}
+
+int
+viac3_crypto_newsession(u_int32_t *sidp, struct cryptoini *cri)
+{
+ struct viac3_softc *sc = vc3_sc;
+ struct viac3_session *ses = NULL;
+ int sesn;
+
+ if (sc == NULL || sidp == NULL || cri == NULL)
+ return (EINVAL);
+ if (cri->cri_next != NULL || cri->cri_alg != CRYPTO_AES_CBC)
+ return (EINVAL);
+ /* Initial version doesn't work for 192/256 */
+ if (cri->cri_klen != 128)
+ return (EINVAL);
+ if (sc->sc_sessions == NULL) {
+ ses = sc->sc_sessions = (struct viac3_session *)malloc(
+ sizeof(*ses), M_DEVBUF, M_NOWAIT);
+ if (ses == NULL)
+ return (ENOMEM);
+ sesn = 0;
+ sc->sc_nsessions = 1;
+ } else {
+ 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) {
+ sesn = sc->sc_nsessions;
+ ses = (struct viac3_session *)malloc((sesn + 1) *
+ sizeof(*ses), M_DEVBUF, M_NOWAIT);
+ if (ses == NULL)
+ return (ENOMEM);
+ bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses));
+ bzero(sc->sc_sessions, sesn * sizeof(*ses));
+ free(sc->sc_sessions, M_DEVBUF);
+ sc->sc_sessions = ses;
+ ses = &sc->sc_sessions[sesn];
+ sc->sc_nsessions++;
+ }
+ }
+
+ bzero(ses, sizeof(*ses));
+ ses->ses_used = 1;
+
+ get_random_bytes(ses->ses_iv, sizeof(ses->ses_iv));
+ ses->ses_klen = cri->cri_klen;
+ bcopy(cri->cri_key, cri->cri_key, ses->ses_klen / 8);
+
+ *sidp = VIAC3_SID(0, sesn);
+ return (0);
+}
+
+int
+viac3_crypto_freesession(u_int64_t tid)
+{
+ struct viac3_softc *sc = vc3_sc;
+ int sesn;
+ u_int32_t sid = ((u_int32_t)tid) & 0xffffffff;
+
+ if (sc == NULL)
+ return (EINVAL);
+ sesn = VIAC3_SESSION(sid);
+ if (sesn >= sc->sc_nsessions)
+ return (EINVAL);
+ bzero(&sc->sc_sessions[sesn], sizeof(sc->sc_sessions[sesn]));
+ return (0);
+}
+
+int
+viac3_crypto_process(struct cryptop *crp)
+{
+ struct viac3_softc *sc = vc3_sc;
+ struct viac3_crypto_op *op = NULL;
+ int sesn, err = 0;
+ struct cryptodesc *crd;
+ struct viac3_session *ses;
+
+ if (crp == NULL || crp->crp_callback == NULL) {
+ err = EINVAL;
+ goto out;
+ }
+ sesn = VIAC3_SESSION(crp->crp_sid);
+ if (sesn >= sc->sc_nsessions) {
+ err = EINVAL;
+ goto out;
+ }
+ ses = &sc->sc_sessions[sesn];
+
+ crd = crp->crp_desc;
+ if (crd == NULL || crd->crd_next != NULL ||
+ crd->crd_alg != CRYPTO_AES_CBC || crd->crd_klen != 128) {
+ err = EINVAL;
+ goto out;
+ }
+
+ op = (struct viac3_crypto_op *)malloc(sizeof(*op), M_DEVBUF, M_NOWAIT);
+ if (op == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ bcopy(crd->crd_key, op->op_key, crd->crd_klen / 8);
+
+ if ((crd->crd_len % 16) != 0) {
+ err = EINVAL;
+ goto out;
+ }
+
+ op->op_src = (char *)malloc(crd->crd_len, M_DEVBUF, M_NOWAIT);
+ if (op->op_src == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ op->op_dst = (char *)malloc(crd->crd_len, M_DEVBUF, M_NOWAIT);
+ if (op->op_dst == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ op->op_cw[0] = C3_CRYPT_CWLO_ALG_AES | C3_CRYPT_CWLO_KEYGEN_HW |
+ C3_CRYPT_CWLO_NORMAL | C3_CRYPT_CWLO_KEY128;
+ op->op_cw[1] = op->op_cw[2] = op->op_cw[3] = 0;
+ if (crd->crd_flags & CRD_F_ENCRYPT) {
+ op->op_cw[0] |= C3_CRYPT_CWLO_ENCRYPT;
+ if (crd->crd_flags & CRD_F_IV_EXPLICIT)
+ bcopy(crd->crd_iv, op->op_iv, 16);
+ else
+ bcopy(ses->ses_iv, op->op_iv, 16);
+
+ 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->op_iv);
+ else if (crp->crp_flags & CRYPTO_F_IOV)
+ cuio_copyback((struct uio *)crp->crp_buf,
+ crd->crd_inject, 16, op->op_iv);
+ else
+ bcopy(op->op_iv,
+ crp->crp_buf + crd->crd_inject, 16);
+ }
+ } else {
+ op->op_cw[0] |= C3_CRYPT_CWLO_DECRYPT;
+ if (crd->crd_flags & CRD_F_IV_EXPLICIT)
+ bcopy(crd->crd_iv, op->op_iv, 16);
+ else {
+ if (crp->crp_flags & CRYPTO_F_IMBUF)
+ m_copydata((struct mbuf *)crp->crp_buf,
+ crd->crd_inject, 16, op->op_iv);
+ else if (crp->crp_flags & CRYPTO_F_IOV)
+ cuio_copydata((struct uio *)crp->crp_buf,
+ crd->crd_inject, 16, op->op_iv);
+ else
+ bcopy(crp->crp_buf + crd->crd_inject,
+ op->op_iv, 16);
+ }
+ }
+
+ if (crp->crp_flags & CRYPTO_F_IMBUF)
+ m_copydata((struct mbuf *)crp->crp_buf,
+ crd->crd_skip, crd->crd_len, op->op_src);
+ else if (crp->crp_flags & CRYPTO_F_IOV)
+ cuio_copydata((struct uio *)crp->crp_buf,
+ crd->crd_skip, crd->crd_len, op->op_src);
+ else
+ bcopy(crp->crp_buf + crd->crd_skip, op->op_src, crd->crd_len);
+
+ viac3_crypto(&op->op_cw, op->op_src, op->op_dst, op->op_key,
+ crd->crd_len / 16, op->op_iv, VIAC3_CRYPTOP_CBC);
+
+ if (crp->crp_flags & CRYPTO_F_IMBUF)
+ m_copyback((struct mbuf *)crp->crp_buf,
+ crd->crd_skip, crd->crd_len, op->op_dst);
+ else if (crp->crp_flags & CRYPTO_F_IOV)
+ cuio_copyback((struct uio *)crp->crp_buf,
+ crd->crd_skip, crd->crd_len, op->op_dst);
+ else
+ bcopy(op->op_dst, crp->crp_buf + crd->crd_skip, crd->crd_len);
+
+ /* 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);
+ else if (crp->crp_flags & CRYPTO_F_IOV)
+ cuio_copydata((struct uio *)crp->crp_buf,
+ crd->crd_skip + crd->crd_len - 16, 16, op->op_iv);
+ else
+ bcopy(crp->crp_buf + crd->crd_skip + crd->crd_len - 16,
+ op->op_iv, 16);
+ }
+
+out:
+ if (op != NULL) {
+ if (op->op_src != NULL)
+ free(op->op_src, M_DEVBUF);
+ if (op->op_dst != NULL)
+ free(op->op_dst, M_DEVBUF);
+ free(op, M_DEVBUF);
+ }
+ crp->crp_etype = err;
+ crypto_done(crp);
+ return (err);
+}
+
+void
+viac3_crypto(void *cw, void *src, void *dst, void *key, int rep,
+ void *iv, int type)
+{
+ unsigned int creg0, creg4;
+ int s;
+
+ s = splhigh();
+
+ /* XXX - should not be needed, but we might need FXSR & FPU for XUnit */
+ creg0 = rcr0();
+ lcr0(creg0 & ~(CR0_EM|CR0_TS));
+ creg4 = rcr4();
+ lcr4(creg4 | CR4_OSFXSR);
+
+ /* Do the deed */
+ switch (type) {
+ case VIAC3_CRYPTOP_RNG:
+ __asm __volatile(
+ "rep;.byte 0x0F,0xA7,0xC0"
+ :
+ : "a" (iv), "b" (key), "c" (rep), "d" (cw), "S" (src), "D" (dst)
+ : "memory", "cc");
+ break;
+ case VIAC3_CRYPTOP_ECB:
+ __asm __volatile(
+ "rep;.byte 0x0F,0xA7,0xC8"
+ :
+ : "a" (iv), "b" (key), "c" (rep), "d" (cw), "S" (src), "D" (dst)
+ : "memory", "cc");
+ break;
+ case VIAC3_CRYPTOP_CBC:
+ __asm __volatile(
+ "rep;.byte 0x0F,0xA7,0xD0"
+ :
+ : "a" (iv), "b" (key), "c" (rep), "d" (cw), "S" (src), "D" (dst)
+ : "memory", "cc");
+ break;
+ case VIAC3_CRYPTOP_CFB:
+ __asm __volatile(
+ "rep;.byte 0x0F,0xA7,0xE0"
+ :
+ : "a" (iv), "b" (key), "c" (rep), "d" (cw), "S" (src), "D" (dst)
+ : "memory", "cc");
+ break;
+ case VIAC3_CRYPTOP_OFB:
+ __asm __volatile(
+ "rep;.byte 0x0F,0xA7,0xE8"
+ :
+ : "a" (iv), "b" (key), "c" (rep), "d" (cw), "S" (src), "D" (dst)
+ : "memory", "cc");
+ break;
+ default:
+ }
+
+ /* XXX - should not be neeeded */
+ lcr0(creg0);
+ lcr4(creg4);
+
+ splx(s);
+}
+
#endif
void
@@ -1137,21 +1486,34 @@ cyrix3_cpu_setup(cpu_device, model, step)
: "=d" (val) : "a" (0xC0000001) : "cc");
}
- /* Stop here if no RNG */
- if (!(val & 0x4))
- break;
+ /* Enable RNG if present and disabled */
+ if (val & 0x44)
+ printf("%s:", cpu_device);
+ if (val & 0x4) {
+ if (!(val & 0x8)) {
+ u_int64_t msreg;
- /* Enable RNG if disabled */
- if (!(val & 0x8)) {
- u_int64_t msreg;
+ msreg = rdmsr(0x110B);
+ msreg |= 0x40;
+ wrmsr(0x110B, msreg);
+ }
+ viac3_rnd_present = 1;
+ printf(" RNG");
+ }
- msreg = rdmsr(0x110B);
- msreg |= 0x40;
- wrmsr(0x110B, msreg);
- printf("Screwed with MSR 0x110B!\n");
+ /* Enable AES engine if present and disabled */
+ if (val & 0x40) {
+ if (!(val & 0x80)) {
+ u_int64_t msreg;
+
+ msreg = rdmsr(0x1107);
+ msreg |= (0x01 << 28);
+ wrmsr(0x1107, msreg);
+ }
+ viac3_crypto_present = 1;
+ printf(" AES");
}
- viac3_rnd_present = 1;
- printf("%s: RNG activated\n", cpu_device);
+ printf("\n");
break;
}
#endif