xref: /freebsd/sys/crypto/armv8/armv8_crypto.c (revision 0957b409)
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