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/malloc.h> 49 #include <sys/mbuf.h> 50 #include <sys/module.h> 51 #include <sys/queue.h> 52 #include <sys/rwlock.h> 53 #include <sys/smp.h> 54 #include <sys/uio.h> 55 56 #include <machine/vfp.h> 57 58 #include <opencrypto/cryptodev.h> 59 #include <cryptodev_if.h> 60 #include <crypto/armv8/armv8_crypto.h> 61 #include <crypto/rijndael/rijndael.h> 62 63 struct armv8_crypto_softc { 64 int dieing; 65 int32_t cid; 66 struct rwlock lock; 67 }; 68 69 static struct mtx *ctx_mtx; 70 static struct fpu_kern_ctx **ctx_vfp; 71 72 #define AQUIRE_CTX(i, ctx) \ 73 do { \ 74 (i) = PCPU_GET(cpuid); \ 75 mtx_lock(&ctx_mtx[(i)]); \ 76 (ctx) = ctx_vfp[(i)]; \ 77 } while (0) 78 #define RELEASE_CTX(i, ctx) \ 79 do { \ 80 mtx_unlock(&ctx_mtx[(i)]); \ 81 (i) = -1; \ 82 (ctx) = NULL; \ 83 } while (0) 84 85 static int armv8_crypto_cipher_process(struct armv8_crypto_session *, 86 struct cryptodesc *, struct cryptop *); 87 88 MALLOC_DEFINE(M_ARMV8_CRYPTO, "armv8_crypto", "ARMv8 Crypto Data"); 89 90 static void 91 armv8_crypto_identify(driver_t *drv, device_t parent) 92 { 93 94 /* NB: order 10 is so we get attached after h/w devices */ 95 if (device_find_child(parent, "armv8crypto", -1) == NULL && 96 BUS_ADD_CHILD(parent, 10, "armv8crypto", -1) == 0) 97 panic("ARMv8 crypto: could not attach"); 98 } 99 100 static int 101 armv8_crypto_probe(device_t dev) 102 { 103 uint64_t reg; 104 int ret = ENXIO; 105 106 reg = READ_SPECIALREG(id_aa64isar0_el1); 107 108 switch (ID_AA64ISAR0_AES(reg)) { 109 case ID_AA64ISAR0_AES_BASE: 110 case ID_AA64ISAR0_AES_PMULL: 111 ret = 0; 112 break; 113 } 114 115 device_set_desc_copy(dev, "AES-CBC"); 116 117 /* TODO: Check more fields as we support more features */ 118 119 return (ret); 120 } 121 122 static int 123 armv8_crypto_attach(device_t dev) 124 { 125 struct armv8_crypto_softc *sc; 126 int i; 127 128 sc = device_get_softc(dev); 129 sc->dieing = 0; 130 131 sc->cid = crypto_get_driverid(dev, sizeof(struct armv8_crypto_session), 132 CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SYNC); 133 if (sc->cid < 0) { 134 device_printf(dev, "Could not get crypto driver id.\n"); 135 return (ENOMEM); 136 } 137 138 rw_init(&sc->lock, "armv8crypto"); 139 140 ctx_mtx = malloc(sizeof(*ctx_mtx) * (mp_maxid + 1), M_ARMV8_CRYPTO, 141 M_WAITOK|M_ZERO); 142 ctx_vfp = malloc(sizeof(*ctx_vfp) * (mp_maxid + 1), M_ARMV8_CRYPTO, 143 M_WAITOK|M_ZERO); 144 145 CPU_FOREACH(i) { 146 ctx_vfp[i] = fpu_kern_alloc_ctx(0); 147 mtx_init(&ctx_mtx[i], "armv8cryptoctx", NULL, MTX_DEF|MTX_NEW); 148 } 149 150 crypto_register(sc->cid, CRYPTO_AES_CBC, 0, 0); 151 152 return (0); 153 } 154 155 static int 156 armv8_crypto_detach(device_t dev) 157 { 158 struct armv8_crypto_softc *sc; 159 int i; 160 161 sc = device_get_softc(dev); 162 163 rw_wlock(&sc->lock); 164 sc->dieing = 1; 165 rw_wunlock(&sc->lock); 166 crypto_unregister_all(sc->cid); 167 168 rw_destroy(&sc->lock); 169 170 CPU_FOREACH(i) { 171 if (ctx_vfp[i] != NULL) { 172 mtx_destroy(&ctx_mtx[i]); 173 fpu_kern_free_ctx(ctx_vfp[i]); 174 } 175 ctx_vfp[i] = NULL; 176 } 177 free(ctx_mtx, M_ARMV8_CRYPTO); 178 ctx_mtx = NULL; 179 free(ctx_vfp, M_ARMV8_CRYPTO); 180 ctx_vfp = NULL; 181 182 return (0); 183 } 184 185 static int 186 armv8_crypto_cipher_setup(struct armv8_crypto_session *ses, 187 struct cryptoini *encini) 188 { 189 int i; 190 191 switch (ses->algo) { 192 case CRYPTO_AES_CBC: 193 switch (encini->cri_klen) { 194 case 128: 195 ses->rounds = AES128_ROUNDS; 196 break; 197 case 192: 198 ses->rounds = AES192_ROUNDS; 199 break; 200 case 256: 201 ses->rounds = AES256_ROUNDS; 202 break; 203 default: 204 CRYPTDEB("invalid CBC/ICM/GCM key length"); 205 return (EINVAL); 206 } 207 break; 208 default: 209 return (EINVAL); 210 } 211 212 rijndaelKeySetupEnc(ses->enc_schedule, encini->cri_key, 213 encini->cri_klen); 214 rijndaelKeySetupDec(ses->dec_schedule, encini->cri_key, 215 encini->cri_klen); 216 for (i = 0; i < nitems(ses->enc_schedule); i++) { 217 ses->enc_schedule[i] = bswap32(ses->enc_schedule[i]); 218 ses->dec_schedule[i] = bswap32(ses->dec_schedule[i]); 219 } 220 221 return (0); 222 } 223 224 static int 225 armv8_crypto_newsession(device_t dev, crypto_session_t cses, 226 struct cryptoini *cri) 227 { 228 struct armv8_crypto_softc *sc; 229 struct armv8_crypto_session *ses; 230 struct cryptoini *encini; 231 int error; 232 233 if (cri == NULL) { 234 CRYPTDEB("no cri"); 235 return (EINVAL); 236 } 237 238 sc = device_get_softc(dev); 239 if (sc->dieing) 240 return (EINVAL); 241 242 ses = NULL; 243 encini = NULL; 244 for (; cri != NULL; cri = cri->cri_next) { 245 switch (cri->cri_alg) { 246 case CRYPTO_AES_CBC: 247 if (encini != NULL) { 248 CRYPTDEB("encini already set"); 249 return (EINVAL); 250 } 251 encini = cri; 252 break; 253 default: 254 CRYPTDEB("unhandled algorithm"); 255 return (EINVAL); 256 } 257 } 258 if (encini == NULL) { 259 CRYPTDEB("no cipher"); 260 return (EINVAL); 261 } 262 263 rw_wlock(&sc->lock); 264 if (sc->dieing) { 265 rw_wunlock(&sc->lock); 266 return (EINVAL); 267 } 268 269 ses = crypto_get_driver_session(cses); 270 ses->algo = encini->cri_alg; 271 272 error = armv8_crypto_cipher_setup(ses, encini); 273 if (error != 0) { 274 CRYPTDEB("setup failed"); 275 return (error); 276 } 277 278 return (0); 279 } 280 281 static int 282 armv8_crypto_process(device_t dev, struct cryptop *crp, int hint __unused) 283 { 284 struct cryptodesc *crd, *enccrd; 285 struct armv8_crypto_session *ses; 286 int error; 287 288 error = 0; 289 enccrd = NULL; 290 291 /* Sanity check. */ 292 if (crp == NULL) 293 return (EINVAL); 294 295 if (crp->crp_callback == NULL || crp->crp_desc == NULL) { 296 error = EINVAL; 297 goto out; 298 } 299 300 for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) { 301 switch (crd->crd_alg) { 302 case CRYPTO_AES_CBC: 303 if (enccrd != NULL) { 304 error = EINVAL; 305 goto out; 306 } 307 enccrd = crd; 308 break; 309 default: 310 error = EINVAL; 311 goto out; 312 } 313 } 314 315 if (enccrd == NULL) { 316 error = EINVAL; 317 goto out; 318 } 319 320 /* We can only handle full blocks for now */ 321 if ((enccrd->crd_len % AES_BLOCK_LEN) != 0) { 322 error = EINVAL; 323 goto out; 324 } 325 326 ses = crypto_get_driver_session(crp->crp_session); 327 error = armv8_crypto_cipher_process(ses, enccrd, crp); 328 329 out: 330 crp->crp_etype = error; 331 crypto_done(crp); 332 return (error); 333 } 334 335 static uint8_t * 336 armv8_crypto_cipher_alloc(struct cryptodesc *enccrd, struct cryptop *crp, 337 int *allocated) 338 { 339 struct mbuf *m; 340 struct uio *uio; 341 struct iovec *iov; 342 uint8_t *addr; 343 344 if (crp->crp_flags & CRYPTO_F_IMBUF) { 345 m = (struct mbuf *)crp->crp_buf; 346 if (m->m_next != NULL) 347 goto alloc; 348 addr = mtod(m, uint8_t *); 349 } else if (crp->crp_flags & CRYPTO_F_IOV) { 350 uio = (struct uio *)crp->crp_buf; 351 if (uio->uio_iovcnt != 1) 352 goto alloc; 353 iov = uio->uio_iov; 354 addr = (uint8_t *)iov->iov_base; 355 } else 356 addr = (uint8_t *)crp->crp_buf; 357 *allocated = 0; 358 addr += enccrd->crd_skip; 359 return (addr); 360 361 alloc: 362 addr = malloc(enccrd->crd_len, M_ARMV8_CRYPTO, M_NOWAIT); 363 if (addr != NULL) { 364 *allocated = 1; 365 crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, 366 enccrd->crd_len, addr); 367 } else 368 *allocated = 0; 369 return (addr); 370 } 371 372 static int 373 armv8_crypto_cipher_process(struct armv8_crypto_session *ses, 374 struct cryptodesc *enccrd, struct cryptop *crp) 375 { 376 struct fpu_kern_ctx *ctx; 377 uint8_t *buf; 378 uint8_t iv[AES_BLOCK_LEN]; 379 int allocated, i; 380 int encflag, ivlen; 381 int kt; 382 383 encflag = (enccrd->crd_flags & CRD_F_ENCRYPT) == CRD_F_ENCRYPT; 384 385 buf = armv8_crypto_cipher_alloc(enccrd, crp, &allocated); 386 if (buf == NULL) 387 return (ENOMEM); 388 389 kt = is_fpu_kern_thread(0); 390 if (!kt) { 391 AQUIRE_CTX(i, ctx); 392 fpu_kern_enter(curthread, ctx, 393 FPU_KERN_NORMAL | FPU_KERN_KTHR); 394 } 395 396 if ((enccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) { 397 panic("CRD_F_KEY_EXPLICIT"); 398 } 399 400 switch (enccrd->crd_alg) { 401 case CRYPTO_AES_CBC: 402 ivlen = AES_BLOCK_LEN; 403 break; 404 } 405 406 /* Setup iv */ 407 if (encflag) { 408 if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) 409 bcopy(enccrd->crd_iv, iv, ivlen); 410 else 411 arc4rand(iv, ivlen, 0); 412 413 if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) 414 crypto_copyback(crp->crp_flags, crp->crp_buf, 415 enccrd->crd_inject, ivlen, iv); 416 } else { 417 if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) 418 bcopy(enccrd->crd_iv, iv, ivlen); 419 else 420 crypto_copydata(crp->crp_flags, crp->crp_buf, 421 enccrd->crd_inject, ivlen, iv); 422 } 423 424 /* Do work */ 425 switch (ses->algo) { 426 case CRYPTO_AES_CBC: 427 if (encflag) 428 armv8_aes_encrypt_cbc(ses->rounds, ses->enc_schedule, 429 enccrd->crd_len, buf, buf, iv); 430 else 431 armv8_aes_decrypt_cbc(ses->rounds, ses->dec_schedule, 432 enccrd->crd_len, buf, iv); 433 break; 434 } 435 436 if (allocated) 437 crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, 438 enccrd->crd_len, buf); 439 440 if (!kt) { 441 fpu_kern_leave(curthread, ctx); 442 RELEASE_CTX(i, ctx); 443 } 444 if (allocated) { 445 bzero(buf, enccrd->crd_len); 446 free(buf, M_ARMV8_CRYPTO); 447 } 448 return (0); 449 } 450 451 static device_method_t armv8_crypto_methods[] = { 452 DEVMETHOD(device_identify, armv8_crypto_identify), 453 DEVMETHOD(device_probe, armv8_crypto_probe), 454 DEVMETHOD(device_attach, armv8_crypto_attach), 455 DEVMETHOD(device_detach, armv8_crypto_detach), 456 457 DEVMETHOD(cryptodev_newsession, armv8_crypto_newsession), 458 DEVMETHOD(cryptodev_process, armv8_crypto_process), 459 460 DEVMETHOD_END, 461 }; 462 463 static DEFINE_CLASS_0(armv8crypto, armv8_crypto_driver, armv8_crypto_methods, 464 sizeof(struct armv8_crypto_softc)); 465 static devclass_t armv8_crypto_devclass; 466 467 DRIVER_MODULE(armv8crypto, nexus, armv8_crypto_driver, armv8_crypto_devclass, 468 0, 0); 469