kerneltest/e32test/defrag/d_ramdefrag.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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;
	}