1ef0a6e20SPawel Jakub Dawidek /*- 2ec7993f8SPawel Jakub Dawidek * Copyright (c) 2005-2008 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3ef0a6e20SPawel Jakub Dawidek * All rights reserved. 4ef0a6e20SPawel Jakub Dawidek * 5ef0a6e20SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 6ef0a6e20SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 7ef0a6e20SPawel Jakub Dawidek * are met: 8ef0a6e20SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 9ef0a6e20SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 10ef0a6e20SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 11ef0a6e20SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 12ef0a6e20SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 13ef0a6e20SPawel Jakub Dawidek * 14ef0a6e20SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15ef0a6e20SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ef0a6e20SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ef0a6e20SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18ef0a6e20SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ef0a6e20SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ef0a6e20SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ef0a6e20SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ef0a6e20SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ef0a6e20SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ef0a6e20SPawel Jakub Dawidek * SUCH DAMAGE. 25ef0a6e20SPawel Jakub Dawidek */ 26ef0a6e20SPawel Jakub Dawidek 27ef0a6e20SPawel Jakub Dawidek #include <sys/cdefs.h> 28ef0a6e20SPawel Jakub Dawidek #include <sys/param.h> 29ef0a6e20SPawel Jakub Dawidek #include <sys/systm.h> 30ef0a6e20SPawel Jakub Dawidek #include <sys/kernel.h> 31ef0a6e20SPawel Jakub Dawidek #include <sys/module.h> 32ef0a6e20SPawel Jakub Dawidek #include <sys/lock.h> 3348aadb63SPawel Jakub Dawidek #include <sys/rwlock.h> 34ef0a6e20SPawel Jakub Dawidek #include <sys/malloc.h> 35ef0a6e20SPawel Jakub Dawidek #include <sys/libkern.h> 362b375b4eSYoshihiro Takahashi #if defined(__amd64__) || defined(__i386__) 37ef0a6e20SPawel Jakub Dawidek #include <machine/cpufunc.h> 38ef0a6e20SPawel Jakub Dawidek #include <machine/cputypes.h> 393b0e353fSJohn Baldwin #include <machine/fpu.h> 404fd58e10SMichael Reifenberger #include <machine/md_var.h> 414fd58e10SMichael Reifenberger #include <machine/specialreg.h> 42ef0a6e20SPawel Jakub Dawidek #endif 43ef0a6e20SPawel Jakub Dawidek 44ef0a6e20SPawel Jakub Dawidek #include <opencrypto/cryptodev.h> 45ef0a6e20SPawel Jakub Dawidek 465333bd47SPawel Jakub Dawidek #include <crypto/via/padlock.h> 47ef0a6e20SPawel Jakub Dawidek 486810ad6fSSam Leffler #include <sys/kobj.h> 496810ad6fSSam Leffler #include <sys/bus.h> 506810ad6fSSam Leffler #include "cryptodev_if.h" 516810ad6fSSam Leffler 525333bd47SPawel Jakub Dawidek /* 535333bd47SPawel Jakub Dawidek * Technical documentation about the PadLock engine can be found here: 545333bd47SPawel Jakub Dawidek * 555333bd47SPawel Jakub Dawidek * http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/programming_guide.pdf 565333bd47SPawel Jakub Dawidek */ 57ef0a6e20SPawel Jakub Dawidek 58ef0a6e20SPawel Jakub Dawidek struct padlock_softc { 59ef0a6e20SPawel Jakub Dawidek int32_t sc_cid; 60ef0a6e20SPawel Jakub Dawidek }; 61ef0a6e20SPawel Jakub Dawidek 62c0341432SJohn Baldwin static int padlock_probesession(device_t, const struct crypto_session_params *); 63c0341432SJohn Baldwin static int padlock_newsession(device_t, crypto_session_t cses, 64c0341432SJohn Baldwin const struct crypto_session_params *); 651b0909d5SConrad Meyer static void padlock_freesession(device_t, crypto_session_t cses); 663b0e353fSJohn Baldwin static void padlock_freesession_one(struct padlock_session *ses); 676810ad6fSSam Leffler static int padlock_process(device_t, struct cryptop *crp, int hint __unused); 68ef0a6e20SPawel Jakub Dawidek 695333bd47SPawel Jakub Dawidek MALLOC_DEFINE(M_PADLOCK, "padlock_data", "PadLock Data"); 70ef0a6e20SPawel Jakub Dawidek 716810ad6fSSam Leffler static void 72a4958494SWarner Losh padlock_identify(driver_t *drv, device_t parent) 73ef0a6e20SPawel Jakub Dawidek { 746810ad6fSSam Leffler /* NB: order 10 is so we get attached after h/w devices */ 756810ad6fSSam Leffler if (device_find_child(parent, "padlock", -1) == NULL && 766810ad6fSSam Leffler BUS_ADD_CHILD(parent, 10, "padlock", -1) == 0) 776810ad6fSSam Leffler panic("padlock: could not attach"); 786810ad6fSSam Leffler } 796810ad6fSSam Leffler 806810ad6fSSam Leffler static int 816810ad6fSSam Leffler padlock_probe(device_t dev) 826810ad6fSSam Leffler { 835333bd47SPawel Jakub Dawidek char capp[256]; 845333bd47SPawel Jakub Dawidek 852b375b4eSYoshihiro Takahashi #if defined(__amd64__) || defined(__i386__) 865333bd47SPawel Jakub Dawidek /* If there is no AES support, we has nothing to do here. */ 874fd58e10SMichael Reifenberger if (!(via_feature_xcrypt & VIA_HAS_AES)) { 886810ad6fSSam Leffler device_printf(dev, "No ACE support.\n"); 89ef0a6e20SPawel Jakub Dawidek return (EINVAL); 905333bd47SPawel Jakub Dawidek } 915333bd47SPawel Jakub Dawidek strlcpy(capp, "AES-CBC", sizeof(capp)); 925333bd47SPawel Jakub Dawidek #if 0 935333bd47SPawel Jakub Dawidek strlcat(capp, ",AES-EBC", sizeof(capp)); 945333bd47SPawel Jakub Dawidek strlcat(capp, ",AES-CFB", sizeof(capp)); 955333bd47SPawel Jakub Dawidek strlcat(capp, ",AES-OFB", sizeof(capp)); 965333bd47SPawel Jakub Dawidek #endif 975333bd47SPawel Jakub Dawidek if (via_feature_xcrypt & VIA_HAS_SHA) { 985333bd47SPawel Jakub Dawidek strlcat(capp, ",SHA1", sizeof(capp)); 995333bd47SPawel Jakub Dawidek strlcat(capp, ",SHA256", sizeof(capp)); 1005333bd47SPawel Jakub Dawidek } 1015333bd47SPawel Jakub Dawidek #if 0 1025333bd47SPawel Jakub Dawidek if (via_feature_xcrypt & VIA_HAS_AESCTR) 1035333bd47SPawel Jakub Dawidek strlcat(capp, ",AES-CTR", sizeof(capp)); 1045333bd47SPawel Jakub Dawidek if (via_feature_xcrypt & VIA_HAS_MM) 1055333bd47SPawel Jakub Dawidek strlcat(capp, ",RSA", sizeof(capp)); 1065333bd47SPawel Jakub Dawidek #endif 1076810ad6fSSam Leffler device_set_desc_copy(dev, capp); 1086810ad6fSSam Leffler return (0); 109ef0a6e20SPawel Jakub Dawidek #else 110ef0a6e20SPawel Jakub Dawidek return (EINVAL); 111ef0a6e20SPawel Jakub Dawidek #endif 1126810ad6fSSam Leffler } 113ef0a6e20SPawel Jakub Dawidek 1146810ad6fSSam Leffler static int 1156810ad6fSSam Leffler padlock_attach(device_t dev) 1166810ad6fSSam Leffler { 1176810ad6fSSam Leffler struct padlock_softc *sc = device_get_softc(dev); 1186810ad6fSSam Leffler 1191b0909d5SConrad Meyer sc->sc_cid = crypto_get_driverid(dev, sizeof(struct padlock_session), 120a3d565a1SJohn Baldwin CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC | 121a3d565a1SJohn Baldwin CRYPTOCAP_F_ACCEL_SOFTWARE); 122ef0a6e20SPawel Jakub Dawidek if (sc->sc_cid < 0) { 1236810ad6fSSam Leffler device_printf(dev, "Could not get crypto driver id.\n"); 124ef0a6e20SPawel Jakub Dawidek return (ENOMEM); 125ef0a6e20SPawel Jakub Dawidek } 126ef0a6e20SPawel Jakub Dawidek 127ef0a6e20SPawel Jakub Dawidek return (0); 128ef0a6e20SPawel Jakub Dawidek } 129ef0a6e20SPawel Jakub Dawidek 130ef0a6e20SPawel Jakub Dawidek static int 1316810ad6fSSam Leffler padlock_detach(device_t dev) 132ef0a6e20SPawel Jakub Dawidek { 1336810ad6fSSam Leffler struct padlock_softc *sc = device_get_softc(dev); 134ef0a6e20SPawel Jakub Dawidek 135ef0a6e20SPawel Jakub Dawidek crypto_unregister_all(sc->sc_cid); 136ef0a6e20SPawel Jakub Dawidek return (0); 137ef0a6e20SPawel Jakub Dawidek } 138ef0a6e20SPawel Jakub Dawidek 139ef0a6e20SPawel Jakub Dawidek static int 140c0341432SJohn Baldwin padlock_probesession(device_t dev, const struct crypto_session_params *csp) 141ef0a6e20SPawel Jakub Dawidek { 142ef0a6e20SPawel Jakub Dawidek 143c0341432SJohn Baldwin if (csp->csp_flags != 0) 14464e18040SPawel Jakub Dawidek return (EINVAL); 14564e18040SPawel Jakub Dawidek 14664e18040SPawel Jakub Dawidek /* 14764e18040SPawel Jakub Dawidek * We only support HMAC algorithms to be able to work with 148b2630c29SGeorge V. Neville-Neil * ipsec(4), so if we are asked only for authentication without 149c0341432SJohn Baldwin * encryption, don't pretend we can accelerate it. 150c0341432SJohn Baldwin * 151c0341432SJohn Baldwin * XXX: For CPUs with SHA instructions we should probably 152c0341432SJohn Baldwin * permit CSP_MODE_DIGEST so that those can be tested. 15364e18040SPawel Jakub Dawidek */ 154c0341432SJohn Baldwin switch (csp->csp_mode) { 155c0341432SJohn Baldwin case CSP_MODE_ETA: 156c0341432SJohn Baldwin if (!padlock_hash_check(csp)) 15764e18040SPawel Jakub Dawidek return (EINVAL); 158c0341432SJohn Baldwin /* FALLTHROUGH */ 159c0341432SJohn Baldwin case CSP_MODE_CIPHER: 160c0341432SJohn Baldwin switch (csp->csp_cipher_alg) { 161c0341432SJohn Baldwin case CRYPTO_AES_CBC: 162c0341432SJohn Baldwin if (csp->csp_ivlen != AES_BLOCK_LEN) 163c0341432SJohn Baldwin return (EINVAL); 164c0341432SJohn Baldwin break; 165c0341432SJohn Baldwin default: 166c0341432SJohn Baldwin return (EINVAL); 167c0341432SJohn Baldwin } 168c0341432SJohn Baldwin break; 169c0341432SJohn Baldwin default: 170c0341432SJohn Baldwin return (EINVAL); 171c0341432SJohn Baldwin } 172c0341432SJohn Baldwin 173c0341432SJohn Baldwin return (CRYPTODEV_PROBE_ACCEL_SOFTWARE); 174c0341432SJohn Baldwin } 175c0341432SJohn Baldwin 176c0341432SJohn Baldwin static int 177c0341432SJohn Baldwin padlock_newsession(device_t dev, crypto_session_t cses, 178c0341432SJohn Baldwin const struct crypto_session_params *csp) 179c0341432SJohn Baldwin { 1803b0e353fSJohn Baldwin struct padlock_session *ses; 181c0341432SJohn Baldwin struct thread *td; 182c0341432SJohn Baldwin int error; 183ef0a6e20SPawel Jakub Dawidek 1841b0909d5SConrad Meyer ses = crypto_get_driver_session(cses); 185ef0a6e20SPawel Jakub Dawidek 186c0341432SJohn Baldwin error = padlock_cipher_setup(ses, csp); 1875333bd47SPawel Jakub Dawidek if (error != 0) { 1883b0e353fSJohn Baldwin padlock_freesession_one(ses); 1895333bd47SPawel Jakub Dawidek return (error); 190ef0a6e20SPawel Jakub Dawidek } 191ef0a6e20SPawel Jakub Dawidek 192c0341432SJohn Baldwin if (csp->csp_mode == CSP_MODE_ETA) { 19304c49e68SKonstantin Belousov td = curthread; 1943b0e353fSJohn Baldwin fpu_kern_enter(td, NULL, FPU_KERN_NORMAL | FPU_KERN_NOCTX); 195c0341432SJohn Baldwin error = padlock_hash_setup(ses, csp); 1963b0e353fSJohn Baldwin fpu_kern_leave(td, NULL); 1975333bd47SPawel Jakub Dawidek if (error != 0) { 1983b0e353fSJohn Baldwin padlock_freesession_one(ses); 1995333bd47SPawel Jakub Dawidek return (error); 20064e18040SPawel Jakub Dawidek } 201ef0a6e20SPawel Jakub Dawidek } 202ef0a6e20SPawel Jakub Dawidek 203ef0a6e20SPawel Jakub Dawidek return (0); 204ef0a6e20SPawel Jakub Dawidek } 205ef0a6e20SPawel Jakub Dawidek 206ec7993f8SPawel Jakub Dawidek static void 2073b0e353fSJohn Baldwin padlock_freesession_one(struct padlock_session *ses) 208ec7993f8SPawel Jakub Dawidek { 209ec7993f8SPawel Jakub Dawidek 210ec7993f8SPawel Jakub Dawidek padlock_hash_free(ses); 211ec7993f8SPawel Jakub Dawidek } 212ec7993f8SPawel Jakub Dawidek 2131b0909d5SConrad Meyer static void 2141b0909d5SConrad Meyer padlock_freesession(device_t dev, crypto_session_t cses) 215ef0a6e20SPawel Jakub Dawidek { 216ef0a6e20SPawel Jakub Dawidek struct padlock_session *ses; 217ef0a6e20SPawel Jakub Dawidek 2181b0909d5SConrad Meyer ses = crypto_get_driver_session(cses); 2193b0e353fSJohn Baldwin padlock_freesession_one(ses); 220ef0a6e20SPawel Jakub Dawidek } 221ef0a6e20SPawel Jakub Dawidek 222ef0a6e20SPawel Jakub Dawidek static int 2236810ad6fSSam Leffler padlock_process(device_t dev, struct cryptop *crp, int hint __unused) 224ef0a6e20SPawel Jakub Dawidek { 225c0341432SJohn Baldwin const struct crypto_session_params *csp; 226c0341432SJohn Baldwin struct padlock_session *ses; 227c0341432SJohn Baldwin int error; 228ef0a6e20SPawel Jakub Dawidek 229c0341432SJohn Baldwin if ((crp->crp_payload_length % AES_BLOCK_LEN) != 0) { 23064e18040SPawel Jakub Dawidek error = EINVAL; 231eb340a61SPawel Jakub Dawidek goto out; 232eb340a61SPawel Jakub Dawidek } 233ef0a6e20SPawel Jakub Dawidek 2341b0909d5SConrad Meyer ses = crypto_get_driver_session(crp->crp_session); 235c0341432SJohn Baldwin csp = crypto_get_params(crp->crp_session); 236ef0a6e20SPawel Jakub Dawidek 237c0341432SJohn Baldwin /* Perform data authentication if requested before decryption. */ 238c0341432SJohn Baldwin if (csp->csp_mode == CSP_MODE_ETA && 239c0341432SJohn Baldwin !CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) { 240c0341432SJohn Baldwin error = padlock_hash_process(ses, crp, csp); 24164e18040SPawel Jakub Dawidek if (error != 0) 24264e18040SPawel Jakub Dawidek goto out; 243ef0a6e20SPawel Jakub Dawidek } 244ef0a6e20SPawel Jakub Dawidek 245c0341432SJohn Baldwin error = padlock_cipher_process(ses, crp, csp); 2465333bd47SPawel Jakub Dawidek if (error != 0) 2475333bd47SPawel Jakub Dawidek goto out; 24864e18040SPawel Jakub Dawidek 24964e18040SPawel Jakub Dawidek /* Perform data authentication if requested after encryption. */ 250c0341432SJohn Baldwin if (csp->csp_mode == CSP_MODE_ETA && 251c0341432SJohn Baldwin CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) { 252c0341432SJohn Baldwin error = padlock_hash_process(ses, crp, csp); 25364e18040SPawel Jakub Dawidek if (error != 0) 25464e18040SPawel Jakub Dawidek goto out; 255ef0a6e20SPawel Jakub Dawidek } 256ef0a6e20SPawel Jakub Dawidek 257ef0a6e20SPawel Jakub Dawidek out: 2585333bd47SPawel Jakub Dawidek #if 0 2595333bd47SPawel Jakub Dawidek /* 2605333bd47SPawel Jakub Dawidek * This code is not necessary, because contexts will be freed on next 2615333bd47SPawel Jakub Dawidek * padlock_setup_mackey() call or at padlock_freesession() call. 2625333bd47SPawel Jakub Dawidek */ 2635333bd47SPawel Jakub Dawidek if (ses != NULL && maccrd != NULL && 2645333bd47SPawel Jakub Dawidek (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) { 2655333bd47SPawel Jakub Dawidek padlock_free_ctx(ses->ses_axf, ses->ses_ictx); 2665333bd47SPawel Jakub Dawidek padlock_free_ctx(ses->ses_axf, ses->ses_octx); 267ef0a6e20SPawel Jakub Dawidek } 2685333bd47SPawel Jakub Dawidek #endif 26964e18040SPawel Jakub Dawidek crp->crp_etype = error; 270ef0a6e20SPawel Jakub Dawidek crypto_done(crp); 271dbc973caSAlan Somers return (0); 272ef0a6e20SPawel Jakub Dawidek } 273ef0a6e20SPawel Jakub Dawidek 2746810ad6fSSam Leffler static device_method_t padlock_methods[] = { 2756810ad6fSSam Leffler DEVMETHOD(device_identify, padlock_identify), 2766810ad6fSSam Leffler DEVMETHOD(device_probe, padlock_probe), 2776810ad6fSSam Leffler DEVMETHOD(device_attach, padlock_attach), 2786810ad6fSSam Leffler DEVMETHOD(device_detach, padlock_detach), 279ef0a6e20SPawel Jakub Dawidek 280c0341432SJohn Baldwin DEVMETHOD(cryptodev_probesession, padlock_probesession), 2816810ad6fSSam Leffler DEVMETHOD(cryptodev_newsession, padlock_newsession), 2826810ad6fSSam Leffler DEVMETHOD(cryptodev_freesession,padlock_freesession), 2836810ad6fSSam Leffler DEVMETHOD(cryptodev_process, padlock_process), 284ef0a6e20SPawel Jakub Dawidek 2856810ad6fSSam Leffler {0, 0}, 286ef0a6e20SPawel Jakub Dawidek }; 2876810ad6fSSam Leffler 2886810ad6fSSam Leffler static driver_t padlock_driver = { 2896810ad6fSSam Leffler "padlock", 2906810ad6fSSam Leffler padlock_methods, 2916810ad6fSSam Leffler sizeof(struct padlock_softc), 2926810ad6fSSam Leffler }; 2936810ad6fSSam Leffler 2946810ad6fSSam Leffler /* XXX where to attach */ 295ab050b2bSJohn Baldwin DRIVER_MODULE(padlock, nexus, padlock_driver, 0, 0); 296ef0a6e20SPawel Jakub Dawidek MODULE_VERSION(padlock, 1); 297ef0a6e20SPawel Jakub Dawidek MODULE_DEPEND(padlock, crypto, 1, 1, 1); 298