[BACK]Return to via.c CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / i386

Annotation of sys/arch/i386/i386/via.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: via.c,v 1.12 2007/08/14 20:10:05 henric Exp $ */
                      2: /*     $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $    */
                      3:
                      4: /*-
                      5:  * Copyright (c) 2003 Jason Wright
                      6:  * Copyright (c) 2003, 2004 Theo de Raadt
                      7:  * All rights reserved.
                      8:  *
                      9:  * Permission to use, copy, modify, and distribute this software for any
                     10:  * purpose with or without fee is hereby granted, provided that the above
                     11:  * copyright notice and this permission notice appear in all copies.
                     12:  *
                     13:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     15:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     19:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     20:  */
                     21:
                     22: #include <sys/param.h>
                     23: #include <sys/systm.h>
                     24: #include <sys/signalvar.h>
                     25: #include <sys/kernel.h>
                     26: #include <sys/proc.h>
                     27: #include <sys/user.h>
                     28: #include <sys/exec.h>
                     29: #include <sys/buf.h>
                     30: #include <sys/reboot.h>
                     31: #include <sys/conf.h>
                     32: #include <sys/file.h>
                     33: #include <sys/timeout.h>
                     34: #include <sys/malloc.h>
                     35: #include <sys/mbuf.h>
                     36: #include <sys/extent.h>
                     37: #include <sys/sysctl.h>
                     38:
                     39: #ifdef CRYPTO
                     40: #include <crypto/cryptodev.h>
                     41: #include <crypto/rijndael.h>
                     42: #include <crypto/xform.h>
                     43: #include <crypto/cryptosoft.h>
                     44: #endif
                     45:
                     46: #include <uvm/uvm_extern.h>
                     47:
                     48: #include <machine/cpu.h>
                     49: #include <machine/cpufunc.h>
                     50: #include <machine/gdt.h>
                     51: #include <machine/pio.h>
                     52: #include <machine/bus.h>
                     53: #include <machine/psl.h>
                     54: #include <machine/reg.h>
                     55: #include <machine/specialreg.h>
                     56: #include <machine/biosvar.h>
                     57:
                     58: #include <dev/rndvar.h>
                     59:
                     60: void   viac3_rnd(void *);
                     61:
                     62:
                     63: #ifdef CRYPTO
                     64:
                     65: struct viac3_session {
                     66:        u_int32_t       ses_ekey[4 * (AES_MAXROUNDS + 1) + 4];  /* 128 bit aligned */
                     67:        u_int32_t       ses_dkey[4 * (AES_MAXROUNDS + 1) + 4];  /* 128 bit aligned */
                     68:        u_int8_t        ses_iv[16];                     /* 128 bit aligned */
                     69:        u_int32_t       ses_cw0;
                     70:        struct swcr_data *swd;
                     71:        int             ses_klen;
                     72:        int             ses_used;
                     73: };
                     74:
                     75: struct viac3_softc {
                     76:        u_int32_t               op_cw[4];               /* 128 bit aligned */
                     77:        u_int8_t                op_iv[16];              /* 128 bit aligned */
                     78:        void                    *op_buf;
                     79:
                     80:        /* normal softc stuff */
                     81:        int32_t                 sc_cid;
                     82:        int                     sc_nsessions;
                     83:        struct viac3_session    *sc_sessions;
                     84: };
                     85:
                     86: #define VIAC3_SESSION(sid)             ((sid) & 0x0fffffff)
                     87: #define        VIAC3_SID(crd,ses)              (((crd) << 28) | ((ses) & 0x0fffffff))
                     88:
                     89: static struct viac3_softc *vc3_sc;
                     90: extern int i386_has_xcrypt;
                     91:
                     92: extern u_int8_t hmac_ipad_buffer[64];
                     93: extern u_int8_t hmac_opad_buffer[64];
                     94:
                     95: void viac3_crypto_setup(void);
                     96: int viac3_crypto_newsession(u_int32_t *, struct cryptoini *);
                     97: int viac3_crypto_process(struct cryptop *);
                     98: int viac3_crypto_swauth(struct cryptop *, struct cryptodesc *,
                     99:     struct swcr_data *, caddr_t);
                    100: int viac3_crypto_encdec(struct cryptop *, struct cryptodesc *,
                    101:     struct viac3_session *, struct viac3_softc *, caddr_t);
                    102: int viac3_crypto_freesession(u_int64_t);
                    103: static __inline void viac3_cbc(void *, void *, void *, void *, int, void *);
                    104:
                    105: void
                    106: viac3_crypto_setup(void)
                    107: {
                    108:        int algs[CRYPTO_ALGORITHM_MAX + 1];
                    109:
                    110:        if ((vc3_sc = malloc(sizeof(*vc3_sc), M_DEVBUF, M_NOWAIT)) == NULL)
                    111:                return;         /* YYY bitch? */
                    112:        bzero(vc3_sc, sizeof(*vc3_sc));
                    113:
                    114:        bzero(algs, sizeof(algs));
                    115:        algs[CRYPTO_AES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
                    116:        algs[CRYPTO_MD5_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
                    117:        algs[CRYPTO_SHA1_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
                    118:        algs[CRYPTO_RIPEMD160_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
                    119:        algs[CRYPTO_SHA2_256_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
                    120:        algs[CRYPTO_SHA2_384_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
                    121:        algs[CRYPTO_SHA2_512_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
                    122:
                    123:        vc3_sc->sc_cid = crypto_get_driverid(0);
                    124:        if (vc3_sc->sc_cid < 0)
                    125:                return;         /* YYY bitch? */
                    126:
                    127:        crypto_register(vc3_sc->sc_cid, algs, viac3_crypto_newsession,
                    128:            viac3_crypto_freesession, viac3_crypto_process);
                    129: }
                    130:
                    131: int
                    132: viac3_crypto_newsession(u_int32_t *sidp, struct cryptoini *cri)
                    133: {
                    134:        struct cryptoini        *c;
                    135:        struct viac3_softc      *sc = vc3_sc;
                    136:        struct viac3_session    *ses = NULL;
                    137:        struct auth_hash        *axf;
                    138:        struct swcr_data        *swd;
                    139:        int                      sesn, i, cw0;
                    140:
                    141:        if (sc == NULL || sidp == NULL || cri == NULL)
                    142:                return (EINVAL);
                    143:
                    144:        if (sc->sc_sessions == NULL) {
                    145:                ses = sc->sc_sessions = malloc(sizeof(*ses), M_DEVBUF,
                    146:                    M_NOWAIT);
                    147:                if (ses == NULL)
                    148:                        return (ENOMEM);
                    149:                sesn = 0;
                    150:                sc->sc_nsessions = 1;
                    151:        } else {
                    152:                for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
                    153:                        if (sc->sc_sessions[sesn].ses_used == 0) {
                    154:                                ses = &sc->sc_sessions[sesn];
                    155:                                break;
                    156:                        }
                    157:                }
                    158:
                    159:                if (ses == NULL) {
                    160:                        sesn = sc->sc_nsessions;
                    161:                        ses = malloc((sesn + 1) * sizeof(*ses), M_DEVBUF,
                    162:                            M_NOWAIT);
                    163:                        if (ses == NULL)
                    164:                                return (ENOMEM);
                    165:                        bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses));
                    166:                        bzero(sc->sc_sessions, sesn * sizeof(*ses));
                    167:                        free(sc->sc_sessions, M_DEVBUF);
                    168:                        sc->sc_sessions = ses;
                    169:                        ses = &sc->sc_sessions[sesn];
                    170:                        sc->sc_nsessions++;
                    171:                }
                    172:        }
                    173:
                    174:        bzero(ses, sizeof(*ses));
                    175:        ses->ses_used = 1;
                    176:
                    177:        for (c = cri; c != NULL; c = c->cri_next) {
                    178:                switch (c->cri_alg) {
                    179:                case CRYPTO_AES_CBC:
                    180:                        switch (c->cri_klen) {
                    181:                        case 128:
                    182:                                cw0 = C3_CRYPT_CWLO_KEY128;
                    183:                                break;
                    184:                        case 192:
                    185:                                cw0 = C3_CRYPT_CWLO_KEY192;
                    186:                                break;
                    187:                        case 256:
                    188:                                cw0 = C3_CRYPT_CWLO_KEY256;
                    189:                                break;
                    190:                        default:
                    191:                                viac3_crypto_freesession(sesn);
                    192:                                return (EINVAL);
                    193:                        }
                    194:                        cw0 |= C3_CRYPT_CWLO_ALG_AES | C3_CRYPT_CWLO_KEYGEN_SW |
                    195:                            C3_CRYPT_CWLO_NORMAL;
                    196:
                    197:                        get_random_bytes(ses->ses_iv, sizeof(ses->ses_iv));
                    198:                        ses->ses_klen = c->cri_klen;
                    199:                        ses->ses_cw0 = cw0;
                    200:
                    201:                        /* Build expanded keys for both directions */
                    202:                        rijndaelKeySetupEnc(ses->ses_ekey, c->cri_key,
                    203:                            c->cri_klen);
                    204:                        rijndaelKeySetupDec(ses->ses_dkey, c->cri_key,
                    205:                            c->cri_klen);
                    206:                        for (i = 0; i < 4 * (AES_MAXROUNDS + 1); i++) {
                    207:                                ses->ses_ekey[i] = ntohl(ses->ses_ekey[i]);
                    208:                                ses->ses_dkey[i] = ntohl(ses->ses_dkey[i]);
                    209:                        }
                    210:
                    211:                        break;
                    212:
                    213:                case CRYPTO_MD5_HMAC:
                    214:                        axf = &auth_hash_hmac_md5_96;
                    215:                        goto authcommon;
                    216:                case CRYPTO_SHA1_HMAC:
                    217:                        axf = &auth_hash_hmac_sha1_96;
                    218:                        goto authcommon;
                    219:                case CRYPTO_RIPEMD160_HMAC:
                    220:                        axf = &auth_hash_hmac_ripemd_160_96;
                    221:                        goto authcommon;
                    222:                case CRYPTO_SHA2_256_HMAC:
                    223:                        axf = &auth_hash_hmac_sha2_256_96;
                    224:                        goto authcommon;
                    225:                case CRYPTO_SHA2_384_HMAC:
                    226:                        axf = &auth_hash_hmac_sha2_384_96;
                    227:                        goto authcommon;
                    228:                case CRYPTO_SHA2_512_HMAC:
                    229:                        axf = &auth_hash_hmac_sha2_512_96;
                    230:                authcommon:
                    231:                        MALLOC(swd, struct swcr_data *,
                    232:                            sizeof(struct swcr_data), M_CRYPTO_DATA,
                    233:                            M_NOWAIT);
                    234:                        if (swd == NULL) {
                    235:                                viac3_crypto_freesession(sesn);
                    236:                                return (ENOMEM);
                    237:                        }
                    238:                        bzero(swd, sizeof(struct swcr_data));
                    239:                        ses->swd = swd;
                    240:
                    241:                        swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
                    242:                            M_NOWAIT);
                    243:                        if (swd->sw_ictx == NULL) {
                    244:                                viac3_crypto_freesession(sesn);
                    245:                                return (ENOMEM);
                    246:                        }
                    247:
                    248:                        swd->sw_octx = malloc(axf->ctxsize, M_CRYPTO_DATA,
                    249:                            M_NOWAIT);
                    250:                        if (swd->sw_octx == NULL) {
                    251:                                viac3_crypto_freesession(sesn);
                    252:                                return (ENOMEM);
                    253:                        }
                    254:
                    255:                        for (i = 0; i < c->cri_klen / 8; i++)
                    256:                                c->cri_key[i] ^= HMAC_IPAD_VAL;
                    257:
                    258:                        axf->Init(swd->sw_ictx);
                    259:                        axf->Update(swd->sw_ictx, c->cri_key, c->cri_klen / 8);
                    260:                        axf->Update(swd->sw_ictx, hmac_ipad_buffer,
                    261:                            HMAC_BLOCK_LEN - (c->cri_klen / 8));
                    262:
                    263:                        for (i = 0; i < c->cri_klen / 8; i++)
                    264:                                c->cri_key[i] ^= (HMAC_IPAD_VAL ^
                    265:                                    HMAC_OPAD_VAL);
                    266:
                    267:                        axf->Init(swd->sw_octx);
                    268:                        axf->Update(swd->sw_octx, c->cri_key, c->cri_klen / 8);
                    269:                        axf->Update(swd->sw_octx, hmac_opad_buffer,
                    270:                            HMAC_BLOCK_LEN - (c->cri_klen / 8));
                    271:
                    272:                        for (i = 0; i < c->cri_klen / 8; i++)
                    273:                                c->cri_key[i] ^= HMAC_OPAD_VAL;
                    274:
                    275:                        swd->sw_axf = axf;
                    276:                        swd->sw_alg = c->cri_alg;
                    277:
                    278:                        break;
                    279:                default:
                    280:                        viac3_crypto_freesession(sesn);
                    281:                        return (EINVAL);
                    282:                }
                    283:        }
                    284:
                    285:        *sidp = VIAC3_SID(0, sesn);
                    286:        return (0);
                    287: }
                    288:
                    289: int
                    290: viac3_crypto_freesession(u_int64_t tid)
                    291: {
                    292:        struct viac3_softc *sc = vc3_sc;
                    293:        struct swcr_data *swd;
                    294:        struct auth_hash *axf;
                    295:        int sesn;
                    296:        u_int32_t sid = ((u_int32_t)tid) & 0xffffffff;
                    297:
                    298:        if (sc == NULL)
                    299:                return (EINVAL);
                    300:        sesn = VIAC3_SESSION(sid);
                    301:        if (sesn >= sc->sc_nsessions)
                    302:                return (EINVAL);
                    303:
                    304:        if (sc->sc_sessions[sesn].swd) {
                    305:                swd = sc->sc_sessions[sesn].swd;
                    306:                axf = swd->sw_axf;
                    307:
                    308:                if (swd->sw_ictx) {
                    309:                        bzero(swd->sw_ictx, axf->ctxsize);
                    310:                        free(swd->sw_ictx, M_CRYPTO_DATA);
                    311:                }
                    312:                if (swd->sw_octx) {
                    313:                        bzero(swd->sw_octx, axf->ctxsize);
                    314:                        free(swd->sw_octx, M_CRYPTO_DATA);
                    315:                }
                    316:                FREE(swd, M_CRYPTO_DATA);
                    317:        }
                    318:
                    319:        bzero(&sc->sc_sessions[sesn], sizeof(sc->sc_sessions[sesn]));
                    320:        return (0);
                    321: }
                    322:
                    323: static __inline void
                    324: viac3_cbc(void *cw, void *src, void *dst, void *key, int rep,
                    325:     void *iv)
                    326: {
                    327:        unsigned int creg0;
                    328:
                    329:        creg0 = rcr0();         /* Permit access to SIMD/FPU path */
                    330:        lcr0(creg0 & ~(CR0_EM|CR0_TS));
                    331:
                    332:        /* Do the deed */
                    333:        __asm __volatile("pushfl; popfl");
                    334:        __asm __volatile("rep xcrypt-cbc" :
                    335:            : "a" (iv), "b" (key), "c" (rep), "d" (cw), "S" (src), "D" (dst)
                    336:            : "memory", "cc");
                    337:
                    338:        lcr0(creg0);
                    339: }
                    340:
                    341: int
                    342: viac3_crypto_swauth(struct cryptop *crp, struct cryptodesc *crd,
                    343:     struct swcr_data *sw, caddr_t buf)
                    344: {
                    345:        int     type;
                    346:
                    347:        if (crp->crp_flags & CRYPTO_F_IMBUF)
                    348:                type = CRYPTO_BUF_MBUF;
                    349:        else
                    350:                type= CRYPTO_BUF_IOV;
                    351:
                    352:        return (swcr_authcompute(crp, crd, sw, buf, type));
                    353: }
                    354:
                    355: int
                    356: viac3_crypto_encdec(struct cryptop *crp, struct cryptodesc *crd,
                    357:     struct viac3_session *ses, struct viac3_softc *sc, caddr_t buf)
                    358: {
                    359:        u_int32_t *key;
                    360:        int     err = 0;
                    361:
                    362:        if ((crd->crd_len % 16) != 0) {
                    363:                err = EINVAL;
                    364:                return (err);
                    365:        }
                    366:
                    367:        sc->op_buf = malloc(crd->crd_len, M_DEVBUF, M_NOWAIT);
                    368:        if (sc->op_buf == NULL) {
                    369:                err = ENOMEM;
                    370:                return (err);
                    371:        }
                    372:
                    373:        if (crd->crd_flags & CRD_F_ENCRYPT) {
                    374:                sc->op_cw[0] = ses->ses_cw0 | C3_CRYPT_CWLO_ENCRYPT;
                    375:                key = ses->ses_ekey;
                    376:                if (crd->crd_flags & CRD_F_IV_EXPLICIT)
                    377:                        bcopy(crd->crd_iv, sc->op_iv, 16);
                    378:                else
                    379:                        bcopy(ses->ses_iv, sc->op_iv, 16);
                    380:
                    381:                if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
                    382:                        if (crp->crp_flags & CRYPTO_F_IMBUF)
                    383:                                m_copyback((struct mbuf *)crp->crp_buf,
                    384:                                    crd->crd_inject, 16, sc->op_iv);
                    385:                        else if (crp->crp_flags & CRYPTO_F_IOV)
                    386:                                cuio_copyback((struct uio *)crp->crp_buf,
                    387:                                    crd->crd_inject, 16, sc->op_iv);
                    388:                        else
                    389:                                bcopy(sc->op_iv,
                    390:                                    crp->crp_buf + crd->crd_inject, 16);
                    391:                }
                    392:        } else {
                    393:                sc->op_cw[0] = ses->ses_cw0 | C3_CRYPT_CWLO_DECRYPT;
                    394:                key = ses->ses_dkey;
                    395:                if (crd->crd_flags & CRD_F_IV_EXPLICIT)
                    396:                        bcopy(crd->crd_iv, sc->op_iv, 16);
                    397:                else {
                    398:                        if (crp->crp_flags & CRYPTO_F_IMBUF)
                    399:                                m_copydata((struct mbuf *)crp->crp_buf,
                    400:                                    crd->crd_inject, 16, sc->op_iv);
                    401:                        else if (crp->crp_flags & CRYPTO_F_IOV)
                    402:                                cuio_copydata((struct uio *)crp->crp_buf,
                    403:                                    crd->crd_inject, 16, sc->op_iv);
                    404:                        else
                    405:                                bcopy(crp->crp_buf + crd->crd_inject,
                    406:                                    sc->op_iv, 16);
                    407:                }
                    408:        }
                    409:
                    410:        if (crp->crp_flags & CRYPTO_F_IMBUF)
                    411:                m_copydata((struct mbuf *)crp->crp_buf,
                    412:                    crd->crd_skip, crd->crd_len, sc->op_buf);
                    413:        else if (crp->crp_flags & CRYPTO_F_IOV)
                    414:                cuio_copydata((struct uio *)crp->crp_buf,
                    415:                    crd->crd_skip, crd->crd_len, sc->op_buf);
                    416:        else
                    417:                bcopy(crp->crp_buf + crd->crd_skip, sc->op_buf, crd->crd_len);
                    418:
                    419:        sc->op_cw[1] = sc->op_cw[2] = sc->op_cw[3] = 0;
                    420:        viac3_cbc(&sc->op_cw, sc->op_buf, sc->op_buf, key,
                    421:            crd->crd_len / 16, sc->op_iv);
                    422:
                    423:        if (crp->crp_flags & CRYPTO_F_IMBUF)
                    424:                m_copyback((struct mbuf *)crp->crp_buf,
                    425:                    crd->crd_skip, crd->crd_len, sc->op_buf);
                    426:        else if (crp->crp_flags & CRYPTO_F_IOV)
                    427:                cuio_copyback((struct uio *)crp->crp_buf,
                    428:                    crd->crd_skip, crd->crd_len, sc->op_buf);
                    429:        else
                    430:                bcopy(sc->op_buf, crp->crp_buf + crd->crd_skip,
                    431:                    crd->crd_len);
                    432:
                    433:        /* copy out last block for use as next session IV */
                    434:        if (crd->crd_flags & CRD_F_ENCRYPT) {
                    435:                if (crp->crp_flags & CRYPTO_F_IMBUF)
                    436:                        m_copydata((struct mbuf *)crp->crp_buf,
                    437:                            crd->crd_skip + crd->crd_len - 16, 16,
                    438:                            ses->ses_iv);
                    439:                else if (crp->crp_flags & CRYPTO_F_IOV)
                    440:                        cuio_copydata((struct uio *)crp->crp_buf,
                    441:                            crd->crd_skip + crd->crd_len - 16, 16,
                    442:                            ses->ses_iv);
                    443:                else
                    444:                        bcopy(crp->crp_buf + crd->crd_skip +
                    445:                            crd->crd_len - 16, ses->ses_iv, 16);
                    446:        }
                    447:
                    448:        if (sc->op_buf != NULL) {
                    449:                bzero(sc->op_buf, crd->crd_len);
                    450:                free(sc->op_buf, M_DEVBUF);
                    451:                sc->op_buf = NULL;
                    452:        }
                    453:
                    454:        return (err);
                    455: }
                    456:
                    457: int
                    458: viac3_crypto_process(struct cryptop *crp)
                    459: {
                    460:        struct viac3_softc *sc = vc3_sc;
                    461:        struct viac3_session *ses;
                    462:        struct cryptodesc *crd;
                    463:        int sesn, err = 0;
                    464:
                    465:        if (crp == NULL || crp->crp_callback == NULL) {
                    466:                err = EINVAL;
                    467:                goto out;
                    468:        }
                    469:
                    470:        sesn = VIAC3_SESSION(crp->crp_sid);
                    471:        if (sesn >= sc->sc_nsessions) {
                    472:                err = EINVAL;
                    473:                goto out;
                    474:        }
                    475:        ses = &sc->sc_sessions[sesn];
                    476:
                    477:        for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
                    478:                switch (crd->crd_alg) {
                    479:                case CRYPTO_AES_CBC:
                    480:                        if ((err = viac3_crypto_encdec(crp, crd, ses, sc,
                    481:                            crp->crp_buf)) != 0)
                    482:                                goto out;
                    483:                        break;
                    484:
                    485:                case CRYPTO_MD5_HMAC:
                    486:                case CRYPTO_SHA1_HMAC:
                    487:                case CRYPTO_RIPEMD160_HMAC:
                    488:                case CRYPTO_SHA2_256_HMAC:
                    489:                case CRYPTO_SHA2_384_HMAC:
                    490:                case CRYPTO_SHA2_512_HMAC:
                    491:                        if ((err = viac3_crypto_swauth(crp, crd, ses->swd,
                    492:                            crp->crp_buf)) != 0)
                    493:                                goto out;
                    494:                        break;
                    495:
                    496:                default:
                    497:                        err = EINVAL;
                    498:                        goto out;
                    499:                }
                    500:        }
                    501: out:
                    502:        crp->crp_etype = err;
                    503:        crypto_done(crp);
                    504:        return (err);
                    505: }
                    506:
                    507: #endif /* CRYPTO */
                    508:
                    509: #if defined(I686_CPU)
                    510: /*
                    511:  * Note, the VIA C3 Nehemiah provides 4 internal 8-byte buffers, which
                    512:  * store random data, and can be accessed a lot quicker than waiting
                    513:  * for new data to be generated.  As we are using every 8th bit only
                    514:  * due to whitening. Since the RNG generates in excess of 21KB/s at
                    515:  * its worst, collecting 64 bytes worth of entropy should not affect
                    516:  * things significantly.
                    517:  *
                    518:  * Note, due to some weirdness in the RNG, we need at least 7 bytes
                    519:  * extra on the end of our buffer.  Also, there is an outside chance
                    520:  * that the VIA RNG can "wedge", as the generated bit-rate is variable.
                    521:  * We could do all sorts of startup testing and things, but
                    522:  * frankly, I don't really see the point.  If the RNG wedges, then the
                    523:  * chances of you having a defective CPU are very high.  Let it wedge.
                    524:  *
                    525:  * Adding to the whole confusion, in order to access the RNG, we need
                    526:  * to have FXSR support enabled, and the correct FPU enable bits must
                    527:  * be there to enable the FPU in kernel.  It would be nice if all this
                    528:  * mumbo-jumbo was not needed in order to use the RNG.  Oh well, life
                    529:  * does go on...
                    530:  */
                    531: #define VIAC3_RNG_BUFSIZ       16              /* 32bit words */
                    532: struct timeout viac3_rnd_tmo;
                    533: int viac3_rnd_present;
                    534:
                    535: void
                    536: viac3_rnd(void *v)
                    537: {
                    538:        struct timeout *tmo = v;
                    539:        unsigned int *p, i, rv, creg0, len = VIAC3_RNG_BUFSIZ;
                    540:        static int buffer[VIAC3_RNG_BUFSIZ + 2];        /* XXX why + 2? */
                    541: #ifdef MULTIPROCESSOR
                    542:        int s = splipi();
                    543: #endif
                    544:
                    545:        creg0 = rcr0();         /* Permit access to SIMD/FPU path */
                    546:        lcr0(creg0 & ~(CR0_EM|CR0_TS));
                    547:
                    548:        /*
                    549:         * Here we collect the random data from the VIA C3 RNG.  We make
                    550:         * sure that we turn on maximum whitening (%edx[0,1] == "11"), so
                    551:         * that we get the best random data possible.
                    552:         */
                    553:        __asm __volatile("rep xstore-rng"
                    554:            : "=a" (rv) : "d" (3), "D" (buffer), "c" (len*sizeof(int))
                    555:            : "memory", "cc");
                    556:
                    557:        lcr0(creg0);
                    558:
                    559: #ifdef MULTIPROCESSOR
                    560:        splx(s);
                    561: #endif
                    562:
                    563:        for (i = 0, p = buffer; i < VIAC3_RNG_BUFSIZ; i++, p++)
                    564:                add_true_randomness(*p);
                    565:
                    566:        timeout_add(tmo, (hz > 100) ? (hz / 100) : 1);
                    567: }
                    568:
                    569: #endif /* defined(I686_CPU) */

CVSweb