Convert Kernelhwsrv package from SFL to EPL
kernel\eka\compsupp is subject to the ARM EABI LICENSE
userlibandfileserver\fatfilenameconversionplugins\unicodeTables is subject to the Unicode license
kernel\eka\kernel\zlib is subject to the zlib license
// Copyright (c) 1995-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_imb.cpp
// Overview:
// Test the RChunk Create Local Code and Instruction Memory Barrier
// control interface.
// API Information:
// RChunk::CreateLocalCode & User::IMB_Range
// Details:
// - Create a code chunk, write a small test function to the chunk, use
// User::IMB_Range to prepare the virtual address range for code execution.
// - Verify the success and failure of the IMB with various processes and with
// different base and size values.
// Platforms/Drives/Compatibility:
// All.
// Assumptions/Requirement/Pre-requisites:
// Failures and causes:
// Base Port information:
//
//
#include <e32test.h>
#include "u32std.h"
#include <e32math.h>
#ifdef __CPU_ARM
typedef TInt (*TSqrtFn)(TReal&, const TReal&);
extern TInt Sqrt(TReal& /*aDest*/, const TReal& /*aSrc*/);
extern TUint Sqrt_Length();
typedef TInt (*TDivideFn)(TRealX&, const TRealX&);
extern TInt Divide(TRealX& /*aDividend*/, const TRealX& /*aDivisor*/);
extern TUint Divide_Length();
extern TInt SDummy(TInt);
extern TUint SDummy_Length();
extern TInt Increment(TInt);
extern TUint Increment_Length();
typedef TInt (*PFI)(TInt);
class RTestHeap : public RHeap
{
public:
TUint8* GetTop() {return iTop;}
};
TInt Thread2(TAny* aPtr)
{
TSqrtFn pSqrt=(TSqrtFn)aPtr;
TReal x,y;
x=2.0;
return pSqrt(y,x);
}
TInt Thread3(TAny* aPtr)
{
return *(TInt*)aPtr;
}
TInt Thread4(TAny* aPtr)
{
*(TInt*)aPtr=0xe7ffffff;
return 0;
}
void SecondaryProcess(const TDesC& aCmd, RTest& test)
{
test.Start(_L("Secondary Process"));
TLex lex(aCmd);
TUint32 addr;
TInt r=lex.Val(addr,EHex);
test(r==KErrNone);
test.Printf(_L("Main process RAM code at %08x\n"),addr);
TInt n=0;
FOREVER
{
RThread t;
TRequestStatus s;
if (n==0)
{
// Create another thread which attempts to execute code from the other process
r=t.Create(_L("Thread2"),Thread2,0x1000,NULL,(TAny*)addr);
}
else if (n==1)
{
// Create another thread which attempts to read code from the other process
r=t.Create(_L("Thread3"),Thread3,0x1000,NULL,(TAny*)addr);
}
else if (n==2)
{
// Create another thread which attempts to write to the the other process' code
r=t.Create(_L("Thread4"),Thread4,0x1000,NULL,(TAny*)addr);
}
test(r==KErrNone);
t.SetPriority(EPriorityMore);
t.Logon(s);
t.Resume();
User::WaitForRequest(s);
TInt exitType=t.ExitType();
TInt exitReason=t.ExitReason();
TBuf<32> exitCat=t.ExitCategory();
CLOSE_AND_WAIT(t);
test(exitType==EExitPanic);
test(exitReason==ECausedException);
test(exitCat==_L("KERN-EXEC"));
if (++n==3)
n=0;
User::After(0);//Force rescheduling of the primary process's thread.
}
}
void Fill32(TUint32* aBase, TUint aSize, TUint32 aValue)
{
for (; aSize; aSize-=4)
*aBase++=aValue;
}
void TestIMB(RTest& test, TUint32* aBase, TUint aOffset, TUint aSize)
{
test.Printf(_L("TestIMB: Base %08x Offset %x Size %x\n"),aBase,aOffset,aSize);
// First fill entire area
Fill32(aBase,0x20000,0xe3a00000); // mov r0, #0
#ifdef __SUPPORT_THUMB_INTERWORKING
aBase[0x8000]=0xe12fff1e; // bx lr
#else
aBase[0x8000]=0xe1a0f00e; // mov pc, lr
#endif
PFI pBase=(PFI)aBase;
PFI pCode=(PFI)((TUint8*)aBase+aOffset);
User::IMB_Range(aBase,aBase+0x8001);
TInt r=pBase(0);
test(r==0);
TUint32* p32=(TUint32*)pCode;
TUint32* pEnd32=p32+aSize/4;
Fill32(p32,aSize-4,0xe2800001); // add r0, r0, #1
#ifdef __SUPPORT_THUMB_INTERWORKING
pEnd32[-1]=0xe12fff1e; // bx lr
#else
pEnd32[-1]=0xe1a0f00e; // mov pc, lr
#endif
User::IMB_Range(p32,pEnd32);
r=pCode(0);
if (r!=(TInt)(aSize/4-1))
{
test.Printf(_L("f(0) expected %d got %d\n"),aSize/4-1,r);
test(0);
}
r=pCode(487);
if (r!=(TInt)(487+aSize/4-1))
{
test.Printf(_L("f(487) expected %d got %d\n"),487+aSize/4-1,r);
test(0);
}
}
GLREF_C TInt E32Main()
{
RTest test(_L("T_IMB"));
test.Title();
TBuf<16> cmd;
User::CommandLine(cmd);
if (cmd.Length()!=0)
{
SecondaryProcess(cmd,test);
return 0;
}
test.Start(_L("Create code chunk"));
TInt pageSize;
TInt r=UserHal::PageSizeInBytes(pageSize);
test(r==KErrNone);
RChunk c;
r=c.CreateLocalCode(pageSize,0x100000);
test(r==KErrNone);
TUint8* pCode=c.Base();
test.Printf(_L("Code chunk at %08x\n"),pCode);
// Copy increment function
Mem::Copy(pCode, (const TAny*)&Increment, Increment_Length());
User::IMB_Range(pCode,pCode+Increment_Length());
PFI pFI=(PFI)pCode;
r=pFI(29);
test(r==30);
// Copy dummy without IMB
Mem::Copy(pCode, (const TAny*)&SDummy, SDummy_Length());
r=pFI(29);
test.Printf(_L("Copy without IMB 1: r=%d\n"),r);
// Now do IMB
User::IMB_Range(pCode,pCode+SDummy_Length());
r=pFI(29);
test(r==29);
// Read the code so it's in DCache
TInt i;
TInt sum=0;
for (i=0; i<15; ++i)
sum+=pCode[i];
// Copy increment function
Mem::Copy(pCode, (const TAny*)&Increment, Increment_Length());
r=pFI(29);
test.Printf(_L("Copy without IMB 2: r=%d\n"),r);
// Now do IMB
User::IMB_Range(pCode,pCode+Increment_Length());
r=pFI(29);
test(r==30);
// Now adjust to 2 pages
r=c.Adjust(2*pageSize);
test(r==KErrNone);
TUint8* pCode2=pCode+pageSize;
// Create another thread
RThread t;
TRequestStatus s;
r=t.Create(_L("Thread2"),Thread2,0x1000,NULL,pCode2);
test(r==KErrNone);
t.SetPriority(EPriorityMore);
t.Logon(s);
// Copy Sqrt code to 2nd page
Mem::Copy(pCode2, (const TAny*)&Sqrt, Sqrt_Length());
User::IMB_Range(pCode2,pCode2+Sqrt_Length());
TSqrtFn pSqrt=(TSqrtFn)pCode2;
TReal x,y,z;
x=2.0;
r=Math::Sqrt(y,x);
test(r==KErrNone);
r=pSqrt(z,x);
test(r==KErrNone);
test(z==y);
// Unmap the second page
r=c.Adjust(pageSize);
test(r==KErrNone);
// Get the second thread to attempt to execute the unmapped code
t.Resume();
User::WaitForRequest(s);
TInt exitType=t.ExitType();
TInt exitReason=t.ExitReason();
TBuf<32> exitCat=t.ExitCategory();
CLOSE_AND_WAIT(t);
test.Printf(_L("Thread2: %d,%d,%S\n"),exitType,exitReason,&exitCat);
test(exitType==EExitPanic);
test(exitReason==ECausedException);
test(exitCat==_L("KERN-EXEC"));
// Copy Sqrt code to 1st page
Mem::Copy(pCode, (const TAny*)&Sqrt, Sqrt_Length());
User::IMB_Range(pCode,pCode+Sqrt_Length());
pSqrt=(TSqrtFn)pCode;
// Do a long test to allow multiple copies of this process to run concurrently
// Spawn a secondary process
RProcess p;
TBuf<16> codeBaseHex;
codeBaseHex.Format(_L("%08x"),pCode);
r=p.Create(RProcess().FileName(),codeBaseHex);
test(r==KErrNone);
p.Logon(s);
p.Resume();
TTime begin;
begin.HomeTime();
i=1;
for (;;)
{
TReal x,y,z;
x=i;
r=Math::Sqrt(y,x);
test(r==KErrNone);
r=pSqrt(z,x);
test(r==KErrNone);
test(z==y);
++i;
TTime now;
now.HomeTime();
if (now.MicroSecondsFrom(begin).Int64()>10000000)
break;
User::After(0);//Force rescheduling of the secondary process's thread
}
p.Kill(0);
User::WaitForRequest(s);
exitType=p.ExitType();
exitReason=p.ExitReason();
exitCat=p.ExitCategory();
CLOSE_AND_WAIT(p);
test.Printf(_L("SecProc: %d,%d,%S\n"),exitType,exitReason,&exitCat);
test(exitType==EExitKill);
test(exitReason==KErrNone);
// Test heap in code chunk
RTestHeap* pCodeHeap=(RTestHeap*) UserHeap::ChunkHeap(c,pageSize,pageSize);
test(pCodeHeap==(RHeap*)c.Base());
test(c.Size()==pageSize);
TUint32* pCode3=(TUint32*)pCodeHeap->Alloc(pageSize);
test(pCode3!=NULL);
test(c.Size()==2*pageSize);
TAny* pCode4=pCodeHeap->Alloc(3*pageSize);
test(pCode4!=NULL);
test(c.Size()==5*pageSize);
pCodeHeap->Free(pCode4);
test(c.Size()==2*pageSize);
TUint8 * oldTop = pCodeHeap->GetTop();
pCodeHeap->Free(pCode3);
TUint8 * newTop = pCodeHeap->GetTop();
// Under some conditions (KHeapShrinkRatio value is low and iGrowBy is at its default value of a page size)
// heap may be reduced at the end of Free() operation
if (oldTop==newTop) // heap was not reduced
test(c.Size()==2*pageSize);
// Test IMB with various base/size values
pCode3=(TUint32*)pCodeHeap->Alloc(0x20004);
test(pCode3!=NULL);
for (i=8; i<1024; i+=32)
{
TestIMB(test,pCode3,0,i);
TestIMB(test,pCode3,4,i);
}
for (i=1024; i<131072; i+=844)
{
TestIMB(test,pCode3,0,i);
TestIMB(test,pCode3,4,i);
}
c.Close();
test.End();
return 0;
}
#else
GLREF_C TInt E32Main()
{
return 0;
}
#endif