| /******************************************************************************* |
| Copyright (C) Marvell International Ltd. and its affiliates |
| |
| This software file (the "File") is owned and distributed by Marvell |
| International Ltd. and/or its affiliates ("Marvell") under the following |
| alternative licensing terms. Once you have made an election to distribute the |
| File under one of the following license alternatives, please (i) delete this |
| introductory statement regarding license alternatives, (ii) delete the two |
| license alternatives that you have not elected to use and (iii) preserve the |
| Marvell copyright notice above. |
| |
| ******************************************************************************** |
| Marvell Commercial License Option |
| |
| If you received this File from Marvell and you have entered into a commercial |
| license agreement (a "Commercial License") with Marvell, the File is licensed |
| to you under the terms of the applicable Commercial License. |
| |
| ******************************************************************************** |
| Marvell GPL License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File in accordance with the terms and conditions of the General |
| Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| available along with the File in the license.txt file or by writing to the Free |
| Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| |
| THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| DISCLAIMED. The GPL License provides additional details about this warranty |
| disclaimer. |
| ******************************************************************************** |
| Marvell BSD License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File under the following licensing terms. |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted provided that the following conditions are met: |
| |
| * Redistributions of source code must retain the above copyright notice, |
| this list of conditions and the following disclaimer. |
| |
| * 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. |
| |
| * Neither the name of Marvell nor the names of its contributors may be |
| used to endorse or promote products derived from this software without |
| specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "cesa/mvCesa.h" |
| |
| #include "ctrlEnv/mvCtrlEnvLib.h" |
| #undef CESA_DEBUG |
| |
| |
| /********** Global variables **********/ |
| |
| /* If request size is more than MV_CESA_MAX_BUF_SIZE the |
| * request is processed as fragmented request. |
| */ |
| |
| MV_CESA_STATS cesaStats; |
| |
| MV_BUF_INFO cesaSramSaBuf; |
| short cesaLastSid = -1; |
| MV_CESA_SA* pCesaSAD = NULL; |
| MV_U16 cesaMaxSA = 0; |
| |
| MV_CESA_REQ* pCesaReqFirst = NULL; |
| MV_CESA_REQ* pCesaReqLast = NULL; |
| MV_CESA_REQ* pCesaReqEmpty = NULL; |
| MV_CESA_REQ* pCesaReqProcess = NULL; |
| int cesaQueueDepth = 0; |
| int cesaReqResources = 0; |
| |
| MV_CESA_SRAM_MAP* cesaSramVirtPtr = NULL; |
| MV_U32 cesaCryptEngBase = 0; |
| void *cesaOsHandle = NULL; |
| #if (MV_CESA_VERSION >= 3) |
| MV_U32 cesaChainLength = 0; |
| int chainReqNum = 0; |
| MV_U32 chainIndex = 0; |
| MV_CESA_REQ* pNextActiveChain = 0; |
| MV_CESA_REQ* pEndCurrChain = 0; |
| MV_BOOL isFirstReq = MV_TRUE; |
| #endif |
| |
| static INLINE MV_U8* mvCesaSramAddrGet(void) |
| { |
| #ifdef MV_CESA_NO_SRAM |
| return (MV_U8*)cesaSramVirtPtr; |
| #else |
| return (MV_U8*)cesaCryptEngBase; |
| #endif /* MV_CESA_NO_SRAM */ |
| } |
| |
| static INLINE MV_ULONG mvCesaSramVirtToPhys(void* pDev, MV_U8* pSramVirt) |
| { |
| #ifdef MV_CESA_NO_SRAM |
| return (MV_ULONG)mvOsIoVirtToPhy(NULL, pSramVirt); |
| #else |
| return (MV_ULONG)pSramVirt; |
| #endif /* MV_CESA_NO_SRAM */ |
| } |
| |
| /* Internal Function prototypes */ |
| |
| static INLINE void mvCesaSramDescrBuild(MV_U32 config, int frag, |
| int cryptoOffset, int ivOffset, int cryptoLength, |
| int macOffset, int digestOffset, int macLength, int macTotalLen, |
| MV_CESA_REQ *pCesaReq, MV_DMA_DESC* pDmaDesc); |
| |
| static INLINE void mvCesaSramSaUpdate(short sid, MV_DMA_DESC *pDmaDesc); |
| |
| static INLINE int mvCesaDmaCopyPrepare(MV_CESA_MBUF* pMbuf, MV_U8* pSramBuf, |
| MV_DMA_DESC* pDmaDesc, MV_BOOL isToMbuf, |
| int offset, int copySize, MV_BOOL skipFlush); |
| |
| static void mvCesaHmacIvGet(MV_CESA_MAC_MODE macMode, unsigned char key[], int keyLength, |
| unsigned char innerIV[], unsigned char outerIV[]); |
| |
| static MV_STATUS mvCesaFragAuthComplete(MV_CESA_REQ* pReq, MV_CESA_SA* pSA, |
| int macDataSize); |
| |
| static MV_CESA_COMMAND* mvCesaCtrModeInit(void); |
| |
| static MV_STATUS mvCesaCtrModePrepare(MV_CESA_COMMAND *pCtrModeCmd, MV_CESA_COMMAND *pCmd); |
| static MV_STATUS mvCesaCtrModeComplete(MV_CESA_COMMAND *pOrgCmd, MV_CESA_COMMAND *pCmd); |
| static void mvCesaCtrModeFinish(MV_CESA_COMMAND *pCmd); |
| |
| static INLINE MV_STATUS mvCesaReqProcess(MV_CESA_REQ* pReq); |
| static MV_STATUS mvCesaFragReqProcess(MV_CESA_REQ* pReq, MV_U8 frag); |
| |
| static INLINE MV_STATUS mvCesaParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd, MV_U8* pFixOffset); |
| static INLINE MV_STATUS mvCesaFragParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd); |
| |
| static INLINE void mvCesaFragSizeFind(MV_CESA_SA* pSA, MV_CESA_REQ* pReq, |
| int cryptoOffset, int macOffset, |
| int* pCopySize, int* pCryptoDataSize, int* pMacDataSize); |
| static MV_STATUS mvCesaMbufCacheUnmap(MV_CESA_MBUF* pMbuf, int offset, int size); |
| |
| |
| /* Go to the next request in the request queue */ |
| static INLINE MV_CESA_REQ* MV_CESA_REQ_NEXT_PTR(MV_CESA_REQ* pReq) |
| { |
| if(pReq == pCesaReqLast) |
| return pCesaReqFirst; |
| |
| return pReq+1; |
| } |
| |
| #if (MV_CESA_VERSION >= 3) |
| /* Go to the previous request in the request queue */ |
| static INLINE MV_CESA_REQ* MV_CESA_REQ_PREV_PTR(MV_CESA_REQ* pReq) |
| { |
| if(pReq == pCesaReqFirst) |
| return pCesaReqLast; |
| |
| return pReq-1; |
| } |
| |
| #endif |
| |
| |
| static INLINE void mvCesaReqProcessStart(MV_CESA_REQ* pReq) |
| { |
| int frag; |
| |
| #if (MV_CESA_VERSION >= 3) |
| pReq->state = MV_CESA_CHAIN; |
| #else |
| pReq->state = MV_CESA_PROCESS; |
| #endif |
| cesaStats.startCount++; |
| |
| if(pReq->fragMode == MV_CESA_FRAG_NONE) |
| { |
| frag = 0; |
| } |
| else |
| { |
| frag = pReq->frags.nextFrag; |
| pReq->frags.nextFrag++; |
| } |
| #if (MV_CESA_VERSION >= 2) |
| /* Enable TDMA engine */ |
| MV_REG_WRITE(MV_CESA_TDMA_CURR_DESC_PTR_REG, 0); |
| MV_REG_WRITE(MV_CESA_TDMA_NEXT_DESC_PTR_REG, |
| (MV_U32)mvCesaVirtToPhys(&pReq->dmaDescBuf, pReq->dma[frag].pDmaFirst)); |
| #else |
| /* Enable IDMA engine */ |
| MV_REG_WRITE(IDMA_CURR_DESC_PTR_REG(0), 0); |
| MV_REG_WRITE(IDMA_NEXT_DESC_PTR_REG(0), |
| (MV_U32)mvCesaVirtToPhys(&pReq->dmaDescBuf, pReq->dma[frag].pDmaFirst)); |
| #endif /* MV_CESA_VERSION >= 2 */ |
| |
| #if defined(MV_BRIDGE_SYNC_REORDER) |
| mvOsBridgeReorderWA(); |
| #endif |
| |
| /* Start Accelerator */ |
| MV_REG_WRITE(MV_CESA_CMD_REG, MV_CESA_CMD_CHAN_ENABLE_MASK); |
| } |
| |
| |
| /******************************************************************************* |
| * mvCesaHalInit - Initialize the CESA driver |
| * |
| * DESCRIPTION: |
| * This function initialize the CESA driver. |
| * 1) Session database |
| * 2) Request queue |
| * 4) DMA descriptor lists - one list per request. Each list |
| * has MV_CESA_MAX_DMA_DESC descriptors. |
| * |
| * INPUT: |
| * numOfSession - maximum number of supported sessions |
| * queueDepth - number of elements in the request queue. |
| * pSramBase - virtual address of Sram |
| * osHandle - A handle used by the OS to allocate memory for the |
| * module (Passed to the OS Services layer) |
| * |
| * RETURN: |
| * MV_OK - Success |
| * MV_NO_RESOURCE - Fail, can't allocate resources: |
| * Session database, request queue, |
| * DMA descriptors list, LRU cache database. |
| * MV_NOT_ALIGNED - Sram base address is not 8 byte aligned. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvCesaHalInit (int numOfSession, int queueDepth, char* pSramBase, MV_U32 cryptEngBase, |
| void *osHandle) |
| { |
| int i, req; |
| MV_U32 descOffsetReg, configReg; |
| MV_CESA_SRAM_SA *pSramSA; |
| |
| |
| mvOsPrintf("mvCesaInit: sessions=%d, queue=%d, pSram=%p\n", |
| numOfSession, queueDepth, pSramBase); |
| |
| cesaOsHandle = osHandle; |
| /* Create Session database */ |
| pCesaSAD = mvOsMalloc(sizeof(MV_CESA_SA)*numOfSession); |
| if(pCesaSAD == NULL) |
| { |
| mvOsPrintf("mvCesaInit: Can't allocate %u bytes for %d SAs\n", |
| sizeof(MV_CESA_SA)*numOfSession, numOfSession); |
| mvCesaFinish(); |
| return MV_NO_RESOURCE; |
| } |
| memset(pCesaSAD, 0, sizeof(MV_CESA_SA)*numOfSession); |
| cesaMaxSA = numOfSession; |
| |
| /* Allocate imag of sramSA in the DRAM */ |
| cesaSramSaBuf.bufSize = sizeof(MV_CESA_SRAM_SA)*numOfSession + |
| CPU_D_CACHE_LINE_SIZE; |
| |
| cesaSramSaBuf.bufVirtPtr = mvOsIoCachedMalloc(osHandle,cesaSramSaBuf.bufSize, |
| &cesaSramSaBuf.bufPhysAddr, |
| &cesaSramSaBuf.memHandle); |
| |
| if(cesaSramSaBuf.bufVirtPtr == NULL) |
| { |
| mvOsPrintf("mvCesaInit: Can't allocate %d bytes for sramSA structures\n", |
| cesaSramSaBuf.bufSize); |
| mvCesaFinish(); |
| return MV_NO_RESOURCE; |
| } |
| memset(cesaSramSaBuf.bufVirtPtr, 0, cesaSramSaBuf.bufSize); |
| pSramSA = (MV_CESA_SRAM_SA*)MV_ALIGN_UP((MV_ULONG)cesaSramSaBuf.bufVirtPtr, |
| CPU_D_CACHE_LINE_SIZE); |
| for(i=0; i<numOfSession; i++) |
| { |
| pCesaSAD[i].pSramSA = &pSramSA[i]; |
| } |
| |
| /* Create request queue */ |
| pCesaReqFirst = mvOsMalloc(sizeof(MV_CESA_REQ)*queueDepth); |
| if(pCesaReqFirst == NULL) |
| { |
| mvOsPrintf("mvCesaInit: Can't allocate %u bytes for %d requests\n", |
| sizeof(MV_CESA_REQ)*queueDepth, queueDepth); |
| mvCesaFinish(); |
| return MV_NO_RESOURCE; |
| } |
| memset(pCesaReqFirst, 0, sizeof(MV_CESA_REQ)*queueDepth); |
| pCesaReqEmpty = pCesaReqFirst; |
| pCesaReqLast = pCesaReqFirst + (queueDepth-1); |
| pCesaReqProcess = pCesaReqEmpty; |
| cesaQueueDepth = queueDepth; |
| cesaReqResources = queueDepth; |
| #if (MV_CESA_VERSION >= 3) |
| cesaChainLength = MAX_CESA_CHAIN_LENGTH; |
| #endif |
| /* pSramBase must be 8 byte aligned */ |
| if( MV_IS_NOT_ALIGN((MV_ULONG)pSramBase, 8) ) |
| { |
| mvOsPrintf("mvCesaInit: pSramBase (%p) must be 8 byte aligned\n", |
| pSramBase); |
| mvCesaFinish(); |
| return MV_NOT_ALIGNED; |
| } |
| cesaSramVirtPtr = (MV_CESA_SRAM_MAP*)pSramBase; |
| |
| cesaCryptEngBase = cryptEngBase; |
| |
| /*memset(cesaSramVirtPtr, 0, sizeof(MV_CESA_SRAM_MAP));*/ |
| |
| /* Clear registers */ |
| MV_REG_WRITE( MV_CESA_CFG_REG, 0); |
| MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0); |
| MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0); |
| |
| /* Initialize DMA descriptor lists for all requests in Request queue */ |
| descOffsetReg = configReg = 0; |
| for(req=0; req<queueDepth; req++) |
| { |
| int frag; |
| MV_CESA_REQ* pReq; |
| MV_DMA_DESC* pDmaDesc; |
| |
| pReq = &pCesaReqFirst[req]; |
| |
| pReq->cesaDescBuf.bufSize = sizeof(MV_CESA_DESC)*MV_CESA_MAX_REQ_FRAGS + |
| CPU_D_CACHE_LINE_SIZE; |
| |
| pReq->cesaDescBuf.bufVirtPtr = |
| mvOsIoCachedMalloc(osHandle,pReq->cesaDescBuf.bufSize, |
| &pReq->cesaDescBuf.bufPhysAddr, |
| &pReq->cesaDescBuf.memHandle); |
| |
| if(pReq->cesaDescBuf.bufVirtPtr == NULL) |
| { |
| mvOsPrintf("mvCesaInit: req=%d, Can't allocate %d bytes for CESA descriptors\n", |
| req, pReq->cesaDescBuf.bufSize); |
| mvCesaFinish(); |
| return MV_NO_RESOURCE; |
| } |
| memset(pReq->cesaDescBuf.bufVirtPtr, 0, pReq->cesaDescBuf.bufSize); |
| pReq->pCesaDesc = (MV_CESA_DESC*)MV_ALIGN_UP((MV_ULONG)pReq->cesaDescBuf.bufVirtPtr, |
| CPU_D_CACHE_LINE_SIZE); |
| |
| pReq->dmaDescBuf.bufSize = sizeof(MV_DMA_DESC)*MV_CESA_MAX_DMA_DESC*MV_CESA_MAX_REQ_FRAGS + |
| CPU_D_CACHE_LINE_SIZE; |
| |
| pReq->dmaDescBuf.bufVirtPtr = |
| mvOsIoCachedMalloc(osHandle,pReq->dmaDescBuf.bufSize, |
| &pReq->dmaDescBuf.bufPhysAddr, |
| &pReq->dmaDescBuf.memHandle); |
| |
| if(pReq->dmaDescBuf.bufVirtPtr == NULL) |
| { |
| mvOsPrintf("mvCesaInit: req=%d, Can't allocate %d bytes for DMA descriptor list\n", |
| req, pReq->dmaDescBuf.bufSize); |
| mvCesaFinish(); |
| return MV_NO_RESOURCE; |
| } |
| memset(pReq->dmaDescBuf.bufVirtPtr, 0, pReq->dmaDescBuf.bufSize); |
| pDmaDesc = (MV_DMA_DESC*)MV_ALIGN_UP((MV_ULONG)pReq->dmaDescBuf.bufVirtPtr, |
| CPU_D_CACHE_LINE_SIZE); |
| |
| for(frag=0; frag<MV_CESA_MAX_REQ_FRAGS; frag++) |
| { |
| MV_CESA_DMA* pDma = &pReq->dma[frag]; |
| |
| pDma->pDmaFirst = pDmaDesc; |
| pDma->pDmaLast = NULL; |
| |
| for(i=0; i<MV_CESA_MAX_DMA_DESC-1; i++) |
| { |
| /* link all DMA descriptors together */ |
| pDma->pDmaFirst[i].phyNextDescPtr = |
| MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, &pDmaDesc[i+1])); |
| } |
| pDma->pDmaFirst[i].phyNextDescPtr = 0; |
| mvOsCacheFlush(NULL, &pDma->pDmaFirst[0], MV_CESA_MAX_DMA_DESC*sizeof(MV_DMA_DESC)); |
| |
| pDmaDesc += MV_CESA_MAX_DMA_DESC; |
| } |
| } |
| /*mvCesaCryptoIvSet(NULL, MV_CESA_MAX_IV_LENGTH);*/ |
| descOffsetReg = (MV_U16)((MV_U8*)&cesaSramVirtPtr->desc - mvCesaSramAddrGet()); |
| MV_REG_WRITE(MV_CESA_CHAN_DESC_OFFSET_REG, descOffsetReg); |
| |
| configReg |= (MV_CESA_CFG_WAIT_DMA_MASK | MV_CESA_CFG_ACT_DMA_MASK); |
| #if (MV_CESA_VERSION >= 3) |
| configReg |= MV_CESA_CFG_CHAIN_MODE_MASK; |
| #endif |
| |
| #if (MV_CESA_VERSION >= 2) |
| /* Initialize TDMA engine */ |
| MV_REG_WRITE(MV_CESA_TDMA_CTRL_REG, MV_CESA_TDMA_CTRL_VALUE); |
| MV_REG_WRITE(MV_CESA_TDMA_BYTE_COUNT_REG, 0); |
| MV_REG_WRITE(MV_CESA_TDMA_CURR_DESC_PTR_REG, 0); |
| #else |
| /* Initialize IDMA #0 engine */ |
| MV_REG_WRITE(IDMA_CTRL_LOW_REG(0), 0); |
| MV_REG_WRITE(IDMA_BYTE_COUNT_REG(0), 0); |
| MV_REG_WRITE(IDMA_CURR_DESC_PTR_REG(0), 0); |
| MV_REG_WRITE(IDMA_CTRL_HIGH_REG(0), ICCHR_ENDIAN_LITTLE |
| #ifdef MV_CPU_LE |
| | ICCHR_DESC_BYTE_SWAP_EN |
| #endif |
| ); |
| /* Clear Cause Byte of IDMA channel to be used */ |
| MV_REG_WRITE( IDMA_CAUSE_REG, ~ICICR_CAUSE_MASK_ALL(0)); |
| MV_REG_WRITE(IDMA_CTRL_LOW_REG(0), MV_CESA_IDMA_CTRL_LOW_VALUE); |
| #endif /* (MV_CESA_VERSION >= 2) */ |
| |
| /* Set CESA configuration registers */ |
| MV_REG_WRITE( MV_CESA_CFG_REG, configReg); |
| mvCesaDebugStatsClear(); |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCesaFinish - Shutdown the CESA driver |
| * |
| * DESCRIPTION: |
| * This function shutdown the CESA driver and free all allocted resources. |
| * |
| * INPUT: None |
| * |
| * RETURN: |
| * MV_OK - Success |
| * Other - Fail |
| * |
| *******************************************************************************/ |
| MV_STATUS mvCesaFinish (void) |
| { |
| int req; |
| MV_CESA_REQ* pReq; |
| |
| mvOsPrintf("mvCesaFinish: \n"); |
| |
| cesaSramVirtPtr = NULL; |
| |
| /* Free all resources: DMA list, etc. */ |
| for(req=0; req<cesaQueueDepth; req++) |
| { |
| pReq = &pCesaReqFirst[req]; |
| if(pReq->dmaDescBuf.bufVirtPtr != NULL) |
| { |
| mvOsIoCachedFree(cesaOsHandle,pReq->dmaDescBuf.bufSize, |
| pReq->dmaDescBuf.bufPhysAddr, |
| pReq->dmaDescBuf.bufVirtPtr, |
| pReq->dmaDescBuf.memHandle); |
| } |
| if(pReq->cesaDescBuf.bufVirtPtr != NULL) |
| { |
| mvOsIoCachedFree(cesaOsHandle,pReq->cesaDescBuf.bufSize, |
| pReq->cesaDescBuf.bufPhysAddr, |
| pReq->cesaDescBuf.bufVirtPtr, |
| pReq->cesaDescBuf.memHandle); |
| } |
| } |
| #if (MV_CESA_VERSION < 2) |
| MV_REG_WRITE(IDMA_CTRL_LOW_REG(0), 0); |
| #endif /* (MV_CESA_VERSION < 2) */ |
| |
| /* Free request queue */ |
| if(pCesaReqFirst != NULL) |
| { |
| mvOsFree(pCesaReqFirst); |
| pCesaReqFirst = pCesaReqLast = NULL; |
| pCesaReqEmpty = pCesaReqProcess = NULL; |
| cesaQueueDepth = cesaReqResources = 0; |
| } |
| /* Free SA database */ |
| if(pCesaSAD != NULL) |
| { |
| mvOsFree(pCesaSAD); |
| pCesaSAD = NULL; |
| cesaMaxSA = 0; |
| } |
| MV_REG_WRITE( MV_CESA_CFG_REG, 0); |
| MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0); |
| MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0); |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCesaCryptoIvSet - Set IV value for Crypto algorithm working in CBC mode |
| * |
| * DESCRIPTION: |
| * This function set IV value using by Crypto algorithms in CBC mode. |
| * Each channel has its own IV value. |
| * This function gets IV value from the caller. If no IV value passed from |
| * the caller or only part of IV passed, the function will init the rest part |
| * of IV value (or the whole IV) by random value. |
| * |
| * INPUT: |
| * MV_U8* pIV - Pointer to IV value supplied by user. If pIV==NULL |
| * the function will generate random IV value. |
| * int ivSize - size (in bytes) of IV provided by user. If ivSize is |
| * smaller than maximum IV size, the function will complete |
| * IV by random value. |
| * |
| * RETURN: |
| * MV_OK - Success |
| * Other - Fail |
| * |
| *******************************************************************************/ |
| MV_STATUS mvCesaCryptoIvSet(MV_U8* pIV, int ivSize) |
| { |
| MV_U8* pSramIV; |
| #if defined(MV646xx) |
| mvOsPrintf("mvCesaCryptoIvSet: ERR. shouldn't use this call on MV64660\n"); |
| #endif |
| pSramIV = cesaSramVirtPtr->cryptoIV; |
| if(ivSize > MV_CESA_MAX_IV_LENGTH) |
| { |
| mvOsPrintf("mvCesaCryptoIvSet: ivSize (%d) is too large\n", ivSize); |
| ivSize = MV_CESA_MAX_IV_LENGTH; |
| } |
| if(pIV != NULL) |
| { |
| memcpy(pSramIV, pIV, ivSize); |
| ivSize = MV_CESA_MAX_IV_LENGTH - ivSize; |
| pSramIV += ivSize; |
| } |
| |
| while(ivSize > 0) |
| { |
| int size, mv_random = mvOsRand(); |
| |
| size = MV_MIN(ivSize, sizeof(mv_random)); |
| memcpy(pSramIV, (void*)&mv_random, size); |
| |
| pSramIV += size; |
| ivSize -= size; |
| } |
| /* |
| mvOsCacheFlush(NULL, cesaSramVirtPtr->cryptoIV, |
| MV_CESA_MAX_IV_LENGTH); |
| mvOsCacheInvalidate(NULL, cesaSramVirtPtr->cryptoIV, |
| MV_CESA_MAX_IV_LENGTH); |
| */ |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCesaSessionOpen - Open new uni-directional crypto session |
| * |
| * DESCRIPTION: |
| * This function open new session. |
| * |
| * INPUT: |
| * MV_CESA_OPEN_SESSION *pSession - pointer to new session input parameters |
| * |
| * OUTPUT: |
| * short *pSid - session ID, should be used for all future |
| * requests over this session. |
| * |
| * RETURN: |
| * MV_OK - Session opend successfully. |
| * MV_FULL - All sessions are in use, no free place in |
| * SA database. |
| * MV_BAD_PARAM - One of session input parameters is invalid. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvCesaSessionOpen(MV_CESA_OPEN_SESSION *pSession, short* pSid) |
| { |
| short sid; |
| MV_U32 config = 0; |
| int digestSize; |
| |
| cesaStats.openedCount++; |
| |
| /* Find free entry in SAD */ |
| for(sid=0; sid<cesaMaxSA; sid++) |
| { |
| if(pCesaSAD[sid].valid == 0) |
| { |
| break; |
| } |
| } |
| if(sid == cesaMaxSA) |
| { |
| mvOsPrintf("mvCesaSessionOpen: SA Database is FULL\n"); |
| return MV_FULL; |
| } |
| |
| /* Check Input parameters for Open session */ |
| if (pSession->operation >= MV_CESA_MAX_OPERATION) |
| { |
| mvOsPrintf("mvCesaSessionOpen: Unexpected operation %d\n", |
| pSession->operation); |
| return MV_BAD_PARAM; |
| } |
| config |= (pSession->operation << MV_CESA_OPERATION_OFFSET); |
| |
| if( (pSession->direction != MV_CESA_DIR_ENCODE) && |
| (pSession->direction != MV_CESA_DIR_DECODE) ) |
| { |
| mvOsPrintf("mvCesaSessionOpen: Unexpected direction %d\n", |
| pSession->direction); |
| return MV_BAD_PARAM; |
| } |
| config |= (pSession->direction << MV_CESA_DIRECTION_BIT); |
| /* Clear SA entry */ |
| /* memset(&pCesaSAD[sid], 0, sizeof(pCesaSAD[sid])); */ |
| |
| /* Check AUTH parameters and update SA entry */ |
| if(pSession->operation != MV_CESA_CRYPTO_ONLY) |
| { |
| /* For HMAC (MD5 and SHA1) - Maximum Key size is 64 bytes */ |
| if( (pSession->macMode == MV_CESA_MAC_HMAC_MD5) || |
| (pSession->macMode == MV_CESA_MAC_HMAC_SHA1) ) |
| { |
| if(pSession->macKeyLength > MV_CESA_MAX_MAC_KEY_LENGTH) |
| { |
| mvOsPrintf("mvCesaSessionOpen: macKeyLength %d is too large\n", |
| pSession->macKeyLength); |
| return MV_BAD_PARAM; |
| } |
| mvCesaHmacIvGet(pSession->macMode, pSession->macKey, pSession->macKeyLength, |
| pCesaSAD[sid].pSramSA->macInnerIV, |
| pCesaSAD[sid].pSramSA->macOuterIV); |
| pCesaSAD[sid].macKeyLength = pSession->macKeyLength; |
| } |
| switch(pSession->macMode) |
| { |
| case MV_CESA_MAC_MD5: |
| case MV_CESA_MAC_HMAC_MD5: |
| digestSize = MV_CESA_MD5_DIGEST_SIZE; |
| break; |
| |
| case MV_CESA_MAC_SHA1: |
| case MV_CESA_MAC_HMAC_SHA1: |
| digestSize = MV_CESA_SHA1_DIGEST_SIZE; |
| break; |
| |
| default: |
| mvOsPrintf("mvCesaSessionOpen: Unexpected macMode %d\n", |
| pSession->macMode); |
| return MV_BAD_PARAM; |
| } |
| config |= (pSession->macMode << MV_CESA_MAC_MODE_OFFSET); |
| |
| /* Supported digest sizes: MD5 - 16 bytes (128 bits), */ |
| /* SHA1 - 20 bytes (160 bits) or 12 bytes (96 bits) for both */ |
| if( (pSession->digestSize != digestSize) && (pSession->digestSize != 12)) |
| { |
| mvOsPrintf("mvCesaSessionOpen: Unexpected digest size %d\n", |
| pSession->digestSize); |
| mvOsPrintf("\t Valid values [bytes]: MD5-16, SHA1-20, Both-12\n"); |
| return MV_BAD_PARAM; |
| } |
| pCesaSAD[sid].digestSize = pSession->digestSize; |
| |
| if(pCesaSAD[sid].digestSize == 12) |
| { |
| /* Set MV_CESA_MAC_DIGEST_SIZE_BIT if digest size is 96 bits */ |
| config |= (MV_CESA_MAC_DIGEST_96B << MV_CESA_MAC_DIGEST_SIZE_BIT); |
| } |
| } |
| |
| /* Check CRYPTO parameters and update SA entry */ |
| if(pSession->operation != MV_CESA_MAC_ONLY) |
| { |
| switch(pSession->cryptoAlgorithm) |
| { |
| case MV_CESA_CRYPTO_DES: |
| pCesaSAD[sid].cryptoKeyLength = MV_CESA_DES_KEY_LENGTH; |
| pCesaSAD[sid].cryptoBlockSize = MV_CESA_DES_BLOCK_SIZE; |
| break; |
| |
| case MV_CESA_CRYPTO_3DES: |
| pCesaSAD[sid].cryptoKeyLength = MV_CESA_3DES_KEY_LENGTH; |
| pCesaSAD[sid].cryptoBlockSize = MV_CESA_DES_BLOCK_SIZE; |
| /* Only EDE mode is supported */ |
| config |= (MV_CESA_CRYPTO_3DES_EDE << |
| MV_CESA_CRYPTO_3DES_MODE_BIT); |
| break; |
| |
| case MV_CESA_CRYPTO_AES: |
| switch(pSession->cryptoKeyLength) |
| { |
| case 16: |
| pCesaSAD[sid].cryptoKeyLength = MV_CESA_AES_128_KEY_LENGTH; |
| config |= (MV_CESA_CRYPTO_AES_KEY_128 << |
| MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET); |
| break; |
| |
| case 24: |
| pCesaSAD[sid].cryptoKeyLength = MV_CESA_AES_192_KEY_LENGTH; |
| config |= (MV_CESA_CRYPTO_AES_KEY_192 << |
| MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET); |
| break; |
| |
| case 32: |
| default: |
| pCesaSAD[sid].cryptoKeyLength = MV_CESA_AES_256_KEY_LENGTH; |
| config |= (MV_CESA_CRYPTO_AES_KEY_256 << |
| MV_CESA_CRYPTO_AES_KEY_LEN_OFFSET); |
| break; |
| } |
| pCesaSAD[sid].cryptoBlockSize = MV_CESA_AES_BLOCK_SIZE; |
| break; |
| |
| default: |
| mvOsPrintf("mvCesaSessionOpen: Unexpected cryptoAlgorithm %d\n", |
| pSession->cryptoAlgorithm); |
| return MV_BAD_PARAM; |
| } |
| config |= (pSession->cryptoAlgorithm << MV_CESA_CRYPTO_ALG_OFFSET); |
| |
| if(pSession->cryptoKeyLength != pCesaSAD[sid].cryptoKeyLength) |
| { |
| mvOsPrintf("cesaSessionOpen: Wrong CryptoKeySize %d != %d\n", |
| pSession->cryptoKeyLength, pCesaSAD[sid].cryptoKeyLength); |
| return MV_BAD_PARAM; |
| } |
| |
| /* Copy Crypto key */ |
| if( (pSession->cryptoAlgorithm == MV_CESA_CRYPTO_AES) && |
| (pSession->direction == MV_CESA_DIR_DECODE)) |
| { |
| /* Crypto Key for AES decode is computed from original key material */ |
| /* and depend on cryptoKeyLength (128/192/256 bits) */ |
| aesMakeKey(pCesaSAD[sid].pSramSA->cryptoKey, pSession->cryptoKey, |
| pSession->cryptoKeyLength*8, MV_CESA_AES_BLOCK_SIZE*8); |
| } |
| else |
| { |
| /*panic("mvCesaSessionOpen2");*/ |
| memcpy(pCesaSAD[sid].pSramSA->cryptoKey, pSession->cryptoKey, |
| pCesaSAD[sid].cryptoKeyLength); |
| |
| } |
| |
| switch(pSession->cryptoMode) |
| { |
| case MV_CESA_CRYPTO_ECB: |
| pCesaSAD[sid].cryptoIvSize = 0; |
| break; |
| |
| case MV_CESA_CRYPTO_CBC: |
| pCesaSAD[sid].cryptoIvSize = pCesaSAD[sid].cryptoBlockSize; |
| break; |
| |
| case MV_CESA_CRYPTO_CTR: |
| /* Supported only for AES algorithm */ |
| if(pSession->cryptoAlgorithm != MV_CESA_CRYPTO_AES) |
| { |
| mvOsPrintf("mvCesaSessionOpen: CRYPTO CTR mode supported for AES only\n"); |
| return MV_BAD_PARAM; |
| } |
| pCesaSAD[sid].cryptoIvSize = 0; |
| pCesaSAD[sid].ctrMode = 1; |
| /* Replace to ECB mode for HW */ |
| pSession->cryptoMode = MV_CESA_CRYPTO_ECB; |
| break; |
| |
| default: |
| mvOsPrintf("mvCesaSessionOpen: Unexpected cryptoMode %d\n", |
| pSession->cryptoMode); |
| return MV_BAD_PARAM; |
| } |
| |
| config |= (pSession->cryptoMode << MV_CESA_CRYPTO_MODE_BIT); |
| } |
| pCesaSAD[sid].config = config; |
| |
| mvOsCacheFlush(NULL, pCesaSAD[sid].pSramSA, sizeof(MV_CESA_SRAM_SA)); |
| if(pSid != NULL) |
| *pSid = sid; |
| |
| pCesaSAD[sid].valid = 1; |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCesaSessionClose - Close active crypto session |
| * |
| * DESCRIPTION: |
| * This function closes existing session |
| * |
| * INPUT: |
| * short sid - Unique identifier of the session to be closed |
| * |
| * RETURN: |
| * MV_OK - Session closed successfully. |
| * MV_BAD_PARAM - Session identifier is out of valid range. |
| * MV_NOT_FOUND - There is no active session with such ID. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvCesaSessionClose(short sid) |
| { |
| cesaStats.closedCount++; |
| |
| if(sid >= cesaMaxSA) |
| { |
| mvOsPrintf("CESA Error: sid (%d) is too big\n", sid); |
| return MV_BAD_PARAM; |
| } |
| if(pCesaSAD[sid].valid == 0) |
| { |
| mvOsPrintf("CESA Warning: Session (sid=%d) is invalid\n", sid); |
| return MV_NOT_FOUND; |
| } |
| if(cesaLastSid == sid) |
| cesaLastSid = -1; |
| |
| pCesaSAD[sid].valid = 0; |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCesaAction - Perform crypto operation |
| * |
| * DESCRIPTION: |
| * This function set new CESA request FIFO queue for further HW processing. |
| * The function checks request parameters before set new request to the queue. |
| * If one of the CESA channels is ready for processing the request will be |
| * passed to HW. When request processing is finished the CESA interrupt will |
| * be generated by HW. The caller should call mvCesaReadyGet() function to |
| * complete request processing and get result. |
| * |
| * INPUT: |
| * MV_CESA_COMMAND *pCmd - pointer to new CESA request. |
| * It includes pointers to Source and Destination |
| * buffers, session identifier get from |
| * mvCesaSessionOpen() function, pointer to caller |
| * private data and all needed crypto parameters. |
| * |
| * RETURN: |
| * MV_OK - request successfully added to request queue |
| * and will be processed. |
| * MV_NO_MORE - request successfully added to request queue and will |
| * be processed, but request queue became Full and next |
| * request will not be accepted. |
| * MV_NO_RESOURCE - request queue is FULL and the request can not |
| * be processed. |
| * MV_OUT_OF_CPU_MEM - memory allocation needed for request processing is |
| * failed. Request can not be processed. |
| * MV_NOT_ALLOWED - This mixed request (CRYPTO+MAC) can not be processed |
| * as one request and should be splitted for two requests: |
| * CRYPTO_ONLY and MAC_ONLY. |
| * MV_BAD_PARAM - One of the request parameters is out of valid range. |
| * The request can not be processed. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvCesaAction (MV_CESA_COMMAND *pCmd) |
| { |
| MV_STATUS status; |
| MV_CESA_REQ* pReq = pCesaReqEmpty; |
| int sid = pCmd->sessionId; |
| MV_CESA_SA* pSA = &pCesaSAD[sid]; |
| #if (MV_CESA_VERSION >= 3) |
| MV_CESA_REQ* pFromReq; |
| MV_CESA_REQ* pToReq; |
| #endif |
| cesaStats.reqCount++; |
| |
| /* Check that the request queue is not FULL */ |
| if(cesaReqResources == 0) |
| return MV_NO_RESOURCE; |
| |
| if( (sid >= cesaMaxSA) || (!pSA->valid) ) |
| { |
| mvOsPrintf("CESA Action Error: Session sid=%d is INVALID\n", sid); |
| return MV_BAD_PARAM; |
| } |
| pSA->count++; |
| |
| if(pSA->ctrMode) |
| { |
| /* AES in CTR mode can't be mixed with Authentication */ |
| if( (pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) |
| { |
| mvOsPrintf("mvCesaAction : CRYPTO CTR mode can't be mixed with AUTH\n"); |
| return MV_NOT_ALLOWED; |
| } |
| /* All other request parameters should not be checked because key stream */ |
| /* (not user data) processed by AES HW engine */ |
| pReq->pOrgCmd = pCmd; |
| /* Allocate temporary pCmd structure for Key stream */ |
| pCmd = mvCesaCtrModeInit(); |
| if(pCmd == NULL) |
| return MV_OUT_OF_CPU_MEM; |
| |
| /* Prepare Key stream */ |
| mvCesaCtrModePrepare(pCmd, pReq->pOrgCmd); |
| pReq->fixOffset = 0; |
| } |
| else |
| { |
| /* Check request parameters and calculae fixOffset */ |
| status = mvCesaParamCheck(pSA, pCmd, &pReq->fixOffset); |
| if(status != MV_OK) |
| { |
| return status; |
| } |
| } |
| pReq->pCmd = pCmd; |
| |
| /* Check if the packet need fragmentation */ |
| if(pCmd->pSrc->mbufSize <= sizeof(cesaSramVirtPtr->buf) ) |
| { |
| /* request size is smaller than single buffer size */ |
| pReq->fragMode = MV_CESA_FRAG_NONE; |
| |
| /* Prepare NOT fragmented packets */ |
| status = mvCesaReqProcess(pReq); |
| if(status != MV_OK) |
| { |
| mvOsPrintf("CesaReady: ReqProcess error: pReq=%p, status=0x%x\n", |
| pReq, status); |
| } |
| #if (MV_CESA_VERSION >= 3) |
| pReq->frags.numFrag = 1; |
| #endif |
| } |
| else |
| { |
| MV_U8 frag = 0; |
| |
| /* request size is larger than buffer size - needs fragmentation */ |
| |
| /* Check restrictions for processing fragmented packets */ |
| status = mvCesaFragParamCheck(pSA, pCmd); |
| if(status != MV_OK) |
| return status; |
| |
| pReq->fragMode = MV_CESA_FRAG_FIRST; |
| pReq->frags.nextFrag = 0; |
| |
| /* Prepare Process Fragmented packets */ |
| while(pReq->fragMode != MV_CESA_FRAG_LAST) |
| { |
| if(frag >= MV_CESA_MAX_REQ_FRAGS) |
| { |
| mvOsPrintf("mvCesaAction Error: Too large request frag=%d\n", frag); |
| return MV_OUT_OF_CPU_MEM; |
| } |
| status = mvCesaFragReqProcess(pReq, frag); |
| if(status == MV_OK) { |
| #if (MV_CESA_VERSION >= 3) |
| if(frag) { |
| pReq->dma[frag-1].pDmaLast->phyNextDescPtr = |
| MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, pReq->dma[frag].pDmaFirst)); |
| mvOsCacheFlush(NULL, pReq->dma[frag-1].pDmaLast, sizeof(MV_DMA_DESC)); |
| } |
| #endif |
| frag++; |
| } |
| } |
| pReq->frags.numFrag = frag; |
| #if (MV_CESA_VERSION >= 3) |
| if(chainReqNum) { |
| chainReqNum += pReq->frags.numFrag; |
| if(chainReqNum >= MAX_CESA_CHAIN_LENGTH) |
| chainReqNum = MAX_CESA_CHAIN_LENGTH; |
| } |
| #endif |
| } |
| |
| pReq->state = MV_CESA_PENDING; |
| |
| pCesaReqEmpty = MV_CESA_REQ_NEXT_PTR(pReq); |
| cesaReqResources -= 1; |
| |
| /* #ifdef CESA_DEBUG */ |
| if( (cesaQueueDepth - cesaReqResources) > cesaStats.maxReqCount) |
| cesaStats.maxReqCount = (cesaQueueDepth - cesaReqResources); |
| /* #endif CESA_DEBUG */ |
| |
| cesaLastSid = sid; |
| |
| #if (MV_CESA_VERSION >= 3) |
| /* Are we within chain bounderies and follows the first request ? */ |
| if((chainReqNum > 0) && (chainReqNum < MAX_CESA_CHAIN_LENGTH)) { |
| if(chainIndex) { |
| pFromReq = MV_CESA_REQ_PREV_PTR(pReq); |
| pToReq = pReq; |
| pReq->state = MV_CESA_CHAIN; |
| /* assume concatenating is possible */ |
| pFromReq->dma[pFromReq->frags.numFrag-1].pDmaLast->phyNextDescPtr = |
| MV_32BIT_LE(mvCesaVirtToPhys(&pToReq->dmaDescBuf, pToReq->dma[0].pDmaFirst)); |
| mvOsCacheFlush(NULL, pFromReq->dma[pFromReq->frags.numFrag-1].pDmaLast, sizeof(MV_DMA_DESC)); |
| |
| /* align active & next pointers */ |
| if(pNextActiveChain->state != MV_CESA_PENDING) |
| pEndCurrChain = pNextActiveChain = MV_CESA_REQ_NEXT_PTR(pReq); |
| } |
| else { /* we have only one chain, start new one */ |
| chainReqNum = 0; |
| chainIndex++; |
| /* align active & next pointers */ |
| if(pNextActiveChain->state != MV_CESA_PENDING) |
| pEndCurrChain = pNextActiveChain = pReq; |
| } |
| } |
| else { |
| /* In case we concatenate full chain */ |
| if(chainReqNum == MAX_CESA_CHAIN_LENGTH) { |
| chainIndex++; |
| if(pNextActiveChain->state != MV_CESA_PENDING) |
| pEndCurrChain = pNextActiveChain = pReq; |
| chainReqNum = 0; |
| } |
| |
| pReq = pCesaReqProcess; |
| if(pReq->state == MV_CESA_PENDING) { |
| pNextActiveChain = pReq; |
| pEndCurrChain = MV_CESA_REQ_NEXT_PTR(pReq); |
| /* Start Process new request */ |
| mvCesaReqProcessStart(pReq); |
| } |
| } |
| |
| chainReqNum++; |
| |
| if((chainIndex < MAX_CESA_CHAIN_LENGTH) && (chainReqNum > cesaStats.maxChainUsage)) |
| cesaStats.maxChainUsage = chainReqNum; |
| |
| #else |
| |
| /* Check status of CESA channels and process requests if possible */ |
| pReq = pCesaReqProcess; |
| if(pReq->state == MV_CESA_PENDING) |
| { |
| /* Start Process new request */ |
| mvCesaReqProcessStart(pReq); |
| } |
| #endif |
| /* If request queue became FULL - return MV_NO_MORE */ |
| if(cesaReqResources == 0) |
| return MV_NO_MORE; |
| |
| return MV_OK; |
| |
| } |
| |
| /******************************************************************************* |
| * mvCesaReadyGet - Get crypto request that processing is finished |
| * |
| * DESCRIPTION: |
| * This function complete request processing and return ready request to |
| * caller. To don't miss interrupts the caller must call this function |
| * while MV_OK or MV_TERMINATE values returned. |
| * |
| * INPUT: |
| * MV_U32 chanMap - map of CESA channels finished thier job |
| * accordingly with CESA Cause register. |
| * MV_CESA_RESULT* pResult - pointer to structure contains information |
| * about ready request. It includes pointer to |
| * user private structure "pReqPrv", session identifier |
| * for this request "sessionId" and return code. |
| * Return code set to MV_FAIL if calculated digest value |
| * on decode direction is different than digest value |
| * in the packet. |
| * |
| * RETURN: |
| * MV_OK - Success, ready request is returned. |
| * MV_NOT_READY - Next request is not ready yet. New interrupt will |
| * be generated for futher request processing. |
| * MV_EMPTY - There is no more request for processing. |
| * MV_BUSY - Fragmented request is not ready yet. |
| * MV_TERMINATE - Call this function once more to complete processing |
| * of fragmented request. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvCesaReadyGet(MV_CESA_RESULT* pResult) |
| { |
| MV_STATUS status, readyStatus = MV_NOT_READY; |
| MV_U32 statusReg; |
| MV_CESA_REQ* pReq; |
| MV_CESA_SA* pSA; |
| |
| #if (MV_CESA_VERSION >= 3) |
| if(isFirstReq == MV_TRUE) { |
| if(chainIndex == 0) |
| chainReqNum = 0; |
| |
| isFirstReq = MV_FALSE; |
| |
| if(pNextActiveChain->state == MV_CESA_PENDING) { |
| /* Start request Process */ |
| mvCesaReqProcessStart(pNextActiveChain); |
| pEndCurrChain = pNextActiveChain; |
| if(chainIndex > 0) |
| chainIndex--; |
| /* Update pNextActiveChain to next chain head */ |
| while(pNextActiveChain->state == MV_CESA_CHAIN) |
| pNextActiveChain = MV_CESA_REQ_NEXT_PTR(pNextActiveChain); |
| } |
| } |
| |
| /* Check if there are more processed requests - can we remove pEndCurrChain ??? */ |
| if(pCesaReqProcess == pEndCurrChain) { |
| isFirstReq = MV_TRUE; |
| pEndCurrChain = pNextActiveChain; |
| #else |
| if(pCesaReqProcess->state != MV_CESA_PROCESS) { |
| #endif |
| return MV_EMPTY; |
| } |
| |
| #ifdef CESA_DEBUG |
| statusReg = MV_REG_READ(MV_CESA_STATUS_REG); |
| if( statusReg & MV_CESA_STATUS_ACTIVE_MASK ) |
| { |
| mvOsPrintf("mvCesaReadyGet: Not Ready, Status = 0x%x\n", statusReg); |
| cesaStats.notReadyCount++; |
| return MV_NOT_READY; |
| } |
| #endif /* CESA_DEBUG */ |
| |
| cesaStats.readyCount++; |
| |
| pReq = pCesaReqProcess; |
| pSA = &pCesaSAD[pReq->pCmd->sessionId]; |
| |
| pResult->retCode = MV_OK; |
| if(pReq->fragMode != MV_CESA_FRAG_NONE) |
| { |
| MV_U8* pNewDigest; |
| int frag; |
| #if (MV_CESA_VERSION >= 3) |
| pReq->frags.nextFrag = 1; |
| while(pReq->frags.nextFrag <= pReq->frags.numFrag) { |
| #endif |
| frag = (pReq->frags.nextFrag - 1); |
| |
| /* Restore DMA descriptor list */ |
| pReq->dma[frag].pDmaLast->phyNextDescPtr = |
| MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, &pReq->dma[frag].pDmaLast[1])); |
| pReq->dma[frag].pDmaLast = NULL; |
| |
| /* Special processing for finished fragmented request */ |
| if(pReq->frags.nextFrag >= pReq->frags.numFrag) |
| { |
| mvCesaMbufCacheUnmap(pReq->pCmd->pDst, 0, pReq->pCmd->pDst->mbufSize); |
| |
| /* Fragmented packet is ready */ |
| if( (pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) |
| { |
| int macDataSize = pReq->pCmd->macLength - pReq->frags.macSize; |
| |
| if(macDataSize != 0) |
| { |
| /* Calculate all other blocks by SW */ |
| mvCesaFragAuthComplete(pReq, pSA, macDataSize); |
| } |
| |
| /* Copy new digest from SRAM to the Destination buffer */ |
| pNewDigest = cesaSramVirtPtr->buf + pReq->frags.newDigestOffset; |
| status = mvCesaCopyToMbuf(pNewDigest, pReq->pCmd->pDst, |
| pReq->pCmd->digestOffset, pSA->digestSize); |
| |
| /* For decryption: Compare new digest value with original one */ |
| if((pSA->config & MV_CESA_DIRECTION_MASK) == |
| (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT)) |
| { |
| if( memcmp(pNewDigest, pReq->frags.orgDigest, pSA->digestSize) != 0) |
| { |
| /* |
| mvOsPrintf("Digest error: chan=%d, newDigest=%p, orgDigest=%p, status = 0x%x\n", |
| chan, pNewDigest, pReq->frags.orgDigest, MV_REG_READ(MV_CESA_STATUS_REG)); |
| */ |
| /* Signiture verification is failed */ |
| pResult->retCode = MV_FAIL; |
| } |
| } |
| } |
| readyStatus = MV_OK; |
| } |
| #if (MV_CESA_VERSION >= 3) |
| pReq->frags.nextFrag++; |
| } |
| #endif |
| } |
| else |
| { |
| mvCesaMbufCacheUnmap(pReq->pCmd->pDst, 0, pReq->pCmd->pDst->mbufSize); |
| |
| /* Restore DMA descriptor list */ |
| pReq->dma[0].pDmaLast->phyNextDescPtr = |
| MV_32BIT_LE(mvCesaVirtToPhys(&pReq->dmaDescBuf, &pReq->dma[0].pDmaLast[1])); |
| pReq->dma[0].pDmaLast = NULL; |
| if( ((pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) && |
| ((pSA->config & MV_CESA_DIRECTION_MASK) == |
| (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT)) ) |
| { |
| /* For AUTH on decode : Check Digest result in Status register */ |
| statusReg = MV_REG_READ(MV_CESA_STATUS_REG); |
| if(statusReg & MV_CESA_STATUS_DIGEST_ERR_MASK) |
| { |
| /* |
| mvOsPrintf("Digest error: chan=%d, status = 0x%x\n", |
| chan, statusReg); |
| */ |
| /* Signiture verification is failed */ |
| pResult->retCode = MV_FAIL; |
| } |
| } |
| readyStatus = MV_OK; |
| } |
| |
| if(readyStatus == MV_OK) |
| { |
| /* If Request is ready - Prepare pResult structure */ |
| pResult->pReqPrv = pReq->pCmd->pReqPrv; |
| pResult->sessionId = pReq->pCmd->sessionId; |
| |
| pReq->state = MV_CESA_IDLE; |
| pCesaReqProcess = MV_CESA_REQ_NEXT_PTR(pReq); |
| cesaReqResources++; |
| |
| if(pSA->ctrMode) |
| { |
| /* For AES CTR mode - complete processing and free allocated resources */ |
| mvCesaCtrModeComplete(pReq->pOrgCmd, pReq->pCmd); |
| mvCesaCtrModeFinish(pReq->pCmd); |
| pReq->pOrgCmd = NULL; |
| } |
| } |
| |
| #if (MV_CESA_VERSION < 3) |
| if(pCesaReqProcess->state == MV_CESA_PROCESS) |
| { |
| /* Start request Process */ |
| mvCesaReqProcessStart(pCesaReqProcess); |
| if(readyStatus == MV_NOT_READY) |
| readyStatus = MV_BUSY; |
| } |
| else if(pCesaReqProcess != pCesaReqEmpty) |
| { |
| /* Start process new request from the queue */ |
| mvCesaReqProcessStart(pCesaReqProcess); |
| } |
| #endif |
| return readyStatus; |
| } |
| |
| /***************** Functions to work with CESA_MBUF structure ******************/ |
| |
| /******************************************************************************* |
| * mvCesaMbufOffset - Locate offset in the Mbuf structure |
| * |
| * DESCRIPTION: |
| * This function locates offset inside Multi-Bufeer structure. |
| * It get fragment number and place in the fragment where the offset |
| * is located. |
| * |
| * |
| * INPUT: |
| * MV_CESA_MBUF* pMbuf - Pointer to multi-buffer structure |
| * int offset - Offset from the beginning of the data presented by |
| * the Mbuf structure. |
| * |
| * OUTPUT: |
| * int* pBufOffset - Offset from the beginning of the fragment where |
| * the offset is located. |
| * |
| * RETURN: |
| * int - Number of fragment, where the offset is located\ |
| * |
| *******************************************************************************/ |
| int mvCesaMbufOffset(MV_CESA_MBUF* pMbuf, int offset, int* pBufOffset) |
| { |
| int frag = 0; |
| |
| while(offset > 0) |
| { |
| if(frag >= pMbuf->numFrags) |
| { |
| mvOsPrintf("mvCesaMbufOffset: Error: frag (%d) > numFrags (%d)\n", |
| frag, pMbuf->numFrags); |
| return MV_INVALID; |
| } |
| if(offset < pMbuf->pFrags[frag].bufSize) |
| { |
| break; |
| } |
| offset -= pMbuf->pFrags[frag].bufSize; |
| frag++; |
| } |
| if(pBufOffset != NULL) |
| *pBufOffset = offset; |
| |
| return frag; |
| } |
| |
| /******************************************************************************* |
| * mvCesaCopyFromMbuf - Copy data from the Mbuf structure to continuous buffer |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_U8* pDstBuf - Pointer to continuous buffer, where data is |
| * copied to. |
| * MV_CESA_MBUF* pSrcMbuf - Pointer to multi-buffer structure where data is |
| * copied from. |
| * int offset - Offset in the Mbuf structure where located first |
| * byte of data should be copied. |
| * int size - Size of data should be copied |
| * |
| * RETURN: |
| * MV_OK - Success, all data is copied successfully. |
| * MV_OUT_OF_RANGE - Failed, offset is out of Multi-buffer data range. |
| * No data is copied. |
| * MV_EMPTY - Multi-buffer structure has not enough data to copy |
| * Data from the offset to end of Mbuf data is copied. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvCesaCopyFromMbuf(MV_U8* pDstBuf, MV_CESA_MBUF* pSrcMbuf, |
| int offset, int size) |
| { |
| int frag, fragOffset, bufSize; |
| MV_U8* pBuf; |
| |
| if(size == 0) |
| return MV_OK; |
| |
| frag = mvCesaMbufOffset(pSrcMbuf, offset, &fragOffset); |
| if(frag == MV_INVALID) |
| { |
| mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset); |
| return MV_OUT_OF_RANGE; |
| } |
| |
| bufSize = pSrcMbuf->pFrags[frag].bufSize - fragOffset; |
| pBuf = pSrcMbuf->pFrags[frag].bufVirtPtr + fragOffset; |
| while(MV_TRUE) |
| { |
| if(size <= bufSize) |
| { |
| memcpy(pDstBuf, pBuf, size); |
| return MV_OK; |
| } |
| memcpy(pDstBuf, pBuf, bufSize); |
| size -= bufSize; |
| frag++; |
| pDstBuf += bufSize; |
| if(frag >= pSrcMbuf->numFrags) |
| break; |
| |
| bufSize = pSrcMbuf->pFrags[frag].bufSize; |
| pBuf = pSrcMbuf->pFrags[frag].bufVirtPtr; |
| } |
| mvOsPrintf("mvCesaCopyFromMbuf: Mbuf is EMPTY - %d bytes isn't copied\n", |
| size); |
| return MV_EMPTY; |
| } |
| |
| /******************************************************************************* |
| * mvCesaCopyToMbuf - Copy data from continuous buffer to the Mbuf structure |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_U8* pSrcBuf - Pointer to continuous buffer, where data is |
| * copied from. |
| * MV_CESA_MBUF* pDstMbuf - Pointer to multi-buffer structure where data is |
| * copied to. |
| * int offset - Offset in the Mbuf structure where located first |
| * byte of data should be copied. |
| * int size - Size of data should be copied |
| * |
| * RETURN: |
| * MV_OK - Success, all data is copied successfully. |
| * MV_OUT_OF_RANGE - Failed, offset is out of Multi-buffer data range. |
| * No data is copied. |
| * MV_FULL - Multi-buffer structure has not enough place to copy |
| * all data. Data from the offset to end of Mbuf data |
| * is copied. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvCesaCopyToMbuf(MV_U8* pSrcBuf, MV_CESA_MBUF* pDstMbuf, |
| int offset, int size) |
| { |
| int frag, fragOffset, bufSize; |
| MV_U8* pBuf; |
| |
| if(size == 0) |
| return MV_OK; |
| |
| frag = mvCesaMbufOffset(pDstMbuf, offset, &fragOffset); |
| if(frag == MV_INVALID) |
| { |
| mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset); |
| return MV_OUT_OF_RANGE; |
| } |
| |
| bufSize = pDstMbuf->pFrags[frag].bufSize - fragOffset; |
| pBuf = pDstMbuf->pFrags[frag].bufVirtPtr + fragOffset; |
| while(MV_TRUE) |
| { |
| if(size <= bufSize) |
| { |
| memcpy(pBuf, pSrcBuf, size); |
| return MV_OK; |
| } |
| memcpy(pBuf, pSrcBuf, bufSize); |
| size -= bufSize; |
| frag++; |
| pSrcBuf += bufSize; |
| if(frag >= pDstMbuf->numFrags) |
| break; |
| |
| bufSize = pDstMbuf->pFrags[frag].bufSize; |
| pBuf = pDstMbuf->pFrags[frag].bufVirtPtr; |
| } |
| mvOsPrintf("mvCesaCopyToMbuf: Mbuf is FULL - %d bytes isn't copied\n", |
| size); |
| return MV_FULL; |
| } |
| |
| /******************************************************************************* |
| * mvCesaMbufCopy - Copy data from one Mbuf structure to the other Mbuf structure |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * |
| * MV_CESA_MBUF* pDstMbuf - Pointer to multi-buffer structure where data is |
| * copied to. |
| * int dstMbufOffset - Offset in the dstMbuf structure where first byte |
| * of data should be copied to. |
| * MV_CESA_MBUF* pSrcMbuf - Pointer to multi-buffer structure where data is |
| * copied from. |
| * int srcMbufOffset - Offset in the srcMbuf structure where first byte |
| * of data should be copied from. |
| * int size - Size of data should be copied |
| * |
| * RETURN: |
| * MV_OK - Success, all data is copied successfully. |
| * MV_OUT_OF_RANGE - Failed, srcMbufOffset or dstMbufOffset is out of |
| * srcMbuf or dstMbuf structure correspondently. |
| * No data is copied. |
| * MV_BAD_SIZE - srcMbuf or dstMbuf structure is too small to copy |
| * all data. Partial data is copied |
| * |
| *******************************************************************************/ |
| MV_STATUS mvCesaMbufCopy(MV_CESA_MBUF* pMbufDst, int dstMbufOffset, |
| MV_CESA_MBUF* pMbufSrc, int srcMbufOffset, int size) |
| { |
| int srcFrag, dstFrag, srcSize, dstSize, srcOffset, dstOffset; |
| int copySize; |
| MV_U8 *pSrc, *pDst; |
| |
| if(size == 0) |
| return MV_OK; |
| |
| srcFrag = mvCesaMbufOffset(pMbufSrc, srcMbufOffset, &srcOffset); |
| if(srcFrag == MV_INVALID) |
| { |
| mvOsPrintf("CESA srcMbuf Error: offset (%d) out of range\n", srcMbufOffset); |
| return MV_OUT_OF_RANGE; |
| } |
| pSrc = pMbufSrc->pFrags[srcFrag].bufVirtPtr + srcOffset; |
| srcSize = pMbufSrc->pFrags[srcFrag].bufSize - srcOffset; |
| |
| dstFrag = mvCesaMbufOffset(pMbufDst, dstMbufOffset, &dstOffset); |
| if(dstFrag == MV_INVALID) |
| { |
| mvOsPrintf("CESA dstMbuf Error: offset (%d) out of range\n", dstMbufOffset); |
| return MV_OUT_OF_RANGE; |
| } |
| pDst = pMbufDst->pFrags[dstFrag].bufVirtPtr + dstOffset; |
| dstSize = pMbufDst->pFrags[dstFrag].bufSize - dstOffset; |
| |
| while(size > 0) |
| { |
| copySize = MV_MIN(srcSize, dstSize); |
| if(size <= copySize) |
| { |
| memcpy(pDst, pSrc, size); |
| return MV_OK; |
| } |
| memcpy(pDst, pSrc, copySize); |
| size -= copySize; |
| srcSize -= copySize; |
| dstSize -= copySize; |
| |
| if(srcSize == 0) |
| { |
| srcFrag++; |
| if(srcFrag >= pMbufSrc->numFrags) |
| break; |
| |
| pSrc = pMbufSrc->pFrags[srcFrag].bufVirtPtr; |
| srcSize = pMbufSrc->pFrags[srcFrag].bufSize; |
| } |
| |
| if(dstSize == 0) |
| { |
| dstFrag++; |
| if(dstFrag >= pMbufDst->numFrags) |
| break; |
| |
| pDst = pMbufDst->pFrags[dstFrag].bufVirtPtr; |
| dstSize = pMbufDst->pFrags[dstFrag].bufSize; |
| } |
| } |
| mvOsPrintf("mvCesaMbufCopy: BAD size - %d bytes isn't copied\n", |
| size); |
| |
| return MV_BAD_SIZE; |
| } |
| |
| static MV_STATUS mvCesaMbufCacheUnmap(MV_CESA_MBUF* pMbuf, int offset, int size) |
| { |
| int frag, fragOffset, bufSize; |
| MV_U8* pBuf; |
| |
| if(size == 0) |
| return MV_OK; |
| |
| frag = mvCesaMbufOffset(pMbuf, offset, &fragOffset); |
| if(frag == MV_INVALID) |
| { |
| mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset); |
| return MV_OUT_OF_RANGE; |
| } |
| |
| bufSize = pMbuf->pFrags[frag].bufSize - fragOffset; |
| pBuf = pMbuf->pFrags[frag].bufVirtPtr + fragOffset; |
| while(MV_TRUE) |
| { |
| if(size <= bufSize) |
| { |
| mvOsCacheUnmap(NULL, mvOsIoVirtToPhy(NULL, pBuf), size); |
| return MV_OK; |
| } |
| |
| mvOsCacheUnmap(NULL, mvOsIoVirtToPhy(NULL, pBuf), bufSize); |
| size -= bufSize; |
| frag++; |
| if(frag >= pMbuf->numFrags) |
| break; |
| |
| bufSize = pMbuf->pFrags[frag].bufSize; |
| pBuf = pMbuf->pFrags[frag].bufVirtPtr; |
| } |
| mvOsPrintf("%s: Mbuf is FULL - %d bytes isn't Unmapped\n", |
| __FUNCTION__, size); |
| return MV_FULL; |
| } |
| |
| |
| /*************************************** Local Functions ******************************/ |
| |
| /******************************************************************************* |
| * mvCesaFragReqProcess - Process fragmented request |
| * |
| * DESCRIPTION: |
| * This function processes a fragment of fragmented request (First, Middle or Last) |
| * |
| * |
| * INPUT: |
| * MV_CESA_REQ* pReq - Pointer to the request in the request queue. |
| * |
| * RETURN: |
| * MV_OK - The fragment is successfully passed to HW for processing. |
| * MV_TERMINATE - Means, that HW finished its work on this packet and no more |
| * interrupts will be generated for this request. |
| * Function mvCesaReadyGet() must be called to complete request |
| * processing and get request result. |
| * |
| *******************************************************************************/ |
| static MV_STATUS mvCesaFragReqProcess(MV_CESA_REQ* pReq, MV_U8 frag) |
| { |
| int i, copySize, cryptoDataSize, macDataSize, sid; |
| int cryptoIvOffset, digestOffset; |
| MV_U32 config; |
| MV_CESA_COMMAND* pCmd = pReq->pCmd; |
| MV_CESA_SA* pSA; |
| MV_CESA_MBUF* pMbuf; |
| MV_DMA_DESC* pDmaDesc = pReq->dma[frag].pDmaFirst; |
| MV_U8* pSramBuf = cesaSramVirtPtr->buf; |
| int macTotalLen = 0; |
| int fixOffset, cryptoOffset, macOffset; |
| |
| cesaStats.fragCount++; |
| |
| sid = pReq->pCmd->sessionId; |
| |
| pSA = &pCesaSAD[sid]; |
| |
| cryptoIvOffset = digestOffset = 0; |
| i = macDataSize = 0; |
| cryptoDataSize = 0; |
| |
| /* First fragment processing */ |
| if(pReq->fragMode == MV_CESA_FRAG_FIRST) |
| { |
| /* pReq->frags monitors processing of fragmented request between fragments */ |
| pReq->frags.bufOffset = 0; |
| pReq->frags.cryptoSize = 0; |
| pReq->frags.macSize = 0; |
| |
| config = pSA->config | (MV_CESA_FRAG_FIRST << MV_CESA_FRAG_MODE_OFFSET); |
| |
| /* fixOffset can be not equal to zero only for FIRST fragment */ |
| fixOffset = pReq->fixOffset; |
| /* For FIRST fragment crypto and mac offsets are taken from pCmd */ |
| cryptoOffset = pCmd->cryptoOffset; |
| macOffset = pCmd->macOffset; |
| |
| copySize = sizeof(cesaSramVirtPtr->buf) - pReq->fixOffset; |
| |
| /* Find fragment size: Must meet all requirements for CRYPTO and MAC |
| * cryptoDataSize - size of data will be encrypted/decrypted in this fragment |
| * macDataSize - size of data will be signed/verified in this fragment |
| * copySize - size of data will be copied from srcMbuf to SRAM and |
| * back to dstMbuf for this fragment |
| */ |
| mvCesaFragSizeFind(pSA, pReq, cryptoOffset, macOffset, |
| ©Size, &cryptoDataSize, &macDataSize); |
| |
| if( (pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) |
| { |
| /* CryptoIV special processing */ |
| if( (pSA->config & MV_CESA_CRYPTO_MODE_MASK) == |
| (MV_CESA_CRYPTO_CBC << MV_CESA_CRYPTO_MODE_BIT) ) |
| { |
| /* In CBC mode for encode direction when IV from user */ |
| if( (pCmd->ivFromUser) && |
| ((pSA->config & MV_CESA_DIRECTION_MASK) == |
| (MV_CESA_DIR_ENCODE << MV_CESA_DIRECTION_BIT)) ) |
| { |
| |
| /* For Crypto Encode in CBC mode HW always takes IV from SRAM IVPointer, |
| * (not from IVBufPointer). So when ivFromUser==1, we should copy IV from user place |
| * in the buffer to SRAM IVPointer |
| */ |
| i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->cryptoIV, &pDmaDesc[i], |
| MV_FALSE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush); |
| } |
| |
| /* Special processing when IV is not located in the first fragment */ |
| if(pCmd->ivOffset > (copySize - pSA->cryptoIvSize)) |
| { |
| /* Prepare dummy place for cryptoIV in SRAM */ |
| cryptoIvOffset = cesaSramVirtPtr->tempCryptoIV - mvCesaSramAddrGet(); |
| |
| /* For Decryption: Copy IV value from pCmd->ivOffset to Special SRAM place */ |
| if((pSA->config & MV_CESA_DIRECTION_MASK) == |
| (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT)) |
| { |
| i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->tempCryptoIV, &pDmaDesc[i], |
| MV_FALSE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush); |
| } |
| else |
| { |
| /* For Encryption when IV is NOT from User: */ |
| /* Copy IV from SRAM to buffer (pCmd->ivOffset) */ |
| if(pCmd->ivFromUser == 0) |
| { |
| /* copy IV value from cryptoIV to Buffer (pCmd->ivOffset) */ |
| i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->cryptoIV, &pDmaDesc[i], |
| MV_TRUE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush); |
| } |
| } |
| } |
| else |
| { |
| cryptoIvOffset = pCmd->ivOffset; |
| } |
| } |
| } |
| |
| if( (pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) |
| { |
| /* MAC digest special processing on Decode direction */ |
| if((pSA->config & MV_CESA_DIRECTION_MASK) == |
| (MV_CESA_DIR_DECODE << MV_CESA_DIRECTION_BIT)) |
| { |
| /* Save digest from pCmd->digestOffset */ |
| mvCesaCopyFromMbuf(pReq->frags.orgDigest, |
| pCmd->pSrc, pCmd->digestOffset, pSA->digestSize); |
| |
| /* If pCmd->digestOffset is not located on the first */ |
| if(pCmd->digestOffset > (copySize - pSA->digestSize)) |
| { |
| MV_U8 digestZero[MV_CESA_MAX_DIGEST_SIZE]; |
| |
| /* Set zeros to pCmd->digestOffset (DRAM) */ |
| memset(digestZero, 0, MV_CESA_MAX_DIGEST_SIZE); |
| mvCesaCopyToMbuf(digestZero, pCmd->pSrc, pCmd->digestOffset, pSA->digestSize); |
| |
| /* Prepare dummy place for digest in SRAM */ |
| digestOffset = cesaSramVirtPtr->tempDigest - mvCesaSramAddrGet(); |
| } |
| else |
| { |
| digestOffset = pCmd->digestOffset; |
| } |
| } |
| } |
| /* Update SA in SRAM */ |
| if(cesaLastSid != sid) |
| { |
| mvCesaSramSaUpdate(sid, &pDmaDesc[i]); |
| i++; |
| } |
| |
| pReq->fragMode = MV_CESA_FRAG_MIDDLE; |
| } |
| else |
| { |
| /* Continue fragment */ |
| fixOffset = 0; |
| cryptoOffset = 0; |
| macOffset = 0; |
| if( (pCmd->pSrc->mbufSize - pReq->frags.bufOffset) <= sizeof(cesaSramVirtPtr->buf)) |
| { |
| /* Last fragment */ |
| config = pSA->config | (MV_CESA_FRAG_LAST << MV_CESA_FRAG_MODE_OFFSET); |
| pReq->fragMode = MV_CESA_FRAG_LAST; |
| copySize = pCmd->pSrc->mbufSize - pReq->frags.bufOffset; |
| |
| if( (pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) |
| { |
| macDataSize = pCmd->macLength - pReq->frags.macSize; |
| |
| /* If pCmd->digestOffset is not located on last fragment */ |
| if(pCmd->digestOffset < pReq->frags.bufOffset) |
| { |
| /* Prepare dummy place for digest in SRAM */ |
| digestOffset = cesaSramVirtPtr->tempDigest - mvCesaSramAddrGet(); |
| } |
| else |
| { |
| digestOffset = pCmd->digestOffset - pReq->frags.bufOffset; |
| } |
| pReq->frags.newDigestOffset = digestOffset; |
| macTotalLen = pCmd->macLength; |
| |
| /* HW can't calculate the Digest correctly for fragmented packets |
| * in the following cases: |
| * - MV88F5182 || |
| * - MV88F5181L when total macLength more that 16 Kbytes || |
| * - total macLength more that 64 Kbytes |
| */ |
| if( (mvCtrlModelGet() == MV_5182_DEV_ID) || |
| ( (mvCtrlModelGet() == MV_5181_DEV_ID) && |
| (mvCtrlRevGet() >= MV_5181L_A0_REV) && |
| (pCmd->macLength >= (1 << 14)) ) ) |
| { |
| return MV_TERMINATE; |
| } |
| } |
| if( (pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET) ) |
| { |
| cryptoDataSize = pCmd->cryptoLength - pReq->frags.cryptoSize; |
| } |
| |
| /* cryptoIvOffset - don't care */ |
| } |
| else |
| { |
| /* WA for MV88F5182 SHA1 and MD5 fragmentation mode */ |
| if( (mvCtrlModelGet() == MV_5182_DEV_ID) && |
| (((pSA->config & MV_CESA_MAC_MODE_MASK) == |
| (MV_CESA_MAC_MD5 << MV_CESA_MAC_MODE_OFFSET)) || |
| ((pSA->config & MV_CESA_MAC_MODE_MASK) == |
| (MV_CESA_MAC_SHA1 << MV_CESA_MAC_MODE_OFFSET))) ) |
| { |
| pReq->frags.newDigestOffset = cesaSramVirtPtr->tempDigest - mvCesaSramAddrGet(); |
| pReq->fragMode = MV_CESA_FRAG_LAST; |
| |
| return MV_TERMINATE; |
| } |
| /* Middle fragment */ |
| config = pSA->config | (MV_CESA_FRAG_MIDDLE << MV_CESA_FRAG_MODE_OFFSET); |
| copySize = sizeof(cesaSramVirtPtr->buf); |
| /* digestOffset and cryptoIvOffset - don't care */ |
| |
| /* Find fragment size */ |
| mvCesaFragSizeFind(pSA, pReq, cryptoOffset, macOffset, |
| ©Size, &cryptoDataSize, &macDataSize); |
| } |
| } |
| /********* Prepare DMA descriptors to copy from pSrc to SRAM *********/ |
| pMbuf = pCmd->pSrc; |
| i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i], |
| MV_FALSE, pReq->frags.bufOffset, copySize, pCmd->skipFlush); |
| |
| /* Prepare CESA descriptor to copy from DRAM to SRAM by DMA */ |
| mvCesaSramDescrBuild(config, frag, |
| cryptoOffset + fixOffset, cryptoIvOffset + fixOffset, |
| cryptoDataSize, macOffset + fixOffset, |
| digestOffset + fixOffset, macDataSize, macTotalLen, |
| pReq, &pDmaDesc[i]); |
| i++; |
| |
| /* Add special descriptor Ownership for CPU */ |
| pDmaDesc[i].byteCnt = 0; |
| pDmaDesc[i].phySrcAdd = 0; |
| pDmaDesc[i].phyDestAdd = 0; |
| i++; |
| |
| /********* Prepare DMA descriptors to copy from SRAM to pDst *********/ |
| pMbuf = pCmd->pDst; |
| i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i], |
| MV_TRUE, pReq->frags.bufOffset, copySize, pCmd->skipFlush); |
| |
| /* Next field of Last DMA descriptor must be NULL */ |
| pDmaDesc[i-1].phyNextDescPtr = 0; |
| pReq->dma[frag].pDmaLast = &pDmaDesc[i-1]; |
| mvOsCacheFlush(NULL, pReq->dma[frag].pDmaFirst, |
| i*sizeof(MV_DMA_DESC)); |
| |
| /*mvCesaDebugDescriptor(&cesaSramVirtPtr->desc[frag]);*/ |
| |
| pReq->frags.bufOffset += copySize; |
| pReq->frags.cryptoSize += cryptoDataSize; |
| pReq->frags.macSize += macDataSize; |
| |
| return MV_OK; |
| } |
| |
| |
| /******************************************************************************* |
| * mvCesaReqProcess - Process regular (Non-fragmented) request |
| * |
| * DESCRIPTION: |
| * This function processes the whole (not fragmented) request |
| * |
| * INPUT: |
| * MV_CESA_REQ* pReq - Pointer to the request in the request queue. |
| * |
| * RETURN: |
| * MV_OK - The request is successfully passed to HW for processing. |
| * Other - Failure. The request will not be processed |
| * |
| *******************************************************************************/ |
| static MV_STATUS mvCesaReqProcess(MV_CESA_REQ* pReq) |
| { |
| MV_CESA_MBUF *pMbuf; |
| MV_DMA_DESC *pDmaDesc; |
| MV_U8 *pSramBuf; |
| int sid, i, fixOffset; |
| MV_CESA_SA *pSA; |
| MV_CESA_COMMAND *pCmd = pReq->pCmd; |
| |
| cesaStats.procCount++; |
| |
| sid = pCmd->sessionId; |
| pSA = &pCesaSAD[sid]; |
| pDmaDesc = pReq->dma[0].pDmaFirst; |
| pSramBuf = cesaSramVirtPtr->buf; |
| fixOffset = pReq->fixOffset; |
| |
| /* |
| mvOsPrintf("mvCesaReqProcess: sid=%d, pSA=%p, pDmaDesc=%p, pSramBuf=%p\n", |
| sid, pSA, pDmaDesc, pSramBuf); |
| */ |
| i = 0; |
| |
| /* Crypto IV Special processing in CBC mode for Encryption direction */ |
| if( ((pSA->config & MV_CESA_OPERATION_MASK) != (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) && |
| ((pSA->config & MV_CESA_CRYPTO_MODE_MASK) == (MV_CESA_CRYPTO_CBC << MV_CESA_CRYPTO_MODE_BIT)) && |
| ((pSA->config & MV_CESA_DIRECTION_MASK) == (MV_CESA_DIR_ENCODE << MV_CESA_DIRECTION_BIT)) && |
| (pCmd->ivFromUser) ) |
| { |
| /* For Crypto Encode in CBC mode HW always takes IV from SRAM IVPointer, |
| * (not from IVBufPointer). So when ivFromUser==1, we should copy IV from user place |
| * in the buffer to SRAM IVPointer |
| */ |
| i += mvCesaDmaCopyPrepare(pCmd->pSrc, cesaSramVirtPtr->cryptoIV, &pDmaDesc[i], |
| MV_FALSE, pCmd->ivOffset, pSA->cryptoIvSize, pCmd->skipFlush); |
| } |
| |
| /* Update SA in SRAM */ |
| if(cesaLastSid != sid) |
| { |
| mvCesaSramSaUpdate(sid, &pDmaDesc[i]); |
| i++; |
| } |
| |
| /********* Prepare DMA descriptors to copy from pSrc to SRAM *********/ |
| pMbuf = pCmd->pSrc; |
| i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i], |
| MV_FALSE, 0, pMbuf->mbufSize, pCmd->skipFlush); |
| |
| /* Prepare Security Accelerator descriptor to SRAM words 0 - 7 */ |
| mvCesaSramDescrBuild(pSA->config, 0, pCmd->cryptoOffset + fixOffset, |
| pCmd->ivOffset + fixOffset, pCmd->cryptoLength, |
| pCmd->macOffset + fixOffset, pCmd->digestOffset + fixOffset, |
| pCmd->macLength, pCmd->macLength, pReq, &pDmaDesc[i]); |
| i++; |
| |
| /* Add special descriptor Ownership for CPU */ |
| pDmaDesc[i].byteCnt = 0; |
| pDmaDesc[i].phySrcAdd = 0; |
| pDmaDesc[i].phyDestAdd = 0; |
| i++; |
| |
| /********* Prepare DMA descriptors to copy from SRAM to pDst *********/ |
| pMbuf = pCmd->pDst; |
| i += mvCesaDmaCopyPrepare(pMbuf, pSramBuf + fixOffset, &pDmaDesc[i], |
| MV_TRUE, 0, pMbuf->mbufSize, pCmd->skipFlush); |
| |
| /* Next field of Last DMA descriptor must be NULL */ |
| pDmaDesc[i-1].phyNextDescPtr = 0; |
| pReq->dma[0].pDmaLast = &pDmaDesc[i-1]; |
| mvOsCacheFlush(NULL, pReq->dma[0].pDmaFirst, i*sizeof(MV_DMA_DESC)); |
| |
| return MV_OK; |
| } |
| |
| |
| /******************************************************************************* |
| * mvCesaSramDescrBuild - Set CESA descriptor in SRAM |
| * |
| * DESCRIPTION: |
| * This function builds CESA descriptor in SRAM from all Command parameters |
| * |
| * |
| * INPUT: |
| * int chan - CESA channel uses the descriptor |
| * MV_U32 config - 32 bits of WORD_0 in CESA descriptor structure |
| * int cryptoOffset - Offset from the beginning of SRAM buffer where |
| * data for encryption/decription is started. |
| * int ivOffset - Offset of crypto IV from the SRAM base. Valid only |
| * for first fragment. |
| * int cryptoLength - Size (in bytes) of data for encryption/descryption |
| * operation on this fragment. |
| * int macOffset - Offset from the beginning of SRAM buffer where |
| * data for Authentication is started |
| * int digestOffset - Offset from the beginning of SRAM buffer where |
| * digest is located. Valid for first and last fragments. |
| * int macLength - Size (in bytes) of data for Authentication |
| * operation on this fragment. |
| * int macTotalLen - Toatl size (in bytes) of data for Authentication |
| * operation on the whole request (packet). Valid for |
| * last fragment only. |
| * |
| * RETURN: None |
| * |
| *******************************************************************************/ |
| static void mvCesaSramDescrBuild(MV_U32 config, int frag, |
| int cryptoOffset, int ivOffset, int cryptoLength, |
| int macOffset, int digestOffset, int macLength, |
| int macTotalLen, MV_CESA_REQ* pReq, MV_DMA_DESC* pDmaDesc) |
| { |
| MV_CESA_DESC* pCesaDesc = &pReq->pCesaDesc[frag]; |
| MV_CESA_DESC* pSramDesc = pSramDesc = &cesaSramVirtPtr->desc; |
| MV_U16 sramBufOffset = (MV_U16)((MV_U8*)cesaSramVirtPtr->buf - mvCesaSramAddrGet()); |
| |
| pCesaDesc->config = MV_32BIT_LE(config); |
| |
| if( (config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET) ) |
| { |
| /* word 1 */ |
| pCesaDesc->cryptoSrcOffset = MV_16BIT_LE(sramBufOffset + cryptoOffset); |
| pCesaDesc->cryptoDstOffset = MV_16BIT_LE(sramBufOffset + cryptoOffset); |
| /* word 2 */ |
| pCesaDesc->cryptoDataLen = MV_16BIT_LE(cryptoLength); |
| /* word 3 */ |
| pCesaDesc->cryptoKeyOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->sramSA.cryptoKey - |
| mvCesaSramAddrGet())); |
| /* word 4 */ |
| pCesaDesc->cryptoIvOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->cryptoIV - |
| mvCesaSramAddrGet())); |
| pCesaDesc->cryptoIvBufOffset = MV_16BIT_LE(sramBufOffset + ivOffset); |
| } |
| |
| if( (config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) |
| { |
| /* word 5 */ |
| pCesaDesc->macSrcOffset = MV_16BIT_LE(sramBufOffset + macOffset); |
| pCesaDesc->macTotalLen = MV_16BIT_LE(macTotalLen); |
| |
| /* word 6 */ |
| pCesaDesc->macDigestOffset = MV_16BIT_LE(sramBufOffset + digestOffset); |
| pCesaDesc->macDataLen = MV_16BIT_LE(macLength); |
| |
| /* word 7 */ |
| pCesaDesc->macInnerIvOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->sramSA.macInnerIV - |
| mvCesaSramAddrGet())); |
| pCesaDesc->macOuterIvOffset = MV_16BIT_LE((MV_U16)(cesaSramVirtPtr->sramSA.macOuterIV - |
| mvCesaSramAddrGet())); |
| } |
| /* Prepare DMA descriptor to CESA descriptor from DRAM to SRAM */ |
| pDmaDesc->phySrcAdd = MV_32BIT_LE(mvCesaVirtToPhys(&pReq->cesaDescBuf, pCesaDesc)); |
| pDmaDesc->phyDestAdd = MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (MV_U8*)pSramDesc)); |
| pDmaDesc->byteCnt = MV_32BIT_LE(sizeof(MV_CESA_DESC) | BIT31); |
| |
| /* flush Source buffer */ |
| mvOsCacheFlush(NULL, pCesaDesc, sizeof(MV_CESA_DESC)); |
| } |
| |
| /******************************************************************************* |
| * mvCesaSramSaUpdate - Move required SA information to SRAM if needed. |
| * |
| * DESCRIPTION: |
| * Copy to SRAM values of the required SA. |
| * |
| * |
| * INPUT: |
| * short sid - Session ID needs SRAM Cache update |
| * MV_DMA_DESC *pDmaDesc - Pointer to DMA descriptor used to |
| * copy SA values from DRAM to SRAM. |
| * |
| * RETURN: |
| * MV_OK - Cache entry for this SA copied to SRAM. |
| * MV_NO_CHANGE - Cache entry for this SA already exist in SRAM |
| * |
| *******************************************************************************/ |
| static INLINE void mvCesaSramSaUpdate(short sid, MV_DMA_DESC *pDmaDesc) |
| { |
| MV_CESA_SA *pSA = &pCesaSAD[sid]; |
| |
| /* Prepare DMA descriptor to Copy CACHE_SA from SA database in DRAM to SRAM */ |
| pDmaDesc->byteCnt = MV_32BIT_LE(sizeof(MV_CESA_SRAM_SA) | BIT31); |
| pDmaDesc->phySrcAdd = MV_32BIT_LE(mvCesaVirtToPhys(&cesaSramSaBuf, pSA->pSramSA)); |
| pDmaDesc->phyDestAdd = |
| MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (MV_U8*)&cesaSramVirtPtr->sramSA)); |
| |
| /* Source buffer is already flushed during OpenSession*/ |
| /*mvOsCacheFlush(NULL, &pSA->sramSA, sizeof(MV_CESA_SRAM_SA));*/ |
| } |
| |
| /******************************************************************************* |
| * mvCesaDmaCopyPrepare - prepare DMA descriptor list to copy data presented by |
| * Mbuf structure from DRAM to SRAM |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_CESA_MBUF* pMbuf - pointer to Mbuf structure contains request |
| * data in DRAM |
| * MV_U8* pSramBuf - pointer to buffer in SRAM where data should |
| * be copied to. |
| * MV_DMA_DESC* pDmaDesc - pointer to first DMA descriptor for this copy. |
| * The function set number of DMA descriptors needed |
| * to copy the copySize bytes from Mbuf. |
| * MV_BOOL isToMbuf - Copy direction. |
| * MV_TRUE means copy from SRAM buffer to Mbuf in DRAM. |
| * MV_FALSE means copy from Mbuf in DRAM to SRAM buffer. |
| * int offset - Offset in the Mbuf structure that copy should be |
| * started from. |
| * int copySize - Size of data should be copied. |
| * |
| * RETURN: |
| * int - number of DMA descriptors used for the copy. |
| * |
| *******************************************************************************/ |
| #ifndef MV_NETBSD |
| static INLINE int mvCesaDmaCopyPrepare(MV_CESA_MBUF* pMbuf, MV_U8* pSramBuf, |
| MV_DMA_DESC* pDmaDesc, MV_BOOL isToMbuf, |
| int offset, int copySize, MV_BOOL skipFlush) |
| { |
| int bufOffset, bufSize, size, frag, i; |
| MV_U8* pBuf; |
| |
| i = 0; |
| |
| /* Calculate start place for copy: fragment number and offset in the fragment */ |
| frag = mvCesaMbufOffset(pMbuf, offset, &bufOffset); |
| bufSize = pMbuf->pFrags[frag].bufSize - bufOffset; |
| pBuf = pMbuf->pFrags[frag].bufVirtPtr + bufOffset; |
| |
| /* Size accumulate total copy size */ |
| size = 0; |
| |
| /* Create DMA lists to copy mBuf from pSrc to SRAM */ |
| while(size < copySize) |
| { |
| /* Find copy size for each DMA descriptor */ |
| bufSize = MV_MIN(bufSize, (copySize - size)); |
| pDmaDesc[i].byteCnt = MV_32BIT_LE(bufSize | BIT31); |
| if(isToMbuf) |
| { |
| pDmaDesc[i].phyDestAdd = MV_32BIT_LE(mvOsIoVirtToPhy(NULL, pBuf)); |
| pDmaDesc[i].phySrcAdd = |
| MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (pSramBuf + size))); |
| /* invalidate the buffer */ |
| if(skipFlush == MV_FALSE) |
| mvOsCacheInvalidate(NULL, pBuf, bufSize); |
| } |
| else |
| { |
| pDmaDesc[i].phySrcAdd = MV_32BIT_LE(mvOsIoVirtToPhy(NULL, pBuf)); |
| pDmaDesc[i].phyDestAdd = |
| MV_32BIT_LE(mvCesaSramVirtToPhys(NULL, (pSramBuf + size))); |
| /* flush the buffer */ |
| if(skipFlush == MV_FALSE) |
| mvOsCacheFlush(NULL, pBuf, bufSize); |
| } |
| |
| /* Count number of used DMA descriptors */ |
| i++; |
| size += bufSize; |
| |
| /* go to next fragment in the Mbuf */ |
| frag++; |
| pBuf = pMbuf->pFrags[frag].bufVirtPtr; |
| bufSize = pMbuf->pFrags[frag].bufSize; |
| } |
| return i; |
| } |
| #else /* MV_NETBSD */ |
| static int mvCesaDmaCopyPrepare(MV_CESA_MBUF* pMbuf, MV_U8* pSramBuf, |
| MV_DMA_DESC* pDmaDesc, MV_BOOL isToMbuf, |
| int offset, int copySize, MV_BOOL skipFlush) |
| { |
| int bufOffset, bufSize, thisSize, size, frag, i; |
| MV_ULONG bufPhys, sramPhys; |
| MV_U8* pBuf; |
| |
| /* |
| * Calculate start place for copy: fragment number and offset in |
| * the fragment |
| */ |
| frag = mvCesaMbufOffset(pMbuf, offset, &bufOffset); |
| |
| /* |
| * Get SRAM physical address only once. We can update it in-place |
| * as we build the descriptor chain. |
| */ |
| sramPhys = mvCesaSramVirtToPhys(NULL, pSramBuf); |
| |
| /* |
| * 'size' accumulates total copy size, 'i' counts desccriptors. |
| */ |
| size = i = 0; |
| |
| /* Create DMA lists to copy mBuf from pSrc to SRAM */ |
| while (size < copySize) { |
| /* |
| * Calculate # of bytes to copy from the current fragment, |
| * and the pointer to the start of data |
| */ |
| bufSize = pMbuf->pFrags[frag].bufSize - bufOffset; |
| pBuf = pMbuf->pFrags[frag].bufVirtPtr + bufOffset; |
| bufOffset = 0; /* First frag may be non-zero */ |
| frag++; |
| |
| /* |
| * As long as there is data in the current fragment... |
| */ |
| while (bufSize > 0) { |
| /* |
| * Ensure we don't cross an MMU page boundary. |
| * XXX: This is NetBSD-specific, but it is a |
| * quick and dirty way to fix the problem. |
| * A true HAL would rely on the OS-specific |
| * driver to do this... |
| */ |
| thisSize = PAGE_SIZE - |
| (((MV_ULONG)pBuf) & (PAGE_SIZE - 1)); |
| thisSize = MV_MIN(bufSize, thisSize); |
| /* |
| * Make sure we don't copy more than requested |
| */ |
| if (thisSize > (copySize - size)) { |
| thisSize = copySize - size; |
| bufSize = 0; |
| } |
| |
| /* |
| * Physicall address of this fragment |
| */ |
| bufPhys = MV_32BIT_LE(mvOsIoVirtToPhy(NULL, pBuf)); |
| |
| /* |
| * Set up the descriptor |
| */ |
| pDmaDesc[i].byteCnt = MV_32BIT_LE(thisSize | BIT31); |
| if(isToMbuf) { |
| pDmaDesc[i].phyDestAdd = bufPhys; |
| pDmaDesc[i].phySrcAdd = MV_32BIT_LE(sramPhys); |
| /* invalidate the buffer */ |
| if(skipFlush == MV_FALSE) |
| mvOsCacheInvalidate(NULL, pBuf, thisSize); |
| } else { |
| pDmaDesc[i].phySrcAdd = bufPhys; |
| pDmaDesc[i].phyDestAdd = MV_32BIT_LE(sramPhys); |
| /* flush the buffer */ |
| if(skipFlush == MV_FALSE) |
| mvOsCacheFlush(NULL, pBuf, thisSize); |
| } |
| |
| pDmaDesc[i].phyNextDescPtr = |
| MV_32BIT_LE(mvOsIoVirtToPhy(NULL,(&pDmaDesc[i+1]))); |
| |
| /* flush the DMA desc */ |
| mvOsCacheFlush(NULL, &pDmaDesc[i], sizeof(MV_DMA_DESC)); |
| |
| /* Update state */ |
| bufSize -= thisSize; |
| sramPhys += thisSize; |
| pBuf += thisSize; |
| size += thisSize; |
| i++; |
| } |
| } |
| |
| return i; |
| } |
| #endif /* MV_NETBSD */ |
| /******************************************************************************* |
| * mvCesaHmacIvGet - Calculate Inner and Outter values from HMAC key |
| * |
| * DESCRIPTION: |
| * This function calculate Inner and Outer values used for HMAC algorithm. |
| * This operation allows improve performance fro the whole HMAC processing. |
| * |
| * INPUT: |
| * MV_CESA_MAC_MODE macMode - Authentication mode: HMAC_MD5 or HMAC_SHA1. |
| * unsigned char key[] - Pointer to HMAC key. |
| * int keyLength - Size of HMAC key (maximum 64 bytes) |
| * |
| * OUTPUT: |
| * unsigned char innerIV[] - HASH(key^inner) |
| * unsigned char outerIV[] - HASH(key^outter) |
| * |
| * RETURN: None |
| * |
| *******************************************************************************/ |
| static void mvCesaHmacIvGet(MV_CESA_MAC_MODE macMode, unsigned char key[], int keyLength, |
| unsigned char innerIV[], unsigned char outerIV[]) |
| { |
| unsigned char inner[MV_CESA_MAX_MAC_KEY_LENGTH]; |
| unsigned char outer[MV_CESA_MAX_MAC_KEY_LENGTH]; |
| int i, digestSize = 0; |
| #if defined(MV_CPU_LE) || defined(MV_PPC) |
| MV_U32 swapped32, val32, *pVal32; |
| #endif |
| for(i=0; i<keyLength; i++) |
| { |
| inner[i] = 0x36 ^ key[i]; |
| outer[i] = 0x5c ^ key[i]; |
| } |
| |
| for(i=keyLength; i<MV_CESA_MAX_MAC_KEY_LENGTH; i++) |
| { |
| inner[i] = 0x36; |
| outer[i] = 0x5c; |
| } |
| if(macMode == MV_CESA_MAC_HMAC_MD5) |
| { |
| MV_MD5_CONTEXT ctx; |
| |
| mvMD5Init(&ctx); |
| mvMD5Update(&ctx, inner, MV_CESA_MAX_MAC_KEY_LENGTH); |
| |
| memcpy(innerIV, ctx.buf, MV_CESA_MD5_DIGEST_SIZE); |
| memset(&ctx, 0, sizeof(ctx)); |
| |
| mvMD5Init(&ctx); |
| mvMD5Update(&ctx, outer, MV_CESA_MAX_MAC_KEY_LENGTH); |
| memcpy(outerIV, ctx.buf, MV_CESA_MD5_DIGEST_SIZE); |
| memset(&ctx, 0, sizeof(ctx)); |
| digestSize = MV_CESA_MD5_DIGEST_SIZE; |
| } |
| else if(macMode == MV_CESA_MAC_HMAC_SHA1) |
| { |
| MV_SHA1_CTX ctx; |
| |
| mvSHA1Init(&ctx); |
| mvSHA1Update(&ctx, inner, MV_CESA_MAX_MAC_KEY_LENGTH); |
| memcpy(innerIV, ctx.state, MV_CESA_SHA1_DIGEST_SIZE); |
| memset(&ctx, 0, sizeof(ctx)); |
| |
| mvSHA1Init(&ctx); |
| mvSHA1Update(&ctx, outer, MV_CESA_MAX_MAC_KEY_LENGTH); |
| memcpy(outerIV, ctx.state, MV_CESA_SHA1_DIGEST_SIZE); |
| memset(&ctx, 0, sizeof(ctx)); |
| digestSize = MV_CESA_SHA1_DIGEST_SIZE; |
| } |
| else |
| { |
| mvOsPrintf("hmacGetIV: Unexpected macMode %d\n", macMode); |
| } |
| #if defined(MV_CPU_LE) || defined(MV_PPC) |
| /* 32 bits Swap of Inner and Outer values */ |
| pVal32 = (MV_U32*)innerIV; |
| for(i=0; i<digestSize/4; i++) |
| { |
| val32 = *pVal32; |
| swapped32 = MV_BYTE_SWAP_32BIT(val32); |
| *pVal32 = swapped32; |
| pVal32++; |
| } |
| pVal32 = (MV_U32*)outerIV; |
| for(i=0; i<digestSize/4; i++) |
| { |
| val32 = *pVal32; |
| swapped32 = MV_BYTE_SWAP_32BIT(val32); |
| *pVal32 = swapped32; |
| pVal32++; |
| } |
| #endif /* defined(MV_CPU_LE) || defined(MV_PPC) */ |
| } |
| |
| |
| /******************************************************************************* |
| * mvCesaFragSha1Complete - Complete SHA1 authentication started by HW using SW |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_CESA_MBUF* pMbuf - Pointer to Mbuf structure where data |
| * for SHA1 is placed. |
| * int offset - Offset in the Mbuf structure where |
| * unprocessed data for SHA1 is started. |
| * MV_U8* pOuterIV - Pointer to OUTER for this session. |
| * If pOuterIV==NULL - MAC mode is HASH_SHA1 |
| * If pOuterIV!=NULL - MAC mode is HMAC_SHA1 |
| * int macLeftSize - Size of unprocessed data for SHA1. |
| * int macTotalSize - Total size of data for SHA1 in the |
| * request (processed + unprocessed) |
| * |
| * OUTPUT: |
| * MV_U8* pDigest - Pointer to place where calculated Digest will |
| * be stored. |
| * |
| * RETURN: None |
| * |
| *******************************************************************************/ |
| static void mvCesaFragSha1Complete(MV_CESA_MBUF* pMbuf, int offset, |
| MV_U8* pOuterIV, int macLeftSize, |
| int macTotalSize, MV_U8* pDigest) |
| { |
| MV_SHA1_CTX ctx; |
| MV_U8 *pData; |
| int i, frag, fragOffset, size; |
| |
| /* Read temporary Digest from HW */ |
| for(i=0; i<MV_CESA_SHA1_DIGEST_SIZE/4; i++) |
| { |
| ctx.state[i] = MV_REG_READ(MV_CESA_AUTH_INIT_VAL_DIGEST_REG(i)); |
| } |
| /* Initialize MV_SHA1_CTX structure */ |
| memset(ctx.buffer, 0, 64); |
| /* Set count[0] in bits. 32 bits is enough for 512 MBytes */ |
| /* so count[1] is always 0 */ |
| ctx.count[0] = ((macTotalSize - macLeftSize) * 8); |
| ctx.count[1] = 0; |
| |
| /* If HMAC - add size of Inner block (64 bytes) ro count[0] */ |
| if(pOuterIV != NULL) |
| ctx.count[0] += (64 * 8); |
| |
| /* Get place of unprocessed data in the Mbuf structure */ |
| frag = mvCesaMbufOffset(pMbuf, offset, &fragOffset); |
| if(frag == MV_INVALID) |
| { |
| mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset); |
| return; |
| } |
| |
| pData = pMbuf->pFrags[frag].bufVirtPtr + fragOffset; |
| size = pMbuf->pFrags[frag].bufSize - fragOffset; |
| |
| /* Complete Inner part */ |
| while(macLeftSize > 0) |
| { |
| if(macLeftSize <= size) |
| { |
| mvSHA1Update(&ctx, pData, macLeftSize); |
| break; |
| } |
| mvSHA1Update(&ctx, pData, size); |
| macLeftSize -= size; |
| frag++; |
| pData = pMbuf->pFrags[frag].bufVirtPtr; |
| size = pMbuf->pFrags[frag].bufSize; |
| } |
| mvSHA1Final(pDigest, &ctx); |
| /* |
| mvOsPrintf("mvCesaFragSha1Complete: pOuterIV=%p, macLeftSize=%d, macTotalSize=%d\n", |
| pOuterIV, macLeftSize, macTotalSize); |
| mvDebugMemDump(pDigest, MV_CESA_SHA1_DIGEST_SIZE, 1); |
| */ |
| |
| if(pOuterIV != NULL) |
| { |
| /* If HMAC - Complete Outer part */ |
| for(i=0; i<MV_CESA_SHA1_DIGEST_SIZE/4; i++) |
| { |
| #if defined(MV_CPU_LE) || defined(MV_ARM) |
| ctx.state[i] = MV_BYTE_SWAP_32BIT(((MV_U32*)pOuterIV)[i]); |
| #else |
| ctx.state[i] = ((MV_U32*)pOuterIV)[i]; |
| #endif |
| } |
| memset(ctx.buffer, 0, 64); |
| |
| ctx.count[0] = 64*8; |
| ctx.count[1] = 0; |
| mvSHA1Update(&ctx, pDigest, MV_CESA_SHA1_DIGEST_SIZE); |
| mvSHA1Final(pDigest, &ctx); |
| } |
| } |
| |
| /******************************************************************************* |
| * mvCesaFragMd5Complete - Complete MD5 authentication started by HW using SW |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_CESA_MBUF* pMbuf - Pointer to Mbuf structure where data |
| * for SHA1 is placed. |
| * int offset - Offset in the Mbuf structure where |
| * unprocessed data for MD5 is started. |
| * MV_U8* pOuterIV - Pointer to OUTER for this session. |
| * If pOuterIV==NULL - MAC mode is HASH_MD5 |
| * If pOuterIV!=NULL - MAC mode is HMAC_MD5 |
| * int macLeftSize - Size of unprocessed data for MD5. |
| * int macTotalSize - Total size of data for MD5 in the |
| * request (processed + unprocessed) |
| * |
| * OUTPUT: |
| * MV_U8* pDigest - Pointer to place where calculated Digest will |
| * be stored. |
| * |
| * RETURN: None |
| * |
| *******************************************************************************/ |
| static void mvCesaFragMd5Complete(MV_CESA_MBUF* pMbuf, int offset, |
| MV_U8* pOuterIV, int macLeftSize, |
| int macTotalSize, MV_U8* pDigest) |
| { |
| MV_MD5_CONTEXT ctx; |
| MV_U8 *pData; |
| int i, frag, fragOffset, size; |
| |
| /* Read temporary Digest from HW */ |
| for(i=0; i<MV_CESA_MD5_DIGEST_SIZE/4; i++) |
| { |
| ctx.buf[i] = MV_REG_READ(MV_CESA_AUTH_INIT_VAL_DIGEST_REG(i)); |
| } |
| memset(ctx.in, 0, 64); |
| |
| /* Set count[0] in bits. 32 bits is enough for 512 MBytes */ |
| /* so count[1] is always 0 */ |
| ctx.bits[0] = ((macTotalSize - macLeftSize) * 8); |
| ctx.bits[1] = 0; |
| |
| /* If HMAC - add size of Inner block (64 bytes) ro count[0] */ |
| if(pOuterIV != NULL) |
| ctx.bits[0] += (64 * 8); |
| |
| frag = mvCesaMbufOffset(pMbuf, offset, &fragOffset); |
| if(frag == MV_INVALID) |
| { |
| mvOsPrintf("CESA Mbuf Error: offset (%d) out of range\n", offset); |
| return; |
| } |
| |
| pData = pMbuf->pFrags[frag].bufVirtPtr + fragOffset; |
| size = pMbuf->pFrags[frag].bufSize - fragOffset; |
| |
| /* Complete Inner part */ |
| while(macLeftSize > 0) |
| { |
| if(macLeftSize <= size) |
| { |
| mvMD5Update(&ctx, pData, macLeftSize); |
| break; |
| } |
| mvMD5Update(&ctx, pData, size); |
| macLeftSize -= size; |
| frag++; |
| pData = pMbuf->pFrags[frag].bufVirtPtr; |
| size = pMbuf->pFrags[frag].bufSize; |
| } |
| mvMD5Final(pDigest, &ctx); |
| |
| /* |
| mvOsPrintf("mvCesaFragMd5Complete: pOuterIV=%p, macLeftSize=%d, macTotalSize=%d\n", |
| pOuterIV, macLeftSize, macTotalSize); |
| mvDebugMemDump(pDigest, MV_CESA_MD5_DIGEST_SIZE, 1); |
| */ |
| if(pOuterIV != NULL) |
| { |
| /* Complete Outer part */ |
| for(i=0; i<MV_CESA_MD5_DIGEST_SIZE/4; i++) |
| { |
| #if defined(MV_CPU_LE) || defined(MV_ARM) |
| ctx.buf[i] = MV_BYTE_SWAP_32BIT(((MV_U32*)pOuterIV)[i]); |
| #else |
| ctx.buf[i] = ((MV_U32*)pOuterIV)[i]; |
| #endif |
| } |
| memset(ctx.in, 0, 64); |
| |
| ctx.bits[0] = 64*8; |
| ctx.bits[1] = 0; |
| mvMD5Update(&ctx, pDigest, MV_CESA_MD5_DIGEST_SIZE); |
| mvMD5Final(pDigest, &ctx); |
| } |
| } |
| |
| /******************************************************************************* |
| * mvCesaFragAuthComplete - |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_CESA_REQ* pReq, |
| * MV_CESA_SA* pSA, |
| * int macDataSize |
| * |
| * RETURN: |
| * MV_STATUS |
| * |
| *******************************************************************************/ |
| static MV_STATUS mvCesaFragAuthComplete(MV_CESA_REQ* pReq, MV_CESA_SA* pSA, |
| int macDataSize) |
| { |
| MV_CESA_COMMAND* pCmd = pReq->pCmd; |
| MV_U8* pDigest; |
| MV_CESA_MAC_MODE macMode; |
| MV_U8* pOuterIV = NULL; |
| |
| /* Copy data from Source fragment to Destination */ |
| if(pCmd->pSrc != pCmd->pDst) |
| { |
| mvCesaMbufCopy(pCmd->pDst, pReq->frags.bufOffset, |
| pCmd->pSrc, pReq->frags.bufOffset, macDataSize); |
| } |
| |
| /* |
| mvCesaCopyFromMbuf(cesaSramVirtPtr->buf[0], pCmd->pSrc, pReq->frags.bufOffset, macDataSize); |
| mvCesaCopyToMbuf(cesaSramVirtPtr->buf[0], pCmd->pDst, pReq->frags.bufOffset, macDataSize); |
| */ |
| pDigest = (mvCesaSramAddrGet() + pReq->frags.newDigestOffset); |
| |
| macMode = (pSA->config & MV_CESA_MAC_MODE_MASK) >> MV_CESA_MAC_MODE_OFFSET; |
| /* |
| mvOsPrintf("macDataSize=%d, macLength=%d, digestOffset=%d, macMode=%d\n", |
| macDataSize, pCmd->macLength, pCmd->digestOffset, macMode); |
| */ |
| switch(macMode) |
| { |
| case MV_CESA_MAC_HMAC_MD5: |
| pOuterIV = pSA->pSramSA->macOuterIV; |
| |
| case MV_CESA_MAC_MD5: |
| mvCesaFragMd5Complete(pCmd->pDst, pReq->frags.bufOffset, pOuterIV, |
| macDataSize, pCmd->macLength, pDigest); |
| break; |
| |
| case MV_CESA_MAC_HMAC_SHA1: |
| pOuterIV = pSA->pSramSA->macOuterIV; |
| |
| case MV_CESA_MAC_SHA1: |
| mvCesaFragSha1Complete(pCmd->pDst, pReq->frags.bufOffset, pOuterIV, |
| macDataSize, pCmd->macLength, pDigest); |
| break; |
| |
| default: |
| mvOsPrintf("mvCesaFragAuthComplete: Unexpected macMode %d\n", macMode); |
| return MV_BAD_PARAM; |
| } |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCesaCtrModeInit - |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: NONE |
| * |
| * |
| * RETURN: |
| * MV_CESA_COMMAND* |
| * |
| *******************************************************************************/ |
| static MV_CESA_COMMAND* mvCesaCtrModeInit(void) |
| { |
| MV_CESA_MBUF *pMbuf; |
| MV_U8 *pBuf; |
| MV_CESA_COMMAND *pCmd; |
| |
| pBuf = mvOsMalloc(sizeof(MV_CESA_COMMAND) + |
| sizeof(MV_CESA_MBUF) + sizeof(MV_BUF_INFO) + 100); |
| if(pBuf == NULL) |
| { |
| mvOsPrintf("mvCesaSessionOpen: Can't allocate %u bytes for CTR Mode\n", |
| sizeof(MV_CESA_COMMAND) + sizeof(MV_CESA_MBUF) + sizeof(MV_BUF_INFO) ); |
| return NULL; |
| } |
| pCmd = (MV_CESA_COMMAND*)pBuf; |
| pBuf += sizeof(MV_CESA_COMMAND); |
| |
| pMbuf = (MV_CESA_MBUF*)pBuf; |
| pBuf += sizeof(MV_CESA_MBUF); |
| |
| pMbuf->pFrags = (MV_BUF_INFO*)pBuf; |
| |
| pMbuf->numFrags = 1; |
| pCmd->pSrc = pMbuf; |
| pCmd->pDst = pMbuf; |
| /* |
| mvOsPrintf("CtrModeInit: pCmd=%p, pSrc=%p, pDst=%p, pFrags=%p\n", |
| pCmd, pCmd->pSrc, pCmd->pDst, |
| pMbuf->pFrags); |
| */ |
| return pCmd; |
| } |
| |
| /******************************************************************************* |
| * mvCesaCtrModePrepare - |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_CESA_COMMAND *pCtrModeCmd, MV_CESA_COMMAND *pCmd |
| * |
| * RETURN: |
| * MV_STATUS |
| * |
| *******************************************************************************/ |
| static MV_STATUS mvCesaCtrModePrepare(MV_CESA_COMMAND *pCtrModeCmd, MV_CESA_COMMAND *pCmd) |
| { |
| MV_CESA_MBUF *pMbuf; |
| MV_U8 *pBuf, *pIV; |
| MV_U32 counter, *pCounter; |
| int cryptoSize = MV_ALIGN_UP(pCmd->cryptoLength, MV_CESA_AES_BLOCK_SIZE); |
| /* |
| mvOsPrintf("CtrModePrepare: pCmd=%p, pCtrSrc=%p, pCtrDst=%p, pOrgCmd=%p, pOrgSrc=%p, pOrgDst=%p\n", |
| pCmd, pCmd->pSrc, pCmd->pDst, |
| pCtrModeCmd, pCtrModeCmd->pSrc, pCtrModeCmd->pDst); |
| */ |
| pMbuf = pCtrModeCmd->pSrc; |
| |
| /* Allocate buffer for Key stream */ |
| pBuf = mvOsIoCachedMalloc(cesaOsHandle,cryptoSize, |
| &pMbuf->pFrags[0].bufPhysAddr, |
| &pMbuf->pFrags[0].memHandle); |
| if(pBuf == NULL) |
| { |
| mvOsPrintf("mvCesaCtrModePrepare: Can't allocate %d bytes\n", cryptoSize); |
| return MV_OUT_OF_CPU_MEM; |
| } |
| memset(pBuf, 0, cryptoSize); |
| mvOsCacheFlush(NULL, pBuf, cryptoSize); |
| |
| pMbuf->pFrags[0].bufVirtPtr = pBuf; |
| pMbuf->mbufSize = cryptoSize; |
| pMbuf->pFrags[0].bufSize = cryptoSize; |
| |
| pCtrModeCmd->pReqPrv = pCmd->pReqPrv; |
| pCtrModeCmd->sessionId = pCmd->sessionId; |
| |
| /* ivFromUser and ivOffset are don't care */ |
| pCtrModeCmd->cryptoOffset = 0; |
| pCtrModeCmd->cryptoLength = cryptoSize; |
| |
| /* digestOffset, macOffset and macLength are don't care */ |
| |
| mvCesaCopyFromMbuf(pBuf, pCmd->pSrc, pCmd->ivOffset, MV_CESA_AES_BLOCK_SIZE); |
| pCounter = (MV_U32*)(pBuf + (MV_CESA_AES_BLOCK_SIZE - sizeof(counter))); |
| counter = *pCounter; |
| counter = MV_32BIT_BE(counter); |
| pIV = pBuf; |
| cryptoSize -= MV_CESA_AES_BLOCK_SIZE; |
| |
| /* fill key stream */ |
| while(cryptoSize > 0) |
| { |
| pBuf += MV_CESA_AES_BLOCK_SIZE; |
| memcpy(pBuf, pIV, MV_CESA_AES_BLOCK_SIZE - sizeof(counter)); |
| pCounter = (MV_U32*)(pBuf + (MV_CESA_AES_BLOCK_SIZE - sizeof(counter))); |
| counter++; |
| *pCounter = MV_32BIT_BE(counter); |
| cryptoSize -= MV_CESA_AES_BLOCK_SIZE; |
| } |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCesaCtrModeComplete - |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_CESA_COMMAND *pOrgCmd, MV_CESA_COMMAND *pCmd |
| * |
| * RETURN: |
| * MV_STATUS |
| * |
| *******************************************************************************/ |
| static MV_STATUS mvCesaCtrModeComplete(MV_CESA_COMMAND *pOrgCmd, MV_CESA_COMMAND *pCmd) |
| { |
| int srcFrag, dstFrag, srcOffset, dstOffset, keyOffset, srcSize, dstSize; |
| int cryptoSize = pCmd->cryptoLength; |
| MV_U8 *pSrc, *pDst, *pKey; |
| MV_STATUS status = MV_OK; |
| /* |
| mvOsPrintf("CtrModeComplete: pCmd=%p, pCtrSrc=%p, pCtrDst=%p, pOrgCmd=%p, pOrgSrc=%p, pOrgDst=%p\n", |
| pCmd, pCmd->pSrc, pCmd->pDst, |
| pOrgCmd, pOrgCmd->pSrc, pOrgCmd->pDst); |
| */ |
| /* XOR source data with key stream to destination data */ |
| pKey = pCmd->pDst->pFrags[0].bufVirtPtr; |
| keyOffset = 0; |
| |
| if( (pOrgCmd->pSrc != pOrgCmd->pDst) && |
| (pOrgCmd->cryptoOffset > 0) ) |
| { |
| /* Copy Prefix from source buffer to destination buffer */ |
| |
| status = mvCesaMbufCopy(pOrgCmd->pDst, 0, |
| pOrgCmd->pSrc, 0, pOrgCmd->cryptoOffset); |
| /* |
| status = mvCesaCopyFromMbuf(tempBuf, pOrgCmd->pSrc, |
| 0, pOrgCmd->cryptoOffset); |
| status = mvCesaCopyToMbuf(tempBuf, pOrgCmd->pDst, |
| 0, pOrgCmd->cryptoOffset); |
| */ |
| } |
| |
| srcFrag = mvCesaMbufOffset(pOrgCmd->pSrc, pOrgCmd->cryptoOffset, &srcOffset); |
| pSrc = pOrgCmd->pSrc->pFrags[srcFrag].bufVirtPtr; |
| srcSize = pOrgCmd->pSrc->pFrags[srcFrag].bufSize; |
| |
| dstFrag = mvCesaMbufOffset(pOrgCmd->pDst, pOrgCmd->cryptoOffset, &dstOffset); |
| pDst = pOrgCmd->pDst->pFrags[dstFrag].bufVirtPtr; |
| dstSize = pOrgCmd->pDst->pFrags[dstFrag].bufSize; |
| |
| while(cryptoSize > 0) |
| { |
| pDst[dstOffset] = (pSrc[srcOffset] ^ pKey[keyOffset]); |
| |
| cryptoSize--; |
| dstOffset++; |
| srcOffset++; |
| keyOffset++; |
| |
| if(srcOffset >= srcSize) |
| { |
| srcFrag++; |
| srcOffset = 0; |
| pSrc = pOrgCmd->pSrc->pFrags[srcFrag].bufVirtPtr; |
| srcSize = pOrgCmd->pSrc->pFrags[srcFrag].bufSize; |
| } |
| |
| if(dstOffset >= dstSize) |
| { |
| dstFrag++; |
| dstOffset = 0; |
| pDst = pOrgCmd->pDst->pFrags[dstFrag].bufVirtPtr; |
| dstSize = pOrgCmd->pDst->pFrags[dstFrag].bufSize; |
| } |
| } |
| |
| if(pOrgCmd->pSrc != pOrgCmd->pDst) |
| { |
| /* Copy Suffix from source buffer to destination buffer */ |
| srcOffset = pOrgCmd->cryptoOffset + pOrgCmd->cryptoLength; |
| |
| if( (pOrgCmd->pDst->mbufSize - srcOffset) > 0) |
| { |
| status = mvCesaMbufCopy(pOrgCmd->pDst, srcOffset, |
| pOrgCmd->pSrc, srcOffset, |
| pOrgCmd->pDst->mbufSize - srcOffset); |
| } |
| |
| /* |
| status = mvCesaCopyFromMbuf(tempBuf, pOrgCmd->pSrc, |
| srcOffset, pOrgCmd->pSrc->mbufSize - srcOffset); |
| status = mvCesaCopyToMbuf(tempBuf, pOrgCmd->pDst, |
| srcOffset, pOrgCmd->pDst->mbufSize - srcOffset); |
| */ |
| } |
| |
| /* Free buffer used for Key stream */ |
| mvOsIoCachedFree(cesaOsHandle,pCmd->pDst->pFrags[0].bufSize, |
| pCmd->pDst->pFrags[0].bufPhysAddr, |
| pCmd->pDst->pFrags[0].bufVirtPtr, |
| pCmd->pDst->pFrags[0].memHandle); |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCesaCtrModeFinish - |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_CESA_COMMAND* pCmd |
| * |
| * RETURN: |
| * MV_STATUS |
| * |
| *******************************************************************************/ |
| static void mvCesaCtrModeFinish(MV_CESA_COMMAND* pCmd) |
| { |
| mvOsFree(pCmd); |
| } |
| |
| /******************************************************************************* |
| * mvCesaParamCheck - |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd, MV_U8* pFixOffset |
| * |
| * RETURN: |
| * MV_STATUS |
| * |
| *******************************************************************************/ |
| static MV_STATUS mvCesaParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd, |
| MV_U8* pFixOffset) |
| { |
| MV_U8 fixOffset = 0xFF; |
| |
| /* Check AUTH operation parameters */ |
| if( ((pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET)) ) |
| { |
| /* MAC offset should be at least 4 byte aligned */ |
| if( MV_IS_NOT_ALIGN(pCmd->macOffset, 4) ) |
| { |
| mvOsPrintf("mvCesaAction: macOffset %d must be 4 byte aligned\n", |
| pCmd->macOffset); |
| return MV_BAD_PARAM; |
| } |
| /* Digest offset must be 4 byte aligned */ |
| if( MV_IS_NOT_ALIGN(pCmd->digestOffset, 4) ) |
| { |
| mvOsPrintf("mvCesaAction: digestOffset %d must be 4 byte aligned\n", |
| pCmd->digestOffset); |
| return MV_BAD_PARAM; |
| } |
| /* In addition all offsets should be the same alignment: 8 or 4 */ |
| if(fixOffset == 0xFF) |
| { |
| fixOffset = (pCmd->macOffset % 8); |
| } |
| else |
| { |
| if( (pCmd->macOffset % 8) != fixOffset) |
| { |
| mvOsPrintf("mvCesaAction: macOffset %d mod 8 must be equal %d\n", |
| pCmd->macOffset, fixOffset); |
| return MV_BAD_PARAM; |
| } |
| } |
| if( (pCmd->digestOffset % 8) != fixOffset) |
| { |
| mvOsPrintf("mvCesaAction: digestOffset %d mod 8 must be equal %d\n", |
| pCmd->digestOffset, fixOffset); |
| return MV_BAD_PARAM; |
| } |
| } |
| /* Check CRYPTO operation parameters */ |
| if( ((pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) ) |
| { |
| /* CryptoOffset should be at least 4 byte aligned */ |
| if( MV_IS_NOT_ALIGN(pCmd->cryptoOffset, 4) ) |
| { |
| mvOsPrintf("CesaAction: cryptoOffset=%d must be 4 byte aligned\n", |
| pCmd->cryptoOffset); |
| return MV_BAD_PARAM; |
| } |
| /* cryptoLength should be the whole number of blocks */ |
| if( MV_IS_NOT_ALIGN(pCmd->cryptoLength, pSA->cryptoBlockSize) ) |
| { |
| mvOsPrintf("mvCesaAction: cryptoLength=%d must be %d byte aligned\n", |
| pCmd->cryptoLength, pSA->cryptoBlockSize); |
| return MV_BAD_PARAM; |
| } |
| if(fixOffset == 0xFF) |
| { |
| fixOffset = (pCmd->cryptoOffset % 8); |
| } |
| else |
| { |
| /* In addition all offsets should be the same alignment: 8 or 4 */ |
| if( (pCmd->cryptoOffset % 8) != fixOffset) |
| { |
| mvOsPrintf("mvCesaAction: cryptoOffset %d mod 8 must be equal %d \n", |
| pCmd->cryptoOffset, fixOffset); |
| return MV_BAD_PARAM; |
| } |
| } |
| |
| /* check for CBC mode */ |
| if(pSA->cryptoIvSize > 0) |
| { |
| /* cryptoIV must not be part of CryptoLength */ |
| if( ((pCmd->ivOffset + pSA->cryptoIvSize) > pCmd->cryptoOffset) && |
| (pCmd->ivOffset < (pCmd->cryptoOffset + pCmd->cryptoLength)) ) |
| { |
| mvOsPrintf("mvCesaFragParamCheck: cryptoIvOffset (%d) is part of cryptoLength (%d+%d)\n", |
| pCmd->ivOffset, pCmd->macOffset, pCmd->macLength); |
| return MV_BAD_PARAM; |
| } |
| |
| /* ivOffset must be 4 byte aligned */ |
| if( MV_IS_NOT_ALIGN(pCmd->ivOffset, 4) ) |
| { |
| mvOsPrintf("CesaAction: ivOffset=%d must be 4 byte aligned\n", |
| pCmd->ivOffset); |
| return MV_BAD_PARAM; |
| } |
| /* In addition all offsets should be the same alignment: 8 or 4 */ |
| if( (pCmd->ivOffset % 8) != fixOffset) |
| { |
| mvOsPrintf("mvCesaAction: ivOffset %d mod 8 must be %d\n", |
| pCmd->ivOffset, fixOffset); |
| return MV_BAD_PARAM; |
| } |
| } |
| } |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCesaFragParamCheck - |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd |
| * |
| * RETURN: |
| * MV_STATUS |
| * |
| *******************************************************************************/ |
| static MV_STATUS mvCesaFragParamCheck(MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd) |
| { |
| int offset; |
| |
| if( ((pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET)) ) |
| { |
| /* macOffset must be less that SRAM buffer size */ |
| if(pCmd->macOffset > (sizeof(cesaSramVirtPtr->buf) - MV_CESA_AUTH_BLOCK_SIZE)) |
| { |
| mvOsPrintf("mvCesaFragParamCheck: macOffset is too large (%d)\n", |
| pCmd->macOffset); |
| return MV_BAD_PARAM; |
| } |
| /* macOffset+macSize must be more than mbufSize - SRAM buffer size */ |
| if( ((pCmd->macOffset + pCmd->macLength) > pCmd->pSrc->mbufSize) || |
| ((pCmd->pSrc->mbufSize - (pCmd->macOffset + pCmd->macLength)) >= |
| sizeof(cesaSramVirtPtr->buf)) ) |
| { |
| mvOsPrintf("mvCesaFragParamCheck: macLength is too large (%d), mbufSize=%d\n", |
| pCmd->macLength, pCmd->pSrc->mbufSize); |
| return MV_BAD_PARAM; |
| } |
| } |
| |
| if( ((pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET)) ) |
| { |
| /* cryptoOffset must be less that SRAM buffer size */ |
| /* 4 for possible fixOffset */ |
| if( (pCmd->cryptoOffset + 4) > (sizeof(cesaSramVirtPtr->buf) - pSA->cryptoBlockSize)) |
| { |
| mvOsPrintf("mvCesaFragParamCheck: cryptoOffset is too large (%d)\n", |
| pCmd->cryptoOffset); |
| return MV_BAD_PARAM; |
| } |
| |
| /* cryptoOffset+cryptoSize must be more than mbufSize - SRAM buffer size */ |
| if( ((pCmd->cryptoOffset + pCmd->cryptoLength) > pCmd->pSrc->mbufSize) || |
| ((pCmd->pSrc->mbufSize - (pCmd->cryptoOffset + pCmd->cryptoLength)) >= |
| (sizeof(cesaSramVirtPtr->buf) - pSA->cryptoBlockSize)) ) |
| { |
| mvOsPrintf("mvCesaFragParamCheck: cryptoLength is too large (%d), mbufSize=%d\n", |
| pCmd->cryptoLength, pCmd->pSrc->mbufSize); |
| return MV_BAD_PARAM; |
| } |
| } |
| |
| /* When MAC_THEN_CRYPTO or CRYPTO_THEN_MAC */ |
| if( ((pSA->config & MV_CESA_OPERATION_MASK) == |
| (MV_CESA_MAC_THEN_CRYPTO << MV_CESA_OPERATION_OFFSET)) || |
| ((pSA->config & MV_CESA_OPERATION_MASK) == |
| (MV_CESA_CRYPTO_THEN_MAC << MV_CESA_OPERATION_OFFSET)) ) |
| { |
| if( (mvCtrlModelGet() == MV_5182_DEV_ID) || |
| ( (mvCtrlModelGet() == MV_5181_DEV_ID) && |
| (mvCtrlRevGet() >= MV_5181L_A0_REV) && |
| (pCmd->macLength >= (1 << 14)) ) ) |
| { |
| return MV_NOT_ALLOWED; |
| } |
| |
| /* abs(cryptoOffset-macOffset) must be aligned cryptoBlockSize */ |
| if(pCmd->cryptoOffset > pCmd->macOffset) |
| { |
| offset = pCmd->cryptoOffset - pCmd->macOffset; |
| } |
| else |
| { |
| offset = pCmd->macOffset - pCmd->cryptoOffset; |
| } |
| |
| if( MV_IS_NOT_ALIGN(offset, pSA->cryptoBlockSize) ) |
| { |
| /* |
| mvOsPrintf("mvCesaFragParamCheck: (cryptoOffset - macOffset) must be %d byte aligned\n", |
| pSA->cryptoBlockSize); |
| */ |
| return MV_NOT_ALLOWED; |
| } |
| /* Digest must not be part of CryptoLength */ |
| if( ((pCmd->digestOffset + pSA->digestSize) > pCmd->cryptoOffset) && |
| (pCmd->digestOffset < (pCmd->cryptoOffset + pCmd->cryptoLength)) ) |
| { |
| /* |
| mvOsPrintf("mvCesaFragParamCheck: digestOffset (%d) is part of cryptoLength (%d+%d)\n", |
| pCmd->digestOffset, pCmd->cryptoOffset, pCmd->cryptoLength); |
| */ |
| return MV_NOT_ALLOWED; |
| } |
| } |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCesaFragSizeFind - |
| * |
| * DESCRIPTION: |
| * |
| * |
| * INPUT: |
| * MV_CESA_SA* pSA, MV_CESA_COMMAND *pCmd, |
| * int cryptoOffset, int macOffset, |
| * |
| * OUTPUT: |
| * int* pCopySize, int* pCryptoDataSize, int* pMacDataSize |
| * |
| * RETURN: |
| * MV_STATUS |
| * |
| *******************************************************************************/ |
| static void mvCesaFragSizeFind(MV_CESA_SA* pSA, MV_CESA_REQ* pReq, |
| int cryptoOffset, int macOffset, |
| int* pCopySize, int* pCryptoDataSize, int* pMacDataSize) |
| { |
| MV_CESA_COMMAND *pCmd = pReq->pCmd; |
| int cryptoDataSize, macDataSize, copySize; |
| |
| cryptoDataSize = macDataSize = 0; |
| copySize = *pCopySize; |
| |
| if( (pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_MAC_ONLY << MV_CESA_OPERATION_OFFSET) ) |
| { |
| cryptoDataSize = MV_MIN( (copySize - cryptoOffset), |
| (pCmd->cryptoLength - (pReq->frags.cryptoSize + 1)) ); |
| |
| /* cryptoSize for each fragment must be the whole number of blocksSize */ |
| if( MV_IS_NOT_ALIGN(cryptoDataSize, pSA->cryptoBlockSize) ) |
| { |
| cryptoDataSize = MV_ALIGN_DOWN(cryptoDataSize, pSA->cryptoBlockSize); |
| copySize = cryptoOffset + cryptoDataSize; |
| } |
| } |
| if( (pSA->config & MV_CESA_OPERATION_MASK) != |
| (MV_CESA_CRYPTO_ONLY << MV_CESA_OPERATION_OFFSET) ) |
| { |
| macDataSize = MV_MIN( (copySize - macOffset), |
| (pCmd->macLength - (pReq->frags.macSize + 1))); |
| |
| /* macSize for each fragment (except last) must be the whole number of blocksSize */ |
| if( MV_IS_NOT_ALIGN(macDataSize, MV_CESA_AUTH_BLOCK_SIZE) ) |
| { |
| macDataSize = MV_ALIGN_DOWN(macDataSize, MV_CESA_AUTH_BLOCK_SIZE); |
| copySize = macOffset + macDataSize; |
| } |
| cryptoDataSize = copySize - cryptoOffset; |
| } |
| *pCopySize = copySize; |
| |
| if(pCryptoDataSize != NULL) |
| *pCryptoDataSize = cryptoDataSize; |
| |
| if(pMacDataSize != NULL) |
| *pMacDataSize = macDataSize; |
| } |