1 /*- 2 * Copyright (c) 2005-2008 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * Copyright (c) 2010 Konstantin Belousov <kib@FreeBSD.org> 4 * Copyright (c) 2014,2016 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * Portions of this software were developed by John-Mark Gurney 8 * under sponsorship of the FreeBSD Foundation and 9 * Rubicon Communications, LLC (Netgate). 10 * 11 * This software was developed by Andrew Turner under 12 * sponsorship from the FreeBSD Foundation. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 /* 37 * This is based on the aesni code. 38 */ 39 40 #include <sys/cdefs.h> 41 __FBSDID("$FreeBSD$"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/bus.h> 47 #include <sys/endian.h> 48 #include <sys/lock.h> 49 #include <sys/malloc.h> 50 #include <sys/mbuf.h> 51 #include <sys/module.h> 52 #include <sys/mutex.h> 53 #include <sys/queue.h> 54 #include <sys/rwlock.h> 55 #include <sys/smp.h> 56 #include <sys/uio.h> 57 58 #include <machine/vfp.h> 59 60 #include <opencrypto/cryptodev.h> 61 #include <cryptodev_if.h> 62 #include <crypto/armv8/armv8_crypto.h> 63 #include <crypto/rijndael/rijndael.h> 64 65 struct armv8_crypto_softc { 66 int dieing; 67 int32_t cid; 68 struct rwlock lock; 69 }; 70 71 static struct mtx *ctx_mtx; 72 static struct fpu_kern_ctx **ctx_vfp; 73 74 #define AQUIRE_CTX(i, ctx) \ 75 do { \ 76 (i) = PCPU_GET(cpuid); \ 77 mtx_lock(&ctx_mtx[(i)]); \ 78 (ctx) = ctx_vfp[(i)]; \ 79 } while (0) 80 #define RELEASE_CTX(i, ctx) \ 81 do { \ 82 mtx_unlock(&ctx_mtx[(i)]); \ 83 (i) = -1; \ 84 (ctx) = NULL; \ 85 } while (0) 86 87 static int armv8_crypto_cipher_process(struct armv8_crypto_session *, 88 struct cryptodesc *, struct cryptop *); 89 90 MALLOC_DEFINE(M_ARMV8_CRYPTO, "armv8_crypto", "ARMv8 Crypto Data"); 91 92 static void 93 armv8_crypto_identify(driver_t *drv, device_t parent) 94 { 95 96 /* NB: order 10 is so we get attached after h/w devices */ 97 if (device_find_child(parent, "armv8crypto", -1) == NULL && 98 BUS_ADD_CHILD(parent, 10, "armv8crypto", -1) == 0) 99 panic("ARMv8 crypto: could not attach"); 100 } 101 102 static int 103 armv8_crypto_probe(device_t dev) 104 { 105 uint64_t reg; 106 int ret = ENXIO; 107 108 reg = READ_SPECIALREG(id_aa64isar0_el1); 109 110 switch (ID_AA64ISAR0_AES(reg)) { 111 case ID_AA64ISAR0_AES_BASE: 112 case ID_AA64ISAR0_AES_PMULL: 113 ret = 0; 114 break; 115 } 116 117 device_set_desc_copy(dev, "AES-CBC"); 118 119 /* TODO: Check more fields as we support more features */ 120 121 return (ret); 122 } 123 124 static int 125 armv8_crypto_attach(device_t dev) 126 { 127 struct armv8_crypto_softc *sc; 128 int i; 129 130 sc = device_get_softc(dev); 131 sc->dieing = 0; 132 133 sc->cid = crypto_get_driverid(dev, sizeof(struct armv8_crypto_session), 134 CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SYNC); 135 if (sc->cid < 0) { 136 device_printf(dev, "Could not get crypto driver id.\n"); 137 return (ENOMEM); 138 } 139 140 rw_init(&sc->lock, "armv8crypto"); 141 142 ctx_mtx = malloc(sizeof(*ctx_mtx) * (mp_maxid + 1), M_ARMV8_CRYPTO, 143 M_WAITOK|M_ZERO); 144 ctx_vfp = malloc(sizeof(*ctx_vfp) * (mp_maxid + 1), M_ARMV8_CRYPTO, 145 M_WAITOK|M_ZERO); 146 147 CPU_FOREACH(i) { 148 ctx_vfp[i] = fpu_kern_alloc_ctx(0); 149 mtx_init(&ctx_mtx[i], "armv8cryptoctx", NULL, MTX_DEF|MTX_NEW); 150 } 151 152 crypto_register(sc->cid, CRYPTO_AES_CBC, 0, 0); 153 154 return (0); 155 } 156 157 static int 158 armv8_crypto_detach(device_t dev) 159 { 160 struct armv8_crypto_softc *sc; 161 int i; 162 163 sc = device_get_softc(dev); 164 165 rw_wlock(&sc->lock); 166 sc->dieing = 1; 167 rw_wunlock(&sc->lock); 168 crypto_unregister_all(sc->cid); 169 170 rw_destroy(&sc->lock); 171 172 CPU_FOREACH(i) { 173 if (ctx_vfp[i] != NULL) { 174 mtx_destroy(&ctx_mtx[i]); 175 fpu_kern_free_ctx(ctx_vfp[i]); 176 } 177 ctx_vfp[i] = NULL; 178 } 179 free(ctx_mtx, M_ARMV8_CRYPTO); 180 ctx_mtx = NULL; 181 free(ctx_vfp, M_ARMV8_CRYPTO); 182 ctx_vfp = NULL; 183 184 return (0); 185 } 186 187 static int 188 armv8_crypto_cipher_setup(struct armv8_crypto_session *ses, 189 struct cryptoini *encini) 190 { 191 int i; 192 193 switch (ses->algo) { 194 case CRYPTO_AES_CBC: 195 switch (encini->cri_klen) { 196 case 128: 197 ses->rounds = AES128_ROUNDS; 198 break; 199 case 192: 200 ses->rounds = AES192_ROUNDS; 201 break; 202 case 256: 203 ses->rounds = AES256_ROUNDS; 204 break; 205 default: 206 CRYPTDEB("invalid CBC/ICM/GCM key length"); 207 return (EINVAL); 208 } 209 break; 210 default: 211 return (EINVAL); 212 } 213 214 rijndaelKeySetupEnc(ses->enc_schedule, encini->cri_key, 215 encini->cri_klen); 216 rijndaelKeySetupDec(ses->dec_schedule, encini->cri_key, 217 encini->cri_klen); 218 for (i = 0; i < nitems(ses->enc_schedule); i++) { 219 ses->enc_schedule[i] = bswap32(ses->enc_schedule[i]); 220 ses->dec_schedule[i] = bswap32(ses->dec_schedule[i]); 221 } 222 223 return (0); 224 } 225 226 static int 227 armv8_crypto_newsession(device_t dev, crypto_session_t cses, 228 struct cryptoini *cri) 229 { 230 struct armv8_crypto_softc *sc; 231 struct armv8_crypto_session *ses; 232 struct cryptoini *encini; 233 int error; 234 235 if (cri == NULL) { 236 CRYPTDEB("no cri"); 237 return (EINVAL); 238 } 239 240 sc = device_get_softc(dev); 241 if (sc->dieing) 242 return (EINVAL); 243 244 ses = NULL; 245 encini = NULL; 246 for (; cri != NULL; cri = cri->cri_next) { 247 switch (cri->cri_alg) { 248 case CRYPTO_AES_CBC: 249 if (encini != NULL) { 250 CRYPTDEB("encini already set"); 251 return (EINVAL); 252 } 253 encini = cri; 254 break; 255 default: 256 CRYPTDEB("unhandled algorithm"); 257 return (EINVAL); 258 } 259 } 260 if (encini == NULL) { 261 CRYPTDEB("no cipher"); 262 return (EINVAL); 263 } 264 265 rw_wlock(&sc->lock); 266 if (sc->dieing) { 267 rw_wunlock(&sc->lock); 268 return (EINVAL); 269 } 270 271 ses = crypto_get_driver_session(cses); 272 ses->algo = encini->cri_alg; 273 274 error = armv8_crypto_cipher_setup(ses, encini); 275 if (error != 0) { 276 CRYPTDEB("setup failed"); 277 rw_wunlock(&sc->lock); 278 return (error); 279 } 280 281 rw_wunlock(&sc->lock); 282 return (0); 283 } 284 285 static int 286 armv8_crypto_process(device_t dev, struct cryptop *crp, int hint __unused) 287 { 288 struct cryptodesc *crd, *enccrd; 289 struct armv8_crypto_session *ses; 290 int error; 291 292 error = 0; 293 enccrd = NULL; 294 295 /* Sanity check. */ 296 if (crp == NULL) 297 return (EINVAL); 298 299 if (crp->crp_callback == NULL || crp->crp_desc == NULL) { 300 error = EINVAL; 301 goto out; 302 } 303 304 for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) { 305 switch (crd->crd_alg) { 306 case CRYPTO_AES_CBC: 307 if (enccrd != NULL) { 308 error = EINVAL; 309 goto out; 310 } 311 enccrd = crd; 312 break; 313 default: 314 error = EINVAL; 315 goto out; 316 } 317 } 318 319 if (enccrd == NULL) { 320 error = EINVAL; 321 goto out; 322 } 323 324 /* We can only handle full blocks for now */ 325 if ((enccrd->crd_len % AES_BLOCK_LEN) != 0) { 326 error = EINVAL; 327 goto out; 328 } 329 330 ses = crypto_get_driver_session(crp->crp_session); 331 error = armv8_crypto_cipher_process(ses, enccrd, crp); 332 333 out: 334 crp->crp_etype = error; 335 crypto_done(crp); 336 return (error); 337 } 338 339 static uint8_t * 340 armv8_crypto_cipher_alloc(struct cryptodesc *enccrd, struct cryptop *crp, 341 int *allocated) 342 { 343 struct mbuf *m; 344 struct uio *uio; 345 struct iovec *iov; 346 uint8_t *addr; 347 348 if (crp->crp_flags & CRYPTO_F_IMBUF) { 349 m = (struct mbuf *)crp->crp_buf; 350 if (m->m_next != NULL) 351 goto alloc; 352 addr = mtod(m, uint8_t *); 353 } else if (crp->crp_flags & CRYPTO_F_IOV) { 354 uio = (struct uio *)crp->crp_buf; 355 if (uio->uio_iovcnt != 1) 356 goto alloc; 357 iov = uio->uio_iov; 358 addr = (uint8_t *)iov->iov_base; 359 } else 360 addr = (uint8_t *)crp->crp_buf; 361 *allocated = 0; 362 addr += enccrd->crd_skip; 363 return (addr); 364 365 alloc: 366 addr = malloc(enccrd->crd_len, M_ARMV8_CRYPTO, M_NOWAIT); 367 if (addr != NULL) { 368 *allocated = 1; 369 crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, 370 enccrd->crd_len, addr); 371 } else 372 *allocated = 0; 373 return (addr); 374 } 375 376 static int 377 armv8_crypto_cipher_process(struct armv8_crypto_session *ses, 378 struct cryptodesc *enccrd, struct cryptop *crp) 379 { 380 struct fpu_kern_ctx *ctx; 381 uint8_t *buf; 382 uint8_t iv[AES_BLOCK_LEN]; 383 int allocated, i; 384 int encflag, ivlen; 385 int kt; 386 387 encflag = (enccrd->crd_flags & CRD_F_ENCRYPT) == CRD_F_ENCRYPT; 388 389 buf = armv8_crypto_cipher_alloc(enccrd, crp, &allocated); 390 if (buf == NULL) 391 return (ENOMEM); 392 393 kt = is_fpu_kern_thread(0); 394 if (!kt) { 395 AQUIRE_CTX(i, ctx); 396 fpu_kern_enter(curthread, ctx, 397 FPU_KERN_NORMAL | FPU_KERN_KTHR); 398 } 399 400 if ((enccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) { 401 panic("CRD_F_KEY_EXPLICIT"); 402 } 403 404 switch (enccrd->crd_alg) { 405 case CRYPTO_AES_CBC: 406 ivlen = AES_BLOCK_LEN; 407 break; 408 } 409 410 /* Setup iv */ 411 if (encflag) { 412 if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) 413 bcopy(enccrd->crd_iv, iv, ivlen); 414 else 415 arc4rand(iv, ivlen, 0); 416 417 if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) 418 crypto_copyback(crp->crp_flags, crp->crp_buf, 419 enccrd->crd_inject, ivlen, iv); 420 } else { 421 if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) 422 bcopy(enccrd->crd_iv, iv, ivlen); 423 else 424 crypto_copydata(crp->crp_flags, crp->crp_buf, 425 enccrd->crd_inject, ivlen, iv); 426 } 427 428 /* Do work */ 429 switch (ses->algo) { 430 case CRYPTO_AES_CBC: 431 if (encflag) 432 armv8_aes_encrypt_cbc(ses->rounds, ses->enc_schedule, 433 enccrd->crd_len, buf, buf, iv); 434 else 435 armv8_aes_decrypt_cbc(ses->rounds, ses->dec_schedule, 436 enccrd->crd_len, buf, iv); 437 break; 438 } 439 440 if (allocated) 441 crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, 442 enccrd->crd_len, buf); 443 444 if (!kt) { 445 fpu_kern_leave(curthread, ctx); 446 RELEASE_CTX(i, ctx); 447 } 448 if (allocated) { 449 bzero(buf, enccrd->crd_len); 450 free(buf, M_ARMV8_CRYPTO); 451 } 452 return (0); 453 } 454 455 static device_method_t armv8_crypto_methods[] = { 456 DEVMETHOD(device_identify, armv8_crypto_identify), 457 DEVMETHOD(device_probe, armv8_crypto_probe), 458 DEVMETHOD(device_attach, armv8_crypto_attach), 459 DEVMETHOD(device_detach, armv8_crypto_detach), 460 461 DEVMETHOD(cryptodev_newsession, armv8_crypto_newsession), 462 DEVMETHOD(cryptodev_process, armv8_crypto_process), 463 464 DEVMETHOD_END, 465 }; 466 467 static DEFINE_CLASS_0(armv8crypto, armv8_crypto_driver, armv8_crypto_methods, 468 sizeof(struct armv8_crypto_softc)); 469 static devclass_t armv8_crypto_devclass; 470 471 DRIVER_MODULE(armv8crypto, nexus, armv8_crypto_driver, armv8_crypto_devclass, 472 0, 0); 473