xref: /openbsd/sys/arch/i386/i386/via.c (revision 0cd0a70e)
1*0cd0a70eSpatrick /*	$OpenBSD: via.c,v 1.50 2021/10/24 10:26:22 patrick Exp $	*/
29d2e931eSderaadt /*	$NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $	*/
39d2e931eSderaadt 
49d2e931eSderaadt /*-
59d2e931eSderaadt  * Copyright (c) 2003 Jason Wright
69d2e931eSderaadt  * Copyright (c) 2003, 2004 Theo de Raadt
79d2e931eSderaadt  * All rights reserved.
89d2e931eSderaadt  *
99d2e931eSderaadt  * Permission to use, copy, modify, and distribute this software for any
109d2e931eSderaadt  * purpose with or without fee is hereby granted, provided that the above
119d2e931eSderaadt  * copyright notice and this permission notice appear in all copies.
129d2e931eSderaadt  *
139d2e931eSderaadt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
149d2e931eSderaadt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
159d2e931eSderaadt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
169d2e931eSderaadt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
179d2e931eSderaadt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
189d2e931eSderaadt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
199d2e931eSderaadt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
209d2e931eSderaadt  */
219d2e931eSderaadt 
229d2e931eSderaadt #include <sys/param.h>
239d2e931eSderaadt #include <sys/systm.h>
249d2e931eSderaadt #include <sys/timeout.h>
259d2e931eSderaadt #include <sys/malloc.h>
269d2e931eSderaadt #include <sys/mbuf.h>
279d2e931eSderaadt 
289d2e931eSderaadt #ifdef CRYPTO
299d2e931eSderaadt #include <crypto/cryptodev.h>
30cb308754Smikeb #include <crypto/aes.h>
31c865fca5Shshoexer #include <crypto/xform.h>
32c865fca5Shshoexer #include <crypto/cryptosoft.h>
339d2e931eSderaadt #endif
349d2e931eSderaadt 
359d2e931eSderaadt #include <machine/cpufunc.h>
369d2e931eSderaadt #include <machine/specialreg.h>
379d2e931eSderaadt 
389d2e931eSderaadt void	viac3_rnd(void *);
399d2e931eSderaadt 
409d2e931eSderaadt 
419d2e931eSderaadt #ifdef CRYPTO
429d2e931eSderaadt 
439d2e931eSderaadt struct viac3_session {
44ba5a924fStedu 	u_int32_t	ses_ekey[4 * (AES_MAXROUNDS + 1) + 4];	/* 128 bit aligned */
45ba5a924fStedu 	u_int32_t	ses_dkey[4 * (AES_MAXROUNDS + 1) + 4];	/* 128 bit aligned */
469d2e931eSderaadt 	u_int32_t	ses_cw0;
47c865fca5Shshoexer 	struct swcr_data *swd;
489d2e931eSderaadt 	int		ses_klen;
499d2e931eSderaadt 	int		ses_used;
509d2e931eSderaadt };
519d2e931eSderaadt 
529d2e931eSderaadt struct viac3_softc {
539d2e931eSderaadt 	u_int32_t		op_cw[4];		/* 128 bit aligned */
549d2e931eSderaadt 	u_int8_t		op_iv[16];		/* 128 bit aligned */
559d2e931eSderaadt 	void			*op_buf;
569d2e931eSderaadt 
579d2e931eSderaadt 	/* normal softc stuff */
589d2e931eSderaadt 	int32_t			sc_cid;
599d2e931eSderaadt 	int			sc_nsessions;
609d2e931eSderaadt 	struct viac3_session	*sc_sessions;
619d2e931eSderaadt };
629d2e931eSderaadt 
639d2e931eSderaadt #define VIAC3_SESSION(sid)		((sid) & 0x0fffffff)
649d2e931eSderaadt #define	VIAC3_SID(crd,ses)		(((crd) << 28) | ((ses) & 0x0fffffff))
659d2e931eSderaadt 
669d2e931eSderaadt static struct viac3_softc *vc3_sc;
679d2e931eSderaadt extern int i386_has_xcrypt;
689d2e931eSderaadt 
698688c78cSmarkus extern const u_int8_t hmac_ipad_buffer[HMAC_MAX_BLOCK_LEN];
708688c78cSmarkus extern const u_int8_t hmac_opad_buffer[HMAC_MAX_BLOCK_LEN];
71c865fca5Shshoexer 
729d2e931eSderaadt void viac3_crypto_setup(void);
739d2e931eSderaadt int viac3_crypto_newsession(u_int32_t *, struct cryptoini *);
749d2e931eSderaadt int viac3_crypto_process(struct cryptop *);
75c865fca5Shshoexer int viac3_crypto_swauth(struct cryptop *, struct cryptodesc *,
76c865fca5Shshoexer     struct swcr_data *, caddr_t);
77c865fca5Shshoexer int viac3_crypto_encdec(struct cryptop *, struct cryptodesc *,
78c865fca5Shshoexer     struct viac3_session *, struct viac3_softc *, caddr_t);
799d2e931eSderaadt int viac3_crypto_freesession(u_int64_t);
809d2e931eSderaadt static __inline void viac3_cbc(void *, void *, void *, void *, int, void *);
819d2e931eSderaadt 
829d2e931eSderaadt void
viac3_crypto_setup(void)839d2e931eSderaadt viac3_crypto_setup(void)
849d2e931eSderaadt {
859d2e931eSderaadt 	int algs[CRYPTO_ALGORITHM_MAX + 1];
869d2e931eSderaadt 
871ba3fe5dSthib 	vc3_sc = malloc(sizeof(*vc3_sc), M_DEVBUF, M_NOWAIT|M_ZERO);
881ba3fe5dSthib 	if (vc3_sc == NULL)
897c07cf69Sfcambus 		return;
909d2e931eSderaadt 
919d2e931eSderaadt 	bzero(algs, sizeof(algs));
929d2e931eSderaadt 	algs[CRYPTO_AES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
93c865fca5Shshoexer 	algs[CRYPTO_MD5_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
94c865fca5Shshoexer 	algs[CRYPTO_SHA1_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
95c865fca5Shshoexer 	algs[CRYPTO_RIPEMD160_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
96c865fca5Shshoexer 	algs[CRYPTO_SHA2_256_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
97c865fca5Shshoexer 	algs[CRYPTO_SHA2_384_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
98c865fca5Shshoexer 	algs[CRYPTO_SHA2_512_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
99c0e25af1Smikeb 	algs[CRYPTO_ESN] = CRYPTO_ALG_FLAG_SUPPORTED;
1009d2e931eSderaadt 
1019d2e931eSderaadt 	vc3_sc->sc_cid = crypto_get_driverid(0);
1021ba3fe5dSthib 	if (vc3_sc->sc_cid < 0) {
103864cf24eSderaadt 		free(vc3_sc, M_DEVBUF, sizeof(*vc3_sc));
104ebfe661dSfcambus 		vc3_sc = NULL;
1057c07cf69Sfcambus 		return;
1061ba3fe5dSthib 	}
1079d2e931eSderaadt 
1089d2e931eSderaadt 	crypto_register(vc3_sc->sc_cid, algs, viac3_crypto_newsession,
1099d2e931eSderaadt 	    viac3_crypto_freesession, viac3_crypto_process);
1109d2e931eSderaadt }
1119d2e931eSderaadt 
1129d2e931eSderaadt int
viac3_crypto_newsession(u_int32_t * sidp,struct cryptoini * cri)1139d2e931eSderaadt viac3_crypto_newsession(u_int32_t *sidp, struct cryptoini *cri)
1149d2e931eSderaadt {
115c865fca5Shshoexer 	struct cryptoini	*c;
1169d2e931eSderaadt 	struct viac3_softc	*sc = vc3_sc;
1179d2e931eSderaadt 	struct viac3_session	*ses = NULL;
1184d13edafSbluhm 	const struct auth_hash	*axf;
119c865fca5Shshoexer 	struct swcr_data	*swd;
1209d2e931eSderaadt 	int			 sesn, i, cw0;
1219d2e931eSderaadt 
122c865fca5Shshoexer 	if (sc == NULL || sidp == NULL || cri == NULL)
1239d2e931eSderaadt 		return (EINVAL);
1249d2e931eSderaadt 
1259d2e931eSderaadt 	if (sc->sc_sessions == NULL) {
126ba6145e1Sgwk 		ses = sc->sc_sessions = malloc(sizeof(*ses), M_DEVBUF,
127ba6145e1Sgwk 		    M_NOWAIT);
1289d2e931eSderaadt 		if (ses == NULL)
1299d2e931eSderaadt 			return (ENOMEM);
1309d2e931eSderaadt 		sesn = 0;
1319d2e931eSderaadt 		sc->sc_nsessions = 1;
1329d2e931eSderaadt 	} else {
1339d2e931eSderaadt 		for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
1349d2e931eSderaadt 			if (sc->sc_sessions[sesn].ses_used == 0) {
1359d2e931eSderaadt 				ses = &sc->sc_sessions[sesn];
1369d2e931eSderaadt 				break;
1379d2e931eSderaadt 			}
1389d2e931eSderaadt 		}
1399d2e931eSderaadt 
1409d2e931eSderaadt 		if (ses == NULL) {
1419d2e931eSderaadt 			sesn = sc->sc_nsessions;
1425714159aSdoug 			ses = mallocarray(sesn + 1, sizeof(*ses), M_DEVBUF,
143ba6145e1Sgwk 			    M_NOWAIT);
1449d2e931eSderaadt 			if (ses == NULL)
1459d2e931eSderaadt 				return (ENOMEM);
1462d571156Sfcambus 			memcpy(ses, sc->sc_sessions, sesn * sizeof(*ses));
147c048ab48Sderaadt 			explicit_bzero(sc->sc_sessions, sesn * sizeof(*ses));
148864cf24eSderaadt 			free(sc->sc_sessions, M_DEVBUF, sesn * sizeof(*ses));
1499d2e931eSderaadt 			sc->sc_sessions = ses;
1509d2e931eSderaadt 			ses = &sc->sc_sessions[sesn];
1519d2e931eSderaadt 			sc->sc_nsessions++;
1529d2e931eSderaadt 		}
1539d2e931eSderaadt 	}
1549d2e931eSderaadt 
1559d2e931eSderaadt 	bzero(ses, sizeof(*ses));
1569d2e931eSderaadt 	ses->ses_used = 1;
1579d2e931eSderaadt 
158c865fca5Shshoexer 	for (c = cri; c != NULL; c = c->cri_next) {
159c865fca5Shshoexer 		switch (c->cri_alg) {
160c865fca5Shshoexer 		case CRYPTO_AES_CBC:
161c865fca5Shshoexer 			switch (c->cri_klen) {
162c865fca5Shshoexer 			case 128:
163c865fca5Shshoexer 				cw0 = C3_CRYPT_CWLO_KEY128;
164c865fca5Shshoexer 				break;
165c865fca5Shshoexer 			case 192:
166c865fca5Shshoexer 				cw0 = C3_CRYPT_CWLO_KEY192;
167c865fca5Shshoexer 				break;
168c865fca5Shshoexer 			case 256:
169c865fca5Shshoexer 				cw0 = C3_CRYPT_CWLO_KEY256;
170c865fca5Shshoexer 				break;
171c865fca5Shshoexer 			default:
17264d2735aSmarkus 				viac3_crypto_freesession(sesn);
173c865fca5Shshoexer 				return (EINVAL);
174c865fca5Shshoexer 			}
175c865fca5Shshoexer 			cw0 |= C3_CRYPT_CWLO_ALG_AES | C3_CRYPT_CWLO_KEYGEN_SW |
176c865fca5Shshoexer 			    C3_CRYPT_CWLO_NORMAL;
177c865fca5Shshoexer 
178c865fca5Shshoexer 			ses->ses_klen = c->cri_klen;
1799d2e931eSderaadt 			ses->ses_cw0 = cw0;
1809d2e931eSderaadt 
1819d2e931eSderaadt 			/* Build expanded keys for both directions */
182cb308754Smikeb 			AES_KeySetup_Encrypt(ses->ses_ekey, c->cri_key,
1831748ed04Smikeb 			    c->cri_klen / 8);
184cb308754Smikeb 			AES_KeySetup_Decrypt(ses->ses_dkey, c->cri_key,
1851748ed04Smikeb 			    c->cri_klen / 8);
186ba5a924fStedu 			for (i = 0; i < 4 * (AES_MAXROUNDS + 1); i++) {
1879d2e931eSderaadt 				ses->ses_ekey[i] = ntohl(ses->ses_ekey[i]);
1889d2e931eSderaadt 				ses->ses_dkey[i] = ntohl(ses->ses_dkey[i]);
1899d2e931eSderaadt 			}
1909d2e931eSderaadt 
191c865fca5Shshoexer 			break;
192c865fca5Shshoexer 
193c865fca5Shshoexer 		case CRYPTO_MD5_HMAC:
194c865fca5Shshoexer 			axf = &auth_hash_hmac_md5_96;
195c865fca5Shshoexer 			goto authcommon;
196c865fca5Shshoexer 		case CRYPTO_SHA1_HMAC:
197c865fca5Shshoexer 			axf = &auth_hash_hmac_sha1_96;
198c865fca5Shshoexer 			goto authcommon;
199c865fca5Shshoexer 		case CRYPTO_RIPEMD160_HMAC:
200c865fca5Shshoexer 			axf = &auth_hash_hmac_ripemd_160_96;
201c865fca5Shshoexer 			goto authcommon;
202c865fca5Shshoexer 		case CRYPTO_SHA2_256_HMAC:
2038688c78cSmarkus 			axf = &auth_hash_hmac_sha2_256_128;
204c865fca5Shshoexer 			goto authcommon;
205c865fca5Shshoexer 		case CRYPTO_SHA2_384_HMAC:
2068688c78cSmarkus 			axf = &auth_hash_hmac_sha2_384_192;
207c865fca5Shshoexer 			goto authcommon;
208c865fca5Shshoexer 		case CRYPTO_SHA2_512_HMAC:
2098688c78cSmarkus 			axf = &auth_hash_hmac_sha2_512_256;
210c865fca5Shshoexer 		authcommon:
21128a8f404Sart 			swd = malloc(sizeof(struct swcr_data), M_CRYPTO_DATA,
21228a8f404Sart 			    M_NOWAIT|M_ZERO);
213c865fca5Shshoexer 			if (swd == NULL) {
214c865fca5Shshoexer 				viac3_crypto_freesession(sesn);
215c865fca5Shshoexer 				return (ENOMEM);
216c865fca5Shshoexer 			}
217c865fca5Shshoexer 			ses->swd = swd;
218c865fca5Shshoexer 
219c865fca5Shshoexer 			swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
220c865fca5Shshoexer 			    M_NOWAIT);
221c865fca5Shshoexer 			if (swd->sw_ictx == NULL) {
222c865fca5Shshoexer 				viac3_crypto_freesession(sesn);
223c865fca5Shshoexer 				return (ENOMEM);
224c865fca5Shshoexer 			}
225c865fca5Shshoexer 
226c865fca5Shshoexer 			swd->sw_octx = malloc(axf->ctxsize, M_CRYPTO_DATA,
227c865fca5Shshoexer 			    M_NOWAIT);
228c865fca5Shshoexer 			if (swd->sw_octx == NULL) {
229c865fca5Shshoexer 				viac3_crypto_freesession(sesn);
230c865fca5Shshoexer 				return (ENOMEM);
231c865fca5Shshoexer 			}
232c865fca5Shshoexer 
233c865fca5Shshoexer 			for (i = 0; i < c->cri_klen / 8; i++)
234c865fca5Shshoexer 				c->cri_key[i] ^= HMAC_IPAD_VAL;
235c865fca5Shshoexer 
236c865fca5Shshoexer 			axf->Init(swd->sw_ictx);
237c865fca5Shshoexer 			axf->Update(swd->sw_ictx, c->cri_key, c->cri_klen / 8);
238c865fca5Shshoexer 			axf->Update(swd->sw_ictx, hmac_ipad_buffer,
2398688c78cSmarkus 			    axf->blocksize - (c->cri_klen / 8));
240c865fca5Shshoexer 
241c865fca5Shshoexer 			for (i = 0; i < c->cri_klen / 8; i++)
242c865fca5Shshoexer 				c->cri_key[i] ^= (HMAC_IPAD_VAL ^
243c865fca5Shshoexer 				    HMAC_OPAD_VAL);
244c865fca5Shshoexer 
245c865fca5Shshoexer 			axf->Init(swd->sw_octx);
246c865fca5Shshoexer 			axf->Update(swd->sw_octx, c->cri_key, c->cri_klen / 8);
247c865fca5Shshoexer 			axf->Update(swd->sw_octx, hmac_opad_buffer,
2488688c78cSmarkus 			    axf->blocksize - (c->cri_klen / 8));
249c865fca5Shshoexer 
250c865fca5Shshoexer 			for (i = 0; i < c->cri_klen / 8; i++)
251c865fca5Shshoexer 				c->cri_key[i] ^= HMAC_OPAD_VAL;
252c865fca5Shshoexer 
253c865fca5Shshoexer 			swd->sw_axf = axf;
254c865fca5Shshoexer 			swd->sw_alg = c->cri_alg;
255c865fca5Shshoexer 
256c865fca5Shshoexer 			break;
257c0e25af1Smikeb 		case CRYPTO_ESN:
258c0e25af1Smikeb 			/* nothing to do */
259c0e25af1Smikeb 			break;
260c865fca5Shshoexer 		default:
26164d2735aSmarkus 			viac3_crypto_freesession(sesn);
262c865fca5Shshoexer 			return (EINVAL);
263c865fca5Shshoexer 		}
264c865fca5Shshoexer 	}
265c865fca5Shshoexer 
2669d2e931eSderaadt 	*sidp = VIAC3_SID(0, sesn);
2679d2e931eSderaadt 	return (0);
2689d2e931eSderaadt }
2699d2e931eSderaadt 
2709d2e931eSderaadt int
viac3_crypto_freesession(u_int64_t tid)2719d2e931eSderaadt viac3_crypto_freesession(u_int64_t tid)
2729d2e931eSderaadt {
2739d2e931eSderaadt 	struct viac3_softc *sc = vc3_sc;
274c865fca5Shshoexer 	struct swcr_data *swd;
2754d13edafSbluhm 	const struct auth_hash *axf;
2769d2e931eSderaadt 	int sesn;
2779d2e931eSderaadt 	u_int32_t sid = ((u_int32_t)tid) & 0xffffffff;
2789d2e931eSderaadt 
2799d2e931eSderaadt 	if (sc == NULL)
2809d2e931eSderaadt 		return (EINVAL);
2819d2e931eSderaadt 	sesn = VIAC3_SESSION(sid);
2829d2e931eSderaadt 	if (sesn >= sc->sc_nsessions)
2839d2e931eSderaadt 		return (EINVAL);
284c865fca5Shshoexer 
285c865fca5Shshoexer 	if (sc->sc_sessions[sesn].swd) {
286c865fca5Shshoexer 		swd = sc->sc_sessions[sesn].swd;
287c865fca5Shshoexer 		axf = swd->sw_axf;
288c865fca5Shshoexer 
289c865fca5Shshoexer 		if (swd->sw_ictx) {
290fa2d22afSderaadt 			explicit_bzero(swd->sw_ictx, axf->ctxsize);
291864cf24eSderaadt 			free(swd->sw_ictx, M_CRYPTO_DATA, axf->ctxsize);
292c865fca5Shshoexer 		}
293c865fca5Shshoexer 		if (swd->sw_octx) {
294fa2d22afSderaadt 			explicit_bzero(swd->sw_octx, axf->ctxsize);
295864cf24eSderaadt 			free(swd->sw_octx, M_CRYPTO_DATA, axf->ctxsize);
296c865fca5Shshoexer 		}
297864cf24eSderaadt 		free(swd, M_CRYPTO_DATA, sizeof(*swd));
298c865fca5Shshoexer 	}
299c865fca5Shshoexer 
300c048ab48Sderaadt 	explicit_bzero(&sc->sc_sessions[sesn], sizeof(sc->sc_sessions[sesn]));
3019d2e931eSderaadt 	return (0);
3029d2e931eSderaadt }
3039d2e931eSderaadt 
3049d2e931eSderaadt static __inline void
viac3_cbc(void * cw,void * src,void * dst,void * key,int rep,void * iv)3059d2e931eSderaadt viac3_cbc(void *cw, void *src, void *dst, void *key, int rep,
3069d2e931eSderaadt     void *iv)
3079d2e931eSderaadt {
3089d2e931eSderaadt 	unsigned int creg0;
3099d2e931eSderaadt 
3109d2e931eSderaadt 	creg0 = rcr0();		/* Permit access to SIMD/FPU path */
3119d2e931eSderaadt 	lcr0(creg0 & ~(CR0_EM|CR0_TS));
3129d2e931eSderaadt 
3139d2e931eSderaadt 	/* Do the deed */
3142df76cc2Sguenther 	__asm volatile("pushfl; popfl");
3152df76cc2Sguenther 	__asm volatile("rep xcryptcbc" :
3169d2e931eSderaadt 	    : "a" (iv), "b" (key), "c" (rep), "d" (cw), "S" (src), "D" (dst)
3179d2e931eSderaadt 	    : "memory", "cc");
3189d2e931eSderaadt 
3199d2e931eSderaadt 	lcr0(creg0);
3209d2e931eSderaadt }
3219d2e931eSderaadt 
3229d2e931eSderaadt int
viac3_crypto_swauth(struct cryptop * crp,struct cryptodesc * crd,struct swcr_data * sw,caddr_t buf)323c865fca5Shshoexer viac3_crypto_swauth(struct cryptop *crp, struct cryptodesc *crd,
324c865fca5Shshoexer     struct swcr_data *sw, caddr_t buf)
3259d2e931eSderaadt {
326c865fca5Shshoexer 	int	type;
327c865fca5Shshoexer 
328c865fca5Shshoexer 	if (crp->crp_flags & CRYPTO_F_IMBUF)
329c865fca5Shshoexer 		type = CRYPTO_BUF_MBUF;
330c865fca5Shshoexer 	else
331c865fca5Shshoexer 		type= CRYPTO_BUF_IOV;
332c865fca5Shshoexer 
333c865fca5Shshoexer 	return (swcr_authcompute(crp, crd, sw, buf, type));
334c865fca5Shshoexer }
335c865fca5Shshoexer 
336c865fca5Shshoexer int
viac3_crypto_encdec(struct cryptop * crp,struct cryptodesc * crd,struct viac3_session * ses,struct viac3_softc * sc,caddr_t buf)337c865fca5Shshoexer viac3_crypto_encdec(struct cryptop *crp, struct cryptodesc *crd,
338c865fca5Shshoexer     struct viac3_session *ses, struct viac3_softc *sc, caddr_t buf)
339c865fca5Shshoexer {
3409d2e931eSderaadt 	u_int32_t *key;
341c865fca5Shshoexer 	int	err = 0;
3429d2e931eSderaadt 
3437c07cf69Sfcambus 	if ((crd->crd_len % 16) != 0)
3447c07cf69Sfcambus 		return (EINVAL);
3459d2e931eSderaadt 
346ba6145e1Sgwk 	sc->op_buf = malloc(crd->crd_len, M_DEVBUF, M_NOWAIT);
3477c07cf69Sfcambus 	if (sc->op_buf == NULL)
3487c07cf69Sfcambus 		return (ENOMEM);
3499d2e931eSderaadt 
3509d2e931eSderaadt 	if (crd->crd_flags & CRD_F_ENCRYPT) {
3519d2e931eSderaadt 		sc->op_cw[0] = ses->ses_cw0 | C3_CRYPT_CWLO_ENCRYPT;
3529d2e931eSderaadt 		key = ses->ses_ekey;
3539d2e931eSderaadt 		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
3542d571156Sfcambus 			memcpy(sc->op_iv, crd->crd_iv, 16);
3559d2e931eSderaadt 		else
3560c4448d4Smikeb 			arc4random_buf(sc->op_iv, 16);
3579d2e931eSderaadt 
3589d2e931eSderaadt 		if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
3599d2e931eSderaadt 			if (crp->crp_flags & CRYPTO_F_IMBUF)
36035d73620Smikeb 				err = m_copyback((struct mbuf *)crp->crp_buf,
36141b18b7eSblambert 				    crd->crd_inject, 16, sc->op_iv, M_NOWAIT);
3629d2e931eSderaadt 			else if (crp->crp_flags & CRYPTO_F_IOV)
3639d2e931eSderaadt 				cuio_copyback((struct uio *)crp->crp_buf,
3649d2e931eSderaadt 				    crd->crd_inject, 16, sc->op_iv);
3659d2e931eSderaadt 			else
3662d571156Sfcambus 				memcpy(crp->crp_buf + crd->crd_inject,
3672d571156Sfcambus 				    sc->op_iv, 16);
36835d73620Smikeb 			if (err)
369c90c9c4fSfcambus 				goto errout;
3709d2e931eSderaadt 		}
3719d2e931eSderaadt 	} else {
3729d2e931eSderaadt 		sc->op_cw[0] = ses->ses_cw0 | C3_CRYPT_CWLO_DECRYPT;
3739d2e931eSderaadt 		key = ses->ses_dkey;
3749d2e931eSderaadt 		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
3752d571156Sfcambus 			memcpy(sc->op_iv, crd->crd_iv, 16);
3769d2e931eSderaadt 		else {
3779d2e931eSderaadt 			if (crp->crp_flags & CRYPTO_F_IMBUF)
3789d2e931eSderaadt 				m_copydata((struct mbuf *)crp->crp_buf,
3799d2e931eSderaadt 				    crd->crd_inject, 16, sc->op_iv);
3809d2e931eSderaadt 			else if (crp->crp_flags & CRYPTO_F_IOV)
3819d2e931eSderaadt 				cuio_copydata((struct uio *)crp->crp_buf,
3829d2e931eSderaadt 				    crd->crd_inject, 16, sc->op_iv);
3839d2e931eSderaadt 			else
3842d571156Sfcambus 				memcpy(sc->op_iv,
3852d571156Sfcambus 				    crp->crp_buf + crd->crd_inject, 16);
3869d2e931eSderaadt 		}
3879d2e931eSderaadt 	}
3889d2e931eSderaadt 
3899d2e931eSderaadt 	if (crp->crp_flags & CRYPTO_F_IMBUF)
3909d2e931eSderaadt 		m_copydata((struct mbuf *)crp->crp_buf,
3919d2e931eSderaadt 		    crd->crd_skip, crd->crd_len, sc->op_buf);
3929d2e931eSderaadt 	else if (crp->crp_flags & CRYPTO_F_IOV)
3939d2e931eSderaadt 		cuio_copydata((struct uio *)crp->crp_buf,
3949d2e931eSderaadt 		    crd->crd_skip, crd->crd_len, sc->op_buf);
3959d2e931eSderaadt 	else
3962d571156Sfcambus 		memcpy(sc->op_buf, crp->crp_buf + crd->crd_skip, crd->crd_len);
3979d2e931eSderaadt 
3989d2e931eSderaadt 	sc->op_cw[1] = sc->op_cw[2] = sc->op_cw[3] = 0;
3999d2e931eSderaadt 	viac3_cbc(&sc->op_cw, sc->op_buf, sc->op_buf, key,
4009d2e931eSderaadt 	    crd->crd_len / 16, sc->op_iv);
4019d2e931eSderaadt 
4029d2e931eSderaadt 	if (crp->crp_flags & CRYPTO_F_IMBUF)
403c90c9c4fSfcambus 		err = m_copyback((struct mbuf *)crp->crp_buf,
40441b18b7eSblambert 		    crd->crd_skip, crd->crd_len, sc->op_buf, M_NOWAIT);
4059d2e931eSderaadt 	else if (crp->crp_flags & CRYPTO_F_IOV)
4069d2e931eSderaadt 		cuio_copyback((struct uio *)crp->crp_buf,
4079d2e931eSderaadt 		    crd->crd_skip, crd->crd_len, sc->op_buf);
4089d2e931eSderaadt 	else
4092d571156Sfcambus 		memcpy(crp->crp_buf + crd->crd_skip, sc->op_buf,
410c865fca5Shshoexer 		    crd->crd_len);
4119d2e931eSderaadt 
412c90c9c4fSfcambus  errout:
4139d2e931eSderaadt 	if (sc->op_buf != NULL) {
414fa2d22afSderaadt 		explicit_bzero(sc->op_buf, crd->crd_len);
415864cf24eSderaadt 		free(sc->op_buf, M_DEVBUF, crd->crd_len);
4169d2e931eSderaadt 		sc->op_buf = NULL;
4179d2e931eSderaadt 	}
418c865fca5Shshoexer 
419c865fca5Shshoexer 	return (err);
420c865fca5Shshoexer }
421c865fca5Shshoexer 
422c865fca5Shshoexer int
viac3_crypto_process(struct cryptop * crp)423c865fca5Shshoexer viac3_crypto_process(struct cryptop *crp)
424c865fca5Shshoexer {
425c865fca5Shshoexer 	struct viac3_softc *sc = vc3_sc;
426c865fca5Shshoexer 	struct viac3_session *ses;
427c865fca5Shshoexer 	struct cryptodesc *crd;
428c865fca5Shshoexer 	int sesn, err = 0;
429e410e70dSpatrick 	int i;
430c865fca5Shshoexer 
4313877526aSbluhm 	KASSERT(crp->crp_ndesc >= 1);
432c865fca5Shshoexer 
433c865fca5Shshoexer 	sesn = VIAC3_SESSION(crp->crp_sid);
434c865fca5Shshoexer 	if (sesn >= sc->sc_nsessions) {
435c865fca5Shshoexer 		err = EINVAL;
436c865fca5Shshoexer 		goto out;
437c865fca5Shshoexer 	}
438c865fca5Shshoexer 	ses = &sc->sc_sessions[sesn];
439a68c2014Smarkus 	if (ses->ses_used == 0) {
440a68c2014Smarkus 		err = EINVAL;
441a68c2014Smarkus 		goto out;
442a68c2014Smarkus 	}
443c865fca5Shshoexer 
444e410e70dSpatrick 	for (i = 0; i < crp->crp_ndesc; i++) {
445e410e70dSpatrick 		crd = &crp->crp_desc[i];
446c865fca5Shshoexer 		switch (crd->crd_alg) {
447c865fca5Shshoexer 		case CRYPTO_AES_CBC:
448c865fca5Shshoexer 			if ((err = viac3_crypto_encdec(crp, crd, ses, sc,
449c865fca5Shshoexer 			    crp->crp_buf)) != 0)
450c865fca5Shshoexer 				goto out;
451c865fca5Shshoexer 			break;
452c865fca5Shshoexer 
453c865fca5Shshoexer 		case CRYPTO_MD5_HMAC:
454c865fca5Shshoexer 		case CRYPTO_SHA1_HMAC:
455c865fca5Shshoexer 		case CRYPTO_RIPEMD160_HMAC:
456c865fca5Shshoexer 		case CRYPTO_SHA2_256_HMAC:
457c865fca5Shshoexer 		case CRYPTO_SHA2_384_HMAC:
458c865fca5Shshoexer 		case CRYPTO_SHA2_512_HMAC:
459c865fca5Shshoexer 			if ((err = viac3_crypto_swauth(crp, crd, ses->swd,
460c865fca5Shshoexer 			    crp->crp_buf)) != 0)
461c865fca5Shshoexer 				goto out;
462c865fca5Shshoexer 			break;
463c865fca5Shshoexer 
464c865fca5Shshoexer 		default:
465c865fca5Shshoexer 			err = EINVAL;
466c865fca5Shshoexer 			goto out;
467c865fca5Shshoexer 		}
468c865fca5Shshoexer 	}
469c865fca5Shshoexer out:
4709d2e931eSderaadt 	return (err);
4719d2e931eSderaadt }
4729d2e931eSderaadt 
4739d2e931eSderaadt #endif /* CRYPTO */
4749d2e931eSderaadt 
4759d2e931eSderaadt /*
4769d2e931eSderaadt  * Note, the VIA C3 Nehemiah provides 4 internal 8-byte buffers, which
4779d2e931eSderaadt  * store random data, and can be accessed a lot quicker than waiting
4789d2e931eSderaadt  * for new data to be generated.  As we are using every 8th bit only
4799d2e931eSderaadt  * due to whitening. Since the RNG generates in excess of 21KB/s at
4800f1683a6Smiod  * its worst, collecting 64 bytes worth of entropy should not affect
4819d2e931eSderaadt  * things significantly.
4829d2e931eSderaadt  *
4839d2e931eSderaadt  * Note, due to some weirdness in the RNG, we need at least 7 bytes
4849d2e931eSderaadt  * extra on the end of our buffer.  Also, there is an outside chance
4859d2e931eSderaadt  * that the VIA RNG can "wedge", as the generated bit-rate is variable.
4869d2e931eSderaadt  * We could do all sorts of startup testing and things, but
4879d2e931eSderaadt  * frankly, I don't really see the point.  If the RNG wedges, then the
4889d2e931eSderaadt  * chances of you having a defective CPU are very high.  Let it wedge.
4899d2e931eSderaadt  *
4909d2e931eSderaadt  * Adding to the whole confusion, in order to access the RNG, we need
4919d2e931eSderaadt  * to have FXSR support enabled, and the correct FPU enable bits must
4929d2e931eSderaadt  * be there to enable the FPU in kernel.  It would be nice if all this
4939d2e931eSderaadt  * mumbo-jumbo was not needed in order to use the RNG.  Oh well, life
4949d2e931eSderaadt  * does go on...
4959d2e931eSderaadt  */
4969d2e931eSderaadt #define VIAC3_RNG_BUFSIZ	16		/* 32bit words */
4979d2e931eSderaadt struct timeout viac3_rnd_tmo;
4989d2e931eSderaadt int viac3_rnd_present;
4999d2e931eSderaadt 
5009d2e931eSderaadt void
viac3_rnd(void * v)5019d2e931eSderaadt viac3_rnd(void *v)
5029d2e931eSderaadt {
5039d2e931eSderaadt 	struct timeout *tmo = v;
5049d2e931eSderaadt 	unsigned int *p, i, rv, creg0, len = VIAC3_RNG_BUFSIZ;
5059d2e931eSderaadt 	static int buffer[VIAC3_RNG_BUFSIZ + 2];	/* XXX why + 2? */
506c6c79816Shenric #ifdef MULTIPROCESSOR
507c6c79816Shenric 	int s = splipi();
508c6c79816Shenric #endif
5099d2e931eSderaadt 
5109d2e931eSderaadt 	creg0 = rcr0();		/* Permit access to SIMD/FPU path */
5119d2e931eSderaadt 	lcr0(creg0 & ~(CR0_EM|CR0_TS));
5129d2e931eSderaadt 
5139d2e931eSderaadt 	/*
5149d2e931eSderaadt 	 * Here we collect the random data from the VIA C3 RNG.  We make
5159d2e931eSderaadt 	 * sure that we turn on maximum whitening (%edx[0,1] == "11"), so
5169d2e931eSderaadt 	 * that we get the best random data possible.
5179d2e931eSderaadt 	 */
5182df76cc2Sguenther 	__asm volatile("rep xstorerng"
5199d2e931eSderaadt 	    : "=a" (rv) : "d" (3), "D" (buffer), "c" (len*sizeof(int))
5209d2e931eSderaadt 	    : "memory", "cc");
5219d2e931eSderaadt 
5229d2e931eSderaadt 	lcr0(creg0);
5239d2e931eSderaadt 
524c6c79816Shenric #ifdef MULTIPROCESSOR
525c6c79816Shenric 	splx(s);
526c6c79816Shenric #endif
527c6c79816Shenric 
5289d2e931eSderaadt 	for (i = 0, p = buffer; i < VIAC3_RNG_BUFSIZ; i++, p++)
5299e9abf5bSjasper 		enqueue_randomness(*p);
5309d2e931eSderaadt 
5315398b2acSblambert 	timeout_add_msec(tmo, 10);
5329d2e931eSderaadt }
533