kerneltest/e32test/mmu/d_cache.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mmu/d_cache.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1176 @@
+// Copyright (c) 2006-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:
+// e32test\debug\d_cache.cpp
+// See e32test\mmu\t_cache.cpp for details
+// 
+//
+
+#include "d_cache.h"
+#include <kernel/kern_priv.h>
+#include <kernel/cache.h>
+
+extern TUint32 GetCacheType();
+extern void TestCodeFunc();
+extern TInt TestCodeFuncSize();
+extern void DataSegmetTestFunct(void* aBase, TInt aSize);
+
+#ifdef __XSCALE_L2_CACHE__
+extern TUint32 L2CacheTypeReg();
+#endif
+
+#if defined(__CPU_MEMORY_TYPE_REMAPPING)
+extern TUint32 CtrlRegister();
+extern TUint32 PRRRRegister();
+extern TUint32 NRRRRegister();
+extern void SetPRRR(TUint32);
+extern void SetNRRR(TUint32);
+#endif
+
+
+typedef void(CodeTest) ();
+
+class DCacheTest : public DLogicalChannelBase
+	{
+public:
+	DCacheTest();
+	~DCacheTest();
+protected:
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
+private:
+	TInt GetCacheInfo(TAny* a1);
+	TInt TestDataChunk(TAny* a1);
+	TInt TestCodeChunk(TAny* a1);
+	TInt TestWriteBackMode(TAny* a1, TBool aWriteAlloc);
+	TInt TestL2Maintenance();
+	TInt GetThreshold(TAny* a1);
+	TInt SetThreshold(TAny* a1);
+	TInt TestUseCase(TAny* a1);
+	void LoopTestCodeFunc(CodeTest* f);
+
+
+	void GetExternalCacheInfo(RCacheTestDevice::TCacheInfo& info);
+
+	void CheckRemapping(RCacheTestDevice::TCacheInfo& info);
+	void Remap(RCacheTestDevice::TCacheAttr aCacheAttr);
+
+	TInt UseCase_ReadFromChunk(RCacheTestDevice::TChunkTest& info);
+	TInt UseCase_ReadFromChunk_ReadFromHeap(RCacheTestDevice::TChunkTest& info);
+	TInt UseCase_WriteToChunk(RCacheTestDevice::TChunkTest& info);
+	TInt UseCase_WriteToChunk_ReadFromHeap(RCacheTestDevice::TChunkTest& info);
+
+
+	//Phys. memory and shared chunk alloc/dealloc primitives
+	TInt AllocPhysicalRam(TInt aSize);
+	void FreePhysicalRam();
+	TInt CreateSharedChunk(TInt aMapAttr, TUint32& aActualMapAttr);
+	void CloseSharedChunk();
+
+private:
+	DChunk* 	iSharedChunk;	// Shared chunk used in the test
+	TPhysAddr 	iPhysAddr;		// Physical address of the allocated memory assigned to the chunk
+	TUint 		iSize;			// The size of the allocated memory.
+	TLinAddr 	iChunkBase;		// Base linear address of the shared chunk.
+
+	TInt* iHeap1;
+	TInt* iHeap2;
+	TUint32 iDummy;
+	};
+
+DCacheTest* CacheTestDriver;
+
+DCacheTest::DCacheTest() 	{}
+
+DCacheTest::~DCacheTest()	{CacheTestDriver = NULL;}
+
+/**Creates the channel*/
+TInt DCacheTest::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& /*aVer*/) {return KErrNone;}
+
+/** Allocates physical memory and sets iPhysAddr & iSize accordingly.*/
+TInt DCacheTest::AllocPhysicalRam(TInt aSize)
+	{
+	iSize = aSize;
+	NKern::ThreadEnterCS();
+	TInt r = Epoc::AllocPhysicalRam(aSize, iPhysAddr, 0); //Allocate physical RAM. This will set iPhysAddr
+	NKern::ThreadLeaveCS();
+	return r;
+	}
+
+/** Frees physical memory.*/
+void DCacheTest::FreePhysicalRam()
+	{
+	NKern::ThreadEnterCS();
+	Epoc::FreePhysicalRam(iPhysAddr, iSize);
+	NKern::ThreadLeaveCS();
+	}
+
+/**
+Creates shared chunks with allocated physical memory and sets iChunkBase accordingly.
+@pre Physical memory is allocated (iPhysAddr & iSize are set accordingly).
+*/
+TInt DCacheTest::CreateSharedChunk(TInt aMapAttr, TUint32& aActualMapAttr)
+	{
+	TInt r;
+    TChunkCreateInfo chunkInfo;
+    chunkInfo.iType         = TChunkCreateInfo::ESharedKernelSingle;
+    chunkInfo.iMaxSize      = iSize;
+    chunkInfo.iMapAttr      = aMapAttr;
+    chunkInfo.iOwnsMemory   = EFalse;
+    chunkInfo.iDestroyedDfc = NULL;
+
+	NKern::ThreadEnterCS();
+    if (KErrNone != (r = Kern::ChunkCreate(chunkInfo, iSharedChunk, iChunkBase, aActualMapAttr)))
+		{
+		FreePhysicalRam();
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	r = Kern::ChunkCommitPhysical(iSharedChunk,0,iSize, iPhysAddr);
+    if(r!=KErrNone)
+        {
+		CloseSharedChunk();
+		FreePhysicalRam();
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	NKern::ThreadLeaveCS();
+	return KErrNone;
+	}
+
+/** Closes shared chunk.*/
+void DCacheTest::CloseSharedChunk()
+	{
+	NKern::ThreadEnterCS();
+	Kern::ChunkClose(iSharedChunk);
+	Kern::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);	// make sure async close has happened
+	NKern::ThreadLeaveCS();
+	}
+
+
+#if defined(__CPU_ARMV7)
+extern TUint32 CacheTypeRegister();
+extern TUint32 CacheLevelIDRegister();
+extern TUint32 CacheSizeIdRegister(TUint32 aType/*0-1*/, TUint32 aLevel/*0-7*/);
+
+void ParseCacheLevelInfo(TInt aCacheSizeIDReg, RCacheTestDevice::TCacheSingle& aCS)
+	{
+	aCS.iSets = ((aCacheSizeIDReg>>13)& 0x7fff)+1;
+	aCS.iWays =   ((aCacheSizeIDReg>>3)& 0x3ff)+1;
+	aCS.iLineSize =1<<((aCacheSizeIDReg & 0x7)+4);//+2 (and +2 as we count in bytes)
+	aCS.iSize = aCS.iSets * aCS.iWays * aCS.iLineSize;
+	}
+#endif
+
+
+void AppendTo(TDes8& aDes, const char* aFmt, ...)
+	{
+	VA_LIST list;
+	VA_START(list,aFmt);
+	Kern::AppendFormat(aDes,aFmt,list);
+	}
+
+/** Checks Memory Remap settings (both memory type and access permission remapping).*/
+void DCacheTest::CheckRemapping(RCacheTestDevice::TCacheInfo& info)
+	{
+#if defined(__CPU_MEMORY_TYPE_REMAPPING)
+	TUint32 cr = CtrlRegister();
+	TUint32 prrr =PRRRRegister();
+	TUint32 nrrr =NRRRRegister();
+	AppendTo(info.iDesc,"Memory Remapping: CtrlReg:%xH, PRRR:%xH NRRR:%xH\n", cr, prrr, nrrr);
+
+	if ( (cr&0x30000000) == 0x30000000)
+		info.iMemoryRemapping = 1;
+	else
+		AppendTo(info.iDesc,"Error:Memory Remapping is OFF \n");
+#endif
+	}
+
+//Remaps aCacheAttr memory type into EMemAttKernelInternal4
+void DCacheTest::Remap(RCacheTestDevice::TCacheAttr aCacheAttr)
+	{
+#if defined(__CPU_MEMORY_TYPE_REMAPPING)
+	TInt inner, outer;
+	switch(aCacheAttr)
+		{
+		case RCacheTestDevice::E_InnerWT_Remapped: 	inner=2;outer=0;break;
+		case RCacheTestDevice::E_InnerWBRA_Remapped:inner=3;outer=0;break;
+		case RCacheTestDevice::E_InnerWB_Remapped:	inner=1;outer=0;break;
+		case RCacheTestDevice::E_OuterWT_Remapped:	inner=0;outer=2;break;
+		case RCacheTestDevice::E_OuterWBRA_Remapped:inner=0;outer=3;break;
+		case RCacheTestDevice::E_OuterWB_Remapped:	inner=0;outer=1;break;
+		case RCacheTestDevice::E_InOutWT_Remapped:	inner=2;outer=2;break;
+		case RCacheTestDevice::E_InOutWBRA_Remapped:inner=3;outer=3;break;
+		case RCacheTestDevice::E_InOutWB_Remapped:	inner=1;outer=1;break;
+		default:Kern::PanicCurrentThread(_L("d_cache driver error"),0);return;
+		}
+
+	TUint32 prrr =PRRRRegister();
+	TUint32 nrrr =NRRRRegister();
+	prrr &= ~(3<<8);	// Clear EMemAttKernelInternal4 setting for memory type
+	nrrr &= ~(3<<8); 	// Clear EMemAttKernelInternal4 setting for normal memory type, inner cache
+	nrrr &= ~(3<<24);	// Clear EMemAttKernelInternal4 setting for normal memory type, outer cache
+	prrr |= 2 <<8; 		// Set EMemAttKernelInternal4 as normal memory
+	nrrr |= inner <<8;	// Set inner cache for EMemAttKernelInternal4 
+	nrrr |= outer << 24;// Set outer cache for EMemAttKernelInternal4 
+
+	SetPRRR(prrr);
+	SetNRRR(nrrr);
+#endif
+	}
+
+
+
+/** Fills in info structure with external cache parameters. */
+void DCacheTest::GetExternalCacheInfo(RCacheTestDevice::TCacheInfo& info)
+	{
+#if defined(__HAS_EXTERNAL_CACHE__)
+	info.iOuterCache=1;
+
+#if defined(__ARM_L210_CACHE__)
+	AppendTo(info.iDesc,"Built as L210 Cache;\n");
+#elif defined(__ARM_L220_CACHE__)
+	AppendTo(info.iDesc,"Built as L220 Cache:\n");
+#elif defined(__ARM_PL310_CACHE__)
+	AppendTo(info.iDesc,"Built as PL310 Cache:\n");
+#endif
+
+	TInt cacheController = Kern::SuperPage().iArmL2CacheBase;
+	if (!cacheController)
+		{
+		AppendTo(info.iDesc,"Warning:No CCB Address in Super Page?\n");
+		return;
+		}
+		
+	TInt rawData = *(TInt*)(cacheController);   //reg 0 in controller is Cache ID Register
+	AppendTo(info.iDesc,"L2 ID Reg:%xH\n", rawData);
+
+	rawData = *(TInt*)(cacheController+4); //reg 4 in controller is Cache Type Register
+	AppendTo(info.iDesc,"L2 Type Reg:%xH\n", rawData);
+
+	RCacheTestDevice::TCacheSingle& cs = info.iCache[info.iCacheCount];
+
+	cs.iLineSize=32; //always
+#if defined(__ARM_L210_CACHE__) || defined(__ARM_L220_CACHE__)
+	cs.iWays = (rawData>>3)&0x0f;	if (cs.iWays > 8) cs.iWays = 8;
+#elif defined(__ARM_PL310_CACHE__)
+	cs.iWays = (rawData&0x40) ? 16:8;
+#endif
+	TInt waySize;
+	switch((rawData>>8)&7)
+		{
+		case 0:		waySize = 0x4000;  break;
+		case 1:		waySize = 0x4000;  break;
+		case 2:		waySize = 0x8000;  break;
+		case 3:		waySize = 0x10000; break;
+		case 4:		waySize = 0x20000; break;
+#if defined(__ARM_L210_CACHE__) || defined(__ARM_L220_CACHE__)
+		default:	waySize = 0x40000; break;
+#elif defined(__ARM_PL310_CACHE__)
+		case 5:		waySize = 0x40000; break;
+		default:	waySize = 0x80000; break;
+#endif
+		}
+	cs.iSize = waySize * cs.iWays;
+	cs.iSets = waySize >> 5; // = waySize / lineLen 
+
+
+	cs.iLevel = 2;
+	cs.iCode = 1;
+	cs.iData = 1;
+	cs.iDesc.SetLength(0);
+	AppendTo(cs.iDesc,"Outer Unified PAPT");
+
+	info.iMaxCacheSize = Max(info.iMaxCacheSize, cs.iSize);
+	info.iCacheCount++;
+#endif //defined(__HAS_EXTERNAL_CACHE__)
+	}
+
+
+/** Passes cache configuration parameters to the user side*/
+TInt DCacheTest::GetCacheInfo(TAny* a1)
+	{
+	TInt ret = KErrNone;
+	RCacheTestDevice::TCacheInfo info;
+
+	info.iDesc.SetLength(0);
+	info.iCacheCount=0;
+	info.iMaxCacheSize=0;
+	info.iMemoryRemapping=0;
+	info.iOuterCache=0;
+
+////////////////////////
+#if defined(__CPU_ARMV7)
+////////////////////////
+	info.iOuterCache=1;
+
+	TUint32 ctr=CacheTypeRegister();
+	TUint32 clr=CacheLevelIDRegister();
+	TInt LoC = (clr>>24)&7;	//The number of levels to be purged/clean to Point-to-Coherency
+	TInt LoU = (clr>>27)&7;	//The number of levels to be purged/clean to Point-to-Unification
+	AppendTo(info.iDesc,"ARMv7 cache - CTR:%xH CLR:%xH LoC:%d LoU:%d\n", ctr, clr, LoC, LoU);
+	
+	RCacheTestDevice::TCacheSingle* cs = &info.iCache[info.iCacheCount];
+	TInt level;
+	for (level=0;level<LoC;level++)
+		{
+		TInt type = (clr >> (level*3)) & 7; //000:NoCache 001:ICache 010:DCache 011:Both 100:Unified
+		
+		if (type==0)		// No Cache. Also no cache below this level
+			break;
+		
+		if(type & 1) 	// Instruction Cache
+			{
+			TInt csr = CacheSizeIdRegister(1,level);
+			ParseCacheLevelInfo(csr, *cs);
+			cs->iLevel = level+1;
+			cs->iCode = 1;
+			cs->iData = 0;
+			AppendTo(cs->iDesc,"ICache CSR:%xH",csr);
+			info.iMaxCacheSize = Max(info.iMaxCacheSize, cs->iSize);
+			cs = &info.iCache[++info.iCacheCount];
+			}
+			
+		if(type & 2) 	// Data Cache
+			{
+			TInt csr = CacheSizeIdRegister(0,level);
+			ParseCacheLevelInfo(csr, *cs);
+			cs->iLevel = level+1;
+			cs->iCode = 0;
+			cs->iData = 1;
+			AppendTo(cs->iDesc,"DCache CSR:%xH",csr);
+			info.iMaxCacheSize = Max(info.iMaxCacheSize, cs->iSize);
+			cs = &info.iCache[++info.iCacheCount];
+			}
+
+		if(type & 4) 	// Unified Cache
+			{
+			TInt csr = CacheSizeIdRegister(0,level);
+			ParseCacheLevelInfo(csr, *cs);
+			cs->iLevel = level+1;
+			cs->iCode = 1;
+			cs->iData = 1;
+			AppendTo(cs->iDesc,"Unified CSR:%xH",csr);
+			info.iMaxCacheSize = Max(info.iMaxCacheSize, cs->iSize);
+			cs = &info.iCache[++info.iCacheCount];
+			}
+		}
+
+///////////////////////////////////
+#elif defined(__CPU_HAS_CACHE_TYPE_REGISTER)
+///////////////////////////////////
+
+	TInt rawData=GetCacheType();
+	TInt splitCache=rawData&0x01000000;
+	AppendTo(info.iDesc,"L1 Cache TypeReg=%xH\n", rawData);
+
+	//Cache #1	
+	TUint32 s=(rawData>>12)&0xfff;  		//s = P[11]:0:size[9:5]:assoc[5:3]:M[2]:len[1:0] 
+	info.iCache[info.iCacheCount].iLineSize = 1 << ((s&2) + 3); 							//1<<(len+3)
+	info.iCache[info.iCacheCount].iWays = (2 + ((s>>2)&1)) << (((s>>3)&0x7) - 1);			//(2+M) << (assoc-1)
+	info.iCache[info.iCacheCount].iSize = (2 + ((s>>2)&1)) << (((s>>6)&0xf) + 8);			//(2+M) << (size+8)
+	info.iCache[info.iCacheCount].iSets = 1 << (((s>>6)&0xf) + 6 - ((s>>3)&0x7) - (s&2));	//(2+M) <<(size + 6 -assoc - len)
+	info.iCache[info.iCacheCount].iData = 1;
+	info.iCache[info.iCacheCount].iLevel = 1;
+
+	if (splitCache)
+		{
+		info.iCache[info.iCacheCount].iCode = 0;
+		info.iCache[info.iCacheCount].iDesc.SetLength(0);
+		AppendTo(info.iCache[info.iCacheCount].iDesc,"Inner DCache");
+
+		#if defined(__CPU_ARMV6)
+		AppendTo(info.iCache[info.iCacheCount].iDesc," VAPT");
+		#else
+		AppendTo(info.iCache[info.iCacheCount].iDesc," VAVT");
+		#endif		
+		info.iMaxCacheSize = Max(info.iMaxCacheSize, info.iCache[info.iCacheCount].iSize);
+		info.iCacheCount++;
+
+		// Cache #2
+		s=rawData&0xfff;  		//s = P[11]:0:size[9:5]:assoc[5:3]:M[2]:len[1:0] 
+		info.iCache[info.iCacheCount].iLineSize = 1 << ((s&2) + 3); 							//1<<(len+3)
+		info.iCache[info.iCacheCount].iWays = (2 + ((s>>2)&1)) << (((s>>3)&0x7) - 1);			//(2+M) << (assoc-1)
+		info.iCache[info.iCacheCount].iSize = (2 + ((s>>2)&1)) << (((s>>6)&0xf) + 8);			//(2+M) << (size+8)
+		info.iCache[info.iCacheCount].iSets = 1 << (((s>>6)&0xf) + 6 - ((s>>3)&0x7) - (s&2));	//(2+M) <<(size + 6 -assoc - len)
+		info.iCache[info.iCacheCount].iLevel = 1;
+		info.iCache[info.iCacheCount].iCode = 1;
+		info.iCache[info.iCacheCount].iData = 0;
+		info.iCache[info.iCacheCount].iDesc.SetLength(0);
+		AppendTo(info.iCache[info.iCacheCount].iDesc,"Inner ICache");
+		#if defined(__CPU_ARMV6)
+		AppendTo(info.iCache[info.iCacheCount].iDesc," VAPT");
+		#else
+		AppendTo(info.iCache[info.iCacheCount].iDesc," VAVT");
+		#endif		
+		}
+	else
+	{
+		info.iCache[info.iCacheCount].iCode = 1;
+		info.iCache[info.iCacheCount].iDesc.SetLength(0);
+		AppendTo(info.iCache[info.iCacheCount].iDesc,"Inner Unified");
+		#if defined(__CPU_ARMV6)
+		AppendTo(info.iCache[info.iCacheCount].iDesc," VAPT");
+		#else
+		AppendTo(info.iCache[info.iCacheCount].iDesc," VAVT");
+		#endif		
+	}		
+	info.iMaxCacheSize = Max(info.iMaxCacheSize, info.iCache[info.iCacheCount].iSize);
+	info.iCacheCount++;
+
+/////
+#else
+/////
+
+	ret = KErrNotSupported;
+
+#endif
+
+	GetExternalCacheInfo(info); // Get ARMl210/20 info
+	CheckRemapping(info);		// Get memory remapping info
+
+	info.iDmaBufferAlignment = Cache::DmaBufferAlignment();
+	kumemput(a1,&info,sizeof(info));
+	return ret;
+	}
+
+/** Get cache thresholds.*/
+TInt DCacheTest::GetThreshold(TAny* a1)
+	{
+	RCacheTestDevice::TThresholdInfo info;
+	kumemget(&info,a1,sizeof(info));
+
+	TCacheThresholds thresholds;
+	TInt r = Cache::GetThresholds(thresholds, info.iCacheType);
+	if (r==KErrNone)
+		{
+		info.iPurge = thresholds.iPurge;	
+		info.iClean = thresholds.iClean;	
+		info.iFlush = thresholds.iFlush;	
+		kumemput(a1,&info,sizeof(info));
+		}
+	return r;
+	}
+
+/** Set cache thresholds.*/
+TInt DCacheTest::SetThreshold(TAny* a1)
+	{
+	RCacheTestDevice::TThresholdInfo info;
+	kumemget(&info,a1,sizeof(info));
+
+	TCacheThresholds thresholds;
+	thresholds.iPurge = info.iPurge;
+	thresholds.iClean = info.iClean;
+	thresholds.iFlush = info.iFlush;
+	return Cache::SetThresholds(thresholds, info.iCacheType);
+	}
+
+// Runs DataSegmetTestFunct against data from a chunk.
+// Chunk cache attributes and its size are specified in input arguments.
+// Measures and returns the time spent.
+TInt DCacheTest::TestDataChunk(TAny* a1)
+	{
+	TInt r = KErrNone;
+	TInt time;
+	
+	RCacheTestDevice::TChunkTest info;
+	kumemget(&info,a1,sizeof(info));
+
+
+	TUint32 chunkAttr = EMapAttrSupRw;
+	if (info.iShared) chunkAttr |= EMapAttrShared;
+#ifdef __SMP__
+	TUint32 force_shared = EMapAttrShared;
+#else
+	TUint32 force_shared = 0;
+#endif
+
+	switch (info.iCacheAttr)
+		{
+
+		case RCacheTestDevice::E_FullyBlocking:	chunkAttr |= EMapAttrFullyBlocking; break;
+		case RCacheTestDevice::E_Buffered_NC:	chunkAttr |= EMapAttrBufferedNC; break;
+		case RCacheTestDevice::E_Buffered_C:	chunkAttr |= EMapAttrBufferedC; break;
+
+		case RCacheTestDevice::E_InnerWT:		chunkAttr |= EMapAttrCachedWTRA|force_shared; break;
+		case RCacheTestDevice::E_InnerWBRA:		chunkAttr |= EMapAttrCachedWBRA|force_shared; break;
+		case RCacheTestDevice::E_InnerWB:		chunkAttr |= EMapAttrCachedWBWA|force_shared; break;
+
+		case RCacheTestDevice::E_OuterWT:		chunkAttr |= EMapAttrL2CachedWTRA; break;
+		case RCacheTestDevice::E_OuterWBRA:		chunkAttr |= EMapAttrL2CachedWBRA; break;
+		case RCacheTestDevice::E_OuterWB:		chunkAttr |= EMapAttrL2CachedWBWA; break;
+
+		case RCacheTestDevice::E_InOutWT:		chunkAttr |= EMapAttrCachedWTRA|EMapAttrL2CachedWTRA|force_shared; break;
+		case RCacheTestDevice::E_InOutWBRA:		chunkAttr |= EMapAttrCachedWBRA|EMapAttrL2CachedWBRA|force_shared; break;
+		case RCacheTestDevice::E_InOutWB:		chunkAttr |= EMapAttrCachedWBWA|EMapAttrL2CachedWBWA|force_shared; break;
+
+		case RCacheTestDevice::E_StronglyOrder:
+			new (&chunkAttr) TMappingAttributes2(EMemAttStronglyOrdered,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_Device:
+			new (&chunkAttr) TMappingAttributes2(EMemAttDevice,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_Normal_Uncached:
+			new (&chunkAttr) TMappingAttributes2(EMemAttNormalUncached,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_Normal_Cached:
+			new (&chunkAttr) TMappingAttributes2(EMemAttNormalCached,EFalse,ETrue,EFalse,(info.iShared|force_shared)?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_KernelInternal4:
+			new (&chunkAttr) TMappingAttributes2(EMemAttKernelInternal4,EFalse,ETrue,ETrue,(info.iShared|force_shared)?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_PlatformSpecific5:
+			new (&chunkAttr) TMappingAttributes2(EMemAttPlatformSpecific5,EFalse,ETrue,ETrue,(info.iShared|force_shared)?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_PlatformSpecific6:
+			new (&chunkAttr) TMappingAttributes2(EMemAttPlatformSpecific6,EFalse,ETrue,ETrue,(info.iShared|force_shared)?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_PlatformSpecific7:
+			new (&chunkAttr) TMappingAttributes2(EMemAttPlatformSpecific7,EFalse,ETrue,ETrue,(info.iShared|force_shared)?ETrue:EFalse);
+			break;
+
+#if defined(__CPU_MEMORY_TYPE_REMAPPING)
+		case RCacheTestDevice::E_InnerWT_Remapped:
+		case RCacheTestDevice::E_InnerWBRA_Remapped:
+		case RCacheTestDevice::E_InnerWB_Remapped:
+		case RCacheTestDevice::E_InOutWT_Remapped:
+		case RCacheTestDevice::E_InOutWBRA_Remapped:
+		case RCacheTestDevice::E_InOutWB_Remapped:
+#ifdef __SMP__
+			info.iShared = ETrue;
+#endif
+		case RCacheTestDevice::E_OuterWT_Remapped:
+		case RCacheTestDevice::E_OuterWBRA_Remapped:
+		case RCacheTestDevice::E_OuterWB_Remapped:
+			Remap(info.iCacheAttr);
+			new (&chunkAttr) TMappingAttributes2(EMemAttKernelInternal4,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse);
+			break;
+#endif
+			
+		case RCacheTestDevice::E_Default:
+			{
+			// Run the test against memory from kernel heap (no need for extra memory chunks)
+			NKern::ThreadEnterCS();
+			TLinAddr bufferBase = (TLinAddr)Kern::Alloc(info.iSize);
+			NKern::ThreadLeaveCS();
+			if (!bufferBase)
+					return KErrNoMemory;
+		
+			//You can't purge  allocated heap memory as it will invalidate other data from the same cache line.
+			//Cache::SyncMemoryAfterDmaRead((TLinAddr)bufferBase, info.iSize);
+
+			// Execute the test
+			time = NKern::TickCount();
+			DataSegmetTestFunct((void*)bufferBase, info.iSize);
+			info.iTime = NKern::TickCount() - time;
+			info.iActualMapAttr = 0;
+			kumemput(a1,&info,sizeof(info));
+
+			NKern::ThreadEnterCS();
+			Kern::Free((TAny*)bufferBase);
+			NKern::ThreadLeaveCS();
+
+			return KErrNone;
+			}
+		default:
+			return KErrArgument;		
+		}
+
+	// Run the test against chunk with cache attributes as specified in info.iCacheState.
+	if (KErrNone!=(r=AllocPhysicalRam(Kern::RoundToPageSize(info.iSize)))) return r;
+	if (KErrNone!=(r=CreateSharedChunk(chunkAttr, info.iActualMapAttr))) return r;
+	
+	Cache::SyncMemoryAfterDmaRead(iChunkBase, info.iSize); // Invalidate (aka purge) cache.
+
+	time = NKern::TickCount();
+	DataSegmetTestFunct((void*)iChunkBase, info.iSize);
+	info.iTime = NKern::TickCount() - time;
+
+	CloseSharedChunk();
+	FreePhysicalRam();
+
+	kumemput(a1,&info,sizeof(info));
+	return KErrNone;
+	}
+
+void DCacheTest::LoopTestCodeFunc(CodeTest* f)
+	{
+	for (TInt x = 0;x<5000;x++)
+		(*f)();
+	}
+
+// Runs TestCodeFunc (contains nops with ret at the end) from a chunk.
+// Chunk cache attributes and the size of function are specified in input arguments
+// Measures and returns the time spent.
+TInt DCacheTest::TestCodeChunk(TAny* a1)
+	{
+	TInt r = KErrNone;
+	TInt time;
+	
+	RCacheTestDevice::TChunkTest info;
+	kumemget(&info,a1,sizeof(info));
+
+
+	info.iActualMapAttr = EMapAttrSupRwx;
+	if (info.iShared) info.iActualMapAttr |= EMapAttrShared;
+#ifdef __SMP__
+	TUint32 force_shared = EMapAttrShared;
+#else
+	TUint32 force_shared = 0;
+#endif
+
+	switch (info.iCacheAttr)
+		{
+		case RCacheTestDevice::E_FullyBlocking:	info.iActualMapAttr |= EMapAttrFullyBlocking; break;
+		case RCacheTestDevice::E_Buffered_NC:	info.iActualMapAttr |= EMapAttrBufferedNC; break;
+		case RCacheTestDevice::E_Buffered_C:	info.iActualMapAttr |= EMapAttrBufferedC; break;
+
+		case RCacheTestDevice::E_InnerWT:		info.iActualMapAttr |= EMapAttrCachedWTRA|force_shared; break;
+		case RCacheTestDevice::E_InnerWBRA:		info.iActualMapAttr |= EMapAttrCachedWBRA|force_shared; break;
+		case RCacheTestDevice::E_InnerWB:		info.iActualMapAttr |= EMapAttrCachedWBWA|force_shared; break;
+
+		case RCacheTestDevice::E_OuterWT:		info.iActualMapAttr |= EMapAttrL2CachedWTRA; break;
+		case RCacheTestDevice::E_OuterWBRA:		info.iActualMapAttr |= EMapAttrL2CachedWBRA; break;
+		case RCacheTestDevice::E_OuterWB:		info.iActualMapAttr |= EMapAttrL2CachedWBWA; break;
+
+		case RCacheTestDevice::E_InOutWT:		info.iActualMapAttr |= EMapAttrCachedWTRA|EMapAttrL2CachedWTRA|force_shared; break;
+		case RCacheTestDevice::E_InOutWBRA:		info.iActualMapAttr |= EMapAttrCachedWBRA|EMapAttrL2CachedWBRA|force_shared; break;
+		case RCacheTestDevice::E_InOutWB:		info.iActualMapAttr |= EMapAttrCachedWBWA|EMapAttrL2CachedWBWA|force_shared; break;
+
+		case RCacheTestDevice::E_StronglyOrder:
+			new (&info.iActualMapAttr) TMappingAttributes2(EMemAttStronglyOrdered,EFalse,ETrue,ETrue,info.iShared?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_Device:
+			new (&info.iActualMapAttr) TMappingAttributes2(EMemAttDevice,EFalse,ETrue,ETrue,info.iShared?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_Normal_Uncached:
+			new (&info.iActualMapAttr) TMappingAttributes2(EMemAttNormalUncached,EFalse,ETrue,ETrue,info.iShared?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_Normal_Cached:
+			new (&info.iActualMapAttr) TMappingAttributes2(EMemAttNormalCached,EFalse,ETrue,ETrue,info.iShared?ETrue:EFalse);
+			break;
+
+#if defined(__CPU_MEMORY_TYPE_REMAPPING)
+		case RCacheTestDevice::E_InnerWT_Remapped:
+		case RCacheTestDevice::E_InnerWBRA_Remapped:
+		case RCacheTestDevice::E_InnerWB_Remapped:
+		case RCacheTestDevice::E_InOutWT_Remapped:
+		case RCacheTestDevice::E_InOutWBRA_Remapped:
+		case RCacheTestDevice::E_InOutWB_Remapped:
+#ifdef __SMP__
+			info.iShared = ETrue;
+#endif
+		case RCacheTestDevice::E_OuterWT_Remapped:
+		case RCacheTestDevice::E_OuterWBRA_Remapped:
+		case RCacheTestDevice::E_OuterWB_Remapped:
+			Remap(info.iCacheAttr);
+			new (&info.iActualMapAttr) TMappingAttributes2(EMemAttKernelInternal4,EFalse,ETrue,ETrue,info.iShared?ETrue:EFalse);
+			break;
+#endif
+			
+		case RCacheTestDevice::E_Default:
+			{
+			// Run the test against test function from rom image (no need for extra memory chunks)
+			if (info.iSize > TestCodeFuncSize())
+				return KErrNoMemory; // TestCodeFunc is not big enough to conduct the test.
+			
+			TInt startAddr = (TInt)TestCodeFunc + TestCodeFuncSize() - info.iSize;
+			
+			// This will invalidate (aka purge) test function from L2 cache.
+			Cache::SyncMemoryAfterDmaRead((TLinAddr)startAddr, info.iSize); 
+
+			// Execute the test
+			time = NKern::TickCount();
+			LoopTestCodeFunc((CodeTest*)startAddr);
+			info.iTime = NKern::TickCount() - time;
+
+			info.iActualMapAttr = 0; //Not relevant.
+			kumemput(a1,&info,sizeof(info));
+			return KErrNone;
+			}
+		default:
+			return KErrArgument;		
+		}
+
+	// Run the test against test function from memory chunk with cache attributes as specified in info.iCacheState.
+	// As we need a chunk with eXecutable permission attribute, can't use shared chunk. Take HwChunk instead.
+	DPlatChunkHw* chunk;
+	TPhysAddr physBase;		// This will be base physical address of the chunk
+    TLinAddr linearBase;	// This will be base linear address of the chunk
+	NKern::ThreadEnterCS();
+	r = Epoc::AllocPhysicalRam(Kern::RoundToPageSize(info.iSize), physBase, 0);//Allocate RAM. This will set aPhysAddr
+	if (r)
+		{
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	r = DPlatChunkHw::New (chunk, physBase, Kern::RoundToPageSize(info.iSize), info.iActualMapAttr);//Create chunk
+	if (r)
+		{
+		Epoc::FreePhysicalRam(physBase, Kern::RoundToPageSize(info.iSize));
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	NKern::ThreadLeaveCS();
+
+	linearBase = chunk->LinearAddress();
+
+	// Create nop,nop,...,nop,ret sequence at the start of the chunk with size = info.iSize
+	TInt nopInstr = ((TInt*)TestCodeFunc)[0]; 						// NOP is the first instruction from TestCodeFunc
+	TInt retInstr = ((TInt*)TestCodeFunc)[TestCodeFuncSize()/4-1];	// RET is the last instruction in TestCodeFunc 	
+	for (TInt i = 0; i < (info.iSize/4-1) ; i++)  	// Put all NOPs...
+		((TInt*)linearBase)[i] = nopInstr;			// ...
+	((TInt*)linearBase)[info.iSize/4-1] = retInstr;	// ... and add RET at the end.
+
+	Cache::IMB_Range((TLinAddr)linearBase, info.iSize); 			// Sync L1 Instruction & Data cache
+	//Fluch the memory from which the test funcion executes. This will give fair chance to all test cases.
+	Cache::SyncMemoryBeforeDmaWrite(linearBase, info.iSize);		// This will clean L1&L2 cache.
+	Cache::SyncMemoryAfterDmaRead(linearBase, info.iSize);			// This will invalidate (aka purge) L1&L2 cache.
+
+	// Execute the test
+	time = NKern::TickCount();
+	LoopTestCodeFunc((CodeTest*)linearBase);
+	info.iTime = NKern::TickCount() - time;
+
+	kumemput(a1,&info,sizeof(info));
+
+	NKern::ThreadEnterCS();
+	chunk->Close(NULL);
+	Epoc::FreePhysicalRam(physBase, Kern::RoundToPageSize(info.iSize));
+	NKern::ThreadLeaveCS();
+	return KErrNone;
+	}
+
+/**
+Tests WriteBack mode:
+	(1)Writes down data into BW cached memory.
+	(2)Purge the cache.
+	(3)Counts the bytes that reach the main memory.
+@param aWriteAlloc True if WriteAllocate to test, EFalse if ReadAllocate
+*/
+TInt DCacheTest::TestWriteBackMode(TAny* a1, TBool aWriteAlloc)
+	{
+	TInt r, cacheAttr = EMapAttrSupRw;
+	TUint i, counter = 0;
+	const TInt pattern = 0xabcdef12;
+
+	RCacheTestDevice::TChunkTest info;
+	kumemget(&info,a1,sizeof(info));
+#ifdef __SMP__
+	TUint32 force_shared = EMapAttrShared;
+#else
+	TUint32 force_shared = 0;
+#endif
+
+	switch (info.iCacheAttr)
+		{
+#if defined(__CPU_MEMORY_TYPE_REMAPPING)
+		case RCacheTestDevice::E_InnerWBRA_Remapped:
+		case RCacheTestDevice::E_InnerWB_Remapped:
+		case RCacheTestDevice::E_OuterWBRA_Remapped:
+		case RCacheTestDevice::E_OuterWB_Remapped:
+			Remap(info.iCacheAttr);
+			new (&cacheAttr) TMappingAttributes2(EMemAttKernelInternal4,EFalse,ETrue,ETrue,force_shared);
+			break;
+#endif
+		case RCacheTestDevice::E_InnerWBRA:	cacheAttr |= EMapAttrCachedWBRA|force_shared; 	break;
+		case RCacheTestDevice::E_InnerWB:	cacheAttr |= EMapAttrCachedWBWA|force_shared; 	break;
+		case RCacheTestDevice::E_OuterWBRA:	cacheAttr |= EMapAttrL2CachedWBRA|force_shared;	break;
+		case RCacheTestDevice::E_OuterWB:	cacheAttr |= EMapAttrL2CachedWBWA|force_shared;	break;
+		default: return KErrArgument;
+		}
+	// Create chunk
+	if (KErrNone!=(r=AllocPhysicalRam(info.iSize))) return r;
+	if (KErrNone!=(r=CreateSharedChunk(cacheAttr, info.iActualMapAttr))) return r;
+	
+	for (i=0; i<(iSize>>2) ; i++) ((TInt*)iChunkBase)[i] = 0;   //Zero-fill cache and...
+	Cache::SyncMemoryBeforeDmaWrite(iChunkBase, iSize);			//... clean the cache down to memory
+
+	Cache::SyncMemoryAfterDmaRead(iChunkBase, iSize);			//Invalidate (aka purge).
+
+	// Fill in cached region with the pattern.
+	for (i=0; i<(iSize>>2); i++)
+	 	{
+	 	if (!aWriteAlloc) iDummy = ((TInt*)iChunkBase)[i]; 		// Don't read if WriteAllocate is tested
+	 	((TInt*)iChunkBase)[i] = pattern;
+	 	}
+		
+	Cache::SyncMemoryAfterDmaRead(iChunkBase, iSize);	//Invalidate (aka purge) cache. Data in cache should be destroyed
+	CloseSharedChunk();									// Close cached chunk.
+	
+	//Create non-cached chunk over the same physical memory
+	if (KErrNone!=(r=CreateSharedChunk(EMapAttrSupRw , iDummy))) return r;
+
+	// Counts out how many bytes have reached RAM
+	for (i=0; i<(iSize>>2); i++) if (((TInt*)iChunkBase)[i] == pattern) counter++;
+
+	info.iSize = counter<<2; //Return the number of bytes that reached the main memory
+	CloseSharedChunk();
+	FreePhysicalRam();
+	
+	kumemput(a1,&info,sizeof(info));
+	return r;
+	}
+
+/**
+Exercises SyncMemoryBeforeDmaWrite & SyncMemoryAfterDmaRead (that call L1/L2 Cache Clean & Purge methods)
+This just ensures that they do not panic (doesn't do any functional test).
+*/
+TInt DCacheTest::TestL2Maintenance()
+	{
+	// Create 20000h big chunk with the the memory commited as:
+	// |0| NotCommited |64K| Commited |128K| NotCommited |192K| Commited |256K| 
+#ifdef __SMP__
+	TUint32 force_shared = EMapAttrShared;
+#else
+	TUint32 force_shared = 0;
+#endif
+	TInt r;
+	TChunkCreateInfo info;
+    info.iType         = TChunkCreateInfo::ESharedKernelSingle;
+	info.iMaxSize      = 0x40000;
+	info.iMapAttr      = EMapAttrSupRw | EMapAttrCachedWBWA | EMapAttrL2CachedWBWA | force_shared;
+	info.iOwnsMemory   = ETrue; // Use memory from system's free pool
+	info.iDestroyedDfc = NULL;
+
+    TLinAddr chunkAddr;
+    TUint32 mapAttr;
+    DChunk* chunk;
+	TInt pageSize = 0x1000; //4K
+
+	NKern::ThreadEnterCS();
+    if (KErrNone != (r = Kern::ChunkCreate(info, chunk, chunkAddr, mapAttr)))
+		{
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	r = Kern::ChunkCommit(chunk,0x10000,0x10000);
+    if(r!=KErrNone)
+        {
+		Kern::ChunkClose(chunk);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	r = Kern::ChunkCommit(chunk,0x30000,0x10000);
+    if(r!=KErrNone)
+        {
+		Kern::ChunkClose(chunk);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+
+	NKern::ThreadLeaveCS();
+
+	TInt valid = chunkAddr+0x10000;
+
+	#if defined(__ARM_L220_CACHE__) || defined(__ARM_L210_CACHE__)
+	// Check L2 cache maintenance for invalid addresses.
+	// On ARMv6, clean/purge L1 cache of the region with invalid addresses panics.
+	// However, cleaning/purging a large region above the threshold will clean/purge entire L1 cache(which doesn't panic).
+	// That is why the following calls run against 256KB. 
+	//We cannot do that on XScale L2 cache as it would generate page walk data abort.
+	TInt invalid = chunkAddr;
+	Cache::SyncMemoryBeforeDmaWrite(invalid+20, 0x40000-20);
+	Cache::SyncMemoryAfterDmaRead(invalid+100,0x40000-101);
+	#endif
+	
+	
+	// The following calls operate against valid memory regions.
+	Cache::SyncMemoryAfterDmaRead(valid+1, 0);
+	Cache::SyncMemoryAfterDmaRead(valid+32, 12);
+	Cache::SyncMemoryAfterDmaRead(valid+1, 0);
+	Cache::SyncMemoryBeforeDmaWrite(valid+2, 1);
+	Cache::SyncMemoryAfterDmaRead(valid+3, 2);
+	Cache::SyncMemoryBeforeDmaWrite(valid+4, 3);
+	Cache::SyncMemoryAfterDmaRead(valid+5, 4);
+	Cache::SyncMemoryBeforeDmaWrite(valid+6, 5);
+	Cache::SyncMemoryAfterDmaRead(valid+7, 6);
+	Cache::SyncMemoryBeforeDmaWrite(valid+8, 7);
+	Cache::SyncMemoryAfterDmaRead(valid+9, 8);
+	Cache::SyncMemoryBeforeDmaWrite(valid+10, 9);
+	Cache::SyncMemoryAfterDmaRead(valid+11, 10);
+	Cache::SyncMemoryBeforeDmaWrite(valid+12, 11);
+	Cache::SyncMemoryAfterDmaRead(valid+13, 12);
+	Cache::SyncMemoryBeforeDmaWrite(valid+14, 13);
+	Cache::SyncMemoryAfterDmaRead(valid+15, 14);
+
+	TLinAddr page = (valid+2*pageSize);
+	Cache::SyncMemoryBeforeDmaWrite(page, 0);
+	Cache::SyncMemoryAfterDmaRead(page, 0);
+	Cache::SyncMemoryBeforeDmaWrite(page-1, 2);
+	Cache::SyncMemoryAfterDmaRead(page-2, 4);
+	Cache::SyncMemoryBeforeDmaWrite(page-3, 6);
+	Cache::SyncMemoryAfterDmaRead(page-4, 8);
+	Cache::SyncMemoryBeforeDmaWrite(page-5, 10);
+	Cache::SyncMemoryAfterDmaRead(page-6, 12);
+
+	Cache::SyncMemoryBeforeDmaWrite(page, 2*pageSize);
+	Cache::SyncMemoryAfterDmaRead(page-1, 2*pageSize);
+	Cache::SyncMemoryBeforeDmaWrite(page+1, 2*pageSize);
+	Cache::SyncMemoryAfterDmaRead(page+3, 2*pageSize);
+	Cache::SyncMemoryBeforeDmaWrite(page-3, 2*pageSize);
+
+	Cache::SyncMemoryBeforeDmaWrite(valid, 64, EMapAttrCachedMax);
+	Cache::SyncMemoryBeforeDmaRead(valid, 64, EMapAttrCachedMax);
+	Cache::SyncMemoryAfterDmaRead(valid, 64, EMapAttrCachedMax);
+
+	
+	Cache::IMB_Range(0, 0xffffffff);//will cause: Clean all DCache & Purge all ICache
+	// Close the chunk
+	NKern::ThreadEnterCS();
+	Kern::ChunkClose(chunk);
+	NKern::ThreadLeaveCS();
+
+
+	//Check maintenance functions against entire cache (we need memory region >=8*cache size)
+    info.iType         = TChunkCreateInfo::ESharedKernelSingle;
+	info.iMaxSize      = 0x100000; //1MB will do
+	info.iMapAttr      = EMapAttrSupRw | EMapAttrCachedWBWA | EMapAttrL2CachedWBWA | force_shared;
+	info.iOwnsMemory   = ETrue; // Use memory from system's free pool
+	info.iDestroyedDfc = NULL;
+
+	NKern::ThreadEnterCS();
+    if (KErrNone != (r = Kern::ChunkCreate(info, chunk, chunkAddr, mapAttr)))
+		{
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	r = Kern::ChunkCommit(chunk,0x0,0x100000);
+    if(r!=KErrNone)
+        {
+		Kern::ChunkClose(chunk);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	NKern::ThreadLeaveCS();
+
+	Cache::SyncMemoryBeforeDmaWrite(chunkAddr, 0x100000);
+	Cache::SyncMemoryAfterDmaRead(chunkAddr, 0x100000);
+
+	// Close the chunk
+	NKern::ThreadEnterCS();
+	Kern::ChunkClose(chunk);
+	NKern::ThreadLeaveCS();
+
+	return KErrNone;
+	}
+
+
+TInt DCacheTest::TestUseCase(TAny* a1)
+	{
+	TInt r = KErrNone;
+	TInt time;
+	
+	RCacheTestDevice::TChunkTest info;
+	kumemget(&info,a1,sizeof(info));
+
+	TUint32 chunkAttr = EMapAttrSupRw;
+#ifdef __SMP__
+	TUint32 force_shared = EMapAttrShared;
+#else
+	TUint32 force_shared = 0;
+#endif
+	if (info.iShared) chunkAttr |= EMapAttrShared;
+
+	switch (info.iCacheAttr)
+		{
+		case RCacheTestDevice::E_StronglyOrder:
+			new (&chunkAttr) TMappingAttributes2(EMemAttStronglyOrdered,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_Device:
+			new (&chunkAttr) TMappingAttributes2(EMemAttDevice,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_Normal_Uncached:
+			new (&chunkAttr) TMappingAttributes2(EMemAttNormalUncached,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse);
+			break;
+		case RCacheTestDevice::E_Normal_Cached:
+			new (&chunkAttr) TMappingAttributes2(EMemAttNormalCached,EFalse,ETrue,EFalse,info.iShared?ETrue:EFalse);
+			break;
+		#if defined(__CPU_MEMORY_TYPE_REMAPPING)
+		case RCacheTestDevice::E_InOutWT_Remapped:
+			Remap(info.iCacheAttr);
+			new (&chunkAttr) TMappingAttributes2(EMemAttKernelInternal4,EFalse,ETrue,EFalse,(info.iShared|force_shared)?ETrue:EFalse);
+		#else
+		case RCacheTestDevice::E_InOutWT:		chunkAttr |= EMapAttrCachedWTRA|EMapAttrL2CachedWTRA|force_shared;
+		#endif
+			break;
+		default:
+			return KErrArgument;		
+		}
+
+	// Create chunk
+	if (KErrNone!=(r=AllocPhysicalRam(Kern::RoundToPageSize(info.iSize)))) return r;
+	if (KErrNone!=(r=CreateSharedChunk(chunkAttr, info.iActualMapAttr))) return r;
+	
+	//Alloc from the heap
+	NKern::ThreadEnterCS();
+	iHeap1 = (TInt*)Kern::Alloc(Max(info.iSize,0x8000));
+	if (iHeap1==NULL) {NKern::ThreadLeaveCS();return KErrNoMemory;}
+	iHeap2 = (TInt*)Kern::Alloc(0x8000);
+	if (iHeap2==NULL) {Kern::Free((TAny*)iHeap1);NKern::ThreadLeaveCS();return KErrNoMemory;}
+	NKern::ThreadLeaveCS();
+	
+	Cache::SyncMemoryAfterDmaRead(iChunkBase, info.iSize); // Invalidate (aka purge) cache.
+	time = NKern::TickCount();
+	switch(info.iUseCase)
+		{
+		case 0:  r = UseCase_ReadFromChunk(info);break;
+		case 1:  r = UseCase_ReadFromChunk_ReadFromHeap(info);break;
+		case 2:  r = UseCase_WriteToChunk(info);break;
+		case 3:  r = UseCase_WriteToChunk_ReadFromHeap(info);break;
+		default: r = KErrArgument;
+		}
+	info.iTime = NKern::TickCount() - time;
+
+	NKern::ThreadEnterCS();
+	Kern::Free((TAny*)iHeap1);
+	Kern::Free((TAny*)iHeap2);
+	NKern::ThreadLeaveCS();
+	
+	CloseSharedChunk();
+	FreePhysicalRam();
+
+	kumemput(a1,&info,sizeof(info));
+	return r;
+	}
+
+TInt DCacheTest::UseCase_ReadFromChunk(RCacheTestDevice::TChunkTest& info)
+	{
+	TInt i;
+	for (i=0; i< info.iLoops; i++)
+		{
+		//Simulate - evict the chunk from the cache)
+		Cache::SyncMemoryBeforeDmaRead(iChunkBase, info.iSize, info.iActualMapAttr); // Invalidate (aka purge) cache.
+
+		//Read DMA data
+		memcpy((TAny*)iHeap1, (const TAny*)iChunkBase, info.iSize);
+		//for (j=0; j < info.iSize>>2; j++) iDummy = *((TInt*)iChunkBase+j);
+		}
+	return KErrNone;
+	}
+
+TInt DCacheTest::UseCase_ReadFromChunk_ReadFromHeap(RCacheTestDevice::TChunkTest& info)
+	{
+	TInt i;
+	for (i=0; i< info.iLoops; i++)
+		{
+		//Simulate - evict the chunk memory from the cache
+		Cache::SyncMemoryBeforeDmaRead(iChunkBase, info.iSize, info.iActualMapAttr); // Invalidate (aka purge) cache.
+
+		//Read DMA memory
+		memcpy((TAny*)iHeap1, (const TAny*)iChunkBase, info.iSize);
+
+		//Simulate Kernel activities - reading heap2
+		memcpy((TAny*)iHeap1, (const TAny*)iHeap2, 0x8000);
+		}
+	return KErrNone;
+	}
+
+TInt DCacheTest::UseCase_WriteToChunk(RCacheTestDevice::TChunkTest& info)
+	{
+	TInt i;
+	for (i=0; i< info.iLoops; i++)
+		{
+		//Simulate - evict the chunk memory from the cache
+		Cache::SyncMemoryBeforeDmaRead(iChunkBase, info.iSize, info.iActualMapAttr); // Invalidate (aka purge) cache.
+
+		//Write DMA memory
+		memcpy((TAny*)iChunkBase, (const TAny*)iHeap1, info.iSize);
+		Cache::SyncMemoryBeforeDmaWrite(iChunkBase, info.iSize, info.iActualMapAttr); // Clean cache.
+
+		}
+	return KErrNone;
+	}
+
+TInt DCacheTest::UseCase_WriteToChunk_ReadFromHeap(RCacheTestDevice::TChunkTest& info)
+	{
+	TInt i;
+	for (i=0; i< info.iLoops; i++)
+		{
+		//Simulate - evict the chunk memory from the cache
+		Cache::SyncMemoryBeforeDmaRead(iChunkBase, info.iSize, info.iActualMapAttr); // Invalidate (aka purge) cache.
+
+		//Write DMA memory
+		memcpy((TAny*)iChunkBase, (const TAny*)iHeap1, info.iSize);
+		Cache::SyncMemoryBeforeDmaWrite(iChunkBase, info.iSize, info.iActualMapAttr); // Clean cache.
+		
+		//Simulate Kernel activities - reading heap2
+		memcpy((TAny*)iHeap1, (const TAny*)iHeap2, 0x8000);
+		}
+	return KErrNone;
+	}
+
+
+// Entry point
+TInt DCacheTest::Request(TInt aFunction, TAny* a1, TAny* a2)
+	{
+	TInt r = KErrNone;
+#ifdef __SMP__
+	TUint32 affinity = NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), 0);
+#endif
+	switch (aFunction)
+	{
+		case RCacheTestDevice::EGetCacheInfo:				r = GetCacheInfo(a1);		break;
+		case RCacheTestDevice::ETestDataChunk:				r = TestDataChunk(a1);		break;
+		case RCacheTestDevice::ETestCodeChunk:				r = TestCodeChunk(a1);		break;
+		case RCacheTestDevice::ETestWriteBackReadAllocate:	r = TestWriteBackMode(a1, EFalse);	break;
+		case RCacheTestDevice::ETestWriteBackWriteAllocate:	r = TestWriteBackMode(a1, ETrue);	break;
+		case RCacheTestDevice::ETesL2Maintenance:			r = TestL2Maintenance();	break;
+		case RCacheTestDevice::EGetThreshold:				r = GetThreshold(a1);		break;
+		case RCacheTestDevice::ESetThreshold:				r = SetThreshold(a1);		break;
+		case RCacheTestDevice::ETestUseCase:				r = TestUseCase(a1);		break;
+		default:											r=KErrNotSupported;
+		}
+#ifdef __SMP__
+	NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), affinity);
+#endif
+	return r;
+	}
+
+//////////////////////////////////////////
+class DTestFactory : public DLogicalDevice
+	{
+public:
+	DTestFactory();
+	// from DLogicalDevice
+	virtual TInt Install();
+	virtual void GetCaps(TDes8& aDes) const;
+	virtual TInt Create(DLogicalChannelBase*& aChannel);
+	};
+
+DTestFactory::DTestFactory()
+    {
+    iParseMask = KDeviceAllowUnit;
+    iUnitsMask = 0x3;
+    }
+
+TInt DTestFactory::Create(DLogicalChannelBase*& aChannel)
+    {
+	CacheTestDriver = new DCacheTest;
+	aChannel = CacheTestDriver;
+	return (aChannel ? KErrNone : KErrNoMemory);
+    }
+
+TInt DTestFactory::Install()
+    {
+    return SetName(&KCacheTestDriverName);
+    }
+
+void DTestFactory::GetCaps(TDes8& /*aDes*/) const
+    {
+    }
+
+DECLARE_STANDARD_LDD()
+	{
+    return new DTestFactory;
+	}