--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mmu/d_memorytest.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -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