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