kerneltest/e32test/mmu/d_memorytest.cpp
changeset 0 a41df078684a
child 39 5d2844f35677
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mmu/d_memorytest.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,582 @@
+// Copyright (c) 2004-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\mmu\d_memorytest.cpp
+// 
+//
+
+#include <kernel/kern_priv.h>
+#include <kernel/cache.h>
+#include "d_memorytest.h"
+
+//
+// Class definitions
+//
+
+class DMemoryTestFactory : public DLogicalDevice
+	{
+public:
+	~DMemoryTestFactory();
+	virtual TInt Install();
+	virtual void GetCaps(TDes8& aDes) const;
+	virtual TInt Create(DLogicalChannelBase*& aChannel);
+	};
+
+class DMemoryTestChannel : public DLogicalChannelBase
+	{
+public:
+	DMemoryTestChannel();
+	~DMemoryTestChannel();
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
+private:
+	TInt TestAllocZerosMemory();
+	TInt TestReAllocZerosMemory();
+	TInt AllocTest1();
+	TInt ReAllocTest1();
+	TInt ReAllocTest2(TUint8*& mem1, TUint8*& mem2, TUint8*& mem3);
+	TInt AllocPhysTest(TUint32 aIters, TUint32 aSize); 
+	TInt AllocPhysTest1(TUint32 aIters, TUint32 aSize); 
+public:
+	DMemoryTestFactory*	iFactory;
+	TVirtualPinObject* iVirtualPinObject;
+	
+	struct{
+		TPhysicalPinObject* iObject;
+		TPhysAddr iPhysAddr;
+		TPhysAddr iPhysPageList[UCPageCount];
+		TUint 	iColour;
+		TUint32 iActualMapAttr;
+		}iPhysicalPinning;
+	TUint32 iPageSize;
+	};
+
+//
+// DMemoryTestFactory
+//
+
+TInt DMemoryTestFactory::Install()
+	{
+	return SetName(&KMemoryTestLddName);
+	}
+
+DMemoryTestFactory::~DMemoryTestFactory()
+	{
+	}
+
+void DMemoryTestFactory::GetCaps(TDes8& /*aDes*/) const
+	{
+	// Not used but required as DLogicalDevice::GetCaps is pure virtual
+	}
+
+TInt DMemoryTestFactory::Create(DLogicalChannelBase*& aChannel)
+	{
+	aChannel = NULL;
+	DMemoryTestChannel* channel=new DMemoryTestChannel;
+	if(!channel)
+		return KErrNoMemory;
+	channel->iFactory = this;
+	aChannel = channel;
+	return KErrNone;
+	}
+
+DECLARE_STANDARD_LDD()
+	{
+	return new DMemoryTestFactory;
+	}
+
+//
+// DMemoryTestChannel
+//
+
+TInt DMemoryTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
+	{
+	return KErrNone;
+	}
+
+DMemoryTestChannel::DMemoryTestChannel()
+	{
+	iPageSize = Kern::RoundToPageSize(1);
+	}
+
+DMemoryTestChannel::~DMemoryTestChannel()
+	{
+	Kern::DestroyVirtualPinObject(iVirtualPinObject);
+	}
+
+
+TInt DMemoryTestChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
+	{
+	TInt r=KErrNotSupported;
+
+	switch(aFunction)
+		{
+	case RMemoryTestLdd::EReadWriteMemory:
+	case RMemoryTestLdd::EReadMemory:
+	case RMemoryTestLdd::EWriteMemory:
+		{
+		TUint32 value=(TUint32)a2;
+#ifdef _DEBUG
+		TInt debugMask = Kern::CurrentThread().iDebugMask;
+		Kern::CurrentThread().iDebugMask = debugMask&~(1<<KPANIC);
+#endif
+		XTRAP(r, XT_DEFAULT,
+			if(aFunction==RMemoryTestLdd::EReadWriteMemory)
+				{
+				kumemget32(&value,a1,4);
+				kumemput32(a1,&value,4);
+				}
+			else if(aFunction==RMemoryTestLdd::EReadMemory)
+				kumemget32(&value,a1,4);
+			else if(aFunction==RMemoryTestLdd::EWriteMemory)
+				kumemput32(a1,&value,4);
+			);
+#ifdef _DEBUG
+		Kern::CurrentThread().iDebugMask = debugMask;
+#endif
+		if(aFunction==RMemoryTestLdd::EReadMemory)
+			kumemput32(a2,&value,sizeof(value));
+
+		return r;
+		}
+
+	case RMemoryTestLdd::ETestAllocZerosMemory:
+	case RMemoryTestLdd::ETestReAllocZerosMemory:
+		{
+		NKern::ThreadEnterCS();		
+		TInt r;
+		if (aFunction==RMemoryTestLdd::ETestAllocZerosMemory)
+			r=TestAllocZerosMemory();
+		else
+			r=TestReAllocZerosMemory();
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+
+	case RMemoryTestLdd::ETestAllocPhysTest:
+		{
+		NKern::ThreadEnterCS();
+		r=AllocPhysTest((TUint32)a1,(TUint32)a2);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+
+	case RMemoryTestLdd::ETestAllocPhysTest1:
+		{
+		NKern::ThreadEnterCS();
+		r=AllocPhysTest1((TUint32)a1,(TUint32)a2);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+
+	case RMemoryTestLdd::ECreateVirtualPinObject:
+		{
+		NKern::ThreadEnterCS();
+		r=Kern::CreateVirtualPinObject(iVirtualPinObject);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+		
+	case RMemoryTestLdd::EPinVirtualMemory:
+		return Kern::PinVirtualMemory(iVirtualPinObject, (TLinAddr)a1, (TUint)a2);
+
+	case RMemoryTestLdd::EUnpinVirtualMemory:
+		Kern::UnpinVirtualMemory(iVirtualPinObject);
+		return KErrNone;
+
+	case RMemoryTestLdd::EDestroyVirtualPinObject:
+		{
+		NKern::ThreadEnterCS();
+		Kern::DestroyVirtualPinObject(iVirtualPinObject);
+		NKern::ThreadLeaveCS();
+		return KErrNone;
+		}
+
+	case RMemoryTestLdd::ESetPanicTrace:
+		{
+		TBool old = false;
+#ifdef _DEBUG
+		DThread& thread = Kern::CurrentThread();
+		TInt debugMask = thread.iDebugMask;
+		if(debugMask&(1<<KPANIC))
+			old = true;
+		if(a1)
+			debugMask |= (1<<KPANIC);
+		else
+			debugMask &= ~(1<<KPANIC);
+		thread.iDebugMask = debugMask;
+#endif
+		return old;
+		}
+
+	case RMemoryTestLdd::EIsMemoryPresent:
+#ifndef __WINS__
+		return Epoc::LinearToPhysical((TLinAddr)a1) != KPhysAddrInvalid;
+#else
+		Kern::PanicCurrentThread(_L("IsMemoryPresent should not be used on the emulator"), KErrNotSupported);
+		return KErrNotSupported;
+#endif
+
+	case RMemoryTestLdd::ECreatePhysicalPinObject:
+		{
+		NKern::ThreadEnterCS();
+		r=Kern::CreatePhysicalPinObject(iPhysicalPinning.iObject);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+
+	case RMemoryTestLdd::EPinPhysicalMemory:
+		return Kern::PinPhysicalMemory(iPhysicalPinning.iObject, (TLinAddr)a1, (TUint)a2, EFalse, iPhysicalPinning.iPhysAddr,
+							iPhysicalPinning.iPhysPageList, iPhysicalPinning.iActualMapAttr, iPhysicalPinning.iColour, NULL);
+
+	case RMemoryTestLdd::EPinPhysicalMemoryRO:
+		return Kern::PinPhysicalMemory(iPhysicalPinning.iObject, (TLinAddr)a1, (TUint)a2, ETrue, iPhysicalPinning.iPhysAddr,
+							iPhysicalPinning.iPhysPageList, iPhysicalPinning.iActualMapAttr, iPhysicalPinning.iColour, NULL);
+
+	case RMemoryTestLdd::ECheckPageList:
+		{
+#ifdef __WINS__
+		return KErrNotSupported;
+#else
+		TInt i;
+		for (i=0;i<UCPageCount; i++)
+			{
+			TPhysAddr addr = Epoc::LinearToPhysical((TLinAddr)a1 + i*iPageSize);
+			if (addr==KPhysAddrInvalid) 				 return KErrGeneral;
+			if (addr!=iPhysicalPinning.iPhysPageList[i]) return KErrNotFound;
+			}
+		return KErrNone;
+#endif		
+		}
+
+	case RMemoryTestLdd::ESyncPinnedPhysicalMemory:
+		return Cache::SyncPhysicalMemoryBeforeDmaWrite(iPhysicalPinning.iPhysPageList,
+									iPhysicalPinning.iColour, (TUint)a1, (TUint)a2, iPhysicalPinning.iActualMapAttr);
+
+	case RMemoryTestLdd::EMovePinnedPhysicalMemory:
+		{
+#ifdef __WINS__
+		return KErrNotSupported;
+#else
+		TPhysAddr newPage;
+		NKern::ThreadEnterCS();
+		r = Epoc::MovePhysicalPage(iPhysicalPinning.iPhysPageList[(TUint)a1], newPage);		
+		NKern::ThreadLeaveCS();
+		return r;
+#endif
+		}
+
+	case RMemoryTestLdd::EInvalidatePinnedPhysicalMemory:
+		{
+		r = Cache::SyncPhysicalMemoryBeforeDmaRead(iPhysicalPinning.iPhysPageList,
+									iPhysicalPinning.iColour, (TUint)a1, (TUint)a2, iPhysicalPinning.iActualMapAttr);
+		if (r==KErrNone)
+			r = Cache::SyncPhysicalMemoryAfterDmaRead(iPhysicalPinning.iPhysPageList,
+										iPhysicalPinning.iColour, (TUint)a1, (TUint)a2, iPhysicalPinning.iActualMapAttr);
+		return r;	
+		}
+		
+	case RMemoryTestLdd::EUnpinPhysicalMemory:
+		return Kern::UnpinPhysicalMemory(iPhysicalPinning.iObject);
+
+	case RMemoryTestLdd::EDestroyPhysicalPinObject:
+		{
+		NKern::ThreadEnterCS();
+		r=Kern::DestroyPhysicalPinObject(iPhysicalPinning.iObject);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+
+	case RMemoryTestLdd::EPinKernelPhysicalMemory:
+		{
+		TPhysicalPinObject* pinObject;
+		TPhysAddr aAddress;
+		TPhysAddr aPages[2];
+		TUint aColour=0;
+		TUint32 actualMemAttr;
+		NKern::ThreadEnterCS();
+		Kern::CreatePhysicalPinObject(pinObject);
+		r = Kern::PinPhysicalMemory(pinObject, (TLinAddr)&aAddress, 4, EFalse, aAddress, aPages, actualMemAttr, aColour, NULL);
+		Cache::SyncPhysicalMemoryBeforeDmaWrite(aPages, aColour, 10, 30, actualMemAttr);
+		Kern::UnpinPhysicalMemory(pinObject);
+		Kern::DestroyPhysicalPinObject(pinObject);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	default:
+		return KErrNotSupported;
+		}
+	}
+
+// Fail a test by returning an error code indicating the problem
+#define FAIL_ALLOC_TEST(testIndex, byteOffset, unexepectedValue) \
+	err = ((testIndex) << 16) | ((byteOffset) << 8) | (unexepectedValue)
+
+TInt DMemoryTestChannel::TestAllocZerosMemory()
+	{
+	TInt count = 100;
+	TInt r = KErrNotSupported;
+
+	do	{	//re-try up to 100 times if memory conditions are not correct
+		r=AllocTest1();
+		} while(((r == KErrNoMemory)||(r == KErrUnknown)) && --count);
+
+	return r;
+	}
+
+TInt DMemoryTestChannel::AllocTest1()
+	{
+	const TInt KSize = 256;
+	TInt err = KErrNone;
+	TUint8* mem1 = (TUint8*)Kern::Alloc(KSize);
+	if (!mem1)
+		return KErrNoMemory;
+	memset(mem1, KSize, 0xff);
+	Kern::Free(mem1);
+	TUint8* mem2 = (TUint8*)Kern::Alloc(KSize);
+	if (!mem2)
+		return KErrNoMemory;
+	if (mem1 != mem2)
+		err = KErrUnknown;	// Test inconclusive, can retry
+	for (TInt i = 0 ; i<KSize && err==KErrNone; ++i)
+		{
+		if (mem2[i] != 0)
+			FAIL_ALLOC_TEST(1, i, mem2[i]);
+		}
+	Kern::Free(mem2);
+
+	return err;
+	}
+
+TInt DMemoryTestChannel::TestReAllocZerosMemory()
+	{
+	TInt count = 100;
+	TInt r = KErrNotSupported;
+
+	do	{	//re-try up to 100 times if memory conditions are not correct
+		r=ReAllocTest1();
+		} while(((r == KErrNoMemory)||(r == KErrUnknown)) && --count);
+
+	if (r!=KErrNone)	
+		return r;
+
+	count = 100;
+	do	{	//	re-try up to 100 times if memory conditions are not correct
+		TUint8* mem1 = NULL;
+		TUint8* mem2 = NULL;
+		TUint8* mem3 = NULL;
+		r=ReAllocTest2(mem1, mem2, mem3);
+		if (mem1)
+			Kern::Free(mem1);
+		if (mem2)
+			Kern::Free(mem2);
+		if (mem3)
+			Kern::Free(mem3);
+		} while(((r == KErrNoMemory)||(r == KErrUnknown)) && --count);
+	
+	return r;
+	}
+
+// The actual size of the block allocated given the size requested.
+#define ALIGNED_SIZE(aReqSize) (_ALIGN_UP(aReqSize + RHeap::EAllocCellSize, RHeap::ECellAlignment) - RHeap::EAllocCellSize)
+
+// We only acllocate blocks where the size we get is the size we ask for - this
+// just makes testing easier.
+const TInt KSize = ALIGNED_SIZE(200), KHalfSize = ALIGNED_SIZE(100), KSmallSize = ALIGNED_SIZE(50);
+
+TInt DMemoryTestChannel::ReAllocTest1()
+	{
+	// Test case where cell grows
+	// 
+	// Expected heap layout:
+	//   1: [-mem1-------]
+	//   2: [-mem1-]
+	//   3: [-mem1-------]
+
+	TInt err = KErrNone;
+	TUint8* mem1 = (TUint8*)Kern::Alloc(KSize); // 1
+	if (!mem1)
+		return KErrNoMemory;
+	memset(mem1, 0xff, KSize);
+	TUint8* mem2 = (TUint8*)Kern::ReAlloc(mem1, KHalfSize); // 2
+	if (mem1 != mem2)
+		{
+		mem1 = 0;
+		Kern::Free(mem2);
+		return KErrUnknown; // Don't expect move on shrink
+		}
+	mem2 = (TUint8*)Kern::ReAlloc(mem1, KSize); // 3
+	if (mem1 != mem2)
+		{
+		mem1 = 0;
+		Kern::Free(mem2);
+		return KErrUnknown; // Expect growth into original area
+		}
+	
+	TInt i;
+	for (i = 0 ; i<KHalfSize && err==KErrNone; ++i)
+		{
+		if (mem1[i] != 0xff)
+			FAIL_ALLOC_TEST(2, i, mem1[i]);
+		}
+	for (i = KHalfSize ; i<KSize && err==KErrNone; ++i)
+		{
+		if (mem1[i] != 0)
+			FAIL_ALLOC_TEST(3, i, mem1[i]);
+		}
+
+	Kern::Free(mem1);
+	return err;
+	}
+
+TInt DMemoryTestChannel::ReAllocTest2(TUint8*& mem1, TUint8*& mem2, TUint8*& mem3)
+	{	
+	// Test case where cell is moved
+	// 
+	// Expected heap layout:
+	//   1: [ mem1 ]
+	//   2: [ mem1 ] [ mem2 ]
+	//   3: [ mem1 ] [ mem2 ] [ mem3       ]
+	//   4:          [ mem2 ] [ mem1       ] 
+
+	mem1 = (TUint8*)Kern::Alloc(KSmallSize); // 1
+	if (!mem1)
+		return KErrNoMemory;
+	memset(mem1, 0xff, KSmallSize);	
+	mem2 = (TUint8*)Kern::Alloc(KSmallSize); // 2
+	if (!mem2)
+		return KErrNoMemory;
+	if (mem2 <= (mem1 + KSmallSize))
+		return KErrUnknown;	// Expect mem2 higher than mem1
+	memset(mem2, 0xee, KSmallSize);		
+	mem3 = (TUint8*)Kern::Alloc(KSize); // 3
+	if (!mem3)
+		return KErrNoMemory;
+	if (mem3 <= (mem2 + KSmallSize))
+		return KErrUnknown;	// Expect mem3 higher than mem2
+	memset(mem3, 0xdd, KSize);
+	Kern::Free(mem3);
+	TUint8* m3 = mem3;
+	mem3 = NULL;
+	TUint8* mem4 = (TUint8*)Kern::ReAlloc(mem1, KSize); // 4
+	if (!mem4)
+		return KErrNoMemory;	
+	if (mem4 == mem1)
+		return KErrUnknown; // Expect move on grow
+	mem1=mem4;
+	if (mem4 != m3)
+		return KErrUnknown; // Expect to realloc to use old mem3 space
+	
+	TInt i;
+	TInt err = KErrNone;
+	for (i = 0 ; i<KSmallSize && err==KErrNone; ++i)
+		{
+		if (mem1[i] != 0xff)
+			FAIL_ALLOC_TEST(4, i, mem1[i]);
+		}
+	for (i = KSmallSize; i<KSize && err==KErrNone; ++i)
+		{
+		if (mem1[i] != 0)
+			FAIL_ALLOC_TEST(5, i, mem1[i]);
+		}
+
+	return err;
+	}
+
+#ifdef __EPOC32__
+#define CHECK(c) { if(!(c)) { Kern::Printf("Fail  %d", __LINE__); ; ret = __LINE__;} }
+
+TInt DMemoryTestChannel::AllocPhysTest(TUint32 aIters, TUint32 aSize)
+	{
+	TInt	ret = KErrNone;
+	TUint32	index;
+
+	TUint32  pageSize = 0;
+	CHECK(Kern::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0)==KErrNone);
+	TUint32  numPages = aSize / pageSize;
+	TUint32  pageIndex;
+	TPhysAddr*	 addrArray = (TPhysAddr *)Kern::AllocZ(sizeof(TPhysAddr) * numPages);
+	CHECK(addrArray);
+	if(!addrArray)
+		{
+		return KErrNoMemory;
+		}
+
+	for (index = 0; index < aIters; index ++)
+		{
+		for (pageIndex = 0; pageIndex < numPages; pageIndex ++)
+			{
+			ret = Epoc::AllocPhysicalRam(pageSize, addrArray[pageIndex], 0);
+			if (ret != KErrNone)
+				{
+				break;
+				}
+			}
+		for (pageIndex = 0; pageIndex < numPages; pageIndex ++)
+			{
+			if (addrArray[pageIndex])
+				{
+				Epoc::FreePhysicalRam(addrArray[pageIndex], pageSize);
+				addrArray[pageIndex] = NULL;
+				}
+			}
+		if (ret != KErrNone)
+			{
+			break;
+			}
+		}
+
+	Kern::Free(addrArray);
+	return ret;
+	}
+
+#else
+
+TInt DMemoryTestChannel::AllocPhysTest(TUint32 , TUint32 )
+	{
+	return KErrNone;
+	}
+
+#endif
+
+#ifdef __EPOC32__
+
+TInt DMemoryTestChannel::AllocPhysTest1(TUint32 aIters, TUint32 aSize)
+	{
+	TInt	ret = KErrNone;
+	TUint32	index;
+
+	TUint32  pageSize = 0;
+	CHECK(Kern::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0)==KErrNone);
+	TUint32 numPages = aSize / pageSize;
+	TPhysAddr*	 addrArray = (TPhysAddr *)Kern::AllocZ(sizeof(TPhysAddr) * numPages);
+	for (index = 0; index < aIters; index ++)
+		{
+		ret = Epoc::AllocPhysicalRam(numPages, addrArray);
+		if (ret != KErrNone)
+			{
+			break;
+			}
+		Epoc::FreePhysicalRam(numPages, addrArray);
+		}
+	Kern::Free(addrArray);
+	return ret;
+	}
+#else
+
+TInt DMemoryTestChannel::AllocPhysTest1(TUint32 , TUint32 )
+	{
+	return KErrNone;
+	}
+
+#endif