1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/mmu/t_imb.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,358 @@
1.4 +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\mmu\t_imb.cpp
1.18 +// Overview:
1.19 +// Test the RChunk Create Local Code and Instruction Memory Barrier
1.20 +// control interface.
1.21 +// API Information:
1.22 +// RChunk::CreateLocalCode & User::IMB_Range
1.23 +// Details:
1.24 +// - Create a code chunk, write a small test function to the chunk, use
1.25 +// User::IMB_Range to prepare the virtual address range for code execution.
1.26 +// - Verify the success and failure of the IMB with various processes and with
1.27 +// different base and size values.
1.28 +// Platforms/Drives/Compatibility:
1.29 +// All.
1.30 +// Assumptions/Requirement/Pre-requisites:
1.31 +// Failures and causes:
1.32 +// Base Port information:
1.33 +//
1.34 +//
1.35 +
1.36 +#include <e32test.h>
1.37 +#include "u32std.h"
1.38 +#include <e32math.h>
1.39 +
1.40 +#ifdef __CPU_ARM
1.41 +typedef TInt (*TSqrtFn)(TReal&, const TReal&);
1.42 +extern TInt Sqrt(TReal& /*aDest*/, const TReal& /*aSrc*/);
1.43 +extern TUint Sqrt_Length();
1.44 +
1.45 +typedef TInt (*TDivideFn)(TRealX&, const TRealX&);
1.46 +extern TInt Divide(TRealX& /*aDividend*/, const TRealX& /*aDivisor*/);
1.47 +extern TUint Divide_Length();
1.48 +
1.49 +extern TInt SDummy(TInt);
1.50 +extern TUint SDummy_Length();
1.51 +
1.52 +extern TInt Increment(TInt);
1.53 +extern TUint Increment_Length();
1.54 +
1.55 +typedef TInt (*PFI)(TInt);
1.56 +
1.57 +class RTestHeap : public RHeap
1.58 + {
1.59 +public:
1.60 + TUint8* GetTop() {return iTop;}
1.61 + };
1.62 +
1.63 +TInt Thread2(TAny* aPtr)
1.64 + {
1.65 + TSqrtFn pSqrt=(TSqrtFn)aPtr;
1.66 + TReal x,y;
1.67 + x=2.0;
1.68 + return pSqrt(y,x);
1.69 + }
1.70 +
1.71 +TInt Thread3(TAny* aPtr)
1.72 + {
1.73 + return *(TInt*)aPtr;
1.74 + }
1.75 +
1.76 +TInt Thread4(TAny* aPtr)
1.77 + {
1.78 + *(TInt*)aPtr=0xe7ffffff;
1.79 + return 0;
1.80 + }
1.81 +
1.82 +void SecondaryProcess(const TDesC& aCmd, RTest& test)
1.83 + {
1.84 + test.Start(_L("Secondary Process"));
1.85 + TLex lex(aCmd);
1.86 + TUint32 addr;
1.87 + TInt r=lex.Val(addr,EHex);
1.88 + test(r==KErrNone);
1.89 + test.Printf(_L("Main process RAM code at %08x\n"),addr);
1.90 + TInt n=0;
1.91 + FOREVER
1.92 + {
1.93 + RThread t;
1.94 + TRequestStatus s;
1.95 + if (n==0)
1.96 + {
1.97 + // Create another thread which attempts to execute code from the other process
1.98 + r=t.Create(_L("Thread2"),Thread2,0x1000,NULL,(TAny*)addr);
1.99 + }
1.100 + else if (n==1)
1.101 + {
1.102 + // Create another thread which attempts to read code from the other process
1.103 + r=t.Create(_L("Thread3"),Thread3,0x1000,NULL,(TAny*)addr);
1.104 + }
1.105 + else if (n==2)
1.106 + {
1.107 + // Create another thread which attempts to write to the the other process' code
1.108 + r=t.Create(_L("Thread4"),Thread4,0x1000,NULL,(TAny*)addr);
1.109 + }
1.110 + test(r==KErrNone);
1.111 + t.SetPriority(EPriorityMore);
1.112 + t.Logon(s);
1.113 + t.Resume();
1.114 + User::WaitForRequest(s);
1.115 + TInt exitType=t.ExitType();
1.116 + TInt exitReason=t.ExitReason();
1.117 + TBuf<32> exitCat=t.ExitCategory();
1.118 + CLOSE_AND_WAIT(t);
1.119 + test(exitType==EExitPanic);
1.120 + test(exitReason==ECausedException);
1.121 + test(exitCat==_L("KERN-EXEC"));
1.122 + if (++n==3)
1.123 + n=0;
1.124 + User::After(0);//Force rescheduling of the primary process's thread.
1.125 + }
1.126 + }
1.127 +
1.128 +void Fill32(TUint32* aBase, TUint aSize, TUint32 aValue)
1.129 + {
1.130 + for (; aSize; aSize-=4)
1.131 + *aBase++=aValue;
1.132 + }
1.133 +
1.134 +void TestIMB(RTest& test, TUint32* aBase, TUint aOffset, TUint aSize)
1.135 + {
1.136 + test.Printf(_L("TestIMB: Base %08x Offset %x Size %x\n"),aBase,aOffset,aSize);
1.137 + // First fill entire area
1.138 + Fill32(aBase,0x20000,0xe3a00000); // mov r0, #0
1.139 +#ifdef __SUPPORT_THUMB_INTERWORKING
1.140 + aBase[0x8000]=0xe12fff1e; // bx lr
1.141 +#else
1.142 + aBase[0x8000]=0xe1a0f00e; // mov pc, lr
1.143 +#endif
1.144 + PFI pBase=(PFI)aBase;
1.145 + PFI pCode=(PFI)((TUint8*)aBase+aOffset);
1.146 + User::IMB_Range(aBase,aBase+0x8001);
1.147 + TInt r=pBase(0);
1.148 + test(r==0);
1.149 +
1.150 + TUint32* p32=(TUint32*)pCode;
1.151 + TUint32* pEnd32=p32+aSize/4;
1.152 + Fill32(p32,aSize-4,0xe2800001); // add r0, r0, #1
1.153 +#ifdef __SUPPORT_THUMB_INTERWORKING
1.154 + pEnd32[-1]=0xe12fff1e; // bx lr
1.155 +#else
1.156 + pEnd32[-1]=0xe1a0f00e; // mov pc, lr
1.157 +#endif
1.158 + User::IMB_Range(p32,pEnd32);
1.159 + r=pCode(0);
1.160 + if (r!=(TInt)(aSize/4-1))
1.161 + {
1.162 + test.Printf(_L("f(0) expected %d got %d\n"),aSize/4-1,r);
1.163 + test(0);
1.164 + }
1.165 + r=pCode(487);
1.166 + if (r!=(TInt)(487+aSize/4-1))
1.167 + {
1.168 + test.Printf(_L("f(487) expected %d got %d\n"),487+aSize/4-1,r);
1.169 + test(0);
1.170 + }
1.171 + }
1.172 +
1.173 +GLREF_C TInt E32Main()
1.174 + {
1.175 + RTest test(_L("T_IMB"));
1.176 + test.Title();
1.177 +
1.178 + TBuf<16> cmd;
1.179 + User::CommandLine(cmd);
1.180 + if (cmd.Length()!=0)
1.181 + {
1.182 + SecondaryProcess(cmd,test);
1.183 + return 0;
1.184 + }
1.185 +
1.186 + test.Start(_L("Create code chunk"));
1.187 + TInt pageSize;
1.188 + TInt r=UserHal::PageSizeInBytes(pageSize);
1.189 + test(r==KErrNone);
1.190 +
1.191 + RChunk c;
1.192 + r=c.CreateLocalCode(pageSize,0x100000);
1.193 + test(r==KErrNone);
1.194 + TUint8* pCode=c.Base();
1.195 + test.Printf(_L("Code chunk at %08x\n"),pCode);
1.196 +
1.197 + // Copy increment function
1.198 + Mem::Copy(pCode, (const TAny*)&Increment, Increment_Length());
1.199 + User::IMB_Range(pCode,pCode+Increment_Length());
1.200 + PFI pFI=(PFI)pCode;
1.201 + r=pFI(29);
1.202 + test(r==30);
1.203 +
1.204 + // Copy dummy without IMB
1.205 + Mem::Copy(pCode, (const TAny*)&SDummy, SDummy_Length());
1.206 + r=pFI(29);
1.207 + test.Printf(_L("Copy without IMB 1: r=%d\n"),r);
1.208 +
1.209 + // Now do IMB
1.210 + User::IMB_Range(pCode,pCode+SDummy_Length());
1.211 + r=pFI(29);
1.212 + test(r==29);
1.213 +
1.214 + // Read the code so it's in DCache
1.215 + TInt i;
1.216 + TInt sum=0;
1.217 + for (i=0; i<15; ++i)
1.218 + sum+=pCode[i];
1.219 +
1.220 + // Copy increment function
1.221 + Mem::Copy(pCode, (const TAny*)&Increment, Increment_Length());
1.222 + r=pFI(29);
1.223 + test.Printf(_L("Copy without IMB 2: r=%d\n"),r);
1.224 +
1.225 + // Now do IMB
1.226 + User::IMB_Range(pCode,pCode+Increment_Length());
1.227 + r=pFI(29);
1.228 + test(r==30);
1.229 +
1.230 + // Now adjust to 2 pages
1.231 + r=c.Adjust(2*pageSize);
1.232 + test(r==KErrNone);
1.233 + TUint8* pCode2=pCode+pageSize;
1.234 +
1.235 + // Create another thread
1.236 + RThread t;
1.237 + TRequestStatus s;
1.238 + r=t.Create(_L("Thread2"),Thread2,0x1000,NULL,pCode2);
1.239 + test(r==KErrNone);
1.240 + t.SetPriority(EPriorityMore);
1.241 + t.Logon(s);
1.242 +
1.243 + // Copy Sqrt code to 2nd page
1.244 + Mem::Copy(pCode2, (const TAny*)&Sqrt, Sqrt_Length());
1.245 + User::IMB_Range(pCode2,pCode2+Sqrt_Length());
1.246 + TSqrtFn pSqrt=(TSqrtFn)pCode2;
1.247 + TReal x,y,z;
1.248 + x=2.0;
1.249 + r=Math::Sqrt(y,x);
1.250 + test(r==KErrNone);
1.251 + r=pSqrt(z,x);
1.252 + test(r==KErrNone);
1.253 + test(z==y);
1.254 +
1.255 + // Unmap the second page
1.256 + r=c.Adjust(pageSize);
1.257 + test(r==KErrNone);
1.258 +
1.259 + // Get the second thread to attempt to execute the unmapped code
1.260 + t.Resume();
1.261 + User::WaitForRequest(s);
1.262 + TInt exitType=t.ExitType();
1.263 + TInt exitReason=t.ExitReason();
1.264 + TBuf<32> exitCat=t.ExitCategory();
1.265 + CLOSE_AND_WAIT(t);
1.266 + test.Printf(_L("Thread2: %d,%d,%S\n"),exitType,exitReason,&exitCat);
1.267 + test(exitType==EExitPanic);
1.268 + test(exitReason==ECausedException);
1.269 + test(exitCat==_L("KERN-EXEC"));
1.270 +
1.271 + // Copy Sqrt code to 1st page
1.272 + Mem::Copy(pCode, (const TAny*)&Sqrt, Sqrt_Length());
1.273 + User::IMB_Range(pCode,pCode+Sqrt_Length());
1.274 + pSqrt=(TSqrtFn)pCode;
1.275 +
1.276 + // Do a long test to allow multiple copies of this process to run concurrently
1.277 + // Spawn a secondary process
1.278 + RProcess p;
1.279 + TBuf<16> codeBaseHex;
1.280 + codeBaseHex.Format(_L("%08x"),pCode);
1.281 + r=p.Create(RProcess().FileName(),codeBaseHex);
1.282 + test(r==KErrNone);
1.283 + p.Logon(s);
1.284 + p.Resume();
1.285 +
1.286 + TTime begin;
1.287 + begin.HomeTime();
1.288 + i=1;
1.289 + for (;;)
1.290 + {
1.291 + TReal x,y,z;
1.292 + x=i;
1.293 + r=Math::Sqrt(y,x);
1.294 + test(r==KErrNone);
1.295 + r=pSqrt(z,x);
1.296 + test(r==KErrNone);
1.297 + test(z==y);
1.298 + ++i;
1.299 + TTime now;
1.300 + now.HomeTime();
1.301 + if (now.MicroSecondsFrom(begin).Int64()>10000000)
1.302 + break;
1.303 + User::After(0);//Force rescheduling of the secondary process's thread
1.304 + }
1.305 + p.Kill(0);
1.306 + User::WaitForRequest(s);
1.307 + exitType=p.ExitType();
1.308 + exitReason=p.ExitReason();
1.309 + exitCat=p.ExitCategory();
1.310 + CLOSE_AND_WAIT(p);
1.311 + test.Printf(_L("SecProc: %d,%d,%S\n"),exitType,exitReason,&exitCat);
1.312 + test(exitType==EExitKill);
1.313 + test(exitReason==KErrNone);
1.314 +
1.315 + // Test heap in code chunk
1.316 + RTestHeap* pCodeHeap=(RTestHeap*) UserHeap::ChunkHeap(c,pageSize,pageSize);
1.317 + test(pCodeHeap==(RHeap*)c.Base());
1.318 + test(c.Size()==pageSize);
1.319 + TUint32* pCode3=(TUint32*)pCodeHeap->Alloc(pageSize);
1.320 + test(pCode3!=NULL);
1.321 + test(c.Size()==2*pageSize);
1.322 + TAny* pCode4=pCodeHeap->Alloc(3*pageSize);
1.323 + test(pCode4!=NULL);
1.324 + test(c.Size()==5*pageSize);
1.325 + pCodeHeap->Free(pCode4);
1.326 + test(c.Size()==2*pageSize);
1.327 + TUint8 * oldTop = pCodeHeap->GetTop();
1.328 + pCodeHeap->Free(pCode3);
1.329 + TUint8 * newTop = pCodeHeap->GetTop();
1.330 + // Under some conditions (KHeapShrinkRatio value is low and iGrowBy is at its default value of a page size)
1.331 + // heap may be reduced at the end of Free() operation
1.332 + if (oldTop==newTop) // heap was not reduced
1.333 + test(c.Size()==2*pageSize);
1.334 +
1.335 + // Test IMB with various base/size values
1.336 + pCode3=(TUint32*)pCodeHeap->Alloc(0x20004);
1.337 + test(pCode3!=NULL);
1.338 +
1.339 + for (i=8; i<1024; i+=32)
1.340 + {
1.341 + TestIMB(test,pCode3,0,i);
1.342 + TestIMB(test,pCode3,4,i);
1.343 + }
1.344 +
1.345 + for (i=1024; i<131072; i+=844)
1.346 + {
1.347 + TestIMB(test,pCode3,0,i);
1.348 + TestIMB(test,pCode3,4,i);
1.349 + }
1.350 +
1.351 + c.Close();
1.352 +
1.353 + test.End();
1.354 + return 0;
1.355 + }
1.356 +#else
1.357 +GLREF_C TInt E32Main()
1.358 + {
1.359 + return 0;
1.360 + }
1.361 +#endif