Fix for Bug 2984 - [GCCE] Illegal inline assembler in kernel/eka/debug/utrace/src/e32utrace.cpp
// Copyright (c) 2005-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_demandpaging.cpp
// Functional tests for demand paging. The test suite covers simple
// paging operations as well as HAL configuration and tuning functions.
// 001.01 DPTest::Attributes
// 001.02 DPTest::FlushCache
// 001.03 DPTest::CacheSize
// 001.04 DPTest::SetCacheSize
// 001.04.01 Changing size of flushed VM cache
// 001.04.02 Changing size of full VM cache
// 002 Loading test drivers
// 003 Test thread realtime state
// 003.01 Enable KREALTIME tracing
// 003.02 Test ERealtimeStateOff
// 003.03 Test ERealtimeStateOn
// 003.04 Test ERealtimeStateWarn
// 003.05 Test server with ERealtimeStateOff
// 003.06 Test server with ERealtimeStateOn
// 003.07 Test server with ERealtimeStateWarn
// 003.08 Disable KREALTIME tracing
// 004 Lock Test
// 005 Lock Test again
// 006 Test writing to paged ROM
// 007 Test IPC read from paged memory
// 007.01 Create server
// 007.02 IPC read from ROM
// 007.03 Stop server
// 008 Test contiguous RAM allocation reclaims paged memory
// 008.01 Start...
// 008.02 Contiguous RAM test: alloc size = 128K align = 16
// 008.03 Contiguous RAM test: alloc size = 128K align = 0
// 008.04 Contiguous RAM test: alloc size = 64K align = 15
// 008.05 Contiguous RAM test: alloc size = 64K align = 14
// 008.06 Contiguous RAM test: alloc size = 64K align = 13
// 008.07 Contiguous RAM test: alloc size = 64K align = 12
// 008.08 Contiguous RAM test: alloc size = 64K align = 0
// 008.09 Contiguous RAM test: alloc size = 8K align = 13
// 008.10 Contiguous RAM test: alloc size = 8K align = 12
// 008.11 Contiguous RAM test: alloc size = 8K align = 0
// 008.12 Contiguous RAM test: alloc size = 4K align = 13
// 008.13 Contiguous RAM test: alloc size = 4K align = 12
// 008.14 Contiguous RAM test: alloc size = 4K align = 0
// 009 Test no kernel faults when copying data from unpaged rom with mutex held
// 010 Close test driver
// 011 Test setting publish and subscribe properties from paged area
// 012 Rom Paging Benchmark
// 012.01 Benchmark ROM paging...
//
//
//! @SYMTestCaseID KBASE-T_DEMANDPAGING-0334
//! @SYMTestType UT
//! @SYMPREQ PREQ1110
//! @SYMTestCaseDesc Demand Paging functional tests.
//! @SYMTestActions 001 Test HAL interface
//! @SYMTestExpectedResults All tests should pass.
//! @SYMTestPriority High
//! @SYMTestStatus Implemented
#define __E32TEST_EXTENSION__
#include <e32test.h>
#include <dptest.h>
#include <e32kpan.h>
#include <e32property.h>
#include <e32rom.h>
#include "d_memorytest.h"
#include "d_demandpaging.h"
#include "d_gobble.h"
#include "mmudetect.h"
#include "t_codepaging_dll.h"
#include "freeram.h"
RTest test(_L("T_DEMANDPAGING"));
_LIT(KTCodePagingDll4, "t_codepaging_dll4.dll");
const TInt KMinBufferSize = 16384;
const TInt KMaxIPCSize = 256*1024;
TInt PageSize = 0;
RDemandPagingTestLdd Ldd;
RLibrary PagedLibrary;
// A buffer containing paged memory, contents may or may not be paged in
const TUint8* LargeBuffer = NULL;
TInt LargeBufferSize = 0;
// A buffer containing paged memeory, contents always paged out before access
const TUint8* SmallBuffer = NULL;
TInt SmallBufferSize = 0;
// A shared buffer mapped to the global address range
TInt SharedBufferSize = KMaxIPCSize+4096;
TLinAddr SharedBufferAddr = 0;
TUint8* SharedBuffer = NULL;
// A descriptor whose header is in paged memory (actually just a pointer to a zero word)
TDesC8* PagedHeaderDes = NULL;
// A data paged chunk used as a buffer, if data paging is supported
_LIT(KChunkName, "t_demandpaging chunk");
RChunk DataPagedChunk;
TBool DataPagingSupported = EFalse;
TUint8* DataPagedBuffer = NULL;
TUint8 ReadByte(volatile TUint8* aPtr)
{
return *aPtr;
}
#define READ(a) ReadByte((volatile TUint8*)(a))
void ThrashPaging(TUint aMaxBytes=KMaxTUint)
{
TUint size = LargeBufferSize;
if(size>aMaxBytes)
size = aMaxBytes;
// read all ROM pages about 10 times each in a random order...
TUint32 random=1;
for(TInt i=size/(PageSize/10); i>0; --i)
{
READ(LargeBuffer+((TInt64(random)*TInt64(size))>>32));
random = random*69069+1;
}
}
void FragmentPagingCache(TUint aMaxBytes)
{
DPTest::FlushCache();
TUint size = Min(LargeBufferSize, aMaxBytes);
if(size<aMaxBytes)
test.Printf(_L("WARNING: LargeBuffer not large enough! Have you built a full test ROM?\n"));
RChunk chunk;
test(KErrNone==chunk.CreateDisconnectedLocal(0,0,size));
TUint32 random = 0;
for(TUint i=0; i<size; i += PageSize)
{
random = random*69069+1;
if(random<0x40000000)
chunk.Commit(i,PageSize); // to make paging cache fragmented
READ(LargeBuffer + i);
}
CLOSE_AND_WAIT(chunk);
UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
}
void RomPagingBenchmark()
{
TInt r=DPTest::FlushCache();
if(r!=KErrNone)
return;
test.Start(_L("Benchmark ROM paging..."));
// change live list to be a small as possible
test(KErrNone==DPTest::SetCacheSize(1,1));
RTimer timer;
test(KErrNone==timer.CreateLocal());
TRequestStatus status;
timer.After(status,1);
User::WaitForRequest(status);
TPckgBuf<DPTest::TEventInfo> events0;
DPTest::EventInfo(events0);
TInt KRunTime = 10*1000*1000;
timer.After(status,KRunTime);
while(status==KRequestPending)
for(const TUint8* ptr=LargeBuffer; ptr<(LargeBuffer+LargeBufferSize); ptr+=PageSize)
{
READ(ptr);
if(status!=KRequestPending)
break;
}
TPckgBuf<DPTest::TEventInfo> events1;
DPTest::EventInfo(events1);
User::WaitForRequest(status);
TUint pages = events1().iPageInReadCount-events0().iPageInReadCount;
test.Printf(_L("%d pages in %d seconds = %d us/page\n"),pages,KRunTime/1000/1000,KRunTime/pages);
// restore live list to default size...
test(KErrNone==DPTest::SetCacheSize(0,0));
test.End();
}
void TestResizeVMCache()
{
TInt r = DPTest::SetCacheSize(0,0); // restore cache size to defaults
test(r==KErrNone);
TUint sizeMin = 0;
TUint sizeMax = 0;
TUint currentSize = 0;
DPTest::CacheSize(sizeMin,sizeMax,currentSize);
TUint originalMin = sizeMin;
TUint originalMax = sizeMax;
test.Printf(_L("original min=%u, original max=%u, current=%u\n"),originalMin/PageSize,originalMax/PageSize,currentSize/PageSize);
int K = currentSize/PageSize+4;
struct
{
TUint iMinPages;
TUint iMaxPages;
TInt iResult;
}
testArgs[] =
{
{ K, K, KErrNone},
{ K-4, K, KErrNone},
{ K, K, KErrNone},
{ K, K*2, KErrNone},
{ K, K, KErrNone},
{ K-1, K, KErrNone},
{ K, K, KErrNone},
{ K, K+1, KErrNone},
{ K, K, KErrNone},
{ K+1, K, KErrArgument},
{ K, K-1, KErrArgument},
{ KMaxTInt, KMaxTInt, KErrNoMemory},
{ K, K, KErrNone},
{ 0, 0, KErrNone}, // restore defaults
{ 0, 0, KMaxTInt} // list end marker
};
for(TInt j=0; j<2; ++j)
{
if(!j)
{
test.Start(_L("Changing size of flushed VM cache"));
test.Printf(_L("Original cache size min == %u, max == %u\n"),originalMin/PageSize,originalMax/PageSize);
}
else
test.Next(_L("Changing size of full VM cache"));
TInt i=0;
while(testArgs[i].iResult!=KMaxTInt)
{
TUint min=testArgs[i].iMinPages*PageSize;
TUint max=testArgs[i].iMaxPages*PageSize;
TInt result=testArgs[i].iResult;
ThrashPaging(max*2);
if(!j)
DPTest::FlushCache();
test.Printf(_L("DPTest::SetCacheSize min=%u, max=%u, expected result=%d\n"),min/PageSize,max/PageSize,result);
TInt r=DPTest::SetCacheSize(min,max);
if(r!=result)
{
test.Printf(_L("result=%d\n"),r);
test(0);
}
if(r==KErrNone)
{
// we've successfully changed the cache size...
if(max)
{
sizeMin = min;
sizeMax = max;
}
else
{
sizeMin = originalMin;
sizeMax = originalMax;
}
}
if(r==KErrNoMemory)
{
// cache size after OOM is unpredictable, so reset our values
DPTest::SetCacheSize(sizeMin,sizeMax);
}
else
{
// test 'get' function returns expected cache size
r=DPTest::CacheSize(min,max,currentSize);
test.Printf(_L("DPTest::CacheSize result=%d min=%u max=%u current=%u\n"),r,min/PageSize,max/PageSize,currentSize/PageSize);
if(r!=KErrNone || min!=sizeMin || max!=sizeMax)
test(0);
test(currentSize >= min && currentSize <= max);
}
++i;
}
}
test.End();
}
void TestResizeVMCache2()
{
TUint originalMin = 0;
TUint originalMax = 0;
TUint currentSize = 0;
test_KErrNone(DPTest::CacheSize(originalMax, originalMax, currentSize));
test_KErrNone(DPTest::SetCacheSize(1, originalMax));
TUint sizeMin = 0;
TUint sizeMax = 0;
test_KErrNone(DPTest::CacheSize(sizeMin, sizeMax, currentSize));
test(sizeMin > 1);
test_KErrNone(DPTest::SetCacheSize(originalMin, originalMax));
}
void TestHAL()
{
test.Start(_L("DPTest::Attributes"));
TUint32 attr=DPTest::Attributes();
test.Printf(_L("Attributes = %08x\n"),attr);
test.Next(_L("DPTest::FlushCache"));
TInt r=DPTest::FlushCache();
if(r==KErrNotSupported)
test.Printf(_L("Not Supported\n"));
else if(r<0)
{
test.Printf(_L("Error = %d\n"),r);
test(0);
}
test.Next(_L("DPTest::CacheSize"));
TUint oldMin = 0;
TUint oldMax = 0;
TUint currentSize = 0;
r=DPTest::CacheSize(oldMin,oldMax,currentSize);
if(r==KErrNotSupported)
test.Printf(_L("Not Supported\n"));
else if(r<0)
{
test.Printf(_L("Error = %d\n"),r);
test(0);
}
else
{
test.Printf(_L("Size = %dk,%dk,%dk\n"),oldMin>>10,oldMax>>10,currentSize>>10);
}
test.Next(_L("DPTest::SetCacheSize"));
r=DPTest::SetCacheSize(oldMin,oldMax);
if(r==KErrNotSupported)
test.Printf(_L("Not Supported\n"));
else if(r<0)
{
test.Printf(_L("Error = %d\n"),r);
test(0);
}
if(r==KErrNone)
{
TestResizeVMCache();
TestResizeVMCache2();
}
test.End();
}
// Test IPC and realtime state
enum TIpcDir
{
EServerRead,
EServerWrite
};
enum TIpcObjectPaged
{
ENothingPaged,
EDesHeaderPaged,
EDesContentPaged
};
enum TRealtimeOutcome
{
ENoError,
EBadDescriptor,
EServerTerminated,
ERealtimePanic
};
class RTestSession : public RSessionBase
{
public:
TInt Create(RServer2 aServer)
{
return CreateSession(aServer,TVersion(),-1);
}
inline TInt Send(const TIpcArgs& aArgs)
{
return RSessionBase::SendReceive(0,aArgs);
}
};
RServer2 TestServer;
TInt IpcTestServerFunc(TAny* aArg)
{
TIpcDir dir = (TIpcDir)(((TInt)aArg) & 0xff);
TIpcObjectPaged paged = (TIpcObjectPaged)((((TInt)aArg) >> 8) & 0xff);
User::TRealtimeState realtime = (User::TRealtimeState)((((TInt)aArg) >> 16) & 0xff);
User::TRealtimeState clientRealtime = (User::TRealtimeState)((((TInt)aArg) >> 24) & 0xff);
TInt r;
// We want the server to fault the client when it is realtime
// and accessing paged out memory.
r = TestServer.CreateGlobal(KNullDesC, EIpcSession_Sharable, EServerRole_Default, EServerOpt_PinClientDescriptorsDisable);
if (r != KErrNone)
return r;
RThread::Rendezvous(KErrNone);
RMessage2 message;
TestServer.Receive(message);
if ((clientRealtime == User::ERealtimeStateOn) != message.ClientIsRealtime())
return KErrGeneral;
message.Complete(KErrNone); // complete connection request
TRequestStatus s;
TestServer.Receive(message,s);
User::WaitForRequest(s);
if (s != KErrNone)
return s.Int();
TInt32 unpagedContent;
TPtr8 unpagedDes((TUint8*)&unpagedContent, 4, 4);
TPtrC8 pagedContentBuf(SmallBuffer,sizeof(TInt));
TPtr8* dataPagedHeaderDes = (TPtr8*)DataPagedBuffer;
if (DataPagingSupported)
new (dataPagedHeaderDes) TPtr8((TUint8*)&unpagedContent, 4);
TPtr8 dataPagedContentDes(DataPagedBuffer + PageSize, 4);
r = DPTest::FlushCache();
if(r != KErrNone)
return r;
User::SetRealtimeState(realtime);
if (dir == EServerRead)
{
switch (paged)
{
case ENothingPaged:
r = message.Read(0,unpagedDes);
break;
case EDesHeaderPaged:
r = DataPagingSupported ? message.Read(0,*dataPagedHeaderDes) : KErrNotSupported;
break;
case EDesContentPaged:
r = DataPagingSupported ? message.Read(0,dataPagedContentDes) : KErrNotSupported;
break;
default:
r = KErrArgument;
break;
}
}
else if (dir == EServerWrite)
{
switch (paged)
{
case ENothingPaged:
r = message.Write(0,unpagedDes);
break;
case EDesHeaderPaged:
r = message.Write(0,*PagedHeaderDes);
break;
case EDesContentPaged:
r = message.Write(0,pagedContentBuf);
break;
default:
r = KErrArgument;
break;
}
}
else
r = KErrArgument;
User::SetRealtimeState(User::ERealtimeStateOff);
message.Complete(KErrNone);
return r;
}
TInt IpcTestClientFunc(TAny* aArg)
{
TIpcDir dir = (TIpcDir)(((TInt)aArg) & 0xff);
TIpcObjectPaged paged = (TIpcObjectPaged)((((TInt)aArg) >> 8) & 0xff);
User::TRealtimeState realtime = (User::TRealtimeState)((((TInt)aArg) >> 16) & 0xff);
RTestSession session;
TInt r = session.Create(TestServer);
if(r != KErrNone)
return r;
TInt32 unpagedContent;
TPtr8 unpagedDes((TUint8*)&unpagedContent, 4, 4);
TPtrC8 pagedContentBuf(SmallBuffer + PageSize, sizeof(TInt));
TPtr8* dataPagedHeaderDes = (TPtr8*)(DataPagedBuffer + (2 * PageSize));
if (DataPagingSupported)
new (dataPagedHeaderDes) TPtr8((TUint8*)&unpagedContent, 4);
TPtr8 dataPagedContentDes(DataPagedBuffer + (3 * PageSize), 4);
r = DPTest::FlushCache();
if(r != KErrNone)
return r;
User::SetRealtimeState(realtime);
if (dir == EServerRead)
{
switch (paged)
{
case ENothingPaged:
r = session.Send(TIpcArgs(&unpagedDes));
break;
case EDesHeaderPaged:
r = session.Send(TIpcArgs(PagedHeaderDes));
break;
case EDesContentPaged:
r = session.Send(TIpcArgs(&pagedContentBuf));
break;
default:
r = KErrArgument;
break;
}
}
else if (dir == EServerWrite)
{
switch (paged)
{
case ENothingPaged:
r = session.Send(TIpcArgs(&unpagedDes));
break;
case EDesHeaderPaged:
r = DataPagingSupported ? session.Send(TIpcArgs(dataPagedHeaderDes)) : KErrNotSupported;
break;
case EDesContentPaged:
r = DataPagingSupported ? session.Send(TIpcArgs(&dataPagedContentDes)) : KErrNotSupported;
break;
default:
r = KErrArgument;
break;
}
}
else
r = KErrArgument;
User::SetRealtimeState(User::ERealtimeStateOff);
session.Close();
return r;
}
void TestRealtimeOutcome(RThread aThread, TRealtimeOutcome aOutcome)
{
switch(aOutcome)
{
case ENoError:
test_Equal(EExitKill, aThread.ExitType());
test_KErrNone(aThread.ExitReason());
break;
case EBadDescriptor:
test_Equal(EExitKill, aThread.ExitType());
test_Equal(KErrBadDescriptor, aThread.ExitReason());
break;
case EServerTerminated:
test_Equal(EExitKill, aThread.ExitType());
test_Equal(KErrServerTerminated, aThread.ExitReason());
break;
case ERealtimePanic:
test_Equal(EExitPanic, aThread.ExitType());
test(aThread.ExitCategory()==_L("KERN-EXEC"));
test_Equal(EIllegalFunctionForRealtimeThread, aThread.ExitReason());
break;
default:
test(EFalse);
}
}
void TestPagedIpc(TIpcDir aIpcDir,
TIpcObjectPaged aClientPaged,
TIpcObjectPaged aServerPaged,
User::TRealtimeState aClientState,
User::TRealtimeState aServerState,
TRealtimeOutcome aClientOutcome,
TRealtimeOutcome aServerOutcome)
{
test.Printf(_L("TestPagedIpc %d %d %d %d %d %d %d\n"), aIpcDir, aClientPaged, aServerPaged,
aClientState, aServerState, aClientOutcome, aServerOutcome);
RThread serverThread;
RThread clientThread;
TRequestStatus serverStatus;
TRequestStatus clientStatus;
TInt serverArg = aIpcDir | (aServerPaged << 8) | (aServerState << 16) | (aClientState << 24);
test_KErrNone(serverThread.Create(KNullDesC, &IpcTestServerFunc, 0x1000, NULL, (TAny*)serverArg));
TName name;
name = serverThread.Name();
test.Printf(_L(" server: %S\n"), &name);
serverThread.Rendezvous(serverStatus);
serverThread.Resume();
User::WaitForRequest(serverStatus);
test_KErrNone(serverStatus.Int());
serverThread.Logon(serverStatus);
TInt clientArg = aIpcDir | (aClientPaged << 8) | (aClientState << 16);
test_KErrNone(clientThread.Create(KNullDesC, &IpcTestClientFunc, 0x1000, NULL, (TAny*)clientArg));
name = clientThread.Name();
test.Printf(_L(" client: %S\n"), &name);
clientThread.Logon(clientStatus);
clientThread.Resume();
User::WaitForRequest(serverStatus);
test.Printf(_L(" server exit type is %d %d\n"), serverThread.ExitType(), serverThread.ExitReason());
TestServer.Close(); // because handle is process-relative, it's not closed if the server dies
User::WaitForRequest(clientStatus);
test.Printf(_L(" client exit type is %d %d\n"), clientThread.ExitType(), clientThread.ExitReason());
TestRealtimeOutcome(serverThread, aServerOutcome);
TestRealtimeOutcome(clientThread, aClientOutcome);
CLOSE_AND_WAIT(serverThread);
CLOSE_AND_WAIT(clientThread);
}
TInt TestThreadFunction(TAny* aType)
{
// Ensure that pageable memory is paged out
TInt r=DPTest::FlushCache();
if(r!=KErrNone)
return r;
// Access pageable data whilst thread is in specified realttime state.
User::SetRealtimeState((User::TRealtimeState)(TInt)aType);
READ(SmallBuffer);
return KErrNone;
}
TInt RunTestThread(User::TRealtimeState aType, TRealtimeOutcome aOutcome)
{
RThread thread;
TInt r=thread.Create(KNullDesC, &TestThreadFunction, 0x1000, NULL, (TAny*)aType);
if(r!=KErrNone)
return r;
TRequestStatus s;
thread.Logon(s);
if(s.Int()!=KRequestPending)
return s.Int();
thread.Resume();
User::WaitForRequest(s);
TestRealtimeOutcome(thread, aOutcome);
CLOSE_AND_WAIT(thread);
return KErrNone;
}
void TestRealtimeState()
{
// make sure live list is big enough
test(KErrNone==DPTest::SetCacheSize(256*PageSize,256*PageSize));
test.Start(_L("Enable KREALTIME tracing"));
Ldd.SetRealtimeTrace(ETrue);
test.Next(_L("Test ERealtimeStateOff"));
RunTestThread(User::ERealtimeStateOff, ENoError);
test.Next(_L("Test ERealtimeStateOn"));
RunTestThread(User::ERealtimeStateOn, ERealtimePanic);
test.Next(_L("Test ERealtimeStateWarn"));
RunTestThread(User::ERealtimeStateWarn, ENoError);
test.Next(_L("Test combinations of IPC with realtime state"));
// ipc dir: client paged: server paged: client state: server state: client outcome: server outcome:
TestPagedIpc(EServerRead, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
TestPagedIpc(EServerRead, EDesHeaderPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
TestPagedIpc(EServerRead, EDesContentPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
TestPagedIpc(EServerWrite, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
TestPagedIpc(EServerWrite, ENothingPaged, EDesHeaderPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
TestPagedIpc(EServerWrite, ENothingPaged, EDesContentPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
if (DataPagingSupported)
{
TestPagedIpc(EServerRead, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
TestPagedIpc(EServerRead, ENothingPaged, EDesHeaderPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
TestPagedIpc(EServerRead, ENothingPaged, EDesContentPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
TestPagedIpc(EServerWrite, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
TestPagedIpc(EServerWrite, EDesHeaderPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
TestPagedIpc(EServerWrite, EDesContentPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, ENoError, ENoError);
}
TestPagedIpc(EServerRead, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
TestPagedIpc(EServerRead, EDesHeaderPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
TestPagedIpc(EServerRead, EDesContentPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
TestPagedIpc(EServerWrite, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
TestPagedIpc(EServerWrite, ENothingPaged, EDesHeaderPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
TestPagedIpc(EServerWrite, ENothingPaged, EDesContentPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
if (DataPagingSupported)
{
TestPagedIpc(EServerRead, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
TestPagedIpc(EServerRead, ENothingPaged, EDesHeaderPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
TestPagedIpc(EServerRead, ENothingPaged, EDesContentPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
TestPagedIpc(EServerWrite, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
TestPagedIpc(EServerWrite, EDesHeaderPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
TestPagedIpc(EServerWrite, EDesContentPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateWarn, ENoError, ENoError);
}
TestPagedIpc(EServerRead, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, ENoError, ENoError);
TestPagedIpc(EServerRead, EDesHeaderPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, ENoError, ENoError);
TestPagedIpc(EServerRead, EDesContentPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, ERealtimePanic, EBadDescriptor);
TestPagedIpc(EServerWrite, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, ENoError, ENoError);
TestPagedIpc(EServerWrite, ENothingPaged, EDesHeaderPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, EServerTerminated, ERealtimePanic);
TestPagedIpc(EServerWrite, ENothingPaged, EDesContentPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, EServerTerminated, ERealtimePanic);
if (DataPagingSupported)
{
TestPagedIpc(EServerRead, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, ENoError, ENoError);
TestPagedIpc(EServerRead, ENothingPaged, EDesHeaderPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, EServerTerminated, ERealtimePanic);
TestPagedIpc(EServerRead, ENothingPaged, EDesContentPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, EServerTerminated, ERealtimePanic);
TestPagedIpc(EServerWrite, ENothingPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, ENoError, ENoError);
TestPagedIpc(EServerWrite, EDesHeaderPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, ENoError, ENoError);
TestPagedIpc(EServerWrite, EDesContentPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOn, ERealtimePanic, EBadDescriptor);
}
test.End();
// retore size of live list
test(KErrNone==DPTest::SetCacheSize(0,0));
}
void TestLock()
{
// make sure live list is big enough
test(KErrNone==DPTest::SetCacheSize(128 * PageSize, 256 * PageSize));
TInt r = Ldd.LockTest(SmallBuffer,SmallBufferSize);
if(r==KErrNone)
{
test.Next(_L("Lock Test again"));
r = Ldd.LockTest(SmallBuffer,SmallBufferSize);
}
if(r)
{
test.Printf(_L("failed at D_DEMANPAGING.CPP line %d\n"),r);
test(0);
}
// restore live list to default size...
test(KErrNone==DPTest::SetCacheSize(0,0));
}
const TInt KSmallPropertySize = 512;
const TInt KLargePropertySize = 16384;
struct SSetPropertyInfo
{
TUid iCategory;
TInt iKey;
TUint8* iData;
TInt iLength;
};
TInt SetPropertyThreadFunction(TAny* aArg)
{
SSetPropertyInfo* info = (SSetPropertyInfo*)aArg;
TInt r;
r = DPTest::FlushCache();
if (r != KErrNone)
return r;
TPtrC8 data(info->iData, info->iLength);
r = RProperty::Set(info->iCategory, info->iKey, data);
if (r != KErrNone)
return r;
RBuf8 buffer;
r = buffer.Create(KLargePropertySize);
if (r != KErrNone)
return r;
r = RProperty::Get(info->iCategory, info->iKey, buffer);
if (r == KErrNone && buffer != data)
r = KErrGeneral;
buffer.Close();
return r;
}
void TestPublishAndSubscribe()
{
RProcess thisProcess;
TUid category = thisProcess.SecureId();
TSecurityPolicy alwaysPass(TSecurityPolicy::EAlwaysPass);
test(RProperty::Define(category, 0, RProperty::EByteArray, alwaysPass, alwaysPass) == KErrNone);
test(RProperty::Define(category, 1, RProperty::ELargeByteArray, alwaysPass, alwaysPass) == KErrNone);
TPtrC8 smallData(SmallBuffer, KSmallPropertySize);
TPtrC8 largeData(SmallBuffer, KLargePropertySize);
RBuf8 buffer;
test(buffer.Create(KLargePropertySize) == KErrNone);
// Set small property from paged data, method 1
test(DPTest::FlushCache() == KErrNone);
test(RProperty::Set(category, 0, smallData) == KErrNone);
test(RProperty::Get(category, 0, buffer) == KErrNone);
test(buffer == smallData);
// Set small property from paged data, method 2
RProperty smallProp;
test(smallProp.Attach(category, 0) == KErrNone);
test(DPTest::FlushCache() == KErrNone);
test(smallProp.Set(smallData) == KErrNone);
test(smallProp.Get(buffer) == KErrNone);
test(buffer == smallData);
// Set large property from paged data, method 1
test(DPTest::FlushCache() == KErrNone);
test(RProperty::Set(category, 1, largeData) == KErrNone);
test(RProperty::Get(category, 1, buffer) == KErrNone);
test(buffer == largeData);
// Set large property from paged data, method 2
RProperty largeProp;
test(largeProp.Attach(category, 1) == KErrNone);
test(DPTest::FlushCache() == KErrNone);
test(largeProp.Set(largeData) == KErrNone);
test(largeProp.Get(buffer) == KErrNone);
test(buffer == largeData);
// Set small property from unmapped address
RThread thread;
#if !defined( __VC32__)
SSetPropertyInfo info = { category, 0, 0, KSmallPropertySize };
#else
SSetPropertyInfo info = { category.iUid, 0, 0, KSmallPropertySize };
#endif
test(thread.Create(_L("SetPropertyThread"), SetPropertyThreadFunction, 4096, NULL, &info) == KErrNone);
thread.Resume();
TRequestStatus status;
thread.Logon(status);
User::WaitForRequest(status);
test(thread.ExitType()==EExitPanic);
test(thread.ExitCategory()==_L("KERN-EXEC"));
test(thread.ExitReason()==ECausedException);
thread.Close();
// Set large property from unmapped address
info.iKey = 1;
info.iLength = KLargePropertySize;
test(thread.Create(_L("SetPropertyThread"), SetPropertyThreadFunction, 4096, NULL, &info) == KErrNone);
thread.Resume();
thread.Logon(status);
User::WaitForRequest(status);
test(thread.ExitType()==EExitPanic);
test(thread.ExitCategory()==_L("KERN-EXEC"));
test(thread.ExitReason()==ECausedException);
thread.Close();
test(RProperty::Delete(category, 0) == KErrNone);
test(RProperty::Delete(category, 1) == KErrNone);
}
void TestWriteToPagedArea()
{
RMemoryTestLdd memoryTest;
test(KErrNone==memoryTest.Open());
TModuleMemoryInfo exeInfo;
test(KErrNone==RProcess().GetMemoryInfo(exeInfo));
test.Printf(_L("test program code is %x+%x"),exeInfo.iCodeBase,exeInfo.iCodeSize);
TUint8* ptr = const_cast<TUint8*>(LargeBuffer);
TUint8* end = ptr + LargeBufferSize;
while(ptr<end)
{
if(ptr>=(TUint8*)_ALIGN_DOWN(exeInfo.iCodeBase,PageSize) && ptr<(TUint8*)_ALIGN_UP(exeInfo.iCodeBase+exeInfo.iCodeSize,PageSize))
{
// avoid testing the ROM which contains this test program
ptr += PageSize;
continue;
}
DPTest::FlushCache();
TInt stateBits = UserSvr::HalFunction(EHalGroupVM, EVMPageState, ptr, 0);
test(stateBits>=0);
// write to paged out memory should cause exception...
test(KErrBadDescriptor==memoryTest.WriteMemory(ptr,0));
// page state should be unchanged...
TInt newStateBits = UserSvr::HalFunction(EHalGroupVM, EVMPageState, ptr, 0);
if(stateBits!=newStateBits)
{
test.Printf(_L("ptr=%x stateBits=%x newStateBits=%x"),ptr,stateBits,newStateBits);
test(0);
}
// page-in in memory...
TUint32 value = *(TUint32*)ptr;
// write to paged out memory should still cause exception...
test(KErrBadDescriptor==memoryTest.WriteMemory(ptr,~value));
// memory should be unchanged...
test(value==*(TUint32*)ptr);
ptr += PageSize;
}
memoryTest.Close();
}
void TestContiguousRamAlloc()
{
test.Start(_L("Start..."));
const TInt KCacheSize = 1024*1024;
DPTest::SetCacheSize(0, KCacheSize); // make sure paging cache is a reasonable size
TInt testData[][2] = /* array of page size (in units of 'half pages') and align values */
{
{64,5},
{64,0},
{32,4},
{32,3},
{32,2},
{32,1},
{32,0},
{4,2},
{4,1},
{4,0},
{2,2},
{2,1},
{2,0},
{1,0},
{0,0}
};
TInt pageShift = 1;
while((1<<pageShift)<PageSize)
++pageShift;
TInt* params = (TInt*)&testData;
while(*params)
{
TInt size = *params++<<(pageShift-1); //Size is units of half pages, so one less shift to get required memory size
TInt align = *params++;
if(align)
align += pageShift - 1;
TBuf<256> title;
title.AppendFormat(_L("Contiguous RAM test: alloc size = %dK align = %d"),size>>10, align);
test.Next(title);
FragmentPagingCache(KCacheSize);
TInt r = Ldd.DoConsumeContiguousRamTest(align, size);
if(r)
{
test.Printf(_L("failed at D_DEMANPAGING.CPP line %d\n"),r);
test(0);
}
}
DPTest::SetCacheSize(0,0); // back to defaults
test.End();
}
void TestReadHoldingMutex()
{
TUint8 localBuf[16];
TUint8* localPtr = localBuf;
if(DPTest::Attributes() & DPTest::EDataPaging) // if data paging supported...
localPtr = 0; // use zero to make driver use kernel memory as data destination
test(Ldd.ReadHoldingMutexTest(localPtr) == KErrNone);
}
#if 0 // rom dump code...
#include <f32file.h>
RFs fs;
RFile file;
test(KErrNone==fs.Connect());
test(KErrNone==file.Replace(fs, _L("d:\\ROMDUMP"),EFileWrite));
TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
TPtrC8 rom((TUint8*)romHeader,romHeader->iRomSize);
test(KErrNone==file.Write(rom));
file.Close();
fs.Close();
return 0;
#endif
class RMySession : public RSessionBase
{
public:
TInt Connect(RServer2 aSrv,TRequestStatus& aStat)
{
TInt r=CreateSession(aSrv,TVersion(),-1,EIpcSession_Sharable,NULL,&aStat);
if(!r) ShareAuto(); return r;
}
TInt Send(TInt function,const TIpcArgs& args)
{return SendReceive(function,args);}
};
TUint8* TestBuffer = 0;
RMySession MySession;
LOCAL_C TInt TestServerThread(TAny* aSize)
{
TInt r = TestServer.CreateGlobal(KNullDesC, EIpcSession_GlobalSharable);
if(r==KErrNone)
{
TestBuffer = (TUint8*)User::Alloc(KMaxIPCSize);
if(!TestBuffer)
r = KErrNoMemory;
}
TPtr8 buffer(TestBuffer,KMaxIPCSize);
RThread::Rendezvous(r);
if (r != KErrNone)
return r;
RMessage2 m;
TestServer.Receive(m);
m.Complete(KErrNone); // connect message
TBool running = ETrue;
while (running)
{
TestServer.Receive(m);
RDebug::Printf("Server received: %d", m.Function());
TInt r = KErrNone;
switch(m.Function())
{
case 0:
// Kill server
running = EFalse;
break;
case 2:
buffer.Set(SharedBuffer,KMaxIPCSize,KMaxIPCSize);
// fall through...
case 1:
// Perform CRC of data passed
{
DPTest::FlushCache();
r=m.Read(0,buffer);
if (r!=KErrNone)
break;
TUint32 crc=0;
Mem::Crc32(crc,buffer.Ptr(),buffer.Size());
r = crc;
}
break;
case 4:
buffer.Set(SharedBuffer,KMaxIPCSize,KMaxIPCSize);
// fall through...
case 3:
// Write data to client descriptor
{
DPTest::FlushCache();
RDebug::Printf("Server writing %08x+%x", m.Int1(), m.Int2());
TPtrC8 ptr((TUint8*)m.Int1(),m.Int2());
r=m.Write(0,ptr);
}
break;
default:
// Just complete anything else
break;
}
m.Complete(r);
}
RDebug::Printf("Server exiting");
User::Free(TestBuffer);
TestBuffer = NULL;
TestServer.Close();
return KErrNone;
}
void TestIPC()
{
__KHEAP_MARK;
const TUint8* start = LargeBuffer + 0x3df; // make range not page aligned
const TUint8* end = start + Min(LargeBufferSize, KMaxIPCSize * 10) - 0x130; // make range not page aligned
const TUint8* pos;
test.Start(_L("Create server"));
RThread t;
TInt r=t.Create(KNullDesC,TestServerThread,0x1000,KMaxIPCSize+0x1000,KMaxIPCSize+0x1000,(void*)0);
test(r==KErrNone);
t.SetPriority(EPriorityMore);
TRequestStatus s;
t.Rendezvous(s);
t.Resume();
User::WaitForRequest(s);
test(TestServer.Handle() != KNullHandle);
test(MySession.Connect(TestServer,s) == KErrNone);
User::WaitForRequest(s); // connected
TInt bufferType; // 0=server uses heap, 1=server uses SharedBuffer
for(bufferType=0; bufferType<=1; ++bufferType)
{
test.Next(_L("IPC read from ROM"));
pos = start;
while(pos<end)
{
TInt size = end-pos;
if(size>KMaxIPCSize)
size = KMaxIPCSize;
RDebug::Printf("read %x+%x",pos,size);
TPtrC8 ptr(pos,size);
TInt r = MySession.Send(1+bufferType,TIpcArgs(&ptr));
DPTest::FlushCache();
TUint32 crc=0;
Mem::Crc32(crc,pos,size);
RDebug::Printf("crc %08x %08x",r,crc);
if((TUint32)r!=crc)
{
RDebug::Printf("FAIL");
DPTest::FlushCache();
TInt count = 0;
for(TInt i=0; i<size; i+=4)
{
TUint32 a = pos[i];
TUint32 b = TestBuffer[i];
if(a!=b)
RDebug::Printf("%08x %02x!=%02x",pos+i,a,b);
if (++count > 100)
break;
}
}
test((TUint32)r==crc);
pos+=size;
}
test.Next(_L("IPC write from ROM"));
pos = start;
while(pos<end)
{
TInt size = end-pos;
if(size>KMaxIPCSize)
size = KMaxIPCSize;
RDebug::Printf("write %x+%x",pos,size);
memclr(TestBuffer, KMaxIPCSize);
TPtr8 ptr(TestBuffer,KMaxIPCSize); // reuse the server's buffer
TInt r = MySession.Send(3+bufferType,TIpcArgs(&ptr,pos,size));
test_KErrNone(r);
DPTest::FlushCache();
TUint32 crc=0;
Mem::Crc32(crc,pos,size);
TUint32 crc2=0;
Mem::Crc32(crc2,TestBuffer,size);
RDebug::Printf("crc %08x %08x",crc,crc2);
if((TUint32)crc!=crc2)
{
RDebug::Printf("FAIL");
DPTest::FlushCache();
TInt count = 0;
for(TInt i=0; i<size; i+=4)
{
TUint32 a = pos[i];
TUint32 b = TestBuffer[i];
if(a!=b)
RDebug::Printf("%08x %02x!=%02x",pos+i,a,b);
if (++count > 100)
break;
}
}
test((TUint32)crc==crc2);
pos+=size;
}
}
if (DPTest::Attributes() & DPTest::ERomPaging)
{
test.Next(_L("Test passing descriptor headers in paged-out memory"));
__KHEAP_MARK;
DPTest::FlushCache();
TInt r = MySession.Send(5,TIpcArgs(PagedHeaderDes));
test_Equal(KErrNone, r);
UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
__KHEAP_MARKEND;
}
test.Next(_L("Stop server"));
MySession.Send(0,TIpcArgs(0));
MySession.Close();
t.Logon(s);
User::WaitForRequest(s);
test_Equal(EExitKill, t.ExitType());
test_Equal(KErrNone, t.ExitReason());
CLOSE_AND_WAIT(t);
test.End();
UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
__KHEAP_MARKEND;
}
TInt E32Main()
{
test.Title();
test_KErrNone(UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&PageSize,0));
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"));
DataPagingSupported = ETrue;
TChunkCreateInfo createInfo;
createInfo.SetNormal(KMinBufferSize, KMinBufferSize);
createInfo.SetPaging(TChunkCreateInfo::EPaged);
createInfo.SetOwner(EOwnerProcess);
createInfo.SetGlobal(KChunkName);
test_KErrNone(DataPagedChunk.Create(createInfo));
test(DataPagedChunk.IsPaged()); // this is only ever called if data paging is supported
DataPagedBuffer = (TUint8*)DataPagedChunk.Base();
}
test.Start(_L("Test HAL interface"));
TestHAL();
if (DPTest::Attributes() & DPTest::ERomPaging)
{
// Use paged part of rom for testing
TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
test(romHeader->iPageableRomStart);
// todo: for some reason the first part of page of paged rom doesn't seem to get paged out
// when we flush the paging cache, hence LargeBuffer starts some way into this
LargeBuffer = (TUint8*)romHeader + romHeader->iPageableRomStart + 64 * PageSize;
LargeBufferSize = romHeader->iPageableRomSize - 64 * PageSize;
test(LargeBufferSize > 0);
// Find a zero word in rom to set PagedHeaderDes to
TUint* ptr = (TUint*)LargeBuffer;
TUint* end = (TUint*)(LargeBuffer + LargeBufferSize);
while (*ptr && ptr < end)
++ptr;
test(*ptr == 0);
test.Printf(_L("Found zero word at %08x\n"), ptr);
PagedHeaderDes = (TDesC8*)ptr;
}
else if (DPTest::Attributes() & DPTest::ECodePaging)
{
// Use code paged DLL for testing
test_KErrNone(PagedLibrary.Load(KTCodePagingDll4));
TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)PagedLibrary.Lookup(KGetAddressOfDataFunctionOrdinal);
LargeBuffer = (TUint8*)func(LargeBufferSize);
test_NotNull(LargeBuffer);
PagedHeaderDes = (TDesC8*)LargeBuffer + 4;
}
else if (DPTest::Attributes() & DPTest::EDataPaging)
{
// Use data paged chunk for testing
LargeBuffer = DataPagedBuffer;
LargeBufferSize = KMinBufferSize;
}
else
{
test.Printf(_L("Demand Paging not supported\n"));
test.End();
return 0;
}
test(LargeBufferSize >= KMinBufferSize);
SmallBuffer = LargeBuffer;
SmallBufferSize = KMinBufferSize;
test.Next(_L("Loading test drivers"));
TInt r = User::LoadLogicalDevice(KDemandPagingTestLddName);
test(r==KErrNone || r==KErrAlreadyExists);
test(Ldd.Open()==KErrNone);
test_KErrNone(Ldd.CreatePlatHwChunk(SharedBufferSize, SharedBufferAddr));
SharedBuffer = (TUint8*)SharedBufferAddr;
RDebug::Printf("SmallBuffer=%x, LargeBuffer=%x, SharedBuffer=%x\n",
SmallBuffer, LargeBuffer, SharedBuffer);
test.Next(_L("Gobble RAM"));
r = User::LoadLogicalDevice(KGobblerLddFileName);
test(r==KErrNone || r==KErrAlreadyExists);
RGobbler gobbler;
r = gobbler.Open();
test(r==KErrNone);
TUint32 taken = gobbler.GobbleRAM(64*1024*1024); // leave 64MB of free RAM
test.Printf(_L("Gobbled: %dK\n"), taken/1024);
test.Printf(_L("Free RAM 0x%08X bytes\n"),FreeRam());
test.Next(_L("Test contiguous RAM allocation reclaims paged memory"));
TestContiguousRamAlloc();
test.Next(_L("Test thread realtime state"));
TestRealtimeState();
test.Next(_L("Lock Test"));
TestLock();
test.Next(_L("Test writing to paged area"));
TestWriteToPagedArea();
test.Next(_L("Test IPC read from paged memory"));
TestIPC();
test.Next(_L("Test no kernel faults when copying data from unpaged rom with mutex held"));
TestReadHoldingMutex();
test.Next(_L("Close test driver"));
Ldd.DestroyPlatHwChunk();
Ldd.Close();
test.Next(_L("Test setting publish and subscribe properties from paged area"));
TestPublishAndSubscribe();
if (DPTest::Attributes() & DPTest::ERomPaging)
{
test.Next(_L("Rom Paging Benchmark"));
RomPagingBenchmark();
}
PagedLibrary.Close();
gobbler.Close();
test.End();
return 0;
}