cryptoplugins/cryptospiplugins/test/h4drv/crypto_h4/cryptoh4aes.cpp
changeset 8 35751d3474b7
child 15 da2ae96f639b
--- /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 <kernel/kern_priv.h>
+#include <cryptodriver.h>
+#ifdef __MARM__
+#include <omap_hrp/assp/shared/omap_reg.h>
+#include <omap_hrp/assp/shared/omap_interrupt.h>
+#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<TDfc *>(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<TUint8 *>(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