Index: head/share/man/man4/Makefile =================================================================== --- head/share/man/man4/Makefile +++ head/share/man/man4/Makefile @@ -53,6 +53,7 @@ ${_aout.4} \ ${_apic.4} \ arcmsr.4 \ + ${_armv8crypto.4} \ ${_asmc.4} \ ata.4 \ ath.4 \ @@ -746,6 +747,10 @@ MLINKS+=xl.4 if_xl.4 MLINKS+=zyd.4 if_zyd.4 +.if ${MACHINE_CPUARCH} == "aarch64" +_armv8crypto.4= armv8crypto.4 +.endif + .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" _acpi_asus.4= acpi_asus.4 _acpi_asus_wmi.4= acpi_asus_wmi.4 Index: head/share/man/man4/armv8crypto.4 =================================================================== --- head/share/man/man4/armv8crypto.4 +++ head/share/man/man4/armv8crypto.4 @@ -0,0 +1,83 @@ +.\" Copyright (c) 2016 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This software was developed by Andrew Turner under +.\" sponsorship from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd October 20, 2016 +.Dt ARMV8CRYPTO 4 +.Os +.Sh NAME +.Nm armv8crypto +.Nd "driver for the AES accelerator on ARM CPUs" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device crypto" +.Cd "device armv8crypto" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +armv8crypto_load="YES" +.Ed +.Sh DESCRIPTION +Starting with the ARMv8 architecture ARM Limited has added optional +cryptography instructions to accelerate AES, SHA-1, SHA-2, and +finite field arithmetic. +.Pp +The processor capability is reported as AES in the Instruction Set +Attributes 0 line at boot. +The +.Nm +driver does not attach on systems that lack the required CPU capability. +.Pp +The +.Nm +driver registers itself to accelerate AES operations for +.Xr crypto 4 . +.Sh SEE ALSO +.Xr crypt 3 , +.Xr crypto 4 , +.Xr intro 4 , +.Xr ipsec 4 , +.Xr random 4 , +.Xr crypto 9 +.Sh HISTORY +The +.Nm +driver first appeared in +.Fx 11.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Andrew Turner Aq Mt andrew@FreeBSD.org . Index: head/sys/conf/files.arm64 =================================================================== --- head/sys/conf/files.arm64 +++ head/sys/conf/files.arm64 @@ -136,6 +136,12 @@ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_util.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" +crypto/armv8/armv8_crypto.c optional armv8crypto +armv8_crypto_wrap.o optional armv8crypto \ + dependency "$S/crypto/armv8/armv8_crypto_wrap.c" \ + compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc:N-mgeneral-regs-only} ${WERROR} ${NO_WCAST_QUAL} ${PROF} -march=armv8a+crypto ${.IMPSRC}" \ + no-implicit-rule \ + clean "armv8_crypto_wrap.o" crypto/blowfish/bf_enc.c optional crypto | ipsec crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/acpica/acpi_if.m optional acpi Index: head/sys/crypto/armv8/armv8_crypto.h =================================================================== --- head/sys/crypto/armv8/armv8_crypto.h +++ head/sys/crypto/armv8/armv8_crypto.h @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Andrew Turner under + * sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _ARMV8_CRYPTO_H_ +#define _ARMV8_CRYPTO_H_ + +#define AES128_ROUNDS 10 +#define AES192_ROUNDS 12 +#define AES256_ROUNDS 14 +#define AES_SCHED_LEN ((AES256_ROUNDS + 1) * AES_BLOCK_LEN) + +struct armv8_crypto_session { + uint32_t enc_schedule[AES_SCHED_LEN/4]; + uint32_t dec_schedule[AES_SCHED_LEN/4]; + int algo; + int rounds; + int used; + uint32_t id; + TAILQ_ENTRY(armv8_crypto_session) next; +}; + +void armv8_aes_encrypt_cbc(int, const void *, size_t, const uint8_t *, + uint8_t *, const uint8_t[static AES_BLOCK_LEN]); +void armv8_aes_decrypt_cbc(int, const void *, size_t, uint8_t *, + const uint8_t[static AES_BLOCK_LEN]); + +#endif /* _ARMV8_CRYPTO_H_ */ Index: head/sys/crypto/armv8/armv8_crypto.c =================================================================== --- head/sys/crypto/armv8/armv8_crypto.c +++ head/sys/crypto/armv8/armv8_crypto.c @@ -0,0 +1,565 @@ +/*- + * Copyright (c) 2005-2008 Pawel Jakub Dawidek + * Copyright (c) 2010 Konstantin Belousov + * Copyright (c) 2014,2016 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by John-Mark Gurney + * under sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * + * This software was developed by Andrew Turner under + * sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This is based on the aesni code. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +struct armv8_crypto_softc { + int dieing; + int32_t cid; + uint32_t sid; + TAILQ_HEAD(armv8_crypto_sessions_head, armv8_crypto_session) sessions; + struct rwlock lock; +}; + +static struct mtx *ctx_mtx; +static struct fpu_kern_ctx **ctx_vfp; + +#define AQUIRE_CTX(i, ctx) \ + do { \ + (i) = PCPU_GET(cpuid); \ + mtx_lock(&ctx_mtx[(i)]); \ + (ctx) = ctx_vfp[(i)]; \ + } while (0) +#define RELEASE_CTX(i, ctx) \ + do { \ + mtx_unlock(&ctx_mtx[(i)]); \ + (i) = -1; \ + (ctx) = NULL; \ + } while (0) + +static void armv8_crypto_freesession_locked(struct armv8_crypto_softc *, + struct armv8_crypto_session *); +static int armv8_crypto_cipher_process(struct armv8_crypto_session *, + struct cryptodesc *, struct cryptop *); + +MALLOC_DEFINE(M_ARMV8_CRYPTO, "armv8_crypto", "ARMv8 Crypto Data"); + +static void +armv8_crypto_identify(driver_t *drv, device_t parent) +{ + + /* NB: order 10 is so we get attached after h/w devices */ + if (device_find_child(parent, "armv8crypto", -1) == NULL && + BUS_ADD_CHILD(parent, 10, "armv8crypto", -1) == 0) + panic("ARMv8 crypto: could not attach"); +} + +static int +armv8_crypto_probe(device_t dev) +{ + uint64_t reg; + int ret = ENXIO; + + reg = READ_SPECIALREG(id_aa64isar0_el1); + + switch (ID_AA64ISAR0_AES(reg)) { + case ID_AA64ISAR0_AES_BASE: + case ID_AA64ISAR0_AES_PMULL: + ret = 0; + break; + } + + device_set_desc_copy(dev, "AES-CBC"); + + /* TODO: Check more fields as we support more features */ + + return (ret); +} + +static int +armv8_crypto_attach(device_t dev) +{ + struct armv8_crypto_softc *sc; + int i; + + sc = device_get_softc(dev); + TAILQ_INIT(&sc->sessions); + sc->dieing = 0; + sc->sid = 1; + + sc->cid = crypto_get_driverid(dev, CRYPTOCAP_F_HARDWARE | + CRYPTOCAP_F_SYNC); + if (sc->cid < 0) { + device_printf(dev, "Could not get crypto driver id.\n"); + return (ENOMEM); + } + + rw_init(&sc->lock, "armv8crypto"); + + ctx_mtx = malloc(sizeof(*ctx_mtx) * (mp_maxid + 1), M_ARMV8_CRYPTO, + M_WAITOK|M_ZERO); + ctx_vfp = malloc(sizeof(*ctx_vfp) * (mp_maxid + 1), M_ARMV8_CRYPTO, + M_WAITOK|M_ZERO); + + CPU_FOREACH(i) { + ctx_vfp[i] = fpu_kern_alloc_ctx(0); + mtx_init(&ctx_mtx[i], "armv8cryptoctx", NULL, MTX_DEF|MTX_NEW); + } + + crypto_register(sc->cid, CRYPTO_AES_CBC, 0, 0); + + return (0); +} + +static int +armv8_crypto_detach(device_t dev) +{ + struct armv8_crypto_softc *sc; + struct armv8_crypto_session *ses; + int i; + + sc = device_get_softc(dev); + + rw_wlock(&sc->lock); + TAILQ_FOREACH(ses, &sc->sessions, next) { + if (ses->used) { + rw_wunlock(&sc->lock); + device_printf(dev, + "Cannot detach, sessions still active.\n"); + return (EBUSY); + } + } + sc->dieing = 1; + while ((ses = TAILQ_FIRST(&sc->sessions)) != NULL) { + TAILQ_REMOVE(&sc->sessions, ses, next); + free(ses, M_ARMV8_CRYPTO); + } + rw_wunlock(&sc->lock); + crypto_unregister_all(sc->cid); + + rw_destroy(&sc->lock); + + CPU_FOREACH(i) { + if (ctx_vfp[i] != NULL) { + mtx_destroy(&ctx_mtx[i]); + fpu_kern_free_ctx(ctx_vfp[i]); + } + ctx_vfp[i] = NULL; + } + free(ctx_mtx, M_ARMV8_CRYPTO); + ctx_mtx = NULL; + free(ctx_vfp, M_ARMV8_CRYPTO); + ctx_vfp = NULL; + + return (0); +} + +static int +armv8_crypto_cipher_setup(struct armv8_crypto_session *ses, + struct cryptoini *encini) +{ + int i; + + switch (ses->algo) { + case CRYPTO_AES_CBC: + switch (encini->cri_klen) { + case 128: + ses->rounds = AES128_ROUNDS; + break; + case 192: + ses->rounds = AES192_ROUNDS; + break; + case 256: + ses->rounds = AES256_ROUNDS; + break; + default: + CRYPTDEB("invalid CBC/ICM/GCM key length"); + return (EINVAL); + } + break; + default: + return (EINVAL); + } + + rijndaelKeySetupEnc(ses->enc_schedule, encini->cri_key, + encini->cri_klen); + rijndaelKeySetupDec(ses->dec_schedule, encini->cri_key, + encini->cri_klen); + for (i = 0; i < nitems(ses->enc_schedule); i++) { + ses->enc_schedule[i] = bswap32(ses->enc_schedule[i]); + ses->dec_schedule[i] = bswap32(ses->dec_schedule[i]); + } + + return (0); +} + +static int +armv8_crypto_newsession(device_t dev, uint32_t *sidp, struct cryptoini *cri) +{ + struct armv8_crypto_softc *sc; + struct armv8_crypto_session *ses; + struct cryptoini *encini; + int error; + + if (sidp == NULL || cri == NULL) { + CRYPTDEB("no sidp or cri"); + return (EINVAL); + } + + sc = device_get_softc(dev); + if (sc->dieing) + return (EINVAL); + + ses = NULL; + encini = NULL; + for (; cri != NULL; cri = cri->cri_next) { + switch (cri->cri_alg) { + case CRYPTO_AES_CBC: + if (encini != NULL) { + CRYPTDEB("encini already set"); + return (EINVAL); + } + encini = cri; + break; + default: + CRYPTDEB("unhandled algorithm"); + return (EINVAL); + } + } + if (encini == NULL) { + CRYPTDEB("no cipher"); + return (EINVAL); + } + + rw_wlock(&sc->lock); + if (sc->dieing) { + rw_wunlock(&sc->lock); + return (EINVAL); + } + + /* + * Free sessions goes first, so if first session is used, we need to + * allocate one. + */ + ses = TAILQ_FIRST(&sc->sessions); + if (ses == NULL || ses->used) { + ses = malloc(sizeof(*ses), M_ARMV8_CRYPTO, M_NOWAIT | M_ZERO); + if (ses == NULL) { + rw_wunlock(&sc->lock); + return (ENOMEM); + } + ses->id = sc->sid++; + } else { + TAILQ_REMOVE(&sc->sessions, ses, next); + } + ses->used = 1; + TAILQ_INSERT_TAIL(&sc->sessions, ses, next); + rw_wunlock(&sc->lock); + ses->algo = encini->cri_alg; + + error = armv8_crypto_cipher_setup(ses, encini); + if (error != 0) { + CRYPTDEB("setup failed"); + rw_wlock(&sc->lock); + armv8_crypto_freesession_locked(sc, ses); + rw_wunlock(&sc->lock); + return (error); + } + + *sidp = ses->id; + return (0); +} + +static void +armv8_crypto_freesession_locked(struct armv8_crypto_softc *sc, + struct armv8_crypto_session *ses) +{ + uint32_t sid; + + rw_assert(&sc->lock, RA_WLOCKED); + + sid = ses->id; + TAILQ_REMOVE(&sc->sessions, ses, next); + *ses = (struct armv8_crypto_session){}; + ses->id = sid; + TAILQ_INSERT_HEAD(&sc->sessions, ses, next); +} + +static int +armv8_crypto_freesession(device_t dev, uint64_t tid) +{ + struct armv8_crypto_softc *sc; + struct armv8_crypto_session *ses; + uint32_t sid; + + sc = device_get_softc(dev); + sid = ((uint32_t)tid) & 0xffffffff; + rw_wlock(&sc->lock); + TAILQ_FOREACH_REVERSE(ses, &sc->sessions, armv8_crypto_sessions_head, + next) { + if (ses->id == sid) + break; + } + if (ses == NULL) { + rw_wunlock(&sc->lock); + return (EINVAL); + } + armv8_crypto_freesession_locked(sc, ses); + rw_wunlock(&sc->lock); + + return (0); +} + +static int +armv8_crypto_process(device_t dev, struct cryptop *crp, int hint __unused) +{ + struct armv8_crypto_softc *sc = device_get_softc(dev); + struct cryptodesc *crd, *enccrd; + struct armv8_crypto_session *ses; + int error; + + error = 0; + enccrd = NULL; + + /* Sanity check. */ + if (crp == NULL) + return (EINVAL); + + if (crp->crp_callback == NULL || crp->crp_desc == NULL) { + error = EINVAL; + goto out; + } + + for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) { + switch (crd->crd_alg) { + case CRYPTO_AES_CBC: + if (enccrd != NULL) { + error = EINVAL; + goto out; + } + enccrd = crd; + break; + default: + error = EINVAL; + goto out; + } + } + + if (enccrd == NULL) { + error = EINVAL; + goto out; + } + + /* We can only handle full blocks for now */ + if ((enccrd->crd_len % AES_BLOCK_LEN) != 0) { + error = EINVAL; + goto out; + } + + rw_rlock(&sc->lock); + TAILQ_FOREACH_REVERSE(ses, &sc->sessions, armv8_crypto_sessions_head, + next) { + if (ses->id == (crp->crp_sid & 0xffffffff)) + break; + } + rw_runlock(&sc->lock); + if (ses == NULL) { + error = EINVAL; + goto out; + } + + error = armv8_crypto_cipher_process(ses, enccrd, crp); + +out: + crp->crp_etype = error; + crypto_done(crp); + return (error); +} + +static uint8_t * +armv8_crypto_cipher_alloc(struct cryptodesc *enccrd, struct cryptop *crp, + int *allocated) +{ + struct mbuf *m; + struct uio *uio; + struct iovec *iov; + uint8_t *addr; + + if (crp->crp_flags & CRYPTO_F_IMBUF) { + m = (struct mbuf *)crp->crp_buf; + if (m->m_next != NULL) + goto alloc; + addr = mtod(m, uint8_t *); + } else if (crp->crp_flags & CRYPTO_F_IOV) { + uio = (struct uio *)crp->crp_buf; + if (uio->uio_iovcnt != 1) + goto alloc; + iov = uio->uio_iov; + addr = (uint8_t *)iov->iov_base; + } else + addr = (uint8_t *)crp->crp_buf; + *allocated = 0; + addr += enccrd->crd_skip; + return (addr); + +alloc: + addr = malloc(enccrd->crd_len, M_ARMV8_CRYPTO, M_NOWAIT); + if (addr != NULL) { + *allocated = 1; + crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, + enccrd->crd_len, addr); + } else + *allocated = 0; + return (addr); +} + +static int +armv8_crypto_cipher_process(struct armv8_crypto_session *ses, + struct cryptodesc *enccrd, struct cryptop *crp) +{ + struct fpu_kern_ctx *ctx; + uint8_t *buf; + uint8_t iv[AES_BLOCK_LEN]; + int allocated, error, i; + int encflag, ivlen; + int kt; + + encflag = (enccrd->crd_flags & CRD_F_ENCRYPT) == CRD_F_ENCRYPT; + + buf = armv8_crypto_cipher_alloc(enccrd, crp, &allocated); + if (buf == NULL) + return (ENOMEM); + + error = 0; + + kt = is_fpu_kern_thread(0); + if (!kt) { + AQUIRE_CTX(i, ctx); + error = fpu_kern_enter(curthread, ctx, + FPU_KERN_NORMAL | FPU_KERN_KTHR); + if (error != 0) + goto out; + } + + if ((enccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) { + panic("CRD_F_KEY_EXPLICIT"); + } + + switch (enccrd->crd_alg) { + case CRYPTO_AES_CBC: + ivlen = AES_BLOCK_LEN; + break; + } + + /* Setup iv */ + if (encflag) { + if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) + bcopy(enccrd->crd_iv, iv, ivlen); + else + arc4rand(iv, ivlen, 0); + + if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) + crypto_copyback(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, ivlen, iv); + } else { + if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) + bcopy(enccrd->crd_iv, iv, ivlen); + else + crypto_copydata(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, ivlen, iv); + } + + /* Do work */ + switch (ses->algo) { + case CRYPTO_AES_CBC: + if (encflag) + armv8_aes_encrypt_cbc(ses->rounds, ses->enc_schedule, + enccrd->crd_len, buf, buf, iv); + else + armv8_aes_decrypt_cbc(ses->rounds, ses->dec_schedule, + enccrd->crd_len, buf, iv); + break; + } + + if (allocated) + crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, + enccrd->crd_len, buf); + + if (!kt) { + fpu_kern_leave(curthread, ctx); +out: + RELEASE_CTX(i, ctx); + } + if (allocated) { + bzero(buf, enccrd->crd_len); + free(buf, M_ARMV8_CRYPTO); + } + return (error); +} + +static device_method_t armv8_crypto_methods[] = { + DEVMETHOD(device_identify, armv8_crypto_identify), + DEVMETHOD(device_probe, armv8_crypto_probe), + DEVMETHOD(device_attach, armv8_crypto_attach), + DEVMETHOD(device_detach, armv8_crypto_detach), + + DEVMETHOD(cryptodev_newsession, armv8_crypto_newsession), + DEVMETHOD(cryptodev_freesession, armv8_crypto_freesession), + DEVMETHOD(cryptodev_process, armv8_crypto_process), + + DEVMETHOD_END, +}; + +static DEFINE_CLASS_0(armv8crypto, armv8_crypto_driver, armv8_crypto_methods, + sizeof(struct armv8_crypto_softc)); +static devclass_t armv8_crypto_devclass; + +DRIVER_MODULE(armv8crypto, nexus, armv8_crypto_driver, armv8_crypto_devclass, + 0, 0); Index: head/sys/crypto/armv8/armv8_crypto_wrap.c =================================================================== --- head/sys/crypto/armv8/armv8_crypto_wrap.c +++ head/sys/crypto/armv8/armv8_crypto_wrap.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Andrew Turner under + * sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This code is built with floating-point enabled. Make sure to have entered + * into floating-point context before calling any of these functions. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include + +#include + +static uint8x16_t +armv8_aes_enc(int rounds, const uint8x16_t *keysched, const uint8x16_t from) +{ + uint8x16_t tmp; + int i; + + tmp = from; + for (i = 0; i < rounds - 1; i += 2) { + tmp = vaeseq_u8(tmp, keysched[i]); + tmp = vaesmcq_u8(tmp); + tmp = vaeseq_u8(tmp, keysched[i + 1]); + tmp = vaesmcq_u8(tmp); + } + + tmp = vaeseq_u8(tmp, keysched[rounds - 1]); + tmp = vaesmcq_u8(tmp); + tmp = vaeseq_u8(tmp, keysched[rounds]); + tmp = veorq_u8(tmp, keysched[rounds + 1]); + + return (tmp); +} + +static uint8x16_t +armv8_aes_dec(int rounds, const uint8x16_t *keysched, const uint8x16_t from) +{ + uint8x16_t tmp; + int i; + + tmp = from; + for (i = 0; i < rounds - 1; i += 2) { + tmp = vaesdq_u8(tmp, keysched[i]); + tmp = vaesimcq_u8(tmp); + tmp = vaesdq_u8(tmp, keysched[i+1]); + tmp = vaesimcq_u8(tmp); + } + + tmp = vaesdq_u8(tmp, keysched[rounds - 1]); + tmp = vaesimcq_u8(tmp); + tmp = vaesdq_u8(tmp, keysched[rounds]); + tmp = veorq_u8(tmp, keysched[rounds + 1]); + + return (tmp); +} + +void +armv8_aes_encrypt_cbc(int rounds, const void *key_schedule, size_t len, + const uint8_t *from, uint8_t *to, const uint8_t iv[static AES_BLOCK_LEN]) +{ + uint8x16_t tot, ivreg, tmp; + size_t i; + + len /= AES_BLOCK_LEN; + ivreg = vld1q_u8(iv); + for (i = 0; i < len; i++) { + tmp = vld1q_u8(from); + tot = armv8_aes_enc(rounds - 1, key_schedule, + veorq_u8(tmp, ivreg)); + ivreg = tot; + vst1q_u8(to, tot); + from += AES_BLOCK_LEN; + to += AES_BLOCK_LEN; + } +} + +void +armv8_aes_decrypt_cbc(int rounds, const void *key_schedule, size_t len, + uint8_t *buf, const uint8_t iv[static AES_BLOCK_LEN]) +{ + uint8x16_t ivreg, nextiv, tmp; + size_t i; + + len /= AES_BLOCK_LEN; + ivreg = vld1q_u8(iv); + for (i = 0; i < len; i++) { + nextiv = vld1q_u8(buf); + tmp = armv8_aes_dec(rounds - 1, key_schedule, nextiv); + vst1q_u8(buf, veorq_u8(tmp, ivreg)); + ivreg = nextiv; + buf += AES_BLOCK_LEN; + } +} Index: head/sys/modules/Makefile =================================================================== --- head/sys/modules/Makefile +++ head/sys/modules/Makefile @@ -42,6 +42,7 @@ ${_apm} \ ${_arcmsr} \ ${_arcnet} \ + ${_armv8crypto} \ ${_asmc} \ ata \ ath \ @@ -539,6 +540,7 @@ .endif .if ${MACHINE_CPUARCH} == "aarch64" +_armv8crypto= armv8crypto _em= em _igb= igb .endif Index: head/sys/modules/armv8crypto/Makefile =================================================================== --- head/sys/modules/armv8crypto/Makefile +++ head/sys/modules/armv8crypto/Makefile @@ -0,0 +1,20 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../crypto/armv8 + +KMOD= armv8crypto +SRCS= armv8_crypto.c +SRCS+= device_if.h bus_if.h opt_bus.h cryptodev_if.h + +OBJS+= armv8_crypto_wrap.o + +# Remove -nostdinc so we can get the intrinsics. +armv8_crypto_wrap.o: armv8_crypto_wrap.c + ${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc:N-mgeneral-regs-only} \ + ${WERROR} ${PROF} \ + -march=armv8a+crypto ${.IMPSRC} + ${CTFCONVERT_CMD} + +armv8_crypto_wrap.o: armv8_crypto.h + +.include