Trying to figure out how to implement my WINC like compatibility layer. Going the emulation way is probably not so smart. We should not use the kernel but rather hook native functions in the Exec calls.
// Copyright (c) 2008-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\t_pin.cpp
// Tests kernel APIs for logical pinning by pinning memory and using a realtime thread to check that
// no page faults are taken while accessing it.
//
//
#define __E32TEST_EXTENSION__
#include <e32test.h>
#include <e32svr.h>
#include <e32rom.h>
#include <e32kpan.h>
#include <u32hal.h>
#include <dptest.h>
#include "d_memorytest.h"
#include "t_codepaging_dll.h"
#include "mmudetect.h"
#include "freeram.h"
RTest test(_L("T_PIN"));
_LIT(KTCodePagingDll4, "t_codepaging_dll4.dll");
const TInt KMinBufferSize = 16384;
RMemoryTestLdd Ldd;
RMemoryTestLdd Ldd2;
RLibrary PagedLibrary;
const TUint8* PagedBuffer = NULL;
const TUint8* UnpagedBuffer = NULL;
TInt PageSize;
TInt FreeRamNoWait()
{
TMemoryInfoV1Buf meminfo;
UserHal::MemoryInfo(meminfo);
return meminfo().iFreeRamInBytes;
}
void CheckMemoryPresent(const TUint8* aBuffer, TInt aSize, TBool aExpected)
{
if (aExpected)
test.Printf(_L(" Checking memory at %08x is present\n"), aBuffer);
else
test.Printf(_L(" Checking memory at %08x is not present\n"), aBuffer);
for (TInt i = 0 ; i < aSize ; i += PageSize)
test_Equal(aExpected, Ldd.IsMemoryPresent(aBuffer + i));
}
void FlushPagingCache()
{
test_KErrNone(DPTest::FlushCache());
}
void TestPinVirtualMemoryUnpaged()
{
test.Printf(_L("Create logical pin object\n"));
test_KErrNone(Ldd.CreateVirtualPinObject());
#ifdef __EPOC32__
CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue);
test.Printf(_L("Perform logical pin operation on zero-length buffer\n"));
test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, 0));
CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue);
test.Printf(_L("Perform logical unpin operation\n"));
test_KErrNone(Ldd.UnpinVirtualMemory());
CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue);
test.Printf(_L("Perform logical pin operation on whole buffer\n"));
test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, KMinBufferSize));
CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue);
test.Printf(_L("Perform logical unpin operation\n"));
test_KErrNone(Ldd.UnpinVirtualMemory());
CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue);
#else
// Don't check for memory presence on emulator as paging not supported.
test.Printf(_L("Perform logical pin operation on zero-length buffer\n"));
test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, 0));
test.Printf(_L("Perform logical unpin operation\n"));
test_KErrNone(Ldd.UnpinVirtualMemory());
test.Printf(_L("Perform logical pin operation on whole buffer\n"));
test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, KMinBufferSize));
test.Printf(_L("Perform logical unpin operation\n"));
test_KErrNone(Ldd.UnpinVirtualMemory());
#endif
test.Printf(_L("Perform logical unpin operation (again)\n"));
test_KErrNone(Ldd.UnpinVirtualMemory()); // test double unpin ok
test.Printf(_L("Destroy logical pin object\n"));
test_KErrNone(Ldd.DestroyVirtualPinObject());
test.Printf(_L("Destroy logical pin object (again)\n"));
test_KErrNone(Ldd.DestroyVirtualPinObject()); // test double destroy ok
}
void TestPinPhysicalMemory()
{
TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
if (mm < EMemModelTypeFlexible)
{
test.Printf(_L("Memory model (%d) doesn't support physical pining\n"),mm);
return;
}
TInt i;
TInt8* UCBase;
RChunk chunk;
test.Printf(_L("Allocate user chunk\n"));
TChunkCreateInfo createInfo;
createInfo.SetDisconnected(0,UCPageCount*PageSize,UCPageCount*PageSize);
createInfo.SetPaging(TChunkCreateInfo::EPaged);
test_KErrNone(chunk.Create(createInfo));
UCBase = (TInt8*)chunk.Base();
test.Printf(_L("Create physical pin object\n"));
test_KErrNone(Ldd.CreatePhysicalPinObject());
test.Printf(_L("Perform physical pin operation on zero-length buffer\n"));
test_KErrNone(Ldd.PinPhysicalMemory((TLinAddr)UCBase, 0));
test.Printf(_L("Perform physical unpin operation\n"));
test_KErrNone(Ldd.UnpinPhysicalMemory());
test.Printf(_L("Perform Physical pin operation on the chunk\n"));
test_KErrNone(Ldd.PinPhysicalMemory((TLinAddr)UCBase, UCPageCount*PageSize));
test.Printf(_L("Test that pinned physical memory preserves its mapping when recommited\n"));
test_KErrNone(chunk.Decommit(0,UCPageCount*PageSize)); //Decommit all
for (i=UCPageCount-1;i>=0;i--) test_KErrNone(chunk.Commit(i*PageSize,PageSize)); //Commit in reverse order
for (i=0;i<UCPageCount;i++) // Recommited memory is not paged in. So, write into each page, before driver
{ // calls Kern::LinearToPhysical or it will get KErrInvalidMemory in return.
volatile TInt8* ptr = (volatile TInt8*)(UCBase+i*PageSize);
*ptr = 10;
}
test_KErrNone(Ldd.CheckPageList(chunk.Base())); // Check that the mapping is preserved.
test.Printf(_L("Sync cache & memory of User Chunk\n"));//Test Cache::SyncPhysicalMemoryBeforeDmaWrite
test_KErrNone(Ldd.SyncPinnedPhysicalMemory(0,UCPageCount*PageSize));
test.Printf(_L("Invalidate cache of User Chunk\n"));//Test Cache::SyncPhysicalMemoryBefore/AfterDmaRead
test_KErrNone(Ldd.InvalidatePinnedPhysicalMemory(0,UCPageCount*PageSize));
test.Printf(_L("Try to move pinned phys. memory...\n")); //RAM defrag should return error code here.
i = Ldd.MovePinnedPhysicalMemory(0);
test.Printf(_L("...returned %d\n"),i);
test(i!=KErrNone);
test.Printf(_L("Close the chunk\n")); // Phys. memory is pinned and shouldn't be ...
chunk.Close(); // ... mapped to another virtual memory.
test.Printf(_L("Allocate & initilise the second chunk\n"));// Kernel sholudn't commit pinned physical memory ...
test_KErrNone(chunk.CreateLocal(2*PageSize,2*PageSize)); // ...that has been just decommited from the first chunk.
UCBase = (TInt8*)chunk.Base();
for (i=0;i<UCPageCount*PageSize;i++) UCBase[i]=0; //Initialise user buffer
test.Printf(_L("Invalidate cache of pinned memory\n"));//This shouldn't affect the second chunk.
test_KErrNone(Ldd.InvalidatePinnedPhysicalMemory(0,UCPageCount*PageSize));
test.Printf(_L("Check data in the second chunk is unaffected\n"));
for (i=0;i<UCPageCount*PageSize;i++) test(UCBase[i]==0);
test.Printf(_L("Close the second chunk\n"));
chunk.Close();
test.Printf(_L("Perform physical unpin operation\n"));
test_KErrNone(Ldd.UnpinPhysicalMemory());
test.Printf(_L("Perform physical unpin operation (again)\n"));
test_KErrNone(Ldd.UnpinPhysicalMemory()); // test double unpin ok
test.Printf(_L("Destroy physical pin object\n"));
test_KErrNone(Ldd.DestroyPhysicalPinObject());
test.Printf(_L("Destroy physical pin object (again)\n"));
test_KErrNone(Ldd.DestroyPhysicalPinObject()); // test double destroy ok
test.Printf(_L("Test phys. pinning and sync of kernel memory.\n"));
test_KErrNone(Ldd.PinKernelPhysicalMemory());// Simple test of phys. pinning of kernel memory
}
void TestPhysicalPinOutOfMemory()
{
TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
if (mm < EMemModelTypeFlexible)
{
test.Printf(_L("Memory model (%d) doesn't support physical pining\n"),mm);
return;
}
TInt8* UCBase;
RChunk chunk;
test.Printf(_L("Allocate user chunk\n"));
test_KErrNone(chunk.CreateDisconnectedLocal(0,UCPageCount*PageSize,UCPageCount*PageSize));
UCBase = (TInt8*)chunk.Base();
const TInt KMaxKernelAllocations = 1024;
TInt r=KErrNoMemory;
TInt i;
__KHEAP_MARK;
for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
{
__KHEAP_FAILNEXT(i);
test.Printf(_L("Create physical pin object\n"));
r = Ldd.CreatePhysicalPinObject();
__KHEAP_RESET;
}
test.Printf(_L("Create physical pin object took %d tries\n"),i);
test_KErrNone(r);
r = KErrNoMemory;
for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
{
__KHEAP_FAILNEXT(i);
test.Printf(_L("Perform physical pin operation\n"));
r = Ldd.PinPhysicalMemory((TLinAddr)UCBase, UCPageCount*PageSize);
__KHEAP_RESET;
}
test.Printf(_L("Perform physical pin operation took %d tries\n"),i);
if (r == KErrNone)
{
test.Printf(_L("Perform physical unpin operation\n"));
Ldd.UnpinPhysicalMemory();
}
test.Printf(_L("Destroy physical pin object\n"));
Ldd.DestroyPhysicalPinObject();
// wait for any async cleanup in the supervisor to finish first...
UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
__KHEAP_MARKEND;
test.Printf(_L("Close the chunk\n"));
chunk.Close();
test_KErrNone(r);
}
void TestPinVirtualMemoryInvalid()
{
test.Printf(_L("Create logical pin object\n"));
test_KErrNone(Ldd.CreateVirtualPinObject());
test.Printf(_L("Attempt logical pin on bad memory address\n"));
TLinAddr bad = (TLinAddr)0x10000;
TInt r = Ldd.PinVirtualMemory(bad,KMinBufferSize);
test.Printf(_L("%08x r=%d"),bad,r);
if(r==KErrNone)
test_KErrNone(Ldd.UnpinVirtualMemory());
if ((MemModelAttributes() & EMemModelTypeMask) == EMemModelTypeMultiple)
{
// test unused part of code chunk...
bad = (TLinAddr)0x7f000000;
r = Ldd.PinVirtualMemory(bad,KMinBufferSize);
test.Printf(_L("%08x r=%d"),bad,r);
if(r==KErrNone)
test_KErrNone(Ldd.UnpinVirtualMemory());
}
test.Printf(_L("Destroy logical pin object\n"));
test_KErrNone(Ldd.DestroyVirtualPinObject());
}
void TestPinVirtualMemoryPaged()
{
test.Printf(_L("Create logical pin object\n"));
test_KErrNone(Ldd.CreateVirtualPinObject());
FlushPagingCache();
CheckMemoryPresent(PagedBuffer, KMinBufferSize, EFalse);
test.Printf(_L("Perform logical pin operation on zero-length buffer\n"));
test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)PagedBuffer, 0));
CheckMemoryPresent(PagedBuffer, KMinBufferSize, EFalse);
test.Printf(_L("Perform logical unpin operation\n"));
test_KErrNone(Ldd.UnpinVirtualMemory());
CheckMemoryPresent(PagedBuffer, KMinBufferSize, EFalse);
test.Printf(_L("Perform logical pin operation on whole buffer\n"));
test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)PagedBuffer, KMinBufferSize));
CheckMemoryPresent(PagedBuffer, KMinBufferSize, ETrue);
FlushPagingCache();
CheckMemoryPresent(PagedBuffer, KMinBufferSize, ETrue);
test.Printf(_L("Perform logical unpin operation\n"));
test_KErrNone(Ldd.UnpinVirtualMemory());
CheckMemoryPresent(PagedBuffer, KMinBufferSize, ETrue);
FlushPagingCache();
CheckMemoryPresent(PagedBuffer, KMinBufferSize, EFalse);
test.Printf(_L("Perform logical unpin operation (again)\n"));
test_KErrNone(Ldd.UnpinVirtualMemory()); // test double unpin ok
test.Printf(_L("Destroy logical pin object\n"));
test_KErrNone(Ldd.DestroyVirtualPinObject());
test.Printf(_L("Destroy logical pin object (again)\n"));
test_KErrNone(Ldd.DestroyVirtualPinObject()); // test double destroy ok
}
volatile TBool SoakEnd = false;
class TRandom
{
public:
TRandom(TUint32 aSeed)
: iSeed(aSeed) {};
inline TUint32 Next()
{ iSeed = iSeed*69069+1; return iSeed; }
TUint32 operator()(TUint32 aRange)
{ return (TUint32)((TUint64(Next())*TUint64(aRange))>>32); }
private:
TUint iSeed;
};
#define SOAK_CHECK(r) \
if(r!=KErrNone) \
{ \
RDebug::Printf("SOAK_CHECK fail at line %d",__LINE__); \
return r; \
} \
TInt SoakThread(TAny*)
{
RMemoryTestLdd ldd;
TInt r = ldd.Open();
SOAK_CHECK(r)
r = ldd.CreateVirtualPinObject();
SOAK_CHECK(r)
TRandom random((TUint32)&ldd);
while(!SoakEnd)
{
TUint start = random(KMinBufferSize);
TUint end = random(KMinBufferSize);
if(start>end)
{
TUint temp = start;
start = end;
end = temp;
}
const TUint32 KPageMask = 0xfff;
start &= ~KPageMask;
end = (end+KPageMask)&~KPageMask;
r = ldd.PinVirtualMemory((TLinAddr)(PagedBuffer+start),end-start);
SOAK_CHECK(r)
r = ldd.UnpinVirtualMemory();
SOAK_CHECK(r)
}
r = ldd.DestroyVirtualPinObject();
SOAK_CHECK(r)
CLOSE_AND_WAIT(ldd);
return KErrNone;
}
void TestPinVirtualMemoryPagedSoak()
{
test.Start(_L("Create timer"));
RTimer timer;
test_KErrNone(timer.CreateLocal());
test.Next(_L("Create threads"));
const TUint KNumThreads = 4;
TRequestStatus status[KNumThreads];
RThread thread[KNumThreads];
TUint i;
for(i=0; i<KNumThreads; i++)
{
test_KErrNone(thread[i].Create(KNullDesC, SoakThread, 0x1000, NULL, 0));
thread[i].Logon(status[i]);
test(status[i].Int()==KRequestPending);
}
test.Next(_L("Start threads"));
RThread().SetPriority(EPriorityMore); // make sure we are higher priority than soak threads
for(i=0; i<KNumThreads; i++)
thread[i].Resume();
test.Next(_L("Wait..."));
TRequestStatus timeoutStatus;
timer.After(timeoutStatus,10*1000000);
User::WaitForAnyRequest();
test_KErrNone(timeoutStatus.Int()); // we should have timed out if soak threads are still running OK
test.Next(_L("Stop threads and check results"));
for(i=0; i<KNumThreads; i++)
test_Equal(KRequestPending,status[i].Int());
SoakEnd = true;
timer.After(timeoutStatus,10*1000000);
for(i=0; i<KNumThreads; i++)
{
User::WaitForAnyRequest();
test_Equal(KRequestPending,timeoutStatus.Int());
}
timer.Cancel();
User::WaitForRequest(timeoutStatus);
RThread().SetPriority(EPriorityNormal); // restore thread priority
// cleanup...
CLOSE_AND_WAIT(timer);
for(i=0; i<KNumThreads; i++)
CLOSE_AND_WAIT(thread[i]);
test.End();
}
void TestPinVirtualMemoryDecommit()
{
const TInt KChunk = 4*1024*1024; // offset of page table boundary on X86 and ARM
const TInt KPage = PageSize;
const TInt TestData[][2] =
{
{0, KPage},
{KPage, KPage},
{KPage, 2*KPage},
{KChunk-KPage, KPage},
{KChunk-2*KPage,2*KPage},
{KChunk-KPage, 2*KPage},
{0,0} // end marker
};
for(TInt i=0; TestData[i][1]; ++i)
{
TInt commitOffset = TestData[i][0];
TInt commitSize = TestData[i][1];
test.Printf(_L("Create chunk 0x%x+0x%x\n"),commitOffset,commitSize);
TChunkCreateInfo createInfo;
createInfo.SetDisconnected(commitOffset,commitOffset+commitSize,commitOffset+commitSize);
createInfo.SetPaging(TChunkCreateInfo::EPaged);
RChunk chunk;
test_KErrNone(chunk.Create(createInfo));
TUint8* buffer = chunk.Base()+commitOffset;
TUint bufferSize = commitSize;
FlushPagingCache(); // start with blank slate as far as paged memory is concerned
test.Printf(_L("Create virtual pin object\n"));
test_KErrNone(Ldd.CreateVirtualPinObject());
test_KErrNone(Ldd2.CreateVirtualPinObject());
CheckMemoryPresent(buffer, bufferSize, EFalse);
TInt initialFreeRam = FreeRam();
test.Printf(_L("Pin memory\n"));
test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)buffer, bufferSize));
CheckMemoryPresent(buffer, bufferSize, ETrue);
TInt pinnedFreeRam = FreeRam();
test_Compare(pinnedFreeRam,<,initialFreeRam);
TUint8 c = *buffer;
memset(buffer,~c,bufferSize); // invert memory
test.Printf(_L("Decommit pinned memory\n"));
test_KErrNone(chunk.Decommit(commitOffset,commitSize));
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(pinnedFreeRam,FreeRam()); // decommited memory should not be freed as it is pinned
test.Printf(_L("Unpin memory\n"));
test_KErrNone(Ldd.UnpinVirtualMemory());
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(initialFreeRam,FreeRam()); // memory should be now freed
//
// test recommitting decommitted pinned memory...
//
test.Printf(_L("Commit memory\n"));
test_KErrNone(chunk.Commit(commitOffset,commitSize));
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(initialFreeRam,FreeRam());
test.Printf(_L("Read memory\n"));
volatile TUint8* p = buffer;
volatile TUint8* pEnd = buffer+bufferSize;
while(p<pEnd)
test_Equal(c,*p++); // memory should have been wiped
test_Equal(initialFreeRam,FreeRam()); // memory now paged in
test.Printf(_L("Pin memory which is already paged in\n"));
test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)buffer, bufferSize));
CheckMemoryPresent(buffer, bufferSize, ETrue);
test_Equal(pinnedFreeRam,FreeRam());
memset(buffer,~c,bufferSize); // invert memory
test.Printf(_L("Decommit pinned memory\n"));
test_KErrNone(chunk.Decommit(commitOffset,commitSize));
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(pinnedFreeRam,FreeRam());
test.Printf(_L("Commit pinned memory again\n"));
test_KErrNone(chunk.Commit(commitOffset,commitSize));
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(pinnedFreeRam,FreeRam());
p = buffer;
pEnd = buffer+bufferSize;
while(p<pEnd)
test_Equal(c,*p++); // memory should have been wiped
test.Printf(_L("Unpin memory\n"));
test_KErrNone(Ldd.UnpinVirtualMemory());
CheckMemoryPresent(buffer, bufferSize, ETrue);
test_Equal(initialFreeRam,FreeRam());
test.Printf(_L("Decommit memory\n"));
test_KErrNone(chunk.Decommit(commitOffset,commitSize));
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Compare(FreeRam(),<=,initialFreeRam);
//
// test pin twice...
//
test.Printf(_L("Commit memory\n"));
test_KErrNone(chunk.Commit(commitOffset,commitSize));
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(initialFreeRam,FreeRam());
test.Printf(_L("Pin memory\n"));
test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)buffer, bufferSize));
CheckMemoryPresent(buffer, bufferSize, ETrue);
test_Equal(pinnedFreeRam,FreeRam());
test.Printf(_L("Pin memory again\n"));
test_KErrNone(Ldd2.PinVirtualMemory((TLinAddr)buffer, bufferSize));
CheckMemoryPresent(buffer, bufferSize, ETrue);
test_Equal(pinnedFreeRam,FreeRam());
test.Printf(_L("Decommit pinned memory\n"));
test_KErrNone(chunk.Decommit(commitOffset,commitSize));
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(pinnedFreeRam,FreeRam()); // decommited memory should not be freed as it is pinned
test.Printf(_L("Unpin memory\n"));
test_KErrNone(Ldd2.UnpinVirtualMemory());
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(pinnedFreeRam,FreeRam()); // memory shouldn't be freed as another pin exists
test.Printf(_L("Unpin memory again\n"));
test_KErrNone(Ldd.UnpinVirtualMemory());
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(initialFreeRam,FreeRam()); // memory should be now freed
//
// test page stealing of decommited memory
//
test.Printf(_L("Commit memory\n"));
test_KErrNone(chunk.Commit(commitOffset,commitSize));
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(initialFreeRam,FreeRam());
test.Printf(_L("Pin memory\n"));
test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)buffer, bufferSize));
CheckMemoryPresent(buffer, bufferSize, ETrue);
test_Equal(pinnedFreeRam,FreeRam());
test.Printf(_L("Decommit pinned memory\n"));
test_KErrNone(chunk.Decommit(commitOffset,commitSize));
CheckMemoryPresent(buffer, bufferSize, EFalse);
test_Equal(pinnedFreeRam,FreeRam());
test.Printf(_L("Unpin memory a higher priority that supervisor thread\n"));
RThread().SetPriority(EPriorityRealTime);
test_KErrNone(Ldd.UnpinVirtualMemory());
// on single core system, supervisor thread can't run and free pages yet
// because we're a higher priority...
test.Printf(_L("memory freed = %d\n"),initialFreeRam==FreeRamNoWait());
test.Printf(_L("Force decommited unpinned pages out of live list\n"));
FlushPagingCache();
RThread().SetPriority(EPriorityNormal);
test_Equal(initialFreeRam,FreeRam()); // memory should be now freed
//
// cleanup...
//
test.Printf(_L("Destroy pin object\n"));
test_KErrNone(Ldd.DestroyVirtualPinObject());
test_KErrNone(Ldd2.DestroyVirtualPinObject());
chunk.Close();
}
test.Printf(_L("Flush paging cache\n"));
FlushPagingCache(); // this is a test that has shown up bugs in the past
}
void TestPinOutOfMemory()
{
// Ensure that if pinning fails with KErrNoMemory,
// there isn't a memory leak
const TInt KMaxKernelAllocations = 1024;
TInt r=KErrNoMemory;
TInt i;
const TUint8* buffer = NULL;
if (PagedBuffer)
{
buffer = PagedBuffer;
}
else
{
buffer = UnpagedBuffer;
}
test_NotNull(buffer);
__KHEAP_MARK;
for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
{
__KHEAP_FAILNEXT(i);
test.Printf(_L("Create logical pin object\n"));
r = Ldd.CreateVirtualPinObject();
__KHEAP_RESET;
}
test.Printf(_L("Create logical pin object took %d tries\n"),i);
test_KErrNone(r);
r = KErrNoMemory;
for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
{
__KHEAP_FAILNEXT(i);
test.Printf(_L("Perform logical pin operation\n"));
r = Ldd.PinVirtualMemory((TLinAddr)buffer, KMinBufferSize);
__KHEAP_RESET;
}
test.Printf(_L("Perform logical pin operation took %d tries\n"),i);
if (r == KErrNone)
{
test.Printf(_L("Perform logical unpin operation\n"));
Ldd.UnpinVirtualMemory();
}
test.Printf(_L("Destroy logical pin object\n"));
Ldd.DestroyVirtualPinObject();
// wait for any async cleanup in the supervisor to finish first...
UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
__KHEAP_MARKEND;
test_KErrNone(r);
}
TInt E32Main()
{
test.Title();
test.Start(_L("Test kernel pinning APIs"));
if (DPTest::Attributes() & DPTest::ERomPaging)
test.Printf(_L("Rom paging supported\n"));
if (DPTest::Attributes() & DPTest::ECodePaging)
test.Printf(_L("Code paging supported\n"));
if (DPTest::Attributes() & DPTest::EDataPaging)
test.Printf(_L("Data paging supported\n"));
test.Next(_L("Loading test drivers"));
test_KErrNone(Ldd.Open());
test_KErrNone(Ldd2.Open());
test.Next(_L("Getting page size"));
test_KErrNone(UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&PageSize,0));
test.Next(_L("Setting up paged and unpaged buffers"));
#ifdef __EPOC32__
// Use unpaged rom for our unpaged buffer
TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
UnpagedBuffer = (TUint8*)romHeader;
TInt size = romHeader->iPageableRomStart ? romHeader->iPageableRomStart : romHeader->iUncompressedSize;
test(size >= KMinBufferSize);
if (DPTest::Attributes() & DPTest::ERomPaging)
{
// Use end of paged ROM for our paged buffer
test(romHeader->iPageableRomStart);
TInt offset = romHeader->iPageableRomStart + romHeader->iPageableRomSize - KMinBufferSize;
offset &= ~0xfff;
test(offset>=romHeader->iPageableRomStart);
PagedBuffer = (TUint8*)romHeader + offset;
}
else if (DPTest::Attributes() & DPTest::ECodePaging)
{
// Use code paged DLL for our paged buffer
test_KErrNone(PagedLibrary.Load(KTCodePagingDll4));
TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)PagedLibrary.Lookup(KGetAddressOfDataFunctionOrdinal);
TInt size;
PagedBuffer = (TUint8*)func(size);
test_NotNull(PagedBuffer);
test(size >= KMinBufferSize);
}
#else
UnpagedBuffer = (TUint8*)User::Alloc(KMinBufferSize);
test_NotNull(UnpagedBuffer);
#endif
RDebug::Printf("UnpagedBuffer=%x\n",UnpagedBuffer);
RDebug::Printf("PagedBuffer=%x\n",PagedBuffer);
__KHEAP_MARK;
test.Next(_L("Logical pin unpaged memory"));
TestPinVirtualMemoryUnpaged();
test.Next(_L("Logical pin invalid memory"));
TestPinVirtualMemoryInvalid();
test.Next(_L("Physical pinning"));
TestPinPhysicalMemory();
test.Next(_L("Physical pinning OOM"));
TestPhysicalPinOutOfMemory();
test.Next(_L("Pin OOM Tests"));
TestPinOutOfMemory();
if (PagedBuffer)
{
test.Next(_L("Logical pin paged memory"));
TestPinVirtualMemoryPaged();
test.Next(_L("Logical pin paged memory soak test"));
TestPinVirtualMemoryPagedSoak();
}
if (DPTest::Attributes() & DPTest::EDataPaging)
{
test.Next(_L("Logical pin then decommit memory"));
TestPinVirtualMemoryDecommit();
}
// wait for any async cleanup in the supervisor to finish first...
UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
__KHEAP_MARKEND;
#ifndef __EPOC32__
User::Free((TAny*)UnpagedBuffer);
#endif
PagedLibrary.Close();
Ldd.Close();
Ldd2.Close();
test.End();
return KErrNone;
}