summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/amd64/autoconf.c28
-rw-r--r--sys/arch/amd64/amd64/identcpu.c97
-rw-r--r--sys/arch/amd64/amd64/via.c567
-rw-r--r--sys/arch/amd64/conf/files.amd643
-rw-r--r--sys/arch/amd64/include/specialreg.h35
5 files changed, 726 insertions, 4 deletions
diff --git a/sys/arch/amd64/amd64/autoconf.c b/sys/arch/amd64/amd64/autoconf.c
index 4e45af2a172..dc8dbce7c25 100644
--- a/sys/arch/amd64/amd64/autoconf.c
+++ b/sys/arch/amd64/amd64/autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.c,v 1.29 2008/08/19 02:02:02 deraadt Exp $ */
+/* $OpenBSD: autoconf.c,v 1.30 2009/05/31 03:20:10 matthieu Exp $ */
/* $NetBSD: autoconf.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */
/*-
@@ -91,6 +91,16 @@
int cold = 1; /* if 1, still working on cold-start */
extern dev_t bootdev;
+/* Support for VIA C3 RNG */
+extern struct timeout viac3_rnd_tmo;
+extern int viac3_rnd_present;
+void viac3_rnd(void *);
+
+#ifdef CRYPTO
+void viac3_crypto_setup(void);
+extern int amd64_has_xcrypt;
+#endif
+
/*
* Determine i/o configuration for a machine.
*/
@@ -122,6 +132,22 @@ cpu_configure(void)
lcr8(0);
spl0();
cold = 0;
+
+ /*
+ * At this point the RNG is running, and if FSXR is set we can
+ * use it. Here we setup a periodic timeout to collect the data.
+ */
+ if (viac3_rnd_present) {
+ timeout_set(&viac3_rnd_tmo, viac3_rnd, &viac3_rnd_tmo);
+ viac3_rnd(&viac3_rnd_tmo);
+ }
+#ifdef CRYPTO
+ /*
+ * Also, if the chip has crypto available, enable it.
+ */
+ if (amd64_has_xcrypt)
+ viac3_crypto_setup();
+#endif
}
void
diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c
index bd2289cd88b..42a423af941 100644
--- a/sys/arch/amd64/amd64/identcpu.c
+++ b/sys/arch/amd64/amd64/identcpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: identcpu.c,v 1.17 2009/02/16 17:24:21 krw Exp $ */
+/* $OpenBSD: identcpu.c,v 1.18 2009/05/31 03:20:10 matthieu Exp $ */
/* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */
/*
@@ -48,6 +48,7 @@
/* sysctl wants this. */
char cpu_model[48];
int cpuspeed;
+int amd64_has_xcrypt;
const struct {
u_int32_t bit;
@@ -152,6 +153,97 @@ intelcore_update_sensor(void *args)
void (*setperf_setup)(struct cpu_info *);
+void via_nano_setup(struct cpu_info *ci);
+
+void
+via_nano_setup(struct cpu_info *ci)
+{
+ u_int32_t regs[4], val;
+ u_int64_t msreg;
+ int model = (ci->ci_signature >> 4) & 15;
+ extern int amd64_has_xcrypt;
+
+ if (model >= 9) {
+ CPUID(0xC0000000, regs[0], regs[1], regs[2], regs[3]);
+ val = regs[0];
+ if (val >= 0xC0000001) {
+ CPUID(0xC0000001, regs[0], regs[1], regs[2], regs[3]);
+ val = regs[3];
+ } else
+ val = 0;
+
+ if (val & (C3_CPUID_HAS_RNG | C3_CPUID_HAS_ACE))
+ printf("%s:", ci->ci_dev->dv_xname);
+
+ /* Enable RNG if present and disabled */
+ if (val & C3_CPUID_HAS_RNG) {
+ extern int viac3_rnd_present;
+
+ if (!(val & C3_CPUID_DO_RNG)) {
+ msreg = rdmsr(0x110B);
+ msreg |= 0x40;
+ wrmsr(0x110B, msreg);
+ }
+ viac3_rnd_present = 1;
+ printf(" RNG");
+ }
+
+ /* Enable AES engine if present and disabled */
+ if (val & C3_CPUID_HAS_ACE) {
+#ifdef CRYPTO
+ if (!(val & C3_CPUID_DO_ACE)) {
+ msreg = rdmsr(0x1107);
+ msreg |= (0x01 << 28);
+ wrmsr(0x1107, msreg);
+ }
+ amd64_has_xcrypt |= C3_HAS_AES;
+#endif /* CRYPTO */
+ printf(" AES");
+ }
+
+ /* Enable ACE2 engine if present and disabled */
+ if (val & C3_CPUID_HAS_ACE2) {
+#ifdef CRYPTO
+ if (!(val & C3_CPUID_DO_ACE2)) {
+ msreg = rdmsr(0x1107);
+ msreg |= (0x01 << 28);
+ wrmsr(0x1107, msreg);
+ }
+ amd64_has_xcrypt |= C3_HAS_AESCTR;
+#endif /* CRYPTO */
+ printf(" AES-CTR");
+ }
+
+ /* Enable SHA engine if present and disabled */
+ if (val & C3_CPUID_HAS_PHE) {
+#ifdef CRYPTO
+ if (!(val & C3_CPUID_DO_PHE)) {
+ msreg = rdmsr(0x1107);
+ msreg |= (0x01 << 28/**/);
+ wrmsr(0x1107, msreg);
+ }
+ amd64_has_xcrypt |= C3_HAS_SHA;
+#endif /* CRYPTO */
+ printf(" SHA1 SHA256");
+ }
+
+ /* Enable MM engine if present and disabled */
+ if (val & C3_CPUID_HAS_PMM) {
+#ifdef CRYPTO
+ if (!(val & C3_CPUID_DO_PMM)) {
+ msreg = rdmsr(0x1107);
+ msreg |= (0x01 << 28/**/);
+ wrmsr(0x1107, msreg);
+ }
+ amd64_has_xcrypt |= C3_HAS_MM;
+#endif /* CRYPTO */
+ printf(" RSA");
+ }
+
+ printf("\n");
+ }
+}
+
void
identifycpu(struct cpu_info *ci)
{
@@ -263,6 +355,9 @@ identifycpu(struct cpu_info *ci)
if (vendor[0] == 0x68747541 && vendor[1] == 0x69746e65 &&
vendor[2] == 0x444d4163) /* DMAc */
amd64_errata(ci);
+
+ if (strncmp(cpu_model, "VIA Nano processor", 18) == 0)
+ ci->cpu_setup = via_nano_setup;
}
void
diff --git a/sys/arch/amd64/amd64/via.c b/sys/arch/amd64/amd64/via.c
new file mode 100644
index 00000000000..7bb25dc6a98
--- /dev/null
+++ b/sys/arch/amd64/amd64/via.c
@@ -0,0 +1,567 @@
+/* $OpenBSD: via.c,v 1.1 2009/05/31 03:20:10 matthieu Exp $ */
+/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 2003 Jason Wright
+ * Copyright (c) 2003, 2004 Theo de Raadt
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/signalvar.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/exec.h>
+#include <sys/buf.h>
+#include <sys/reboot.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/timeout.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/extent.h>
+#include <sys/sysctl.h>
+
+#ifdef CRYPTO
+#include <crypto/cryptodev.h>
+#include <crypto/rijndael.h>
+#include <crypto/xform.h>
+#include <crypto/cryptosoft.h>
+#endif
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/gdt.h>
+#include <machine/pio.h>
+#include <machine/bus.h>
+#include <machine/psl.h>
+#include <machine/reg.h>
+#include <machine/specialreg.h>
+#include <machine/biosvar.h>
+
+#include <dev/rndvar.h>
+
+void viac3_rnd(void *);
+
+
+#ifdef CRYPTO
+
+struct viac3_session {
+ u_int32_t ses_ekey[4 * (AES_MAXROUNDS + 1) + 4]; /* 128 bit aligned */
+ u_int32_t ses_dkey[4 * (AES_MAXROUNDS + 1) + 4]; /* 128 bit aligned */
+ u_int8_t ses_iv[16]; /* 128 bit aligned */
+ u_int32_t ses_cw0;
+ struct swcr_data *swd;
+ int ses_klen;
+ int ses_used;
+};
+
+struct viac3_softc {
+ u_int32_t op_cw[4]; /* 128 bit aligned */
+ u_int8_t op_iv[16]; /* 128 bit aligned */
+ void *op_buf;
+
+ /* normal softc stuff */
+ 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))
+
+static struct viac3_softc *vc3_sc;
+
+extern const u_int8_t hmac_ipad_buffer[64];
+extern const u_int8_t hmac_opad_buffer[64];
+
+void viac3_crypto_setup(void);
+int viac3_crypto_newsession(u_int32_t *, struct cryptoini *);
+int viac3_crypto_process(struct cryptop *);
+int viac3_crypto_swauth(struct cryptop *, struct cryptodesc *,
+ struct swcr_data *, caddr_t);
+int viac3_crypto_encdec(struct cryptop *, struct cryptodesc *,
+ struct viac3_session *, struct viac3_softc *, caddr_t);
+int viac3_crypto_freesession(u_int64_t);
+static __inline void viac3_cbc(void *, void *, void *, void *, int, void *);
+
+void
+viac3_crypto_setup(void)
+{
+ int algs[CRYPTO_ALGORITHM_MAX + 1];
+
+ if ((vc3_sc = malloc(sizeof(*vc3_sc), M_DEVBUF,
+ M_NOWAIT|M_ZERO)) == NULL)
+ return; /* YYY bitch? */
+
+ bzero(algs, sizeof(algs));
+ algs[CRYPTO_AES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
+ algs[CRYPTO_MD5_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
+ algs[CRYPTO_SHA1_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
+ algs[CRYPTO_RIPEMD160_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
+ algs[CRYPTO_SHA2_256_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
+ algs[CRYPTO_SHA2_384_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
+ algs[CRYPTO_SHA2_512_HMAC] = 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 cryptoini *c;
+ struct viac3_softc *sc = vc3_sc;
+ struct viac3_session *ses = NULL;
+ struct auth_hash *axf;
+ struct swcr_data *swd;
+ int sesn, i, cw0;
+
+ if (sc == NULL || sidp == NULL || cri == NULL)
+ return (EINVAL);
+
+ if (sc->sc_sessions == NULL) {
+ ses = sc->sc_sessions = 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 = 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;
+
+ for (c = cri; c != NULL; c = c->cri_next) {
+ switch (c->cri_alg) {
+ case CRYPTO_AES_CBC:
+ switch (c->cri_klen) {
+ case 128:
+ cw0 = C3_CRYPT_CWLO_KEY128;
+ break;
+ case 192:
+ cw0 = C3_CRYPT_CWLO_KEY192;
+ break;
+ case 256:
+ cw0 = C3_CRYPT_CWLO_KEY256;
+ break;
+ default:
+ viac3_crypto_freesession(sesn);
+ return (EINVAL);
+ }
+ cw0 |= C3_CRYPT_CWLO_ALG_AES | C3_CRYPT_CWLO_KEYGEN_SW |
+ C3_CRYPT_CWLO_NORMAL;
+
+ arc4random_buf(ses->ses_iv, sizeof(ses->ses_iv));
+ ses->ses_klen = c->cri_klen;
+ ses->ses_cw0 = cw0;
+
+ /* Build expanded keys for both directions */
+ rijndaelKeySetupEnc(ses->ses_ekey, c->cri_key,
+ c->cri_klen);
+ rijndaelKeySetupDec(ses->ses_dkey, c->cri_key,
+ c->cri_klen);
+ for (i = 0; i < 4 * (AES_MAXROUNDS + 1); i++) {
+ ses->ses_ekey[i] = ntohl(ses->ses_ekey[i]);
+ ses->ses_dkey[i] = ntohl(ses->ses_dkey[i]);
+ }
+
+ break;
+
+ case CRYPTO_MD5_HMAC:
+ axf = &auth_hash_hmac_md5_96;
+ goto authcommon;
+ case CRYPTO_SHA1_HMAC:
+ axf = &auth_hash_hmac_sha1_96;
+ goto authcommon;
+ case CRYPTO_RIPEMD160_HMAC:
+ axf = &auth_hash_hmac_ripemd_160_96;
+ goto authcommon;
+ case CRYPTO_SHA2_256_HMAC:
+ axf = &auth_hash_hmac_sha2_256_96;
+ goto authcommon;
+ case CRYPTO_SHA2_384_HMAC:
+ axf = &auth_hash_hmac_sha2_384_96;
+ goto authcommon;
+ case CRYPTO_SHA2_512_HMAC:
+ axf = &auth_hash_hmac_sha2_512_96;
+ authcommon:
+ swd = malloc(sizeof(struct swcr_data), M_CRYPTO_DATA,
+ M_NOWAIT|M_ZERO);
+ if (swd == NULL) {
+ viac3_crypto_freesession(sesn);
+ return (ENOMEM);
+ }
+ ses->swd = swd;
+
+ swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
+ M_NOWAIT);
+ if (swd->sw_ictx == NULL) {
+ viac3_crypto_freesession(sesn);
+ return (ENOMEM);
+ }
+
+ swd->sw_octx = malloc(axf->ctxsize, M_CRYPTO_DATA,
+ M_NOWAIT);
+ if (swd->sw_octx == NULL) {
+ viac3_crypto_freesession(sesn);
+ return (ENOMEM);
+ }
+
+ for (i = 0; i < c->cri_klen / 8; i++)
+ c->cri_key[i] ^= HMAC_IPAD_VAL;
+
+ axf->Init(swd->sw_ictx);
+ axf->Update(swd->sw_ictx, c->cri_key, c->cri_klen / 8);
+ axf->Update(swd->sw_ictx, hmac_ipad_buffer,
+ HMAC_BLOCK_LEN - (c->cri_klen / 8));
+
+ for (i = 0; i < c->cri_klen / 8; i++)
+ c->cri_key[i] ^= (HMAC_IPAD_VAL ^
+ HMAC_OPAD_VAL);
+
+ axf->Init(swd->sw_octx);
+ axf->Update(swd->sw_octx, c->cri_key, c->cri_klen / 8);
+ axf->Update(swd->sw_octx, hmac_opad_buffer,
+ HMAC_BLOCK_LEN - (c->cri_klen / 8));
+
+ for (i = 0; i < c->cri_klen / 8; i++)
+ c->cri_key[i] ^= HMAC_OPAD_VAL;
+
+ swd->sw_axf = axf;
+ swd->sw_alg = c->cri_alg;
+
+ break;
+ default:
+ viac3_crypto_freesession(sesn);
+ return (EINVAL);
+ }
+ }
+
+ *sidp = VIAC3_SID(0, sesn);
+ return (0);
+}
+
+int
+viac3_crypto_freesession(u_int64_t tid)
+{
+ struct viac3_softc *sc = vc3_sc;
+ struct swcr_data *swd;
+ struct auth_hash *axf;
+ 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);
+
+ if (sc->sc_sessions[sesn].swd) {
+ swd = sc->sc_sessions[sesn].swd;
+ axf = swd->sw_axf;
+
+ if (swd->sw_ictx) {
+ bzero(swd->sw_ictx, axf->ctxsize);
+ free(swd->sw_ictx, M_CRYPTO_DATA);
+ }
+ if (swd->sw_octx) {
+ bzero(swd->sw_octx, axf->ctxsize);
+ free(swd->sw_octx, M_CRYPTO_DATA);
+ }
+ free(swd, M_CRYPTO_DATA);
+ }
+
+ bzero(&sc->sc_sessions[sesn], sizeof(sc->sc_sessions[sesn]));
+ return (0);
+}
+
+static __inline void
+viac3_cbc(void *cw, void *src, void *dst, void *key, int rep,
+ void *iv)
+{
+ unsigned int creg0;
+
+ creg0 = rcr0(); /* Permit access to SIMD/FPU path */
+ lcr0(creg0 & ~(CR0_EM|CR0_TS));
+
+ /* Do the deed */
+ __asm __volatile("pushf; popf");
+ __asm __volatile("rep xcrypt-cbc" :
+ : "a" (iv), "b" (key), "c" (rep), "d" (cw), "S" (src), "D" (dst)
+ : "memory", "cc");
+
+ lcr0(creg0);
+}
+
+int
+viac3_crypto_swauth(struct cryptop *crp, struct cryptodesc *crd,
+ struct swcr_data *sw, caddr_t buf)
+{
+ int type;
+
+ if (crp->crp_flags & CRYPTO_F_IMBUF)
+ type = CRYPTO_BUF_MBUF;
+ else
+ type= CRYPTO_BUF_IOV;
+
+ return (swcr_authcompute(crp, crd, sw, buf, type));
+}
+
+int
+viac3_crypto_encdec(struct cryptop *crp, struct cryptodesc *crd,
+ struct viac3_session *ses, struct viac3_softc *sc, caddr_t buf)
+{
+ u_int32_t *key;
+ int err = 0;
+
+ if ((crd->crd_len % 16) != 0) {
+ err = EINVAL;
+ return (err);
+ }
+
+ sc->op_buf = malloc(crd->crd_len, M_DEVBUF, M_NOWAIT);
+ if (sc->op_buf == NULL) {
+ err = ENOMEM;
+ return (err);
+ }
+
+ if (crd->crd_flags & CRD_F_ENCRYPT) {
+ sc->op_cw[0] = ses->ses_cw0 | C3_CRYPT_CWLO_ENCRYPT;
+ key = ses->ses_ekey;
+ if (crd->crd_flags & CRD_F_IV_EXPLICIT)
+ bcopy(crd->crd_iv, sc->op_iv, 16);
+ else
+ bcopy(ses->ses_iv, sc->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, sc->op_iv);
+ else if (crp->crp_flags & CRYPTO_F_IOV)
+ cuio_copyback((struct uio *)crp->crp_buf,
+ crd->crd_inject, 16, sc->op_iv);
+ else
+ bcopy(sc->op_iv,
+ crp->crp_buf + crd->crd_inject, 16);
+ }
+ } else {
+ sc->op_cw[0] = ses->ses_cw0 | C3_CRYPT_CWLO_DECRYPT;
+ key = ses->ses_dkey;
+ if (crd->crd_flags & CRD_F_IV_EXPLICIT)
+ bcopy(crd->crd_iv, sc->op_iv, 16);
+ else {
+ if (crp->crp_flags & CRYPTO_F_IMBUF)
+ m_copydata((struct mbuf *)crp->crp_buf,
+ crd->crd_inject, 16, sc->op_iv);
+ else if (crp->crp_flags & CRYPTO_F_IOV)
+ cuio_copydata((struct uio *)crp->crp_buf,
+ crd->crd_inject, 16, sc->op_iv);
+ else
+ bcopy(crp->crp_buf + crd->crd_inject,
+ sc->op_iv, 16);
+ }
+ }
+
+ if (crp->crp_flags & CRYPTO_F_IMBUF)
+ m_copydata((struct mbuf *)crp->crp_buf,
+ crd->crd_skip, crd->crd_len, sc->op_buf);
+ else if (crp->crp_flags & CRYPTO_F_IOV)
+ cuio_copydata((struct uio *)crp->crp_buf,
+ crd->crd_skip, crd->crd_len, sc->op_buf);
+ else
+ bcopy(crp->crp_buf + crd->crd_skip, sc->op_buf, crd->crd_len);
+
+ sc->op_cw[1] = sc->op_cw[2] = sc->op_cw[3] = 0;
+ viac3_cbc(&sc->op_cw, sc->op_buf, sc->op_buf, key,
+ crd->crd_len / 16, sc->op_iv);
+
+ if (crp->crp_flags & CRYPTO_F_IMBUF)
+ m_copyback((struct mbuf *)crp->crp_buf,
+ crd->crd_skip, crd->crd_len, sc->op_buf);
+ else if (crp->crp_flags & CRYPTO_F_IOV)
+ cuio_copyback((struct uio *)crp->crp_buf,
+ crd->crd_skip, crd->crd_len, sc->op_buf);
+ else
+ bcopy(sc->op_buf, 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,
+ ses->ses_iv);
+ else
+ bcopy(crp->crp_buf + crd->crd_skip +
+ crd->crd_len - 16, ses->ses_iv, 16);
+ }
+
+ if (sc->op_buf != NULL) {
+ bzero(sc->op_buf, crd->crd_len);
+ free(sc->op_buf, M_DEVBUF);
+ sc->op_buf = NULL;
+ }
+
+ return (err);
+}
+
+int
+viac3_crypto_process(struct cryptop *crp)
+{
+ struct viac3_softc *sc = vc3_sc;
+ struct viac3_session *ses;
+ struct cryptodesc *crd;
+ int sesn, err = 0;
+
+ 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];
+ if (ses->ses_used == 0) {
+ err = EINVAL;
+ goto out;
+ }
+
+ for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
+ switch (crd->crd_alg) {
+ case CRYPTO_AES_CBC:
+ if ((err = viac3_crypto_encdec(crp, crd, ses, sc,
+ crp->crp_buf)) != 0)
+ goto out;
+ break;
+
+ case CRYPTO_MD5_HMAC:
+ case CRYPTO_SHA1_HMAC:
+ case CRYPTO_RIPEMD160_HMAC:
+ case CRYPTO_SHA2_256_HMAC:
+ case CRYPTO_SHA2_384_HMAC:
+ case CRYPTO_SHA2_512_HMAC:
+ if ((err = viac3_crypto_swauth(crp, crd, ses->swd,
+ crp->crp_buf)) != 0)
+ goto out;
+ break;
+
+ default:
+ err = EINVAL;
+ goto out;
+ }
+ }
+out:
+ crp->crp_etype = err;
+ crypto_done(crp);
+ return (err);
+}
+
+#endif /* CRYPTO */
+
+/*
+ * Note, the VIA C3 Nehemiah provides 4 internal 8-byte buffers, which
+ * store random data, and can be accessed a lot quicker than waiting
+ * for new data to be generated. As we are using every 8th bit only
+ * due to whitening. Since the RNG generates in excess of 21KB/s at
+ * its worst, collecting 64 bytes worth of entropy should not affect
+ * things significantly.
+ *
+ * Note, due to some weirdness in the RNG, we need at least 7 bytes
+ * extra on the end of our buffer. Also, there is an outside chance
+ * that the VIA RNG can "wedge", as the generated bit-rate is variable.
+ * We could do all sorts of startup testing and things, but
+ * frankly, I don't really see the point. If the RNG wedges, then the
+ * chances of you having a defective CPU are very high. Let it wedge.
+ *
+ * Adding to the whole confusion, in order to access the RNG, we need
+ * to have FXSR support enabled, and the correct FPU enable bits must
+ * be there to enable the FPU in kernel. It would be nice if all this
+ * mumbo-jumbo was not needed in order to use the RNG. Oh well, life
+ * does go on...
+ */
+#define VIAC3_RNG_BUFSIZ 16 /* 32bit words */
+struct timeout viac3_rnd_tmo;
+int viac3_rnd_present;
+
+void
+viac3_rnd(void *v)
+{
+ struct timeout *tmo = v;
+ unsigned int *p, i, rv, creg0, len = VIAC3_RNG_BUFSIZ;
+ static int buffer[VIAC3_RNG_BUFSIZ + 2]; /* XXX why + 2? */
+#ifdef MULTIPROCESSOR
+ int s = splipi();
+#endif
+
+ creg0 = rcr0(); /* Permit access to SIMD/FPU path */
+ lcr0(creg0 & ~(CR0_EM|CR0_TS));
+
+ /*
+ * Here we collect the random data from the VIA C3 RNG. We make
+ * sure that we turn on maximum whitening (%edx[0,1] == "11"), so
+ * that we get the best random data possible.
+ */
+ __asm __volatile("rep xstore-rng"
+ : "=a" (rv) : "d" (3), "D" (buffer), "c" (len*sizeof(int))
+ : "memory", "cc");
+
+ lcr0(creg0);
+
+#ifdef MULTIPROCESSOR
+ splx(s);
+#endif
+
+ for (i = 0, p = buffer; i < VIAC3_RNG_BUFSIZ; i++, p++)
+ add_true_randomness(*p);
+
+ timeout_add(tmo, (hz > 100) ? (hz / 100) : 1);
+}
diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64
index b3b74da2334..d60980af530 100644
--- a/sys/arch/amd64/conf/files.amd64
+++ b/sys/arch/amd64/conf/files.amd64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.amd64,v 1.48 2009/05/09 19:23:07 mglocker Exp $
+# $OpenBSD: files.amd64,v 1.49 2009/05/31 03:20:10 matthieu Exp $
maxpartitions 16
maxusers 2 16 128
@@ -9,6 +9,7 @@ file arch/amd64/amd64/disksubr.c disk
file arch/amd64/amd64/gdt.c
file arch/amd64/amd64/machdep.c
file arch/amd64/amd64/identcpu.c
+file arch/amd64/amd64/via.c
file arch/amd64/amd64/amd64errata.c
file arch/amd64/amd64/mem.c
file arch/amd64/amd64/amd64_mem.c mtrr
diff --git a/sys/arch/amd64/include/specialreg.h b/sys/arch/amd64/include/specialreg.h
index f8d7448843e..b825a206d9e 100644
--- a/sys/arch/amd64/include/specialreg.h
+++ b/sys/arch/amd64/include/specialreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: specialreg.h,v 1.13 2008/08/13 15:44:44 art Exp $ */
+/* $OpenBSD: specialreg.h,v 1.14 2009/05/31 03:20:10 matthieu Exp $ */
/* $NetBSD: specialreg.h,v 1.1 2003/04/26 18:39:48 fvdl Exp $ */
/* $NetBSD: x86/specialreg.h,v 1.2 2003/04/25 21:54:30 fvdl Exp $ */
@@ -638,3 +638,36 @@
#define K7_BP1_MATCH 0xdd
#define K7_BP2_MATCH 0xde
#define K7_BP3_MATCH 0xdf
+
+/* VIA C3 crypto featureset: for i386_has_xcrypt */
+#define C3_HAS_AES 1 /* cpu has AES */
+#define C3_HAS_SHA 2 /* cpu has SHA1 & SHA256 */
+#define C3_HAS_MM 4 /* cpu has RSA instructions */
+#define C3_HAS_AESCTR 8 /* cpu has AES-CTR instructions */
+
+/* Centaur Extended Feature flags */
+#define C3_CPUID_HAS_RNG 0x000004
+#define C3_CPUID_DO_RNG 0x000008
+#define C3_CPUID_HAS_ACE 0x000040
+#define C3_CPUID_DO_ACE 0x000080
+#define C3_CPUID_HAS_ACE2 0x000100
+#define C3_CPUID_DO_ACE2 0x000200
+#define C3_CPUID_HAS_PHE 0x000400
+#define C3_CPUID_DO_PHE 0x000800
+#define C3_CPUID_HAS_PMM 0x001000
+#define C3_CPUID_DO_PMM 0x002000
+
+/* VIA C3 xcrypt-* instruction context control options */
+#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 */