⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 safe.c

📁 linux下基于加密芯片的加密设备
💻 C
📖 第 1 页 / 共 4 页
字号:
/*- * The linux port of this code done by David McCullough <davidm@snapgear.com> * The license and original author are listed below. * Copyright (C) 2004 David McCullough <davidm@snapgear.com> * * Copyright (c) 2003 Sam Leffler, Errno Consulting * Copyright (c) 2003 Global Technology Associates, Inc. * All rights reserved. * * 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. */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/wait.h>#include <linux/sched.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/spinlock.h>#include <linux/random.h>#include <asm/io.h>/* * some support for older kernels */#ifndef IRQ_NONE#define IRQ_NONE#define IRQ_HANDLED#define irqreturn_t void#endif/* * SafeNet SafeXcel-1141 hardware crypto accelerator */#include <cryptodev.h>#include <uio.h>#include <safe/safereg.h>#include <safe/safevar.h>#define bswap32(x)  /* seems the code using this below is buggy */#define read_random(p,l) get_random_bytes(p,l)#define KASSERT(c,p)	if (!c) { printk p ; } else#if 1#define	DPRINTF(a...)	if (debug) { printk("safe: " a); } else#else#define	DPRINTF(a...)#endif#define DELAY(x)	udelay(x)#define bcopy(s,d,l)			memcpy(d,s,l)#define bzero(p,l)				memset(p,0,l)#define	READ_REG(sc,r)			readl((sc)->sc_base_addr + (r))#define WRITE_REG(sc,r,val)		writel((val), (sc)->sc_base_addr + (r))/* add proc entry for this */struct safe_stats safestats;static	int debug = 0;MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Enable debug");#ifndef SAFE_NO_RNGstatic	int safe_rnginterval = 1;		/* poll once a second */MODULE_PARM(safe_rnginterval, "i");MODULE_PARM_DESC(safe_rnginterval, "RNG polling interval (secs)");static	int safe_rngbufsize = 16;		/* 64 bytes each poll  */MODULE_PARM(safe_rngbufsize, "i");MODULE_PARM_DESC(safe_rngbufsize, "RNG polling buffer size (32-bit words)");static	int safe_rngmaxalarm = 8;		/* max alarms before reset */MODULE_PARM(safe_rngmaxalarm, "i");MODULE_PARM_DESC(safe_rngmaxalarm, "RNG max alarms before reset");#endif /* SAFE_NO_RNG */static void safe_callback(struct safe_softc *sc, struct safe_ringentry *re);static void safe_totalreset(struct safe_softc *sc);static int safe_dmamap_aligned(const struct safe_operand *op);static int safe_dmamap_uniform(const struct safe_operand *op);static int safe_free_entry(struct safe_softc *sc, struct safe_ringentry *re);/* * map in a given buffer (great on some arches :-) */static intpci_map_uio(struct safe_softc *sc, struct safe_operand *buf, struct uio *uio){	struct iovec *iov = uio->uio_iov;	DPRINTF("%s()\n", __FUNCTION__);	buf->mapsize = 0;	for (buf->nsegs = 0; buf->nsegs < uio->uio_iovcnt; ) {		buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_dev,				iov->iov_base, iov->iov_len,				PCI_DMA_BIDIRECTIONAL);		buf->segs[buf->nsegs].ds_len = iov->iov_len;		buf->mapsize += iov->iov_len;		iov++;		buf->nsegs++;	}	/* identify this buffer by the first segment */	buf->map = (void *) buf->segs[0].ds_addr;	return(0);}static voidpci_sync_iov(struct safe_softc *sc, struct safe_operand *buf){	int i;	DPRINTF("%s()\n", __FUNCTION__);	for (i = 0; i < buf->nsegs; i++)		pci_dma_sync_single(sc->sc_dev, buf->segs[i].ds_addr,				buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL);}static voidpci_unmap_iov(struct safe_softc *sc, struct safe_operand *buf){	int i;	DPRINTF("%s()\n", __FUNCTION__);	for (i = 0; i < buf->nsegs; i++) {		pci_unmap_single(sc->sc_dev, buf->segs[i].ds_addr,				buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL);		buf->segs[i].ds_addr = 0;		buf->segs[i].ds_len = 0;	}	buf->nsegs = 0;	buf->mapsize = 0;	buf->map = 0;}/* * SafeXcel Interrupt routine */static irqreturn_tsafe_intr(int irq, void *arg, struct pt_regs *regs){	struct safe_softc *sc = arg;	int stat, flags;	stat = READ_REG(sc, SAFE_HM_STAT);	DPRINTF("%s(stat=0x%x)\n", __FUNCTION__, stat);	if (stat == 0)		/* shared irq, not for us */		return IRQ_NONE;	WRITE_REG(sc, SAFE_HI_CLR, stat);	/* IACK */	if ((stat & SAFE_INT_PE_DDONE)) {		/*		 * Descriptor(s) done; scan the ring and		 * process completed operations.		 */		spin_lock_irqsave(&sc->sc_ringmtx, flags);		while (sc->sc_back != sc->sc_front) {			struct safe_ringentry *re = sc->sc_back;#ifdef SAFE_DEBUG			if (debug) {				safe_dump_ringstate(sc, __func__);				safe_dump_request(sc, __func__, re);			}#endif			/*			 * safe_process marks ring entries that were allocated			 * but not used with a csr of zero.  This insures the			 * ring front pointer never needs to be set backwards			 * in the event that an entry is allocated but not used			 * because of a setup error.			 */			DPRINTF("%s re->re_desc.d_csr=0x%x\n", __FUNCTION__, re->re_desc.d_csr);			if (re->re_desc.d_csr != 0) {				if (!SAFE_PE_CSR_IS_DONE(re->re_desc.d_csr)) {					DPRINTF("%s !CSR_IS_DONE\n", __FUNCTION__);					break;				}				if (!SAFE_PE_LEN_IS_DONE(re->re_desc.d_len)) {					DPRINTF("%s !LEN_IS_DONE\n", __FUNCTION__);					break;				}				sc->sc_nqchip--;				safe_callback(sc, re);			}			if (++(sc->sc_back) == sc->sc_ringtop)				sc->sc_back = sc->sc_ring;		}		spin_unlock_irqrestore(&sc->sc_ringmtx, flags);	}	/*	 * Check to see if we got any DMA Error	 */	if (stat & SAFE_INT_PE_ERROR) {		printk("safe: dmaerr dmastat %08x\n",				(int)READ_REG(sc, SAFE_PE_DMASTAT));		safestats.st_dmaerr++;		safe_totalreset(sc);#if 0		safe_feed(sc);#endif	}	if (sc->sc_needwakeup) {		/* XXX check high watermark */		int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ);		DPRINTF("%s: wakeup crypto %x\n", __func__,			sc->sc_needwakeup);		sc->sc_needwakeup &= ~wakeup;		crypto_unblock(sc->sc_cid, wakeup);	}		return IRQ_HANDLED;}/* * safe_feed() - post a request to chip */static voidsafe_feed(struct safe_softc *sc, struct safe_ringentry *re){	DPRINTF("%s()\n", __FUNCTION__);#ifdef SAFE_DEBUG	if (debug) {		safe_dump_ringstate(sc, __func__);		safe_dump_request(sc, __func__, re);	}#endif	sc->sc_nqchip++;	if (sc->sc_nqchip > safestats.st_maxqchip)		safestats.st_maxqchip = sc->sc_nqchip;	/* poke h/w to check descriptor ring, any value can be written */	WRITE_REG(sc, SAFE_HI_RD_DESCR, 0);}/* * Allocate a new 'session' and return an encoded session id.  'sidp' * contains our registration id, and should contain an encoded session * id on successful allocation. */static intsafe_newsession(void *arg, u_int32_t *sidp, struct cryptoini *cri){#define	N(a)	(sizeof(a) / sizeof (a[0]))	struct cryptoini *c, *encini = NULL, *macini = NULL;	struct safe_softc *sc = arg;	struct safe_session *ses = NULL;#if NOTYET	MD5_CTX md5ctx;	SHA1_CTX sha1ctx;#endif	int i, sesn;	DPRINTF("%s()\n", __FUNCTION__);	if (sidp == NULL || cri == NULL || sc == NULL)		return (EINVAL);	for (c = cri; c != NULL; c = c->cri_next) {		if (c->cri_alg == CRYPTO_MD5_HMAC ||		    c->cri_alg == CRYPTO_SHA1_HMAC ||		    c->cri_alg == CRYPTO_NULL_HMAC) {			if (macini)				return (EINVAL);			macini = c;		} else if (c->cri_alg == CRYPTO_DES_CBC ||		    c->cri_alg == CRYPTO_3DES_CBC ||		    c->cri_alg == CRYPTO_AES_CBC ||		    c->cri_alg == CRYPTO_NULL_CBC) {			if (encini)				return (EINVAL);			encini = c;		} else			return (EINVAL);	}	if (encini == NULL && macini == NULL)		return (EINVAL);	if (encini) {			/* validate key length */		switch (encini->cri_alg) {		case CRYPTO_DES_CBC:			if (encini->cri_klen != 64)				return (EINVAL);			break;		case CRYPTO_3DES_CBC:			if (encini->cri_klen != 192)				return (EINVAL);			break;		case CRYPTO_AES_CBC:			if (encini->cri_klen != 128 &&			    encini->cri_klen != 192 &&			    encini->cri_klen != 256)				return (EINVAL);			break;		}	}	if (sc->sc_sessions == NULL) {		ses = sc->sc_sessions = (struct safe_session *)			kmalloc(sizeof(struct safe_session), GFP_ATOMIC);		if (ses == NULL)			return (ENOMEM);		memset(ses, 0, sizeof(struct safe_session));		sesn = 0;		sc->sc_nsessions = 1;	} else {		for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {			if (sc->sc_sessions[sesn].ses_used == 0) {				ses = &sc->sc_sessions[sesn];				break;			}		}		if (ses == NULL) {			sesn = sc->sc_nsessions;			ses = (struct safe_session *)				kmalloc((sesn + 1) * sizeof(struct safe_session), GFP_ATOMIC);			if (ses == NULL)				return (ENOMEM);			memset(ses, 0, (sesn + 1) * sizeof(struct safe_session));			bcopy(sc->sc_sessions, ses, sesn *			    sizeof(struct safe_session));			bzero(sc->sc_sessions, sesn *			    sizeof(struct safe_session));			kfree(sc->sc_sessions);			sc->sc_sessions = ses;			ses = &sc->sc_sessions[sesn];			sc->sc_nsessions++;		}	}	bzero(ses, sizeof(struct safe_session));	ses->ses_used = 1;	if (encini) {		/* get an IV */		/* XXX may read fewer than requested */		read_random(ses->ses_iv, sizeof(ses->ses_iv));		ses->ses_klen = encini->cri_klen;		bcopy(encini->cri_key, ses->ses_key, ses->ses_klen / 8);		/* PE is little-endian, insure proper byte order */		for (i = 0; i < N(ses->ses_key); i++)			ses->ses_key[i] = cpu_to_le32(ses->ses_key[i]);	}	if (macini) {#if NOTYET		for (i = 0; i < macini->cri_klen / 8; i++)			macini->cri_key[i] ^= HMAC_IPAD_VAL;		if (macini->cri_alg == CRYPTO_MD5_HMAC) {			MD5Init(&md5ctx);			MD5Update(&md5ctx, macini->cri_key,			    macini->cri_klen / 8);			MD5Update(&md5ctx, hmac_ipad_buffer,			    HMAC_BLOCK_LEN - (macini->cri_klen / 8));			bcopy(md5ctx.state, ses->ses_hminner,			    sizeof(md5ctx.state));		} else {			SHA1Init(&sha1ctx);			SHA1Update(&sha1ctx, macini->cri_key,			    macini->cri_klen / 8);			SHA1Update(&sha1ctx, hmac_ipad_buffer,			    HMAC_BLOCK_LEN - (macini->cri_klen / 8));			bcopy(sha1ctx.h.b32, ses->ses_hminner,			    sizeof(sha1ctx.h.b32));		}		for (i = 0; i < macini->cri_klen / 8; i++)			macini->cri_key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);		if (macini->cri_alg == CRYPTO_MD5_HMAC) {			MD5Init(&md5ctx);			MD5Update(&md5ctx, macini->cri_key,			    macini->cri_klen / 8);			MD5Update(&md5ctx, hmac_opad_buffer,			    HMAC_BLOCK_LEN - (macini->cri_klen / 8));			bcopy(md5ctx.state, ses->ses_hmouter,			    sizeof(md5ctx.state));		} else {			SHA1Init(&sha1ctx);			SHA1Update(&sha1ctx, macini->cri_key,			    macini->cri_klen / 8);			SHA1Update(&sha1ctx, hmac_opad_buffer,			    HMAC_BLOCK_LEN - (macini->cri_klen / 8));			bcopy(sha1ctx.h.b32, ses->ses_hmouter,			    sizeof(sha1ctx.h.b32));		}		for (i = 0; i < macini->cri_klen / 8; i++)			macini->cri_key[i] ^= HMAC_OPAD_VAL;		/* PE is little-endian, insure proper byte order */		for (i = 0; i < N(ses->ses_hminner); i++) {			ses->ses_hminner[i] = cpu_to_le32(ses->ses_hminner[i]);			ses->ses_hmouter[i] = cpu_to_le32(ses->ses_hmouter[i]);		}#else		printk("safe: no MD5 or SHA yet\n");#endif	}	*sidp = SAFE_SID(sc->sc_num, sesn);	return (0);#undef N}/* * Deallocate a session. */static intsafe_freesession(void *arg, u_int64_t tid){	struct safe_softc *sc = arg;	int session, ret;	u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;	DPRINTF("%s()\n", __FUNCTION__);	if (sc == NULL)		return (EINVAL);	session = SAFE_SESSION(sid);	if (session < sc->sc_nsessions) {		bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session]));		ret = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -