root/arch/i386/i386/via.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. viac3_crypto_setup
  2. viac3_crypto_newsession
  3. viac3_crypto_freesession
  4. viac3_cbc
  5. viac3_crypto_swauth
  6. viac3_crypto_encdec
  7. viac3_crypto_process
  8. viac3_rnd

    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) */

/* [<][>][^][v][top][bottom][index][help] */