diff -r 675a964f4eb5 -r 35751d3474b7 cryptoplugins/cryptospiplugins/test/h4drv/crypto_h4/cryptoh4aes.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cryptoplugins/cryptospiplugins/test/h4drv/crypto_h4/cryptoh4aes.cpp Thu Sep 10 14:01:51 2009 +0300 @@ -0,0 +1,941 @@ +/* +* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +/** + @file + @internalComponent + @released +*/ +#include +#include +#ifdef __MARM__ +#include +#include +#endif +#include "cryptoh4aes.h" + +#if 0 +#undef __MARM__ +#ifndef __MARM__ +#warning "h/w disabled" +#endif +#endif + +#ifdef DUMPBUFFER +LOCAL_D void dumpBuffer(const char *aName, TUint32 *aBuf, TUint32 aLen); +#else +#define dumpBuffer(aName, aBuf, aLen) +#endif + +CryptoH4JobAes::CryptoH4JobAes(DLddChanAes &aLddChanAes) + : iLddChanAes(aLddChanAes), + iEncrypt(EFalse), + iKeyLengthBytes(0), + iSwWriteByteOffset(0), + iHwReadIndex(0), + iHwWriteIndex(0), + iSwReadByteOffset(0), + iHwRunning(EFalse), + iDmaToHwPending(0), + iDmaFromHwPending(0), +#ifdef FAKE_DMA + iFakeDmaToHwQueued(0), + iFakeDmaFromHwQueued(0), +#endif + iDmaToHwCompleteDfc(DmaToHwCompleteDfc, this, 1), // DFC is priority '1' + iDmaFromHwCompleteDfc(DmaFromHwCompleteDfc, this, 1) + { + TRACE_FUNCTION("CryptoH4JobAes"); + } + +CryptoH4JobAes::~CryptoH4JobAes() + { + TRACE_FUNCTION("~CryptoH4JobAes"); + StopHw(); + } + + +void CryptoH4JobAes::SetDfcQ(TDfcQue *aDfcQue) + { + TRACE_FUNCTION("SetDfcQ"); + iDmaToHwCompleteDfc.SetDfcQ(aDfcQue); + iDmaFromHwCompleteDfc.SetDfcQ(aDfcQue); + } + +TUint8 *CryptoH4JobAes::GetKeyBuffer() + { + TRACE_FUNCTION("GetKeyBuffer"); + return (TUint8 *) &iKey; + } + +TUint8 *CryptoH4JobAes::GetIVBuffer() + { + TRACE_FUNCTION("GetIVBuffer"); + return (TUint8 *) &iIV; + } + +TUint32 CryptoH4JobAes::MaxBytes() const + { + TRACE_FUNCTION("MaxBytes"); + return sizeof(iAesBuffer); // return size in bytes + } + +TUint8 *CryptoH4JobAes::GetIOBuffer() + { + TRACE_FUNCTION("GetIOBuffer"); + return (TUint8 *) &iAesBuffer; + } + +void CryptoH4JobAes::GetToPddBuffer(TUint8 * &aBuf, TUint32 &aBufLen, TBool &aMore) + { + TRACE_FUNCTION("GetToPddBuffer"); + CheckIndexes(); + TUint8 *p = (TUint8 *) iAesBuffer; + aBuf = &p[iSwWriteByteOffset]; + + if(iSwReadByteOffset > iSwWriteByteOffset) + { + // Available buffer is contiguous + aBufLen = iSwReadByteOffset - iSwWriteByteOffset; + if(aBufLen) --aBufLen; // Never use all space to stop index collision + aMore = EFalse; + return; + } + else + { + // Available data crosses buffer end so return two regions + // OR indexes are equal + aBufLen = sizeof(iAesBuffer) - iSwWriteByteOffset; + if(iSwReadByteOffset == 0) + { + // Do not fill to end of buffer because index would wrap and collid + --aBufLen; + aMore = EFalse; + return; + } + aMore = (iSwReadByteOffset != iSwWriteByteOffset); // Another region to read + return; + } + // Never gets here + } + +void CryptoH4JobAes::BytesWrittenToPdd(TUint32 aBytes) + { + TRACE_FUNCTION("BytesWrittenToPdd"); + CheckIndexes(); + iSwWriteByteOffset += aBytes; + if(iSwWriteByteOffset >= sizeof(iAesBuffer)) + { + iSwWriteByteOffset -= sizeof(iAesBuffer); + } + + CheckIndexes(); + } + +void CryptoH4JobAes::GetFromPddBuffer(TUint8 * &aBuf, TUint32 &aBufLen, TBool &aMore) + { + TRACE_FUNCTION("GetFromPddBuffer"); + CheckIndexes(); + TInt hwWrite8Index = iHwWriteIndex * 4; + TUint8 *p = (TUint8 *) iAesBuffer; + aBuf = &p[iSwReadByteOffset]; + + TInt len = hwWrite8Index - iSwReadByteOffset; + if(len >= 0) + { + aBufLen = len; + aMore = EFalse; + } + else + { + // Wrap round condition, but can only return contiguous bytes + aBufLen = sizeof(iAesBuffer) - iSwReadByteOffset; + aMore = (hwWrite8Index != 0); + } + CheckIndexes(); + } + +void CryptoH4JobAes::BytesReadFromPdd(TUint32 aBytes) + { + TRACE_FUNCTION("BytesReadFromPdd"); + CheckIndexes(); + iSwReadByteOffset += aBytes; + if(iSwReadByteOffset >= sizeof(iAesBuffer)) + { + iSwReadByteOffset -= sizeof(iAesBuffer); + } + CheckIndexes(); + iReadRequestLength -= aBytes; + } + + + +TInt CryptoH4JobAes::SetDetails(DCryptoJobScheduler *aJobScheduler, + MCryptoJobCallbacks *aCallbacks, + TBool aEncrypt, + TInt aKeyLengthBytes, + RCryptoDriver::TChainingMode aMode) + { + TRACE_FUNCTION("TChainingMode"); + // Kern::Printf("AES Details %s: Key len %d, Mode %s (%d)", + // aEncrypt?"Encrypt":"Decrypt", aKeyLengthBytes, (aMode == RCryptoDriver::ECbcMode)?"CBC":"ECB", aMode); + + if(State() != ECreated) + { + return KErrArgument; + } + + iJobScheduler = aJobScheduler; + iCallbacks = aCallbacks; + iEncrypt = aEncrypt; + iKeyLengthBytes = aKeyLengthBytes; + + if((aMode != RCryptoDriver::EEcbMode) && (aMode != RCryptoDriver::ECbcMode)) + { + return KErrArgument; + } + iMode = aMode; + if(iMode == RCryptoDriver::ECbcMode) + { + // For CBC we need to save the IV incase we need to + // re-initialise the h/w mid-job + TUint32 *from; + TUint32 *to; + if(iEncrypt) + { + // For encryption - DoSaveState saves the last encrypted + // block. We set this to the IV to handle the case where + // we do not encrypt any blocks before being suspended. + from = &iIV[0]; + to = &iAesBuffer[((sizeof(iAesBuffer)-16)/4)]; + } + else + { + // For decryption - MaybeSetupWriteDmaToHw maintains + // iSavedState as a copy of the last ciphertext + // (pre-decryption) so DoSaveState does not need to do + // anything. + // + // To cover the case where we do not decrypt any blocks + // before being suspended, we initialise iSavedState to the IV. + from = &iIV[0]; + to = &iSavedState[0]; + } + // Save the IV + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; + if(iEncrypt) + { + dumpBuffer("SetDetails - end of iAesBuffer", to-4, 4); + } + else + { + dumpBuffer("SetDetails - iSavedState", iSavedState, 4); + } + } + + // Reset indexes + iSwWriteByteOffset = 0; + iHwReadIndex = 0, + iHwWriteIndex = 0, + iSwReadByteOffset = 0; + + return KErrNone; + } + +void CryptoH4JobAes::DoSlice(TBool aFirstSlice) + { + TRACE_FUNCTION("DoSlice"); + // Kern::Printf("DoSlice %s", aFirstSlice?"FIRST":""); + if(aFirstSlice) + { + SetupHw(EFalse); + } + + // Push any available data to user + TInt r = iCallbacks->DataAvailable(); + if(r != KErrNone) + { + iJobScheduler->JobComplete(this,r); + return; + } + // Read available data from user + r = iCallbacks->DataRequired(); + if(r != KErrNone) + { + iJobScheduler->JobComplete(this,r); + return; + } + + // Setup to read data (if enough is available). + // Kern::Printf("DoSlice - calling MaybeSetupWriteDmaToHw"); + MaybeSetupWriteDmaToHw(); + + FAKE_DMA(); + + if(!iDmaToHwPending && !iDmaFromHwPending) + { + Stalled(); + } + + return; + } + +TBool CryptoH4JobAes::DoSaveState() + { + TRACE_FUNCTION("DoSaveState"); + + if((iMode == RCryptoDriver::ECbcMode) && iEncrypt) + { + // Doing CBC encryption - Need to save a copy of the last + // ciphertext block (after encryption) so we can use it as the + // IV if we are later resumed. + // + // Last block processed by h/w just BEFORE iHwWriteIndex. If + // we have not processed any data, then SetDetails will have + // initialised this to the IV + TInt32 fromIndex = (iHwWriteIndex!=0) ? (iHwWriteIndex-4) : ((sizeof(iAesBuffer)-16)/4); + TUint32 *from = &iAesBuffer[fromIndex]; + TUint32 *to = &iSavedState[0]; + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; + dumpBuffer("DoSaveState - iSavedState", iSavedState, 4); + } + + StopHw(); + return ETrue; // We want DoRestoreState to be called + } + +void CryptoH4JobAes::DoRestoreState() + { + TRACE_FUNCTION("DoRestoreState"); + SetupHw(ETrue); + } + +void CryptoH4JobAes::DoReleaseHw() + { + TRACE_FUNCTION("DoReleaseHw"); + StopHw(); +#ifndef FAKE_DMA + // Cancel DFCs - Doesn't work for FAKE_DMA case.... + iDmaToHwCompleteDfc.Cancel(); + iDmaFromHwCompleteDfc.Cancel(); +#endif + } + +void CryptoH4JobAes::MaybeSetupWriteDmaToHw() + { + TRACE_FUNCTION("MaybeSetupWriteDmaToHw"); + if(!iDmaToHwPending) + { + // Calculate space between H/W read index and S/W write index or end of buffer + TInt hwReadIndex8 = iHwReadIndex*4; + TInt avail = (iSwWriteByteOffset >= hwReadIndex8) ? (iSwWriteByteOffset - hwReadIndex8) : (sizeof(iAesBuffer) - hwReadIndex8); + + if(avail >= 16) + { + // At least another block of data is available. + if((avail <= 31) && (iMode == RCryptoDriver::ECbcMode) && !iEncrypt) + { + // Only one complete block is available + + // Doing CBC decryption, so need to save a copy of the + // last ciphertext block (before it is decrypted) so we + // can use it as the IV if we are kicked off the h/w + // and have to reconfigure. + // Last block available for h/w is at hwReadIndex8 + TUint32 *from = &iAesBuffer[iHwReadIndex]; + TUint32 *to = &iSavedState[0]; + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; + dumpBuffer("MaybeSetupWriteDmaToHw - iSavedState", iSavedState, 4); + } + SetupDma((TUint32)&iAesBuffer[iHwReadIndex], ETrue); + } + } + } + + +#ifdef FAKE_DMA +void CryptoH4JobAes::FakeDma() + { + TRACE_FUNCTION("FakeDma"); + if(iFakeDmaToHwQueued < iDmaToHwPending) + { + // Calculate number of 32 bit values in the h/w + TInt inHw32 = iHwReadIndex - iHwWriteIndex; + if(inHw32 < 0) + { + inHw32 += sizeof(iAesBuffer)/sizeof(iAesBuffer[0]); + } + // Convert to number of 16 byte blocks in h/w + TInt inHwBlocks = inHw32/4; + + if((inHwBlocks + iFakeDmaToHwQueued) < 2) + { + // Pipeline is not full, so the next DMA to complete would be a "to h/w" + // Wait for h/w to be ready +#ifdef __MARM__ + // Kern::Printf("CryptoH4JobAes::FakeDma - Start waiting for h/w input ready (%x)", TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL)); + while(! (TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL) & KHtAesCtrlInputReady)) + { + Kern::Printf("CryptoH4JobAes::FakeDma - Waiting for h/w input ready (%x)", TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL)); + } +#endif + // Queue the fake "to dma" complete DFC + iDmaToHwCompleteDfc.Enque(); + ++iFakeDmaToHwQueued; + return; + } + } + + // Either pipeline is full, or we are out of input data. + + // Check for output + if(iFakeDmaFromHwQueued < iDmaFromHwPending) + { +#ifdef __MARM__ + // Kern::Printf("CryptoH4JobAes::FakeDma - Start waiting for output ready (%x)", TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL)); + while(! (TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL) & KHtAesCtrlOutputReady)) + { + Kern::Printf("CryptoH4JobAes::FakeDma - waiting for output ready (%x)",TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL)); + } +#endif + // Queue the fake "from dma" complete DFC + iDmaFromHwCompleteDfc.Enque(); + ++iFakeDmaFromHwQueued; + return; + } + + return; + } +#endif + + + + +void CryptoH4JobAes::SetupHw(TBool aUseSavedState) + { + TRACE_FUNCTION("SetupHw"); + // Kern::Printf("SetupHw"); +#ifdef __MARM__ + // AES_MASK +#ifdef FAKE_DMA + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_MASK, KHtAesMaskAutoIdle); +#else + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_MASK, + KHtAesMaskDmaReqIn | KHtAesMaskDmaReqOut | KHtAesMaskAutoIdle); +#endif + iHwRunning = EFalse; // Previous MASK register write cleared the start bit. + + TUint32 ctrl = 0; + if(iEncrypt) + { + ctrl |= KHtAesCtrlDirection; + } + + switch(iKeyLengthBytes) + { + case 32: + // KEYS + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY1_L, iKey[0]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY1_H, iKey[1]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY2_L, iKey[2]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY2_H, iKey[3]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY3_L, iKey[4]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY3_H, iKey[5]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY4_L, iKey[6]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY4_H, iKey[7]); + ctrl |= KHtAesCtrlKeySize256; + break; + case 24: + // KEYS + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY1_L, iKey[0]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY1_H, iKey[1]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY2_L, iKey[2]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY2_H, iKey[3]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY3_L, iKey[4]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY3_H, iKey[5]); + ctrl |= KHtAesCtrlKeySize192; + break; + case 16: + // KEYS + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY1_L, iKey[0]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY1_H, iKey[1]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY2_L, iKey[2]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_KEY2_H, iKey[3]); + ctrl |= KHtAesCtrlKeySize128; + break; + } + + + + // IV (CBC only) + if(iMode == RCryptoDriver::ECbcMode) + { + if(!aUseSavedState) + { + // Kern::Printf("Setting IV"); + // Set IV + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_IV_1, iIV[0]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_IV_2, iIV[1]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_IV_3, iIV[2]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_IV_4, iIV[3]); + dumpBuffer("SetupHw(EFalse) - iIV", iIV, 4); + } + else + { + // Set IV to saved state + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_IV_1, iSavedState[0]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_IV_2, iSavedState[1]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_IV_3, iSavedState[2]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_IV_4, iSavedState[3]); + dumpBuffer("SetupHw(ETrue) - iSavedState", iSavedState, 4); + } + + ctrl |= KHsAesCtrlCBC; + } + + // AES_CTRL + // Kern::Printf("Setting crtl to %x", ctrl); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_CTRL, ctrl); + + // AES_MASK START bit to start DMA + // This is done by SetupDma +#else + (void)aUseSavedState; + +#endif + } + +void CryptoH4JobAes::SetupDma(TUint32 aPtr, TBool aToHw) + { + TRACE_FUNCTION("SetupDma"); + // Kern::Printf("\t\tSetupDMA - %s, iHwReadIndex %d iHwWriteIndex %d", + // aToHw?"toHw":"fromHw", iHwReadIndex, iHwWriteIndex); + // Start the h/w + if(!iHwRunning) + { + // Kern::Printf("SetupDma - starting h/w"); +#ifdef __MARM__ + // If h/w is not enabled yet, then set the start bit. This is + // required even when NOT using DMA... + TUint32 mask = TOmap::Register32(KHwBaseAesReg + KHoAES_MASK); + // Kern::Printf("mask is %x", mask); + mask |= KHtDesMaskDmaReqStart; + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_MASK, mask); + // Kern::Printf("changed to %x", TOmap::Register32(KHwBaseAesReg + KHoAES_MASK)); +#else + (void)aPtr; +#endif + iHwRunning = ETrue; + } + + if(aToHw) + { + ++iDmaToHwPending; + SetRunning(ETrue); + } + else + { + ++iDmaFromHwPending; + SetRunning(ETrue); + } + + } + + +void CryptoH4JobAes::StopHw() + { + TRACE_FUNCTION("StopHw"); +#ifdef __MARM__ + // Disable h/w + TUint32 mask = TOmap::Register32(KHwBaseAesReg + KHoAES_MASK); + mask &= ~KHtDesMaskDmaReqStart; + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_MASK, mask); +#endif + iHwRunning = EFalse; + } + + + +/** + Called when the current h/w opperation is complete +*/ +void CryptoH4JobAes::DmaComplete(DDmaRequest::TResult aResult, TAny *aPtr) + { + TRACE_FUNCTION("TResult"); + (void)aResult; + // Queue our DFC to action the DMA complete notification in our thread. + reinterpret_cast(aPtr)->Enque(); + } + + + + +void CryptoH4JobAes::DmaToHwCompleteDfc(TAny* aPtr) + { + ((CryptoH4JobAes*)aPtr)->DoDmaToHwCompleteDfc(); + } + + +void CryptoH4JobAes::DoDmaToHwCompleteDfc() + { + TRACE_FUNCTION("DoDmaToHwCompleteDfc"); + // Kern::Printf("**DoDmaToHwCompleteDfc iHwReadIndex %d, iHwWriteIndex %d",iHwReadIndex, iHwWriteIndex); + --iDmaToHwPending; + if(iDmaToHwPending < 0) Kern::Fault("DoDmaToHwCompleteDfc - iDmaToHwPending is negative",1); + +#ifdef FAKE_DMA + --iFakeDmaToHwQueued; + if(iFakeDmaToHwQueued < 0) Kern::Fault("DoDmaToHwCompleteDfc - iFakeDmaToHwQueued is negative",2); +#endif + + CheckIndexes(); + +#ifdef __MARM__ + if(! (TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL) & KHtAesCtrlInputReady)) + { + Kern::Fault("DoDmaToHwCompleteDfc - h/w not ready for input!",3); + } + // Kern::Printf("DoDmaToHwCompleteDfc - Writing data into h/w index %d (%x)", iHwReadIndex, TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL)); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_DATA_1, iAesBuffer[iHwReadIndex]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_DATA_2, iAesBuffer[iHwReadIndex+1]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_DATA_3, iAesBuffer[iHwReadIndex+2]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_DATA_4, iAesBuffer[iHwReadIndex+3]); +#endif + + // Update index to point at next block to be passed to the h/w + iHwReadIndex += 4; // 4x32bit == 16bytes == block length + if(iHwReadIndex == sizeof(iAesBuffer)/sizeof(TUint32)) + { + iHwReadIndex = 0; + } + + if(!iDmaFromHwPending) + { + SetupDma((TUint32)&iAesBuffer[iHwWriteIndex], EFalse); + } + + CheckIndexes(); + + // Setup to read data (if enough is available). + MaybeSetupWriteDmaToHw(); + + FAKE_DMA(); + } + +void CryptoH4JobAes::DmaFromHwCompleteDfc(TAny* aPtr) + { + ((CryptoH4JobAes*)aPtr)->DoDmaFromHwCompleteDfc(); + } + + +void CryptoH4JobAes::DoDmaFromHwCompleteDfc() + { + TRACE_FUNCTION("DoDmaFromHwCompleteDfc"); + // Kern::Printf("**DoDmaFromHwCompleteDfc iHwReadIndex %d, iHwWriteIndex %d", iHwReadIndex, iHwWriteIndex); + + --iDmaFromHwPending; + if(iDmaFromHwPending < 0) Kern::Fault("DoDmaFromHwCompleteDfc - iDmaFromHwPending is negative",1); + +#ifdef FAKE_DMA + --iFakeDmaFromHwQueued; + if(iFakeDmaFromHwQueued < 0) Kern::Fault("iFakeDmaFromHwQueued - iFakeDmaFromHwQueued is negative",2); +#endif + + CheckIndexes(); + +#ifdef __MARM__ + if(! (TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL) & KHtAesCtrlOutputReady)) + { + Kern::Fault("DoDmaToHwCompleteDfc - h/w not ready for output!",3); + } + + // Kern::Printf("DoDmaFromHwCompleteDfc - Reading data from h/w index %d (%x)", iHwWriteIndex, TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL)); + iAesBuffer[iHwWriteIndex] = TOmap::Register32(KHwBaseAesReg + KHoAES_DATA_1); + iAesBuffer[iHwWriteIndex+1] = TOmap::Register32(KHwBaseAesReg + KHoAES_DATA_2); + iAesBuffer[iHwWriteIndex+2] = TOmap::Register32(KHwBaseAesReg + KHoAES_DATA_3); + iAesBuffer[iHwWriteIndex+3] = TOmap::Register32(KHwBaseAesReg + KHoAES_DATA_4); +#endif + + // Update index to point at next block to be read from the h/w + iHwWriteIndex += 4; // 4x32bit == 16bytes == block length + if(iHwWriteIndex == sizeof(iAesBuffer)/sizeof(TUint32)) + { + iHwWriteIndex= 0; + } + + CheckIndexes(); + + + + TInt hwWrite8Index = iHwWriteIndex * 4; + TInt hwRead8Index = iHwReadIndex * 4; + + // Check if we either have enough data to finish the current LDD + // user read request, or if we are running out of space + // + // Calculate data available for xfer to user + TInt availableForUser = hwWrite8Index - iSwReadByteOffset; + if(availableForUser < 0) + { + availableForUser += sizeof(iAesBuffer); + } + + if((availableForUser >= sizeof(iAesBuffer) - 32) || + (availableForUser >= iReadRequestLength)) + { + // Pass available data to user + TInt r = iCallbacks->DataAvailable(); + if(r != KErrNone) + { + iJobScheduler->JobComplete(this,r); + return; + } + } + + // Are we running short of data? + TInt availableForHw = iSwWriteByteOffset - hwRead8Index; + if(availableForHw < 0) + { + availableForHw += sizeof(iAesBuffer); + } + + if(availableForHw < 16) + { + TInt r = iCallbacks->DataRequired(); + if(r != KErrNone) + { + iJobScheduler->JobComplete(this,r); + return; + } + } + + // Kick off a new to h/w DMA if one is not already running + MaybeSetupWriteDmaToHw(); + + // Current h/w -> iAesBuffer DMA request has completed + if(iHwWriteIndex != iHwReadIndex) + { + SetupDma((TUint32)&iAesBuffer[iHwWriteIndex], EFalse); + } + + if(!iDmaToHwPending && ! iDmaFromHwPending) + { + // Kern::Printf("\t\tDoDmaFromHwCompleteDfc STALLED (underrun), iHwReadIndex %d iHwWriteIndex %d", + // iHwReadIndex, iHwWriteIndex); + // Run out of data to process! + // Tell the scheduler that we are stalled & therefore this slice is done + Stalled(); + return; + } + + + CheckIndexes(); + + FAKE_DMA(); + } + +void CryptoH4JobAes::CheckIndexes() const + { + TRACE_FUNCTION("CheckIndexes"); + if(iSwWriteByteOffset < 0 || iSwWriteByteOffset > sizeof(iAesBuffer)) Kern::Fault("CryptoH4JobAes::checkIndexes", 1); + + if(iHwReadIndex < 0 || iHwReadIndex > sizeof(iAesBuffer)/sizeof(iAesBuffer[0])) Kern::Fault("CryptoH4JobAes::checkIndexes", 2); + + if(iHwWriteIndex < 0 || iHwWriteIndex > sizeof(iAesBuffer)/sizeof(iAesBuffer[0])) Kern::Fault("CryptoH4JobAes::checkIndexes", 3); + + if(iSwReadByteOffset < 0 || iSwReadByteOffset > sizeof(iAesBuffer)) Kern::Fault("CryptoH4JobAes::checkIndexes", 4); + + + TInt32 d = iSwWriteByteOffset; + TInt32 c = iHwReadIndex * 4; + TInt32 b = iHwWriteIndex * 4; + TInt32 a = iSwReadByteOffset; + + // Kern::Printf("%d %d %d %d", a, b, c, d); + + TInt32 offset = 0; + if(b < a) offset = sizeof(iAesBuffer); + b += offset; + if(c < b) offset = sizeof(iAesBuffer); + c += offset; + if(d < c) offset = sizeof(iAesBuffer); + d += offset; + + if(a>b) Kern::Fault("CryptoH4JobAes::CheckIndexes", 5); + if(b>c) Kern::Fault("CryptoH4JobAes::CheckIndexes", 6); + if(c>d) Kern::Fault("CryptoH4JobAes::CheckIndexes", 7); + } + + +void CryptoH4JobAes::NotifyReadRequestLength(TUint32 aReadRequestLength) + { + TRACE_FUNCTION("NotifyReadRequestLength"); + iReadRequestLength = aReadRequestLength; + } + +/** + HwPerfCheck + + This function uses 100% of the CPU power to attempt to drive + the AES h/w as fast as possible. + + This will give some indication of the maximum achievable speed of the h/w + excluding the overhead of (almost all of) the driver framework. + */ +void CryptoH4JobAes::HwPerfCheck() + { + TRACE_FUNCTION("HwPerfCheck"); + SetupHw(EFalse); + + // Start h/w +#ifdef __MARM__ + TUint32 mask = TOmap::Register32(KHwBaseAesReg + KHoAES_MASK); + mask |= KHtDesMaskDmaReqStart; + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_MASK, mask); +#endif + + // Reset indexes + iSwWriteByteOffset = 0; + iHwReadIndex = 0, + iHwWriteIndex = 0, + iSwReadByteOffset = 0; + + // Read data + iCallbacks->DataRequired(); + // Process all data + while(iHwWriteIndex*4 < iSwWriteByteOffset) + { +#ifdef __MARM__ + // Kern::Printf("Ctrl %08x", TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL)); +#endif + // Have we got more data to write to h/w? + if(iHwReadIndex < iSwWriteByteOffset/4) + { + // Yes, but is h/w ready for it? +#ifdef __MARM__ + if(TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL) & KHtAesCtrlInputReady) + { + // Kern::Printf("toHw iHwReadIndex=%d", iHwReadIndex); + // ok, write data to h/w + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_DATA_1, iAesBuffer[iHwReadIndex]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_DATA_2, iAesBuffer[iHwReadIndex+1]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_DATA_3, iAesBuffer[iHwReadIndex+2]); + TOmap::SetRegister32(KHwBaseAesReg + KHoAES_DATA_4, iAesBuffer[iHwReadIndex+3]); + iHwReadIndex += 4; + } +#else + iHwReadIndex += 4; +#endif + } + // Do we expect more data from the h/w? + if(iHwWriteIndex < iSwWriteByteOffset/4) + { + // Yes, but is h/w ready? +#ifdef __MARM__ + if(TOmap::Register32(KHwBaseAesReg + KHoAES_CTRL) & KHtAesCtrlOutputReady) + { + // Kern::Printf("ReadHw to iHwWriteIndex=%d", iHwWriteIndex); + iAesBuffer[iHwWriteIndex] = TOmap::Register32(KHwBaseAesReg + KHoAES_DATA_1); + iAesBuffer[iHwWriteIndex+1] = TOmap::Register32(KHwBaseAesReg + KHoAES_DATA_2); + iAesBuffer[iHwWriteIndex+2] = TOmap::Register32(KHwBaseAesReg + KHoAES_DATA_3); + iAesBuffer[iHwWriteIndex+3] = TOmap::Register32(KHwBaseAesReg + KHoAES_DATA_4); + iHwWriteIndex += 4; + } +#else + iHwWriteIndex += 4; +#endif + } + } + + // Write data back to user + iCallbacks->DataAvailable(); + } + + + + +#ifdef TDFC_WRAPPER +TDfcWrapper::TDfcWrapper(const TDfcWrapper &aOrig) + : TDfc(DfcWrapperFunc, this, aOrig.iPriority) + { + TRACE_FUNCTION("TDfcWrapper"); + iRealFunction = aOrig.iRealFunction, + iRealPtr = aOrig.iRealPtr; + SetDfcQ(aOrig.iDfcQ); + } + + +TDfcWrapper::TDfcWrapper(TDfcFn aFunction, TAny* aPtr, TInt aPriority) + : TDfc(DfcWrapperFunc, this, aPriority), + iRealFunction(aFunction), + iRealPtr(aPtr) + { + TRACE_FUNCTION("TDfcWrapper"); + } + +void TDfcWrapper::Enque() + { + TRACE_FUNCTION("Enque"); + // Clone self and queue the clone + TDfcWrapper *p = new TDfcWrapper(*this); + p->BaseEnque(); + } + +void TDfcWrapper::BaseEnque() + { + TRACE_FUNCTION("BaseEnque"); + TDfc::Enque(); + } + + +void TDfcWrapper::DfcWrapperFunc(TAny* aPtr) + { + TRACE_FUNCTION("DfcWrapperFunc"); + TDfcWrapper *p = (TDfcWrapper *) aPtr; + p->iRealFunction(p->iRealPtr); + delete p; + } +#endif + +#ifdef DUMPBUFFER +LOCAL_D void dumpBuffer(const char *aName, TUint32 *aBuf, TUint32 aLen) + { + Kern::Printf("%s =", aName); + TUint8 *buf8 = reinterpret_cast(aBuf); + for(TInt i = 0 ; i < aLen*4; ++i) + { + if(i%16 == 0) + { + Kern::Printf("\n "); + } + Kern::Printf("%02x ", buf8[i]); + } + Kern::Printf("\n"); + } +#endif + +// End of file