[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/crypto/via/padlock.c

Version: -  FREEBSD  -  FREEBSD8  -  FREEBSD7  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  OPENSOLARIS  -  minix-3-1-1  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

    1 /*-
    2  * Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 #include <sys/module.h>
   34 #include <sys/lock.h>
   35 #include <sys/mutex.h>
   36 #include <sys/malloc.h>
   37 #include <sys/libkern.h>
   38 #if defined(__amd64__) || (defined(__i386__) && !defined(PC98))
   39 #include <machine/cpufunc.h>
   40 #include <machine/cputypes.h>
   41 #include <machine/md_var.h>
   42 #include <machine/specialreg.h>
   43 #endif
   44 
   45 #include <opencrypto/cryptodev.h>
   46 
   47 #include <crypto/via/padlock.h>
   48 
   49 #include <sys/kobj.h>
   50 #include <sys/bus.h>
   51 #include "cryptodev_if.h"
   52 
   53 /*
   54  * Technical documentation about the PadLock engine can be found here:
   55  *
   56  * http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/programming_guide.pdf
   57  */
   58 
   59 struct padlock_softc {
   60         int32_t         sc_cid;
   61         uint32_t        sc_sid;
   62         TAILQ_HEAD(, padlock_session) sc_sessions;
   63         struct mtx      sc_sessions_mtx;
   64 };
   65 
   66 static int padlock_newsession(device_t, uint32_t *sidp, struct cryptoini *cri);
   67 static int padlock_freesession(device_t, uint64_t tid);
   68 static int padlock_process(device_t, struct cryptop *crp, int hint __unused);
   69 
   70 MALLOC_DEFINE(M_PADLOCK, "padlock_data", "PadLock Data");
   71 
   72 static void
   73 padlock_identify(device_t *dev, device_t parent)
   74 {
   75         /* NB: order 10 is so we get attached after h/w devices */
   76         if (device_find_child(parent, "padlock", -1) == NULL &&
   77             BUS_ADD_CHILD(parent, 10, "padlock", -1) == 0)
   78                 panic("padlock: could not attach");
   79 }
   80 
   81 static int
   82 padlock_probe(device_t dev)
   83 {
   84         char capp[256];
   85 
   86 #if defined(__amd64__) || (defined(__i386__) && !defined(PC98))
   87         /* If there is no AES support, we has nothing to do here. */
   88         if (!(via_feature_xcrypt & VIA_HAS_AES)) {
   89                 device_printf(dev, "No ACE support.\n");
   90                 return (EINVAL);
   91         }
   92         strlcpy(capp, "AES-CBC", sizeof(capp));
   93 #if 0
   94         strlcat(capp, ",AES-EBC", sizeof(capp));
   95         strlcat(capp, ",AES-CFB", sizeof(capp));
   96         strlcat(capp, ",AES-OFB", sizeof(capp));
   97 #endif
   98         if (via_feature_xcrypt & VIA_HAS_SHA) {
   99                 strlcat(capp, ",SHA1", sizeof(capp));
  100                 strlcat(capp, ",SHA256", sizeof(capp));
  101         }
  102 #if 0
  103         if (via_feature_xcrypt & VIA_HAS_AESCTR)
  104                 strlcat(capp, ",AES-CTR", sizeof(capp));
  105         if (via_feature_xcrypt & VIA_HAS_MM)
  106                 strlcat(capp, ",RSA", sizeof(capp));
  107 #endif
  108         device_set_desc_copy(dev, capp);
  109         return (0);
  110 #else
  111         return (EINVAL);
  112 #endif
  113 }
  114 
  115 static int
  116 padlock_attach(device_t dev)
  117 {
  118         struct padlock_softc *sc = device_get_softc(dev);
  119 
  120         TAILQ_INIT(&sc->sc_sessions);
  121         sc->sc_sid = 1;
  122 
  123         sc->sc_cid = crypto_get_driverid(dev, CRYPTOCAP_F_HARDWARE);
  124         if (sc->sc_cid < 0) {
  125                 device_printf(dev, "Could not get crypto driver id.\n");
  126                 return (ENOMEM);
  127         }
  128 
  129         mtx_init(&sc->sc_sessions_mtx, "padlock_mtx", NULL, MTX_DEF);
  130         crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
  131         crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
  132         crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
  133         crypto_register(sc->sc_cid, CRYPTO_RIPEMD160_HMAC, 0, 0);
  134         crypto_register(sc->sc_cid, CRYPTO_SHA2_256_HMAC, 0, 0);
  135         crypto_register(sc->sc_cid, CRYPTO_SHA2_384_HMAC, 0, 0);
  136         crypto_register(sc->sc_cid, CRYPTO_SHA2_512_HMAC, 0, 0);
  137         return (0);
  138 }
  139 
  140 static int
  141 padlock_detach(device_t dev)
  142 {
  143         struct padlock_softc *sc = device_get_softc(dev);
  144         struct padlock_session *ses;
  145 
  146         mtx_lock(&sc->sc_sessions_mtx);
  147         TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
  148                 if (ses->ses_used) {
  149                         mtx_unlock(&sc->sc_sessions_mtx);
  150                         device_printf(dev,
  151                             "Cannot detach, sessions still active.\n");
  152                         return (EBUSY);
  153                 }
  154         }
  155         for (ses = TAILQ_FIRST(&sc->sc_sessions); ses != NULL;
  156             ses = TAILQ_FIRST(&sc->sc_sessions)) {
  157                 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
  158                 free(ses, M_PADLOCK);
  159         }
  160         mtx_destroy(&sc->sc_sessions_mtx);
  161         crypto_unregister_all(sc->sc_cid);
  162         return (0);
  163 }
  164 
  165 static int
  166 padlock_newsession(device_t dev, uint32_t *sidp, struct cryptoini *cri)
  167 {
  168         struct padlock_softc *sc = device_get_softc(dev);
  169         struct padlock_session *ses = NULL;
  170         struct cryptoini *encini, *macini;
  171         int error;
  172 
  173         if (sidp == NULL || cri == NULL)
  174                 return (EINVAL);
  175 
  176         encini = macini = NULL;
  177         for (; cri != NULL; cri = cri->cri_next) {
  178                 switch (cri->cri_alg) {
  179                 case CRYPTO_NULL_HMAC:
  180                 case CRYPTO_MD5_HMAC:
  181                 case CRYPTO_SHA1_HMAC:
  182                 case CRYPTO_RIPEMD160_HMAC:
  183                 case CRYPTO_SHA2_256_HMAC:
  184                 case CRYPTO_SHA2_384_HMAC:
  185                 case CRYPTO_SHA2_512_HMAC:
  186                         if (macini != NULL)
  187                                 return (EINVAL);
  188                         macini = cri;
  189                         break;
  190                 case CRYPTO_AES_CBC:
  191                         if (encini != NULL)
  192                                 return (EINVAL);
  193                         encini = cri;
  194                         break;
  195                 default:
  196                         return (EINVAL);
  197                 }
  198         }
  199 
  200         /*
  201          * We only support HMAC algorithms to be able to work with
  202          * ipsec(4), so if we are asked only for authentication without
  203          * encryption, don't pretend we can accellerate it.
  204          */
  205         if (encini == NULL)
  206                 return (EINVAL);
  207 
  208         /*
  209          * Let's look for a free session structure.
  210          */
  211         mtx_lock(&sc->sc_sessions_mtx);
  212         /*
  213          * Free sessions goes first, so if first session is used, we need to
  214          * allocate one.
  215          */
  216         ses = TAILQ_FIRST(&sc->sc_sessions);
  217         if (ses == NULL || ses->ses_used)
  218                 ses = NULL;
  219         else {
  220                 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
  221                 ses->ses_used = 1;
  222                 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
  223         }
  224         mtx_unlock(&sc->sc_sessions_mtx);
  225         if (ses == NULL) {
  226                 ses = malloc(sizeof(*ses), M_PADLOCK, M_NOWAIT | M_ZERO);
  227                 if (ses == NULL)
  228                         return (ENOMEM);
  229                 ses->ses_used = 1;
  230                 mtx_lock(&sc->sc_sessions_mtx);
  231                 ses->ses_id = sc->sc_sid++;
  232                 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
  233                 mtx_unlock(&sc->sc_sessions_mtx);
  234         }
  235 
  236         error = padlock_cipher_setup(ses, encini);
  237         if (error != 0) {
  238                 padlock_freesession(NULL, ses->ses_id);
  239                 return (error);
  240         }
  241 
  242         if (macini != NULL) {
  243                 error = padlock_hash_setup(ses, macini);
  244                 if (error != 0) {
  245                         padlock_freesession(NULL, ses->ses_id);
  246                         return (error);
  247                 }
  248         }
  249 
  250         *sidp = ses->ses_id;
  251         return (0);
  252 }
  253 
  254 static int
  255 padlock_freesession(device_t dev, uint64_t tid)
  256 {
  257         struct padlock_softc *sc = device_get_softc(dev);
  258         struct padlock_session *ses;
  259         uint32_t sid = ((uint32_t)tid) & 0xffffffff;
  260 
  261         mtx_lock(&sc->sc_sessions_mtx);
  262         TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
  263                 if (ses->ses_id == sid)
  264                         break;
  265         }
  266         if (ses == NULL) {
  267                 mtx_unlock(&sc->sc_sessions_mtx);
  268                 return (EINVAL);
  269         }
  270         TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
  271         padlock_hash_free(ses);
  272         bzero(ses, sizeof(*ses));
  273         ses->ses_used = 0;
  274         TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
  275         mtx_unlock(&sc->sc_sessions_mtx);
  276         return (0);
  277 }
  278 
  279 static int
  280 padlock_process(device_t dev, struct cryptop *crp, int hint __unused)
  281 {
  282         struct padlock_softc *sc = device_get_softc(dev);
  283         struct padlock_session *ses = NULL;
  284         struct cryptodesc *crd, *enccrd, *maccrd;
  285         int error = 0;
  286 
  287         enccrd = maccrd = NULL;
  288 
  289         if (crp == NULL || crp->crp_callback == NULL || crp->crp_desc == NULL) {
  290                 error = EINVAL;
  291                 goto out;
  292         }
  293 
  294         for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) {
  295                 switch (crd->crd_alg) {
  296                 case CRYPTO_NULL_HMAC:
  297                 case CRYPTO_MD5_HMAC:
  298                 case CRYPTO_SHA1_HMAC:
  299                 case CRYPTO_RIPEMD160_HMAC:
  300                 case CRYPTO_SHA2_256_HMAC:
  301                 case CRYPTO_SHA2_384_HMAC:
  302                 case CRYPTO_SHA2_512_HMAC:
  303                         if (maccrd != NULL) {
  304                                 error = EINVAL;
  305                                 goto out;
  306                         }
  307                         maccrd = crd;
  308                         break;
  309                 case CRYPTO_AES_CBC:
  310                         if (enccrd != NULL) {
  311                                 error = EINVAL;
  312                                 goto out;
  313                         }
  314                         enccrd = crd;
  315                         break;
  316                 default:
  317                         return (EINVAL);
  318                 }
  319         }
  320         if (enccrd == NULL || (enccrd->crd_len % AES_BLOCK_LEN) != 0) {
  321                 error = EINVAL;
  322                 goto out;
  323         }
  324 
  325         mtx_lock(&sc->sc_sessions_mtx);
  326         TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
  327                 if (ses->ses_id == (crp->crp_sid & 0xffffffff))
  328                         break;
  329         }
  330         mtx_unlock(&sc->sc_sessions_mtx);
  331         if (ses == NULL) {
  332                 error = EINVAL;
  333                 goto out;
  334         }
  335 
  336         /* Perform data authentication if requested before encryption. */
  337         if (maccrd != NULL && maccrd->crd_next == enccrd) {
  338                 error = padlock_hash_process(ses, maccrd, crp);
  339                 if (error != 0)
  340                         goto out;
  341         }
  342 
  343         error = padlock_cipher_process(ses, enccrd, crp);
  344         if (error != 0)
  345                 goto out;
  346 
  347         /* Perform data authentication if requested after encryption. */
  348         if (maccrd != NULL && enccrd->crd_next == maccrd) {
  349                 error = padlock_hash_process(ses, maccrd, crp);
  350                 if (error != 0)
  351                         goto out;
  352         }
  353 
  354 out:
  355 #if 0
  356         /*
  357          * This code is not necessary, because contexts will be freed on next
  358          * padlock_setup_mackey() call or at padlock_freesession() call.
  359          */
  360         if (ses != NULL && maccrd != NULL &&
  361             (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) {
  362                 padlock_free_ctx(ses->ses_axf, ses->ses_ictx);
  363                 padlock_free_ctx(ses->ses_axf, ses->ses_octx);
  364         }
  365 #endif
  366         crp->crp_etype = error;
  367         crypto_done(crp);
  368         return (error);
  369 }
  370 
  371 static device_method_t padlock_methods[] = {
  372         DEVMETHOD(device_identify,      padlock_identify),
  373         DEVMETHOD(device_probe,         padlock_probe),
  374         DEVMETHOD(device_attach,        padlock_attach),
  375         DEVMETHOD(device_detach,        padlock_detach),
  376 
  377         DEVMETHOD(cryptodev_newsession, padlock_newsession),
  378         DEVMETHOD(cryptodev_freesession,padlock_freesession),
  379         DEVMETHOD(cryptodev_process,    padlock_process),
  380 
  381         {0, 0},
  382 };
  383 
  384 static driver_t padlock_driver = {
  385         "padlock",
  386         padlock_methods,
  387         sizeof(struct padlock_softc),
  388 };
  389 static devclass_t padlock_devclass;
  390 
  391 /* XXX where to attach */
  392 DRIVER_MODULE(padlock, nexus, padlock_driver, padlock_devclass, 0, 0);
  393 MODULE_VERSION(padlock, 1);
  394 MODULE_DEPEND(padlock, crypto, 1, 1, 1);

Cache object: 41e7b0f9630c6dac60d8ac6c9f018df6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.