diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/autoconf.c | 28 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/identcpu.c | 97 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/via.c | 567 | ||||
-rw-r--r-- | sys/arch/amd64/conf/files.amd64 | 3 | ||||
-rw-r--r-- | sys/arch/amd64/include/specialreg.h | 35 |
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 */ |