kerneltest/e32test/defrag/d_ramdefrag.cpp
changeset 0 a41df078684a
child 43 c1f20ce4abcf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/defrag/d_ramdefrag.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1765 @@
+// 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:
+// e32test\defrag\d_testramdefrag.cpp
+// 
+//
+
+//#define DEBUG_VER				// Uncomment for tracing
+
+#include "platform.h"
+#include <kernel/kern_priv.h>
+#include <kernel/cache.h>
+#include "t_ramdefrag.h"
+
+//
+// Class definitions
+//
+const TInt KMajorVersionNumber=0;
+const TInt KMinorVersionNumber=1;
+const TInt KBuildVersionNumber=1;
+
+
+const TInt KDefragCompleteThreadPriority = 27;
+_LIT(KDefragCompleteThread,"DefragCompleteThread");
+
+class DRamDefragFuncTestFactory : public DLogicalDevice
+	{
+public:
+
+	DRamDefragFuncTestFactory();
+	~DRamDefragFuncTestFactory();
+	virtual TInt Install();
+	virtual void GetCaps(TDes8& aDes) const;
+	virtual TInt Create(DLogicalChannelBase*& aChannel);
+
+	TDynamicDfcQue* iDfcQ;
+	};
+
+class DRamDefragFuncTestChannel : public DLogicalChannelBase
+	{
+public:
+	DRamDefragFuncTestChannel(TDfcQue* aDfcQ);
+
+	DRamDefragFuncTestChannel();
+	~DRamDefragFuncTestChannel();
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
+
+	TInt FreeAllFixedPages();
+	TInt AllocFixedPages(TInt aNumPages);
+	TInt AllocFixedArray(TInt aNumPages);
+	TInt AllocateFixed2(TInt aNumPages);
+	TInt GetAllocDiff(TUint aNumPages);
+	TInt FreeAllFixedPagesRead();
+	TInt AllocFixedPagesWrite(TInt aNumPages);
+	TInt ZoneAllocContiguous(TUint aZoneID, TUint aNumBytes);
+	TInt ZoneAllocContiguous(TUint* aZoneIdList, TUint aZoneIdCount, TUint aNumBytes);
+	TInt ZoneAllocDiscontiguous(TUint aZoneID, TInt aNumPages);
+	TInt ZoneAllocDiscontiguous(TUint* aZoneIdList, TUint aZoneIdCount, TInt aNumPages);
+	TInt ZoneAllocToMany(TInt aZoneIndex, TInt aNumPages);
+	TInt ZoneAllocToManyArray(TInt aZoneIndex, TInt aNumPages);
+	TInt ZoneAllocToMany2(TInt aZoneIndex, TInt aNumPages);
+	TInt AllocContiguous(TUint aNumBytes);
+	TInt FreeZone(TInt aNumPages);
+	TInt FreeFromAllZones();
+	TInt FreeFromAddr(TInt aNumPages, TUint32 aAddr);
+	TInt PageCount(TUint aId, STestUserSidePageCount* aPageData);
+	TInt CancelDefrag();
+	TInt CheckCancel(STestParameters* aParams);
+	TInt CallDefrag(STestParameters* aParams);
+	TInt CheckPriorities(STestParameters* aParams);
+	TInt SetZoneFlag(STestFlagParams* aParams);
+	TInt GetDefragOrder();
+	TInt FreeRam();
+	TInt DoSetDebugFlag(TInt aState);
+	TInt ResetDriver();
+	TInt ZoneAllocDiscontiguous2(TUint aZoneID, TInt aNumPages);
+public:
+	DRamDefragFuncTestFactory*	iFactory;
+
+protected:
+	static void DefragCompleteDfc(TAny* aSelf);
+	void DefragComplete();
+		static void Defrag2CompleteDfc(TAny* aSelf);
+	void Defrag2Complete();
+		static void Defrag3CompleteDfc(TAny* aSelf);
+	void Defrag3Complete();
+private:
+	TPhysAddr				iContigAddr;		/**< The base address of fixed contiguous allocations*/
+	TUint					iContigBytes;		/**< The no. of contiguous fixed bytes allocated*/
+	TPhysAddr*				iAddrArray;	
+	TUint					iAddrArrayPages;
+	TUint					iAddrArraySize;
+	TPhysAddr**				iAddrPtrArray;			
+	TInt*					iNumPagesArray;
+	TInt					iDebug;
+	TInt					iThreadCounter;
+	DChunk*					iChunk;
+	TLinAddr				iKernAddrStart;
+	TInt					iPageSize;
+	TUint 					iPageShift;			/**< The system's page shift */
+	TUint					iZoneCount;
+	TRamDefragRequest		iDefragRequest;		//	Defrag request object
+	TRamDefragRequest		iDefragRequest2;
+	TRamDefragRequest		iDefragRequest3;
+	TUint*					iZoneIdArray;		/**< Pointer to an kernel heap array of zone IDs*/
+
+
+	DSemaphore*				iDefragSemaphore;	//	Semaphore enusre only one defrag operation is active per channel
+	TRequestStatus*			iCompleteReq;		//	Pointer to a request status that will signal to the user side client once the defrag has completed
+	TRequestStatus*			iCompleteReq2;
+	TRequestStatus*			iCompleteReq3;		
+	TRequestStatus			iTmpRequestStatus1;	
+	TRequestStatus			iTmpRequestStatus2;
+	DThread*				iRequestThread;		//	Pointer to the thread that made the defrag request
+	DThread*				iRequestThread2;
+	DThread*				iRequestThread3;		
+
+	TDfcQue*				iDfcQ;				//	The DFC queue used for driver functions 
+	TDfc					iDefragCompleteDfc;	//	DFC to be queued once a defrag operation has completed 
+	TDfc					iDefragComplete2Dfc;
+	TDfc					iDefragComplete3Dfc;
+	TInt					iCounter;			//	Counts the number of defrags that have taken place
+	TInt					iOrder;				//	Stores the order in which queued defrags took place
+	};
+
+
+
+//
+// DRamDefragFuncTestFactory
+//
+
+DRamDefragFuncTestFactory::DRamDefragFuncTestFactory()
+//
+// Constructor
+//
+    {
+    iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+    //iParseMask=0;//No units, no info, no PDD
+    //iUnitsMask=0;//Only one thing
+    }
+    
+TInt DRamDefragFuncTestFactory::Install()
+	{
+	return SetName(&KRamDefragFuncTestLddName);
+	}
+
+DRamDefragFuncTestFactory::~DRamDefragFuncTestFactory()
+	{
+	if (iDfcQ != NULL)
+		{// Destroy the DFC queue created when this device drvier was loaded.
+		iDfcQ->Destroy();
+		}
+	}
+
+void DRamDefragFuncTestFactory::GetCaps(TDes8& /*aDes*/) const
+	{
+	// Not used but required as DLogicalDevice::GetCaps is pure virtual
+	}
+
+TInt DRamDefragFuncTestFactory::Create(DLogicalChannelBase*& aChannel)
+	{
+	DRamDefragFuncTestChannel* channel=new DRamDefragFuncTestChannel(iDfcQ);
+	if(!channel)
+		return KErrNoMemory;
+	channel->iFactory = this;
+	aChannel = channel;
+	return KErrNone;
+	}
+
+DECLARE_STANDARD_LDD()
+	{
+	DRamDefragFuncTestFactory* factory = new DRamDefragFuncTestFactory;
+	if (factory)
+		{
+		// Allocate a kernel thread to run the DFC 
+		TInt r = Kern::DynamicDfcQCreate(factory->iDfcQ, KDefragCompleteThreadPriority, KDefragCompleteThread);
+
+		if (r != KErrNone)
+			{// Must close rather than delete factory as it is a DObject object.
+			factory->AsyncClose();
+			return NULL; 	
+			} 	
+		}
+    return factory;
+	}
+
+//
+// DRamDefragFuncTestChannel
+//
+
+TInt DRamDefragFuncTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
+	{
+
+	TInt ret = Kern::HalFunction(EHalGroupRam, ERamHalGetZoneCount, (TAny*)&iZoneCount, NULL);
+
+
+	// Retrieve the page size and use it to detemine the page shift (assumes 32-bit system).
+	TInt r = Kern::HalFunction(EHalGroupKernel, EKernelHalPageSizeInBytes, &iPageSize, 0);
+	if (r != KErrNone)
+		{
+		TESTDEBUG(Kern::Printf("ERROR - Unable to determine page size"));
+		return r;
+		}
+	TUint32 pageMask = iPageSize;
+	TUint i = 0;
+	for (; i < 32; i++)
+		{
+		if (pageMask & 1)
+			{
+			if (pageMask & ~1u)
+				{
+				TESTDEBUG(Kern::Printf("ERROR - page size not a power of 2"));
+				return KErrNotSupported;
+				}
+			iPageShift = i;
+			break;
+			}
+		pageMask >>= 1;
+		}
+
+	// Create a semaphore to protect defrag invocation.  OK to just use one name as
+	// the semaphore is not global so it's name doesn't need to be unique.
+	ret = Kern::SemaphoreCreate(iDefragSemaphore, _L("DefragRefSem"), 1);
+	if (ret != KErrNone)
+		{
+		return ret;
+		}
+	iDefragCompleteDfc.SetDfcQ(iDfcQ);
+	iDefragComplete2Dfc.SetDfcQ(iDfcQ);
+	iDefragComplete3Dfc.SetDfcQ(iDfcQ);
+
+	// Create an array to store some RAM zone IDs for use but the multi-zone 
+	// specific allcoation methods.
+	NKern::ThreadEnterCS();
+	iZoneIdArray = new TUint[KMaxRamZones];
+	if (iZoneIdArray == NULL)
+		{
+		ret = KErrNoMemory;
+		}
+	NKern::ThreadLeaveCS();
+
+	return ret;
+	}
+
+DRamDefragFuncTestChannel::DRamDefragFuncTestChannel(TDfcQue* aDfcQ)
+	: 
+	iContigAddr(KPhysAddrInvalid),
+	iContigBytes(0),
+	iAddrArray(NULL), 
+	iAddrArrayPages(0),
+	iAddrArraySize(0),
+	iAddrPtrArray(NULL),
+	iNumPagesArray(NULL),
+	iDebug(0), 
+	iThreadCounter(1),
+	iChunk(NULL),
+	iPageSize(0), 
+	iPageShift(0),
+	iZoneCount(0),
+	iZoneIdArray(NULL),
+	iDefragSemaphore(NULL),
+	iCompleteReq(NULL),
+	iCompleteReq2(NULL),
+	iCompleteReq3(NULL),
+	iRequestThread(NULL),
+	iRequestThread2(NULL),
+	iRequestThread3(NULL),
+	iDfcQ(aDfcQ),
+	iDefragCompleteDfc(DefragCompleteDfc, (TAny*)this, 1),
+	iDefragComplete2Dfc(Defrag2CompleteDfc, (TAny*)this, 1), 
+	iDefragComplete3Dfc(Defrag3CompleteDfc, (TAny*)this, 1), 
+	iCounter(0), 
+	iOrder(0)
+	{
+	}
+
+DRamDefragFuncTestChannel::~DRamDefragFuncTestChannel()
+	{
+	if (iDefragSemaphore != NULL)
+		{
+		iDefragSemaphore->Close(NULL);
+		}
+	if (iZoneIdArray != NULL)
+		{
+		NKern::ThreadEnterCS();
+		delete[] iZoneIdArray;
+		NKern::ThreadLeaveCS();
+		}
+	}
+
+TInt DRamDefragFuncTestChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
+	{
+	TInt threadCount = __e32_atomic_tas_ord32(&iThreadCounter, 1, 1, 0);
+	if (threadCount >= 2)
+		{
+		Kern::Printf("DRamDefragFuncTestChannel::Request threadCount = %d\n", threadCount);
+		}
+
+	Kern::SemaphoreWait(*iDefragSemaphore);
+
+
+	TInt retVal = KErrNotSupported;
+	switch(aFunction)
+		{
+		case RRamDefragFuncTestLdd::EAllocateFixed:
+			retVal = DRamDefragFuncTestChannel::AllocFixedPages((TInt)a1);
+			break;
+			
+		case RRamDefragFuncTestLdd::EAllocFixedArray:
+			retVal = DRamDefragFuncTestChannel::AllocFixedArray((TInt)a1);
+			break;
+						
+		case RRamDefragFuncTestLdd::EAllocateFixed2:
+			retVal = DRamDefragFuncTestChannel::AllocateFixed2((TInt)a1);
+			break;
+		
+		case RRamDefragFuncTestLdd::EGetAllocDiff:
+			retVal = DRamDefragFuncTestChannel::GetAllocDiff((TUint)a1);
+			break;
+
+		case RRamDefragFuncTestLdd::EFreeAllFixed:
+			retVal = DRamDefragFuncTestChannel::FreeAllFixedPages();
+			break;
+
+		case RRamDefragFuncTestLdd::EAllocateFixedWrite:
+			retVal = DRamDefragFuncTestChannel::AllocFixedPagesWrite((TInt)a1);
+			break;
+		
+		case RRamDefragFuncTestLdd::EFreeAllFixedRead:
+			retVal = DRamDefragFuncTestChannel::FreeAllFixedPagesRead();
+			break;
+		
+		case RRamDefragFuncTestLdd::EZoneAllocContiguous:
+			retVal = DRamDefragFuncTestChannel::ZoneAllocContiguous((TUint)a1, (TUint)a2);
+			break;
+
+		case RRamDefragFuncTestLdd::EMultiZoneAllocContiguous:
+			{
+			SMultiZoneAlloc multiZone;
+			kumemget(&multiZone, a1, sizeof(SMultiZoneAlloc));
+			retVal = DRamDefragFuncTestChannel::ZoneAllocContiguous(multiZone.iZoneId, multiZone.iZoneIdSize, (TUint)a2);
+			}
+			break;
+
+		case RRamDefragFuncTestLdd::EZoneAllocDiscontiguous:
+			retVal = DRamDefragFuncTestChannel::ZoneAllocDiscontiguous((TUint)a1, (TUint)a2);	
+			break;
+
+		case RRamDefragFuncTestLdd::EMultiZoneAllocDiscontiguous:
+			{
+			SMultiZoneAlloc multiZone;
+			kumemget(&multiZone, a1, sizeof(SMultiZoneAlloc));
+			retVal = DRamDefragFuncTestChannel::ZoneAllocDiscontiguous(multiZone.iZoneId, multiZone.iZoneIdSize, (TUint)a2);	
+			}
+			break;
+
+		case RRamDefragFuncTestLdd::EZoneAllocDiscontiguous2:
+			retVal = DRamDefragFuncTestChannel::ZoneAllocDiscontiguous2((TUint)a1, (TUint)a2);	
+			break;
+
+		case RRamDefragFuncTestLdd::EZoneAllocToMany:
+			retVal = DRamDefragFuncTestChannel::ZoneAllocToMany((TUint)a1, (TInt)a2);	
+			break;
+
+		case RRamDefragFuncTestLdd::EZoneAllocToManyArray:
+			retVal = DRamDefragFuncTestChannel::ZoneAllocToManyArray((TUint)a1, (TInt)a2);	
+			break;
+
+		case RRamDefragFuncTestLdd::EZoneAllocToMany2:
+			retVal = DRamDefragFuncTestChannel::ZoneAllocToMany2((TUint)a1, (TInt)a2);	
+			break;
+
+		case RRamDefragFuncTestLdd::EAllocContiguous:
+			retVal = DRamDefragFuncTestChannel::AllocContiguous((TUint)a1);	
+			break;
+
+		case RRamDefragFuncTestLdd::EFreeZone:
+			retVal = DRamDefragFuncTestChannel::FreeZone((TInt)a1);
+			break;
+
+		case RRamDefragFuncTestLdd::EFreeFromAllZones:
+			retVal = DRamDefragFuncTestChannel::FreeFromAllZones();	
+			break;
+		
+		case RRamDefragFuncTestLdd::EFreeFromAddr:
+			retVal = DRamDefragFuncTestChannel::FreeFromAddr((TInt)a1, (TUint32)a2);	
+			break;
+			
+		case RRamDefragFuncTestLdd::EPageCount:
+			retVal = DRamDefragFuncTestChannel::PageCount((TUint)a1, (STestUserSidePageCount*)a2);	
+			break;
+		
+		case RRamDefragFuncTestLdd::ECheckCancel:
+			retVal = DRamDefragFuncTestChannel::CheckCancel((STestParameters*)a1);	
+			break;
+
+		case RRamDefragFuncTestLdd::ECallDefrag:
+			retVal = DRamDefragFuncTestChannel::CallDefrag((STestParameters*)a1);	
+			break;
+
+		case RRamDefragFuncTestLdd::ESetZoneFlag:
+			retVal = DRamDefragFuncTestChannel::SetZoneFlag((STestFlagParams*)a1);	
+			break;
+
+		case RRamDefragFuncTestLdd::ECheckPriorities:
+			retVal = DRamDefragFuncTestChannel::CheckPriorities((STestParameters*)a1);	
+			break;
+
+		case RRamDefragFuncTestLdd::EGetDefragOrder:
+			retVal = DRamDefragFuncTestChannel::GetDefragOrder();	
+			break;
+
+		case RRamDefragFuncTestLdd::EDoSetDebugFlag:
+			retVal = DoSetDebugFlag((TInt) a1);
+			break;
+		
+		case RRamDefragFuncTestLdd::EResetDriver:
+			retVal = ResetDriver();
+			break;
+
+		default: 
+			break;
+		}
+
+	Kern::SemaphoreSignal(*iDefragSemaphore);
+	__e32_atomic_tas_ord32(&iThreadCounter, 1, -1, 0);
+	return retVal;
+	}
+
+
+#define CHECK(c) { if(!(c)) { Kern::Printf("Fail  %d", __LINE__); ; retVal = __LINE__;} }
+
+
+//
+// FreeAllFixedPages
+//
+// Free ALL of the fixed pages that were allocated
+//
+TInt DRamDefragFuncTestChannel::FreeAllFixedPages()
+	{
+	NKern::ThreadEnterCS();
+
+	TInt retVal = KErrNone;
+
+	if (iAddrArray != NULL)
+		{
+		retVal = Epoc::FreePhysicalRam(iAddrArrayPages, iAddrArray);
+		CHECK(retVal == KErrNone);
+
+		delete[] iAddrArray;
+		iAddrArray = NULL;
+		iAddrArrayPages = 0;
+		}
+	
+	if (iContigAddr != KPhysAddrInvalid)
+		{
+		retVal = Epoc::FreePhysicalRam(iContigAddr, iContigBytes);
+		iContigAddr = KPhysAddrInvalid;
+		iContigBytes = 0;
+		CHECK(retVal == KErrNone);
+		}
+	NKern::ThreadLeaveCS();
+
+	retVal = FreeFromAllZones();
+	return retVal;
+	}
+
+
+
+//
+// FreeAllFixedPagesRead()
+//
+// Read the fixed pages that were mapped to iChunk and verify that 
+// the contents have not changed.  Then free the fixed pages 
+// that were allocated for iChunk.
+//
+TInt DRamDefragFuncTestChannel::FreeAllFixedPagesRead()
+	{
+
+	TInt retVal = KErrNone;
+	TUint index;
+	
+	if (iAddrArray == NULL || iChunk == NULL || !iAddrArrayPages)
+		{
+		return KErrCorrupt;
+		}
+	
+	TInt r = Kern::ChunkAddress(iChunk, 0, iAddrArrayPages << iPageShift, iKernAddrStart);
+	if (r != KErrNone)
+		{
+		Kern::Printf("ERROR ? FreeAllFixedPages : Couldn't get linear address of iChunk! %d", r);
+		}
+	else
+		{
+		for (index = 0; index < iAddrArrayPages; index ++)
+			{
+			if (iAddrArray[index] != NULL)
+				{
+				TUint* pInt = (TUint *)(iKernAddrStart + (index << iPageShift));
+				TUint* pIntEnd = pInt + (iPageSize / sizeof(TInt));
+				// Read each word in this the page and verify that 
+				// they are still the index of the current page in the chunk.
+				while (pInt < pIntEnd)
+					{
+					if (*pInt++ != index)
+						{
+						Kern::Printf("ERROR ? FreeAllFixedPages : page at index %d is corrupt! 0x%08x", index, *pInt);
+						}
+					}
+				}
+			}
+		}
+	NKern::ThreadEnterCS();
+
+	// Must close chunk before we free memory otherwise it would still be 
+	// possible to access memory that has been freed and potentially reused.
+	Kern::ChunkClose(iChunk);
+	iChunk = NULL;
+	retVal = Epoc::FreePhysicalRam(iAddrArrayPages, iAddrArray);
+	delete[] iAddrArray;
+
+	NKern::ThreadLeaveCS();
+
+	iAddrArray = NULL;
+	iAddrArrayPages = 0;
+	return retVal;
+	}
+
+//
+// AllocFixedPagesWrite
+//
+// Allocate a number of fixed pages to memory then create a shared chunk and map these pages into the chunk
+//
+TInt DRamDefragFuncTestChannel::AllocFixedPagesWrite(TInt aNumPages)
+	{
+
+	TInt retVal = KErrNone;
+	TUint index = 0;
+	TChunkCreateInfo 	chunkInfo;
+	TUint32 			mapAttr;
+
+	if (iAddrArray != NULL || iChunk != NULL)
+		{
+		return KErrInUse;
+		}
+
+	if (aNumPages == FILL_ALL_FIXED)
+		{// Fill memory with fixed pages, leaving room for the kernel to expand.
+		TUint freePages = FreeRam() >> iPageShift;
+		// Calculate how many page tables will be required:
+		// 	1024 pages per page table 
+		//	4 page table per page
+		TUint pageTablePages = (freePages >> 10) >> 2;
+		TUint physAddrPages = (sizeof(TPhysAddr) * freePages) >> iPageShift;
+		TESTDEBUG(Kern::Printf("pageTablePages %d physAddrPages %d", pageTablePages, physAddrPages));
+		// Determine how many heap pages will be required, with some extra space as well.
+		TUint fixedOverhead = (pageTablePages + physAddrPages) << 4;
+		TESTDEBUG(Kern::Printf("freePages %d fixedOverhead %d", freePages, fixedOverhead));
+		aNumPages = freePages - fixedOverhead;
+		TESTDEBUG(Kern::Printf("aNumPages = %d", aNumPages));
+		}
+
+	NKern::ThreadEnterCS();
+
+	iAddrArray = new TPhysAddr[aNumPages];
+	if(!iAddrArray)
+		{
+		retVal = KErrNoMemory;
+		goto exit;
+		}
+	
+	TESTDEBUG(Kern::Printf("amount of free pages = %d", FreeRam() >> iPageShift));	
+
+	// create a shared chunk and map these pages into the chunk.
+	
+	chunkInfo.iType			= TChunkCreateInfo::ESharedKernelSingle;
+	chunkInfo.iMaxSize		= aNumPages << iPageShift;
+	chunkInfo.iMapAttr		= EMapAttrFullyBlocking;
+	chunkInfo.iOwnsMemory	= EFalse;
+
+	TESTDEBUG(Kern::Printf("Creating chunk - amount of free pages = %d\n", FreeRam() >> iPageShift));
+	retVal = Kern::ChunkCreate(chunkInfo, iChunk, iKernAddrStart, mapAttr);
+	if (retVal != KErrNone)
+		{
+		Kern::Printf("ChunkCreate failed retVal = %d", retVal);
+		goto exit;
+		}
+
+	TESTDEBUG(Kern::Printf("Created chunk - amount of free pages = %d\n", FreeRam() >> iPageShift));
+
+	retVal = Epoc::AllocPhysicalRam(aNumPages, iAddrArray);
+	if (retVal != KErrNone)
+		{
+		TESTDEBUG(Kern::Printf("Alloc of %d pages was unsuccessful\n", aNumPages));
+		goto exit;
+		}
+	iAddrArrayPages = aNumPages;
+	TESTDEBUG(Kern::Printf("Committing chunk - amount of free pages = %d\n", FreeRam() >> iPageShift));
+	retVal = Kern::ChunkCommitPhysical(iChunk, 0, iAddrArrayPages << iPageShift, iAddrArray);
+	if (retVal != KErrNone)
+		{
+		Kern::Printf("Commit was bad retVal = %d", retVal);
+		goto exit;
+		}
+	TESTDEBUG(Kern::Printf("Committed chunk - amount of free pages = %d\n", FreeRam() >> iPageShift));
+	TESTDEBUG(Kern::Printf("Start - 0x%08x\n", iKernAddrStart));
+	for (index = 0; index < iAddrArrayPages; index ++)
+		{
+		TInt* pInt = (TInt *)(iKernAddrStart + (index << iPageShift));
+		TInt* pIntEnd = pInt + (iPageSize / sizeof(TInt));
+		// write the index into all of the words of the page.
+		while (pInt < pIntEnd)
+			{
+			*pInt++ = index;
+			}
+		}
+
+	TESTDEBUG(Kern::Printf("Allocated %d pages\n", iAddrArrayPages));
+exit:
+	if (retVal != KErrNone)
+		{// Cleanup as something went wrong
+		if (iChunk)
+			{
+			Kern::ChunkClose(iChunk);
+			iChunk = NULL;
+			}
+		if (iAddrArray != NULL)
+			{
+			Epoc::FreePhysicalRam(iAddrArrayPages, iAddrArray);
+			delete[] iAddrArray;
+			iAddrArray = NULL;
+			}
+		iAddrArrayPages = 0;
+		}
+
+	NKern::ThreadLeaveCS();
+	return retVal;
+	}
+
+TInt DRamDefragFuncTestChannel::GetAllocDiff(TUint aNumPages)
+	{
+	TUint initialFreeRam = FreeRam();
+	TInt ret = KErrNone;
+	TInt ramDifference;
+
+	NKern::ThreadEnterCS();
+
+	if (iAddrArray != NULL)
+		{
+		ret = KErrInUse;
+		goto exit;
+		}
+	iAddrArray = (TPhysAddr *)Kern::AllocZ(sizeof(TPhysAddr) * aNumPages);
+
+	if(!iAddrArray)
+		{
+		ret = KErrNoMemory;
+		goto exit;
+		}
+	
+	ramDifference = initialFreeRam - FreeRam();
+	
+	Kern::Free(iAddrArray);
+	iAddrArray = NULL;
+	
+	ret = ramDifference >> iPageShift;
+exit:
+	NKern::ThreadLeaveCS();
+	return ret;
+	}
+//
+// AllocFixedPages
+//
+// Allocate a number of fixed pages to memory
+//
+TInt DRamDefragFuncTestChannel::AllocFixedPages(TInt aNumPages)
+	{
+	TInt r = AllocFixedArray(aNumPages);
+	if (r != KErrNone)
+		{
+		return r;
+		}
+	return AllocateFixed2(aNumPages);
+	}
+
+/**
+Allocate the array required to store the physical addresses of 
+number of fixed pages to be allocated.
+
+@param aNumPages 	The number of fixed pages to be allocated.
+@return KErrNone on success.
+*/
+TInt DRamDefragFuncTestChannel::AllocFixedArray(TInt aNumPages)
+	{	
+	if (iAddrArray != NULL)
+		{
+		return KErrInUse;
+		}
+	
+	if (aNumPages == FILL_ALL_FIXED)
+		{// Fill memory with fixed pages.
+		aNumPages = FreeRam() >> iPageShift;
+		TESTDEBUG(Kern::Printf("aNumPages %d FreeRam() %d", aNumPages, FreeRam()));
+		}
+	NKern::ThreadEnterCS();
+
+	iAddrArray = new TPhysAddr[aNumPages];
+	iAddrArraySize = aNumPages;	// Only required for AllocateFixed2() when aNumPages == FILL_ALL_FIXED.
+	iAddrArrayPages = 0;	// No physical pages have been allocated yet.
+
+	NKern::ThreadLeaveCS();
+
+	if (!iAddrArray)
+		{
+		return KErrNoMemory;
+		}
+	return KErrNone;
+	}
+
+
+/**
+Allocate the specified number of fixed pages.
+This should only be invoked when iAddrArray has already been allocated
+
+@param aNumPages 	The number of pages to allocate.
+*/	
+TInt DRamDefragFuncTestChannel::AllocateFixed2(TInt aNumPages)
+	{
+	if (iAddrArray == NULL)
+		{
+		return KErrGeneral;
+		}
+	TInt retVal = KErrNone;
+	NKern::ThreadEnterCS();
+	if (aNumPages == FILL_ALL_FIXED)
+		{
+		// Allocate a number of fixed pages to RAM a page at time so that the allocations
+		// will always fill as much memory as possible.
+		TPhysAddr* addrPtr = iAddrArray;
+		TPhysAddr* addrPtrEnd = addrPtr + iAddrArraySize;
+		while (addrPtr < addrPtrEnd)
+			{
+			retVal = Epoc::AllocPhysicalRam(1, addrPtr++);
+			if (retVal != KErrNone)
+				break;
+			iAddrArrayPages++;
+			}
+		}
+	else
+		{
+		retVal = Epoc::AllocPhysicalRam(aNumPages, iAddrArray);
+		if (retVal != KErrNone)
+			{
+			TESTDEBUG(Kern::Printf("aNumPages %d FreeRam() %d", aNumPages, FreeRam()));
+			delete[] iAddrArray;
+			iAddrArray = NULL;
+			TESTDEBUG(Kern::Printf("aNumPages %d FreeRam() %d", aNumPages, FreeRam()));
+			TESTDEBUG(Kern::Printf("Fixed pages alloc was unsuccessful\n"));
+			}
+		else
+			iAddrArrayPages = aNumPages;
+		}
+
+	NKern::ThreadLeaveCS();
+	return retVal;
+	}	
+//
+// CheckCancel
+//
+// Check that when a defrag is cancelled, the correct return value is reported
+//
+TInt DRamDefragFuncTestChannel::CheckCancel(STestParameters* aParams)
+	{
+	TInt returnValue = KErrNone;
+	STestParameters params;
+	kumemget(&params, aParams, sizeof(STestParameters));
+
+	Kern::Printf(	"defragtype = %d, defragversion = %d, priority = %d, maxpages = %d, ID = %d", 
+					params.iDefragType, params.iDefragVersion, params.iPriority, params.iMaxPages, params.iID);
+
+
+	NFastSemaphore sem;
+	NKern::FSSetOwner(&sem, 0);
+	TPhysAddr zoneAddress;
+	TInt maxPages = 0;
+	TInt priority = (NKern::CurrentThread()->iPriority) - 2;
+
+	if (params.iDefragType == DEFRAG_TYPE_GEN) // DefragRam
+		{
+		returnValue = iDefragRequest.DefragRam(&sem, priority, maxPages);
+		}
+	else if (params.iDefragType == DEFRAG_TYPE_EMPTY) // EmptyRamZone
+		{
+		returnValue = iDefragRequest.EmptyRamZone(params.iID, &sem, priority);
+		}
+	else if (params.iDefragType == DEFRAG_TYPE_CLAIM) // ClaimRamZone
+		{
+		returnValue = iDefragRequest.ClaimRamZone(params.iID, zoneAddress, &sem, priority);
+		}
+	else
+		{
+		Kern::Printf("A valid defrag type was not specified");
+		return KErrGeneral;
+		}
+
+	iDefragRequest.Cancel();
+	NKern::FSWait(&sem);
+	returnValue = iDefragRequest.Result();
+	return returnValue;
+	}
+
+
+//
+// CheckPriorities
+//
+// Queue defrags with differing priorities and ensure they complete in the correct order 
+//
+TInt DRamDefragFuncTestChannel::CheckPriorities(STestParameters* aParams)
+	{
+	STestParameters params;
+	kumemget(&params, aParams, sizeof(STestParameters));
+
+	// Still have an outstanding defrag operation
+	if (iCompleteReq != NULL | iCompleteReq2 != NULL | iCompleteReq3 != NULL)
+		{
+		return KErrInUse;
+		}
+	
+	// Open a handle to the thread so that it isn't destroyed as defrag dfc may 
+	// then try to complete the request on a destroyed thread.
+	iRequestThread = &Kern::CurrentThread();
+	iRequestThread->Open();
+	iCompleteReq = params.iReqStat;
+
+	// Open a reference on this channel to stop the destructor running before
+	// this defrag request has completed.
+	Open();
+	TUint defragZone = params.iID - 1;	
+	TInt returnValue = iDefragRequest.EmptyRamZone(defragZone, &iDefragCompleteDfc, 1);
+	if (returnValue != KErrNone)
+		{
+		AsyncClose();
+		iCompleteReq = NULL;
+		iRequestThread->AsyncClose();
+		iRequestThread = NULL;
+		return returnValue;
+		}
+
+	// Open a handle to the thread so that it isn't destroyed as defrag dfc may 
+	// then try to complete the request on a destroyed thread.
+	iRequestThread2 = &Kern::CurrentThread();
+	iRequestThread2->Open();
+	iCompleteReq2 = params.iReqStat2;
+	// Open a reference on this channel to stop the destructor running before
+	// this defrag request has completed.
+	Open();
+	defragZone = params.iID;
+	returnValue = iDefragRequest2.EmptyRamZone(defragZone, &iDefragComplete2Dfc, 30);
+	if (returnValue != KErrNone)
+		{
+		// Cancel any successfully queued operations.
+		// Set dfcs to signal dummy request statuses as user side
+		// request status shouldn't be signalled.
+		iCompleteReq = &iTmpRequestStatus1;
+		iDefragRequest.Cancel();
+
+		// Clean up this operation.
+		AsyncClose();
+		iCompleteReq2 = NULL;
+		iRequestThread2->AsyncClose();
+		iRequestThread2 = NULL;
+		return returnValue;
+		}
+
+	// Open a handle to the thread so that it isn't destroyed as defrag dfc may 
+	// then try to complete the request on a destroyed thread.
+	iRequestThread3 = &Kern::CurrentThread();
+	iRequestThread3->Open();
+	iCompleteReq3 = params.iReqStat3;
+	// Open a reference on this channel to stop the destructor running before
+	// this defrag request has completed.
+	Open();
+	defragZone = params.iID + 2;
+	returnValue = iDefragRequest3.EmptyRamZone(defragZone, &iDefragComplete3Dfc, 60);
+	if (returnValue != KErrNone)
+		{
+		// Cancel any successfully queued operations.
+		// Set dfcs to signal dummy request statuses as user side
+		// request status shouldn't be signalled.
+		iCompleteReq = &iTmpRequestStatus1;
+		iCompleteReq2 = &iTmpRequestStatus2;
+		iDefragRequest.Cancel();
+		iDefragRequest2.Cancel();
+
+		// clean up this defrag operation
+		AsyncClose();
+		iCompleteReq3 = NULL;
+		iRequestThread3->AsyncClose();
+		iRequestThread3 = NULL;
+		return returnValue;
+		}
+	return returnValue;
+	}
+
+//
+// GetDefragOrder
+//
+// Get the order in which the defrags were completed 
+//
+TInt DRamDefragFuncTestChannel::GetDefragOrder()
+	{
+	Kern::Printf("order = %d", iOrder);
+	return iOrder;
+	}
+
+
+//
+// CallDefrag
+//
+// Call a specific defrag depening on the parameters that it is called with
+//
+TInt DRamDefragFuncTestChannel::CallDefrag(STestParameters* aParams)
+	{
+	TInt returnValue = 0;
+	STestParameters params;
+	kumemget(&params, aParams, sizeof(STestParameters));
+	
+	TESTDEBUG(Kern::Printf("defragtype = %d, defragversion = %d, priority = %d, maxpages = %d, ID = %d", 
+					params.iDefragType, params.iDefragVersion, params.iPriority, params.iMaxPages, params.iID));
+
+
+	NFastSemaphore sem;
+	NKern::FSSetOwner(&sem, 0);
+
+	if (params.iDefragType == DEFRAG_TYPE_GEN) // DefragRam
+		{
+		switch(params.iDefragVersion) 
+			{
+			case DEFRAG_VER_SYNC: // Sync
+				returnValue = iDefragRequest.DefragRam(params.iPriority, params.iMaxPages);
+				break;
+			
+			case DEFRAG_VER_SEM: // Semaphore
+				returnValue = iDefragRequest.DefragRam(&sem, params.iPriority, params.iMaxPages);
+				NKern::FSWait(&sem);
+				returnValue = iDefragRequest.Result();
+				break;
+		
+			case DEFRAG_VER_DFC: // Dfc
+				// Open a handle to the thread so that it isn't destroyed as defrag dfc may 
+				// then try to complete the request on a destroyed thread.
+				if (iCompleteReq == NULL)
+					{
+					iRequestThread = &Kern::CurrentThread();
+					iRequestThread->Open();
+					iCompleteReq = params.iReqStat;
+					// Open a reference on this channel to stop the destructor running before
+					// the defrag request has completed.
+					Open();
+					
+					returnValue = iDefragRequest.DefragRam(&iDefragCompleteDfc, params.iPriority, params.iMaxPages);
+					if (returnValue != KErrNone)
+						{// defrag operation didn't start so close all openned handles
+						AsyncClose();
+						iRequestThread->AsyncClose();
+						iRequestThread = NULL;
+						iCompleteReq = NULL;
+						}
+					}
+				else
+					{// Still have a pending defrag request
+					returnValue = KErrInUse;
+					}
+				break;
+				
+			default: 
+			break;	
+			}
+		}
+
+	else if (params.iDefragType == DEFRAG_TYPE_EMPTY) // EmptyRamZone
+		{
+		switch(params.iDefragVersion) 
+			{
+			case DEFRAG_VER_SYNC: // Sync
+				
+				returnValue = iDefragRequest.EmptyRamZone(params.iID, params.iPriority);
+				break;
+			
+			case DEFRAG_VER_SEM: // Semaphore
+				returnValue = iDefragRequest.EmptyRamZone(params.iID, &sem, params.iPriority);
+				NKern::FSWait(&sem);
+				returnValue = iDefragRequest.Result();
+				break;
+		
+			case DEFRAG_VER_DFC: // Dfc
+				if (iCompleteReq == NULL)
+					{
+					// Open a handle to the thread so that it isn't destroyed as defrag dfc may 
+					// then try to complete the request on a destroyed thread.
+					iRequestThread = &Kern::CurrentThread();
+					iRequestThread->Open();
+					iCompleteReq = params.iReqStat;
+					// Open a reference on this channel to stop the destructor running before
+					// the defrag request has completed.
+					Open();
+					
+					returnValue = iDefragRequest.EmptyRamZone(params.iID, &iDefragCompleteDfc, params.iPriority);
+					if (returnValue != KErrNone)
+						{// defrag operation didn't start so close all openned handles
+						AsyncClose();
+						iRequestThread->AsyncClose();
+						iRequestThread = NULL;
+						iCompleteReq = NULL;
+						}
+					}
+				else
+					{// Still have a pending defrag request
+					returnValue = KErrInUse;
+					}
+				break;
+				
+			default: 
+				break;	
+			}
+		}
+
+	else if (params.iDefragType == DEFRAG_TYPE_CLAIM) // ClaimRamZone
+		{
+		if (iContigAddr != KPhysAddrInvalid)
+			{
+			return KErrInUse;
+			}
+		switch(params.iDefragVersion) 
+			{
+			case DEFRAG_VER_SYNC: // Sync
+				
+				returnValue = iDefragRequest.ClaimRamZone(params.iID, iContigAddr, params.iPriority);
+				break;
+			
+			case DEFRAG_VER_SEM: // Semaphore
+				returnValue = iDefragRequest.ClaimRamZone(params.iID, iContigAddr, &sem, params.iPriority);
+				NKern::FSWait(&sem);
+				returnValue = iDefragRequest.Result();
+				break;
+		
+			case DEFRAG_VER_DFC: // Dfc
+				if (iCompleteReq == NULL)
+					{
+					// Open a handle to the thread so that it isn't destroyed as defrag dfc may 
+					// then try to complete the request on a destroyed thread.
+					iRequestThread = &Kern::CurrentThread();
+					iRequestThread->Open();
+					iCompleteReq = params.iReqStat;
+					// Open a reference on this channel to stop the destructor running before
+					// the defrag request has completed.
+					Open();
+					
+					// If the claim is successful iContigAddr will be set just before the dfc 
+					// callback function to the physical base address of the RAM zone claimed.  
+					// Therefore, the check for iContigAddr is not necessarily safe so use 
+					// this DFC version with care and don't use it combination with any 
+					// contiguous allocation methods.
+					returnValue = iDefragRequest.ClaimRamZone(params.iID, iContigAddr, &iDefragCompleteDfc, 
+																params.iPriority);
+					if (returnValue != KErrNone)
+						{// defrag operation didn't start so close all openned handles
+						AsyncClose();
+						iRequestThread->AsyncClose();
+						iRequestThread = NULL;
+						iCompleteReq = NULL;
+						}
+					}
+				else
+					{// Still have a pending defrag request
+					returnValue = KErrInUse;
+					}
+				break;
+				
+			default: 
+				break;
+			}
+		if (returnValue == KErrNone && params.iDefragVersion != DEFRAG_VER_DFC)
+			{
+			// Get the size of the zone just claimed so that it can be freed.  Don't set
+			// iContigBytes for DFC method as it will be cleared by address in t_ramdefrag
+
+			NKern::ThreadEnterCS();
+
+			SRamZonePageCount pageCount;
+			returnValue = Epoc::GetRamZonePageCount(params.iID, pageCount);
+
+			NKern::ThreadLeaveCS();
+
+			__NK_ASSERT_ALWAYS(returnValue == KErrNone); // If this fails something is seriously wrong
+			iContigBytes = pageCount.iFixedPages << iPageShift;
+			}
+		else
+			{// The claim failed so allow other contiguous allocations.
+			iContigAddr = KPhysAddrInvalid;
+			}
+		}
+
+	return returnValue;
+	} 
+
+
+
+//
+// SetZoneFlag
+//
+// Change the flag settings of a zone
+//
+TInt DRamDefragFuncTestChannel::SetZoneFlag(STestFlagParams* aParams)
+	{
+
+	TInt returnValue = 0;
+	STestFlagParams flagParams;
+	kumemget(&flagParams, aParams, sizeof(STestFlagParams));
+	TUint setFlag = 0x0;
+	switch(flagParams.iSetFlag)
+		{ 
+		case NO_FIXED_FLAG:
+			setFlag = KRamZoneFlagNoFixed;
+			break;
+
+		case NO_MOVE_FLAG:
+			setFlag = KRamZoneFlagNoMovable;
+			break;
+
+		case NO_DISCARD_FLAG:
+			setFlag = KRamZoneFlagNoDiscard;
+			break;
+
+		case NO_ALLOC_FLAG:
+			setFlag = KRamZoneFlagNoAlloc;
+			break;
+
+		case ONLY_DISCARD_FLAG:
+			setFlag = KRamZoneFlagDiscardOnly;
+			break;
+		
+		case RESET_FLAG:
+			setFlag = 0x00;
+			break;
+		
+		case ORIG_FLAG:
+			setFlag = flagParams.iOptSetFlag;
+			break;
+		
+			default: 
+			break;	
+		}
+
+	NKern::ThreadEnterCS();
+
+	returnValue = Epoc::ModifyRamZoneFlags(flagParams.iZoneID, flagParams.iZoneFlag, setFlag);
+
+	NKern::ThreadLeaveCS();
+	return returnValue;
+	}
+//
+// PageCount
+//
+// Call the GetRamZonePageCount function
+//
+TInt DRamDefragFuncTestChannel::PageCount(TUint aId, STestUserSidePageCount* aPageData)
+	{	
+	TInt returnValue = 0;
+	STestUserSidePageCount pageData;
+	SRamZonePageCount pageCount; 
+
+	NKern::ThreadEnterCS();
+
+	returnValue = Epoc::GetRamZonePageCount(aId, pageCount);
+
+	NKern::ThreadLeaveCS();
+
+	pageData.iFreePages = pageCount.iFreePages;
+	pageData.iFixedPages = pageCount.iFixedPages;
+	pageData.iMovablePages = pageCount.iMovablePages;
+	pageData.iDiscardablePages = pageCount.iDiscardablePages;
+
+	kumemput(aPageData, &pageData, sizeof(STestUserSidePageCount));
+	return returnValue;
+	}
+
+//
+// ZoneAllocContiguous
+//
+// Call the contiguous overload of the Epoc::ZoneAllocPhysicalRam() function
+//
+TInt DRamDefragFuncTestChannel::ZoneAllocContiguous(TUint aZoneID, TUint aNumBytes)
+	{
+	TInt returnValue = KErrNone;
+	
+	if (iContigAddr != KPhysAddrInvalid)
+		{
+		return KErrInUse;
+		}
+	iContigBytes = aNumBytes;
+
+	NKern::ThreadEnterCS();
+
+	returnValue = Epoc::ZoneAllocPhysicalRam(aZoneID, iContigBytes, iContigAddr, 0);
+
+	NKern::ThreadLeaveCS();
+	
+	if (returnValue != KErrNone)
+		{
+		iContigAddr = KPhysAddrInvalid;
+		}
+	return returnValue;
+	}
+
+//
+// ZoneAllocContiguous
+//
+// Call the contiguous overload of the Epoc::ZoneAllocPhysicalRam() function
+//
+TInt DRamDefragFuncTestChannel::ZoneAllocContiguous(TUint* aZoneIdList, TUint aZoneIdCount, TUint aNumBytes)
+	{
+	TInt returnValue = KErrNone;
+	
+	if (iContigAddr != KPhysAddrInvalid)
+		{
+		return KErrInUse;
+		}
+	iContigBytes = aNumBytes;
+
+	// Copy the RAM zone IDs from user side memory to kernel memory.
+	if (aZoneIdCount > KMaxRamZones)
+		{// Too many IDs.
+		return KErrArgument;
+		}
+	kumemget32(iZoneIdArray, aZoneIdList, sizeof(TUint) * aZoneIdCount);
+
+	NKern::ThreadEnterCS();
+
+	returnValue = Epoc::ZoneAllocPhysicalRam(iZoneIdArray, aZoneIdCount, iContigBytes, iContigAddr, 0);
+
+	NKern::ThreadLeaveCS();
+	
+	if (returnValue != KErrNone)
+		{
+		iContigAddr = KPhysAddrInvalid;
+		}
+	return returnValue;
+	}
+
+//
+// AllocContiguous
+//
+// Call the contiguous overload of Epoc::AllocPhysicalRam()
+//
+TInt DRamDefragFuncTestChannel::AllocContiguous(TUint aNumBytes)
+	{
+	TInt returnValue = 0;
+
+	if (iContigAddr != KPhysAddrInvalid)
+		{
+		return KErrInUse;
+		}
+
+	NKern::ThreadEnterCS();
+
+	returnValue = Epoc::AllocPhysicalRam(aNumBytes, iContigAddr, 0);
+
+	NKern::ThreadLeaveCS();
+
+	if (returnValue != KErrNone)
+		{
+		iContigAddr = KPhysAddrInvalid;
+		}
+	iContigBytes = aNumBytes;
+	return returnValue;
+	}
+
+
+//
+// ZoneAllocDiscontiguous
+//
+// Call the discontiguous overload of Epoc::ZoneAllocPhysicalRam() function
+//
+TInt DRamDefragFuncTestChannel::ZoneAllocDiscontiguous(TUint aZoneId, TInt aNumPages)
+	{
+	TInt r = AllocFixedArray(aNumPages);
+	if (r != KErrNone)
+		{
+		return r;
+		}
+	return ZoneAllocDiscontiguous2(aZoneId, aNumPages);
+	}
+
+/**
+Allocate the specified number of fixed pages from the specified RAM zone.
+This should only be invoked when iAddrArray has already been allocated
+
+@param aZoneID		The ID of the RAM zone to allocate from
+@param aNumPages 	The number of pages to allocate.
+*/	
+TInt DRamDefragFuncTestChannel::ZoneAllocDiscontiguous2(TUint aZoneID, TInt aNumPages)
+	{
+	if (iAddrArray == NULL)
+		{
+		return KErrGeneral;
+		}
+
+	NKern::ThreadEnterCS();
+
+	TESTDEBUG(Kern::Printf("Allocating fixed pages"));
+	TInt returnValue = Epoc::ZoneAllocPhysicalRam(aZoneID, aNumPages, iAddrArray);
+	
+	if (KErrNone != returnValue)
+		{
+		TESTDEBUG(Kern::Printf("Alloc was unsuccessful, r = %d\n", returnValue));
+		TESTDEBUG(Kern::Printf("aNumPages = %d, aZoneID = %d", aNumPages, aZoneID));
+		Kern::Free(iAddrArray);
+		iAddrArray = NULL;
+		goto exit;
+		}
+	iAddrArrayPages = aNumPages;
+	TESTDEBUG(Kern::Printf("iAddrArrayPages = %d, aZoneID = %d", iAddrArrayPages, aZoneID));
+
+exit:
+	NKern::ThreadLeaveCS();
+	return returnValue;
+	}
+
+
+//
+// ZoneAllocDiscontiguous
+//
+// Call the discontiguous overload of Epoc::ZoneAllocPhysicalRam() function
+//
+TInt DRamDefragFuncTestChannel::ZoneAllocDiscontiguous(TUint* aZoneIdList, TUint aZoneIdCount, TInt aNumPages)
+	{
+	TInt returnValue = 0;
+	
+	if (iAddrArray != NULL)
+		{
+		return KErrInUse;
+		}
+	NKern::ThreadEnterCS();
+
+	iAddrArray = new TPhysAddr[aNumPages];
+
+	NKern::ThreadLeaveCS();
+
+	if (iAddrArray == NULL)
+		{
+		return KErrNoMemory;
+		}
+
+	// copy user side data to kernel side buffer.
+	if (aZoneIdCount > KMaxRamZones)
+		{// Too many IDs.
+		return KErrArgument;
+		}
+	kumemget(iZoneIdArray, aZoneIdList, sizeof(TUint) * aZoneIdCount);
+	
+	NKern::ThreadEnterCS();
+
+	TESTDEBUG(Kern::Printf("Allocating fixed pages"));
+	returnValue = Epoc::ZoneAllocPhysicalRam(iZoneIdArray, aZoneIdCount, aNumPages, iAddrArray);
+	
+	if (KErrNone != returnValue)
+		{
+		TESTDEBUG(Kern::Printf("Alloc was unsuccessful, r = %d\n", returnValue));
+		TESTDEBUG(Kern::Printf("aNumPages = %d, aZoneID = %d", aNumPages, aZoneIdCount));
+		delete[] iAddrArray;
+		iAddrArray = NULL;
+		goto exit;
+		}
+	iAddrArrayPages = aNumPages;
+	TESTDEBUG(Kern::Printf("iAddrArrayPages = %d, zones = %d", iAddrArrayPages, aZoneIdCount));
+
+exit:
+	NKern::ThreadLeaveCS();
+	return returnValue;
+	}
+
+//
+// ZoneAllocToMany
+//
+// Call the overloaded Epoc::ZoneAllocPhysicalRam function on a number of zones
+//
+TInt DRamDefragFuncTestChannel::ZoneAllocToMany(TInt aZoneIndex, TInt aNumPages)
+	{
+	TInt r = ZoneAllocToManyArray(aZoneIndex, aNumPages);
+	if (r != KErrNone)
+		{
+		return r;
+		}
+	return ZoneAllocToMany2(aZoneIndex, aNumPages);
+	}
+
+//
+// ZoneAllocToManyArray
+//
+// Allocate the arrays required to store the physical addresses of the different zones 
+// for the number of fixed pages to be allocated to that zone.
+//
+TInt DRamDefragFuncTestChannel::ZoneAllocToManyArray(TInt aZoneIndex, TInt aNumPages)
+	{
+	TInt returnValue = KErrNone;
+	NKern::ThreadEnterCS();
+	
+	if (iAddrPtrArray == NULL)
+		{
+		iAddrPtrArray = (TPhysAddr**)Kern::AllocZ(sizeof(TPhysAddr*) * iZoneCount);
+		}
+	if (iNumPagesArray == NULL)
+		{
+		iNumPagesArray = (TInt *)Kern::AllocZ(sizeof(TInt) * iZoneCount);
+		}
+	
+	if (iAddrPtrArray[aZoneIndex] != NULL)
+		{
+		returnValue = KErrInUse;
+		goto exit;
+		}
+	
+	iAddrPtrArray[aZoneIndex] = (TPhysAddr *)Kern::AllocZ(sizeof(TPhysAddr) * aNumPages);
+	if (iAddrPtrArray[aZoneIndex] == NULL)
+		{
+		returnValue = KErrNoMemory;
+		goto exit;
+		}
+
+exit:
+	NKern::ThreadLeaveCS();
+	return returnValue;
+	}
+
+//
+// ZoneAllocToMany2
+//
+// Call the overloaded Epoc::ZoneAllocPhysicalRam function on a number of zones
+// This should only be invoked when iAddrPtrArray, iNumPagesArray and iAddrPtrArray[aZoneIndex]
+// have already been allocated
+//
+TInt DRamDefragFuncTestChannel::ZoneAllocToMany2(TInt aZoneIndex, TInt aNumPages)
+	{
+	TInt returnValue = KErrNone;
+	struct SRamZoneConfig	zoneConfig;
+	TUint zoneID = KRamZoneInvalidId;
+
+	if (iAddrPtrArray == NULL ||
+		iNumPagesArray == NULL ||
+		iAddrPtrArray[aZoneIndex] == NULL)
+		{
+		return KErrGeneral;
+		}
+
+
+	NKern::ThreadEnterCS();
+	
+	// Get the zone ID
+	Kern::HalFunction(EHalGroupRam,ERamHalGetZoneConfig,(TAny*)aZoneIndex, (TAny*)&zoneConfig);
+	zoneID = zoneConfig.iZoneId;
+	returnValue = Epoc::ZoneAllocPhysicalRam(zoneID, aNumPages, iAddrPtrArray[aZoneIndex]);
+	
+	if (KErrNone != returnValue)
+		{
+		TESTDEBUG(Kern::Printf("Alloc was unsuccessful, r = %d\n", returnValue));
+		Kern::Free(iAddrPtrArray[aZoneIndex]);
+		iAddrPtrArray[aZoneIndex] = NULL;
+		goto exit;
+		}
+	iNumPagesArray[aZoneIndex] = aNumPages;
+
+exit:
+	NKern::ThreadLeaveCS();
+	return returnValue;
+	}
+
+//
+// FreeZone
+//
+// Call the overloaded Epoc::FreePhysicalRam function
+//
+TInt DRamDefragFuncTestChannel::FreeZone(TInt aNumPages)
+	{
+	TInt returnValue = 0;
+
+	if (iAddrArray == NULL)
+		{
+		return KErrCorrupt;
+		}
+
+	NKern::ThreadEnterCS();
+	
+	returnValue = Epoc::FreePhysicalRam(aNumPages, iAddrArray);
+	
+	Kern::Free(iAddrArray);
+	iAddrArray = NULL;
+
+	NKern::ThreadLeaveCS();
+	return returnValue;
+	}
+
+//
+// FreeFromAllZones
+//
+// Call the overloaded Epoc::FreePhysicalRam function
+//
+TInt DRamDefragFuncTestChannel::FreeFromAllZones()
+	{
+	TInt returnValue = 0;
+
+	if (iAddrPtrArray == NULL)
+		{
+		return KErrCorrupt;
+		}
+
+	NKern::ThreadEnterCS();
+
+	for (TUint i=0; i<iZoneCount; i++)
+		{
+		if (iAddrPtrArray[i] != NULL)
+			{
+			returnValue = Epoc::FreePhysicalRam(iNumPagesArray[i], iAddrPtrArray[i]);
+			iAddrPtrArray[i] = NULL;
+			}
+		}
+	Kern::Free(iAddrPtrArray);
+	iAddrPtrArray = NULL;
+
+	Kern::Free(iNumPagesArray);
+	iNumPagesArray = NULL;
+
+	NKern::ThreadLeaveCS();	
+	return returnValue;
+	}
+//
+// FreeFromAddr
+//
+// Free a specific number of pages starting from a specific address
+//
+TInt DRamDefragFuncTestChannel::FreeFromAddr(TInt aNumPages, TUint32 aAddr)
+	{
+	TInt returnValue = 0;
+	TPhysAddr address = aAddr;
+
+	NKern::ThreadEnterCS();
+
+	returnValue = Epoc::FreePhysicalRam(address, aNumPages << iPageShift);
+
+	NKern::ThreadLeaveCS();
+
+	return returnValue;
+	}
+
+//
+// FreeRam
+//
+// Returns the current free RAM available in bytes
+//
+TInt DRamDefragFuncTestChannel::FreeRam()
+	{
+	return Kern::FreeRamInBytes();
+	}
+
+TInt DRamDefragFuncTestChannel::DoSetDebugFlag(TInt aState)
+	{
+	iDebug = aState;
+	return KErrNone;
+	}
+
+
+//
+//	DefragCompleteDfc
+//
+//	DFC callback called when a defrag operation has completed.
+//
+void DRamDefragFuncTestChannel::DefragCompleteDfc(TAny* aSelf)
+	{
+	// Just call non-static method
+	TESTDEBUG(Kern::Printf("Calling DefragCompleteDfc"));
+	((DRamDefragFuncTestChannel*)aSelf)->DefragComplete();
+	}
+
+
+//
+//	DefragComplete
+//
+//	Invoked by the DFC callback which is called when a defrag 
+//	operation has completed.
+//
+void DRamDefragFuncTestChannel::DefragComplete()
+	{
+	TESTDEBUG(Kern::Printf(">DDefragChannel::DefragComplete - First Defrag"));
+	TInt result = iDefragRequest.Result();
+	TESTDEBUG(Kern::Printf("complete code %d", result));
+
+	// Complete the request and close the handle to the driver
+	Kern::SemaphoreWait(*iDefragSemaphore);
+
+	Kern::RequestComplete(iRequestThread, iCompleteReq, result);
+	iCompleteReq = NULL;
+	iRequestThread->Close(NULL);
+	iRequestThread = NULL;
+
+	Kern::SemaphoreSignal(*iDefragSemaphore);
+
+	++iCounter;
+	if (iCounter == 1)
+		iOrder = 1;
+	else if (iCounter == 2 && iOrder == 2)
+		iOrder = 21;
+	else if (iCounter == 2 && iOrder == 3)
+		iOrder = 31;
+	else if (iCounter == 3 && iOrder == 23)
+		iOrder = 231;
+	else if (iCounter == 3 && iOrder == 32)
+		iOrder = 321;
+	TESTDEBUG(Kern::Printf("order = %d", iOrder));
+	TESTDEBUG(Kern::Printf("<DDefragChannel::DefragComplete"));
+
+	// Close the handle on this channel - WARNING this channel may be 
+	// deleted immmediately after this call so don't access any members
+	AsyncClose();
+	}
+
+
+//
+//	Defrag2CompleteDfc
+//
+//	DFC callback called when a defrag operation has completed.
+//	This is used for a particular test case when 3 
+//	defrags are queued at the same time. 
+//
+void DRamDefragFuncTestChannel::Defrag2CompleteDfc(TAny* aSelf)
+	{
+	// Just call non-static method
+	TESTDEBUG(Kern::Printf("Calling DefragCompleteDfc"));
+	((DRamDefragFuncTestChannel*)aSelf)->Defrag2Complete();
+	}
+
+
+//
+//	Defrag2Complete
+//
+//	Invoked by the DFC callback which is called when a defrag 
+//	operation has completed. This is used for a particular test case when 3 
+//	defrags are queued at the same time. 
+//
+void DRamDefragFuncTestChannel::Defrag2Complete()
+	{
+	TESTDEBUG(Kern::Printf(">DDefragChannel::Defrag2Complete - Second Defrag"));
+	TInt result = iDefragRequest2.Result();
+	TESTDEBUG(Kern::Printf("complete code %d", result));
+	// Complete the request and close the handle to the driver
+	Kern::SemaphoreWait(*iDefragSemaphore);
+
+	Kern::RequestComplete(iRequestThread2, iCompleteReq2, result);
+	iCompleteReq2 = NULL;
+	iRequestThread2->Close(NULL);
+	iRequestThread2 = NULL;
+
+	Kern::SemaphoreSignal(*iDefragSemaphore);
+
+	++iCounter;
+	if (iCounter == 1)
+		iOrder = 2;
+	else if (iCounter == 2 && iOrder == 1)
+		iOrder = 12;
+	else if (iCounter == 2 && iOrder == 3)
+		iOrder = 32;
+	else if (iCounter == 3 && iOrder == 13)
+		iOrder = 132;
+	else if (iCounter == 3 && iOrder == 31)
+		iOrder = 312;
+	TESTDEBUG(Kern::Printf("order = %d", iOrder));
+	TESTDEBUG(Kern::Printf("<DDefragChannel::DefragComplete"));
+
+	// Close the handle on this channel - WARNING this channel may be 
+	// deleted immmediately after this call so don't access any members
+	AsyncClose();
+	}
+
+
+//
+//	Defrag3CompleteDfc
+//
+//	DFC callback called when a defrag operation has completed. 
+//	This is used for a particular test case when 3 
+//	defrags are queued at the same time. 
+//
+void DRamDefragFuncTestChannel::Defrag3CompleteDfc(TAny* aSelf)
+	{
+	// Just call non-static method
+	TESTDEBUG(Kern::Printf("Calling DefragCompleteDfc"));
+	((DRamDefragFuncTestChannel*)aSelf)->Defrag3Complete();
+	}
+
+//
+//	Defrag3Complete
+//
+//	Invoked by the DFC callback which is called when a defrag 
+//	operation has completed. This is used for a particular test case when 3 
+//	defrags are queued at the same time. 
+//
+void DRamDefragFuncTestChannel::Defrag3Complete()
+	{
+	TESTDEBUG(Kern::Printf(">DDefragChannel::DefragComplete - Third Defrag"));
+	TInt result = iDefragRequest3.Result();
+	TESTDEBUG(Kern::Printf("complete code %d", result));
+
+	Kern::SemaphoreWait(*iDefragSemaphore);
+
+	Kern::RequestComplete(iRequestThread3, iCompleteReq3, result);
+	iCompleteReq3 = NULL;
+	iRequestThread3->Close(NULL);
+	iRequestThread3 = NULL;
+
+	Kern::SemaphoreSignal(*iDefragSemaphore);
+
+
+	++iCounter;
+	if (iCounter == 1)
+		iOrder = 3;
+	else if (iCounter == 2 && iOrder == 1)
+		iOrder = 13;
+	else if (iCounter == 2 && iOrder == 2)
+		iOrder = 23;
+	else if (iCounter == 3 && iOrder == 12)
+		iOrder = 123;
+	else if (iCounter == 3 && iOrder == 21)
+		iOrder = 213;
+	TESTDEBUG(Kern::Printf("order = %d", iOrder));
+	TESTDEBUG(Kern::Printf("<DDefragChannel::DefragComplete"));
+
+	// Close the handle on this channel - WARNING this channel may be 
+	// deleted immmediately after this call so don't access any members
+	AsyncClose();
+	}
+
+//
+// ResetDriver
+// 
+// Reset all the member variables in the driver
+//
+TInt DRamDefragFuncTestChannel::ResetDriver()
+	{
+	iDebug = 0; 
+	iThreadCounter = 1; 
+	iCounter = 0;
+	iOrder = 0;
+	FreeAllFixedPages();
+
+	return KErrNone;
+	}