kerneltest/e32test/defrag/t_pagemove.cpp
changeset 0 a41df078684a
child 31 56f325a607ea
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\defrag\t_pagemove.cpp
       
    15 
       
    16 //
       
    17 //--------------------------------------------------------------------------------------------------
       
    18 //! @SYMTestCaseID			KBASE-T_PAGEMOVE-0572
       
    19 //! @SYMTestType			UT
       
    20 //! @SYMPREQ				PREQ308
       
    21 //! @SYMTestCaseDesc		Test physical page moving
       
    22 //!							t_pagemove loads and opens the logical device driver ("D_PAGEMOVE.LDD"). 
       
    23 //!							Following this, it requests that the driver attempt to move  
       
    24 //!							various kinds of pages directly. 
       
    25 //!
       
    26 //!							API Information:
       
    27 //!								RBusLogicalChannel
       
    28 //!
       
    29 //!							Platforms/Drives/Compatibility:
       
    30 //!								Hardware only. No defrag support on emulator. 
       
    31 //!
       
    32 //! @SYMTestActions			1  -  Move regular local data pages
       
    33 //! 						2  -  Move regular global data pages
       
    34 //! 						3  -  Move DLL writable static data pages
       
    35 //! 						4  -  Move user self-modifying code chunk pages
       
    36 //! 						5  -  Move RAM drive pages
       
    37 //!							6  -  Move kernel heap pages (*********DISABLED************)
       
    38 //! 						7  -  Move kernel stack pages
       
    39 //! 						8  -  Move kernel code pages
       
    40 //! 						9  -  Move regular code pages
       
    41 //! 						10 -  Move code whilst the page is being modified
       
    42 //! 						11 -  Move code (async) whilst the page is being modified
       
    43 //! 						12 -  Move ROM locale DLL pages
       
    44 //! 						13 -  Move RAM locale DLL pages
       
    45 //! 						14 -  Moving pages whilst they are being virtually pinned and unpinned.
       
    46 //! 						15 -  Moving pages whilst they are being physically pinned and unpinned.
       
    47 //! @SYMTestExpectedResults All tests should pass.
       
    48 //! @SYMTestPriority        High
       
    49 //! @SYMTestStatus          Implemented
       
    50 //--------------------------------------------------------------------------------------------------
       
    51 //
       
    52 #define __E32TEST_EXTENSION__
       
    53 #include <e32test.h>
       
    54 #include <e32math.h>
       
    55 #include <e32uid.h>
       
    56 #include <e32hal.h>
       
    57 #include <e32std.h>
       
    58 #include <e32std_private.h>
       
    59 #include <dptest.h>
       
    60 #include "d_pagemove.h"
       
    61 #include "t_pagemove_dll.h"
       
    62 #include "t_pmwsd.h"
       
    63 #include "..\mmu\mmudetect.h"
       
    64 #include "..\debug\d_codemodifier.h"
       
    65 #include "..\mmu\d_memorytest.h"
       
    66 
       
    67 //#define _DEBUG_MSG
       
    68 #ifdef _DEBUG_MSG
       
    69 #define _R_PRINTF(x) 	RDebug::Printf(x)
       
    70 #define _T_PRINTF(x)	test.Printf(x)
       
    71 #else
       
    72 #define _R_PRINTF(x)
       
    73 #define _T_PRINTF(x)
       
    74 #endif
       
    75 
       
    76 LOCAL_D RTest test(_L("T_PAGEMOVE"));
       
    77 
       
    78 _LIT(ELOCL_DEFAULT, "");
       
    79 _LIT(ELOCLUS, "T_LOCLUS_RAM");
       
    80 _LIT(ELOCLUS_ROM, "T_LOCLUS");
       
    81 LOCAL_C TInt E32TestLocale(TInt);
       
    82 
       
    83 RCodeModifierDevice Device;
       
    84 extern TInt TestCodeModFunc();
       
    85 
       
    86 extern TInt Increment(TInt);
       
    87 extern TUint Increment_Length();
       
    88 extern TInt Decrement(TInt);
       
    89 extern TUint Decrement_Length();
       
    90 typedef TInt (*PFI)(TInt);
       
    91 
       
    92 LOCAL_C void StartCodeModifierDriver();
       
    93 LOCAL_C void StopCodeModifierDriver();
       
    94 LOCAL_C TInt TestCodeModification(RPageMove &);
       
    95 LOCAL_C TInt TestCodeModificationAsync(RPageMove& pagemove);
       
    96 
       
    97 
       
    98 const TPtrC KLddFileName=_L("D_PAGEMOVE.LDD");
       
    99 TInt Repitions=4000;
       
   100 
       
   101 TInt PageSize;
       
   102 TUint NumberOfCpus;
       
   103 
       
   104 volatile TBool ThreadDie;
       
   105 
       
   106 TBool gDataPagingSupported;
       
   107 TBool gRomPagingSupported;
       
   108 TBool gCodePagingSupported;
       
   109 TBool gPinningSupported;
       
   110 
       
   111 // This executable is ram loaded (see mmp file) so this function will do fine
       
   112 // as a test of RAM-loaded code.
       
   113 TInt RamLoadedFunction()
       
   114 	{
       
   115 	return KArbitraryNumber;
       
   116 	}
       
   117 
       
   118 struct SPinThreadArgs
       
   119 	{
       
   120 	TLinAddr iLinAddr;
       
   121 	TTestFunction iTestFunc;
       
   122 	RThread iParentThread;
       
   123 	User::TRealtimeState iRealtimeState;
       
   124 	};
       
   125 
       
   126 
       
   127 void StartThreads(	TUint aNumThreads, RThread* aThreads, TRequestStatus* aStatus, 
       
   128 					TThreadFunction aThreadFunc, SPinThreadArgs& aThreadArgs)
       
   129 	{
       
   130 	for (TUint i = 0; i < aNumThreads; i++)
       
   131 		{
       
   132 		test_KErrNone(aThreads[i].Create(KNullDesC, aThreadFunc, KDefaultStackSize, NULL, &aThreadArgs));
       
   133 		aThreads[i].Logon(aStatus[i]);
       
   134 		TRequestStatus threadInitialised;
       
   135 		aThreads[i].Rendezvous(threadInitialised);
       
   136 		aThreads[i].Resume();
       
   137 		_T_PRINTF(_L("wait for child\n"));
       
   138 		User::WaitForRequest(threadInitialised);
       
   139 		test_KErrNone(threadInitialised.Int());
       
   140 		}
       
   141 	}
       
   142 
       
   143 void EndThreads(TUint aNumThreads, RThread* aThreads, TRequestStatus* aStatus)
       
   144 	{
       
   145 	for (TUint i = 0; i < aNumThreads; i++)
       
   146 		{
       
   147 		User::WaitForRequest(aStatus[i]);
       
   148 		test_Equal(EExitKill, aThreads[i].ExitType());
       
   149 		test_KErrNone(aThreads[i].ExitReason());
       
   150 		aThreads[i].Close();
       
   151 		}
       
   152 	}
       
   153 
       
   154 
       
   155 void Reschedule(TInt64& aSeed)
       
   156 	{
       
   157 	if (NumberOfCpus == 1)
       
   158 		{
       
   159 		TInt rand = Math::Rand(aSeed);
       
   160 		if ((rand & 0x5) == 5)
       
   161 			User::AfterHighRes(rand & 0x7);
       
   162 		}
       
   163 	}
       
   164 
       
   165 TInt ReadWriteByte(TAny* aParam)
       
   166 	{
       
   167 	SPinThreadArgs* args = (SPinThreadArgs*)aParam;
       
   168 	volatile TUint8* byte = (volatile TUint8*)args->iLinAddr;
       
   169 	TInt64 seed = Math::Random()*Math::Random();
       
   170 
       
   171 	test_KErrNone(User::SetRealtimeState(args->iRealtimeState));
       
   172 
       
   173 	// Ensure the the parentThread has moved the page at least once
       
   174 	// before we start accessing it.
       
   175 	TRequestStatus status;
       
   176 	args->iParentThread.Rendezvous(status);
       
   177 	RThread::Rendezvous(KErrNone);
       
   178 	_R_PRINTF("wait for parent");
       
   179 	User::WaitForRequest(status);
       
   180 	_R_PRINTF("acesssing page");
       
   181 
       
   182 	FOREVER
       
   183 		{
       
   184 		*byte = *byte;
       
   185 		Reschedule(seed);
       
   186 		if (ThreadDie)
       
   187 			break;
       
   188 		}
       
   189 	return KErrNone;
       
   190 	}
       
   191 
       
   192 
       
   193 TInt RunCodeThread(TAny* aParam)
       
   194 	{
       
   195 	TInt64 seed = Math::Random()*Math::Random();
       
   196 	SPinThreadArgs* args = (SPinThreadArgs*)aParam;
       
   197 
       
   198 	test_KErrNone(User::SetRealtimeState(args->iRealtimeState));
       
   199 
       
   200 	// Ensure the the parentThread has moved the page at least once
       
   201 	// before we start accessing it.
       
   202 	TRequestStatus status;
       
   203 	args->iParentThread.Rendezvous(status);
       
   204 	RThread::Rendezvous(KErrNone);
       
   205 	_R_PRINTF("wait for parent");
       
   206 	User::WaitForRequest(status);
       
   207 	_R_PRINTF("acesssing page");
       
   208 
       
   209 	FOREVER
       
   210 		{
       
   211 		TInt r = args->iTestFunc();
       
   212 		if (r != KArbitraryNumber)
       
   213 			return KErrGeneral;
       
   214 		Reschedule(seed);
       
   215 		if (ThreadDie)
       
   216 			break;
       
   217 		}
       
   218 	return KErrNone;
       
   219 	}
       
   220 
       
   221 
       
   222 TInt VirtualPinPage(TAny* aParam)
       
   223 	{
       
   224 	TInt64 seed = Math::Random()*Math::Random();
       
   225 	SPinThreadArgs* args = (SPinThreadArgs*)aParam;
       
   226 	RMemoryTestLdd ldd;
       
   227 	test_KErrNone(ldd.Open());
       
   228 
       
   229 	test_KErrNone(ldd.CreateVirtualPinObject());
       
   230 
       
   231 	TBool firstRun = ETrue;
       
   232 	FOREVER
       
   233 		{
       
   234 		// Pin the page of aParam.
       
   235 		test_KErrNone(ldd.PinVirtualMemory(args->iLinAddr, PageSize));
       
   236 		if (firstRun)
       
   237 			{// On the first run ensure that the page is definitely pinned when
       
   238 			// the parent thread first attempts to move it.
       
   239 			TRequestStatus status;
       
   240 			args->iParentThread.Rendezvous(status);
       
   241 			RThread::Rendezvous(KErrNone);
       
   242 			User::WaitForRequest(status);
       
   243 			test_KErrNone(status.Int());
       
   244 			firstRun = EFalse;
       
   245 			}
       
   246 		Reschedule(seed);
       
   247 		test_KErrNone(ldd.UnpinVirtualMemory());
       
   248 		if (ThreadDie)
       
   249 			break;
       
   250 		}
       
   251 	test_KErrNone(ldd.DestroyVirtualPinObject());
       
   252 	ldd.Close();
       
   253 	return KErrNone;
       
   254 	}
       
   255 
       
   256 
       
   257 TInt PhysicalPinPage(TAny* aParam)
       
   258 	{
       
   259 	TInt64 seed = Math::Random()*Math::Random();
       
   260 	SPinThreadArgs* args = (SPinThreadArgs*)aParam;
       
   261 
       
   262 	RMemoryTestLdd ldd;
       
   263 	test_KErrNone(ldd.Open());
       
   264 
       
   265 	test_KErrNone(ldd.CreatePhysicalPinObject());
       
   266 
       
   267 	TBool firstRun = ETrue;
       
   268 	FOREVER
       
   269 		{
       
   270 		// Pin the page of aParam, use a read only pinning so that pinning code 
       
   271 		// doesn't return KErrAccessDenied as writable mappings not allowed on code.
       
   272 		test_KErrNone(ldd.PinPhysicalMemoryRO(args->iLinAddr, PageSize));
       
   273 		if (firstRun)
       
   274 			{// On the first run ensure that the page is definitely pinned when
       
   275 			// the parent thread first attempts to move it.
       
   276 			TRequestStatus status;
       
   277 			args->iParentThread.Rendezvous(status);
       
   278 			RThread::Rendezvous(KErrNone);
       
   279 			User::WaitForRequest(status);
       
   280 			test_KErrNone(status.Int());
       
   281 			firstRun = EFalse;
       
   282 			}
       
   283 		Reschedule(seed);
       
   284 		test_KErrNone(ldd.UnpinPhysicalMemory());
       
   285 		if (ThreadDie)
       
   286 			break;
       
   287 		}
       
   288 	test_KErrNone(ldd.DestroyPhysicalPinObject());
       
   289 	ldd.Close();
       
   290 	return KErrNone;
       
   291 	}
       
   292 
       
   293 TInt ModifyCodeThread(TAny* aParam)
       
   294 	{
       
   295 	SPinThreadArgs* args = (SPinThreadArgs*)aParam;
       
   296 	TUint8* p = (TUint8*)args->iLinAddr;
       
   297 	PFI func = (PFI)p;
       
   298 
       
   299 	// Ensure the the parentThread has moved the page at least once
       
   300 	// before we start accessing it.
       
   301 	TRequestStatus status;
       
   302 	args->iParentThread.Rendezvous(status);
       
   303 	RThread::Rendezvous(KErrNone);
       
   304 	_R_PRINTF("wait for parent");
       
   305 	User::WaitForRequest(status);
       
   306 	_R_PRINTF("modifiying page");
       
   307 
       
   308 	while (!ThreadDie)
       
   309 		{
       
   310 		Mem::Copy(p, (TAny*)&Increment, Increment_Length());
       
   311 		User::IMB_Range(p, p+Increment_Length());
       
   312 		test_Equal(8, func(7));
       
   313 
       
   314 		Mem::Copy(p, (TAny*)&Decrement, Decrement_Length());
       
   315 		User::IMB_Range(p, p+Decrement_Length());
       
   316 		test_Equal(6, func(7));
       
   317 		}
       
   318 	return KErrNone;
       
   319 	}
       
   320 
       
   321 
       
   322 enum TMovingPinStage
       
   323 	{
       
   324 	ENoPinning,
       
   325 	EVirtualPinning,
       
   326 	EPhysicalPinning,
       
   327 	EMovingPinStages,
       
   328 	};
       
   329 
       
   330 void TestUserData(RPageMove& pagemove, TUint8* array, TInt size, TBool aPagedData=EFalse)
       
   331 	{
       
   332 	_T_PRINTF(_L("Fill the array with some data\n"));
       
   333 	for (TInt i=0; i<size; i++) array[i] = i*i;
       
   334 
       
   335 	TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)array, PageSize);
       
   336 	RThread thread;
       
   337 	thread.Open(RThread().Id());
       
   338 	SPinThreadArgs threadArgs;
       
   339 	threadArgs.iLinAddr = (TLinAddr)array;
       
   340 	threadArgs.iParentThread = thread;
       
   341 	threadArgs.iRealtimeState = User::ERealtimeStateOff;
       
   342 
       
   343 	TMovingPinStage endStage = EMovingPinStages;
       
   344 	if (!gPinningSupported)
       
   345 		endStage = EVirtualPinning;
       
   346 
       
   347 	for (TUint state = ENoPinning; state < (TUint)endStage; state++)
       
   348 		{
       
   349 		TThreadFunction threadFunc = NULL;
       
   350 		switch (state)
       
   351 			{
       
   352 			case ENoPinning:
       
   353 				test.Printf(_L("Attempt to move pages while they are being modified\n"));
       
   354 				threadFunc = &ReadWriteByte;
       
   355 				break;
       
   356 			case EVirtualPinning:
       
   357 				test.Printf(_L("Attempt to move pages while they are being virtually pinned\n"));
       
   358 				threadFunc = &VirtualPinPage;
       
   359 				break;
       
   360 			case EPhysicalPinning:
       
   361 				test.Printf(_L("Attempt to move pages while they are being physically pinned\n"));
       
   362 				threadFunc = &PhysicalPinPage;
       
   363 				break;
       
   364 			}
       
   365 		ThreadDie = EFalse;
       
   366 		TUint numThreads = (NumberOfCpus > 1) ? NumberOfCpus - 1 : 1;
       
   367 		RThread* userDataThread = new RThread[numThreads];
       
   368 		TRequestStatus* s = new TRequestStatus[numThreads];
       
   369 		StartThreads(numThreads, userDataThread, s, threadFunc, threadArgs);
       
   370 
       
   371 		_T_PRINTF(_L("Move first array page repeatedly\n"));
       
   372 		TBool success=EFalse;
       
   373 		TUint inuse = 0;
       
   374 		array[0] = array[0];	// Ensure the page of the first entry is paged in for the first move.
       
   375 		for (TInt i=0; i < Repitions*2; i++)
       
   376 			{
       
   377 			TInt r = pagemove.TryMovingUserPage(firstpage, ETrue);
       
   378 			if (i == 0)
       
   379 				{// If this is the first run allow the pinning threads to 
       
   380 				// unpin the memory now that we've definitely done at least 
       
   381 				// one page move with the page pinned.
       
   382 				_T_PRINTF(_L("signal to child\n"));
       
   383 				RThread::Rendezvous(KErrNone);
       
   384 				}
       
   385 			switch (r)
       
   386 				{
       
   387 				case KErrInUse:
       
   388 					inuse++;
       
   389 					break;
       
   390 				case KErrArgument:
       
   391 					// The page was paged out, this should only happen for paged data.
       
   392 					test(aPagedData);
       
   393 					break;
       
   394 				default:
       
   395 					test_KErrNone(r);
       
   396 					success=ETrue;
       
   397 					break;
       
   398 				}
       
   399 			}
       
   400 		// Can't guarantee that for paged data the page and its page tables will
       
   401 		// be paged in, in most cases it will be at least once.
       
   402 		// Pinning the page should always return KErrInUse except for virtually 
       
   403 		// pinned non-paged memory as virtual pinning is a nop for unpaged memory.
       
   404 		test.Printf(_L("inuse test removed; inuse %d\n"),inuse);
       
   405 		//test(inuse || aPagedData || state == EVirtualPinning);
       
   406 		test(success || state == EPhysicalPinning || aPagedData);
       
   407 
       
   408 		ThreadDie = ETrue;
       
   409 		EndThreads(numThreads, userDataThread, s);
       
   410 
       
   411 		_T_PRINTF(_L("Validate page data\n"));
       
   412 		for (TInt i=0; i<size; i++)
       
   413 			test_Equal((TUint8)(i*i), array[i]);
       
   414 		}
       
   415 	thread.Close();
       
   416 	}
       
   417 
       
   418 
       
   419 void TestMovingCode(RPageMove& aPagemove, TTestFunction aFunc, TBool aPaged=EFalse)
       
   420 	{
       
   421 	TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)aFunc, PageSize);
       
   422 	RThread thread;
       
   423 	thread.Open(RThread().Id());
       
   424 	SPinThreadArgs threadArgs;
       
   425 	threadArgs.iLinAddr = (TLinAddr)firstpage;
       
   426 	threadArgs.iTestFunc = aFunc;
       
   427 	threadArgs.iParentThread = thread;
       
   428 	threadArgs.iRealtimeState = User::ERealtimeStateOff;
       
   429 
       
   430 	TMovingPinStage endStage = EMovingPinStages;
       
   431 	if (!gPinningSupported)
       
   432 		endStage = EVirtualPinning;
       
   433 
       
   434 	for (TUint state = ENoPinning; state < (TUint)endStage; state++)
       
   435 		{
       
   436 		TThreadFunction threadFunc = NULL;
       
   437 		switch (state)
       
   438 			{
       
   439 			case ENoPinning:
       
   440 				test.Printf(_L("Attempt to move pages while they are being executed\n"));
       
   441 				threadFunc = &RunCodeThread;
       
   442 				test_Equal(KArbitraryNumber, aFunc()); // Ensure the page is paged in.
       
   443 				break;
       
   444 			case EVirtualPinning:
       
   445 				test.Printf(_L("Attempt to move pages while they are being virtually pinned\n"));
       
   446 				threadFunc = &VirtualPinPage;
       
   447 				break;
       
   448 			case EPhysicalPinning:
       
   449 				test.Printf(_L("Attempt to move pages while they are being physically pinned\n"));
       
   450 				threadFunc = &PhysicalPinPage;
       
   451 				break;
       
   452 			}
       
   453 		ThreadDie = EFalse;
       
   454 		TUint numThreads = (NumberOfCpus > 1) ? NumberOfCpus - 1 : 1;
       
   455 		RThread* codeRunThread = new RThread[numThreads];
       
   456 		TRequestStatus* s = new TRequestStatus[numThreads];
       
   457 		StartThreads(numThreads, codeRunThread, s, threadFunc, threadArgs);
       
   458 
       
   459 		_T_PRINTF(_L("Move first code page repeatedly\n"));
       
   460 		TBool inuse=EFalse, success=EFalse;
       
   461 		for (TInt i=0; i < Repitions; i++)
       
   462 			{
       
   463 			TInt r = aPagemove.TryMovingUserPage(firstpage, ETrue);
       
   464 			if (i == 0)
       
   465 				{// If this is the first run allow the pinning threads to 
       
   466 				// unpin the memory now that we've definitely done at least 
       
   467 				// one page move with the page pinned.
       
   468 				_T_PRINTF(_L("signal to child\n"));
       
   469 				RThread::Rendezvous(KErrNone);
       
   470 				}
       
   471 			switch (r)
       
   472 				{
       
   473 				case KErrInUse:
       
   474 					inuse=ETrue;
       
   475 					break;
       
   476 				case KErrArgument:
       
   477 					// The page was paged out, this should only happen for paged code.
       
   478 					test(aPaged);
       
   479 					break;
       
   480 				default:
       
   481 					test_KErrNone(r);
       
   482 					success=ETrue;
       
   483 					break;
       
   484 				}
       
   485 			}
       
   486 		// Physical pinning or adding a new pinning while a page is being moved
       
   487 		// should prevent code pages being moved.
       
   488 		switch (state)
       
   489 		{
       
   490 			case ENoPinning :			
       
   491 				test(!inuse || aPaged);	// Stealing may get KErrInUse but this should only happen for paged code.
       
   492 			case EVirtualPinning :
       
   493 				test(success);
       
   494 				break;
       
   495 			case EPhysicalPinning :
       
   496 				break;
       
   497 		}
       
   498 
       
   499 		ThreadDie = ETrue;
       
   500 		EndThreads(numThreads, codeRunThread, s);
       
   501 
       
   502 		_T_PRINTF(_L("Validate page data\n"));
       
   503 		test_Equal(KArbitraryNumber, aFunc());		
       
   504 		}
       
   505 	thread.Close();
       
   506 	}
       
   507 
       
   508 
       
   509 void TestMovingRealtime(RPageMove& aPagemove, TUint8* aArray, TInt aSize, TTestFunction aFunc, TBool aCode, TBool aPaged=EFalse)
       
   510 	{
       
   511 	TThreadFunction threadFunc;
       
   512 	TLinAddr pageAddr;
       
   513 	RThread thread;
       
   514 	TUint8* firstpage;
       
   515 	thread.Open(RThread().Id());
       
   516 	SPinThreadArgs threadArgs;
       
   517 	threadArgs.iParentThread = thread;
       
   518 	if (aCode)
       
   519 		{
       
   520 		pageAddr = (TLinAddr)aFunc;
       
   521 		firstpage = (TUint8*)_ALIGN_DOWN(pageAddr, PageSize);
       
   522 		threadArgs.iLinAddr = (TLinAddr)firstpage;
       
   523 		threadFunc = RunCodeThread;
       
   524 		threadArgs.iTestFunc = aFunc;
       
   525 		test_Equal(KArbitraryNumber, aFunc());
       
   526 		}
       
   527 	else
       
   528 		{
       
   529 		pageAddr = (TLinAddr)aArray;
       
   530 		firstpage = (TUint8*)_ALIGN_DOWN(pageAddr, PageSize);
       
   531 		threadArgs.iLinAddr = (TLinAddr)aArray;
       
   532 		threadFunc = ReadWriteByte;
       
   533 		_T_PRINTF(_L("Fill the array with some data\n"));
       
   534 		for (TInt i=0; i<aSize; i++) aArray[i] = i*i;
       
   535 		}
       
   536 
       
   537 	RMemoryTestLdd ldd;
       
   538 
       
   539 	TMovingPinStage endStage = EMovingPinStages;
       
   540 	if (gPinningSupported)
       
   541 		{
       
   542 		test_KErrNone(ldd.Open());
       
   543 		test_KErrNone(ldd.CreateVirtualPinObject());
       
   544 		test_KErrNone(ldd.CreatePhysicalPinObject());
       
   545 		}
       
   546 	else
       
   547 		endStage = EVirtualPinning;
       
   548 
       
   549 	for (TUint state = ENoPinning; state < (TUint)endStage; state++)
       
   550 		{
       
   551 		switch (state)
       
   552 			{
       
   553 			case ENoPinning:
       
   554 				test.Printf(_L("Attempt to move pages while they are being accessed\n"));
       
   555 				break;
       
   556 			case EVirtualPinning:
       
   557 				test.Printf(_L("Attempt to move pages while they are virtually pinned\n"));
       
   558 				test_KErrNone(ldd.PinVirtualMemory((TLinAddr)firstpage, PageSize));
       
   559 
       
   560 				break;
       
   561 			case EPhysicalPinning:
       
   562 				test.Printf(_L("Attempt to move pages while they are physically pinned\n"));
       
   563 				test_KErrNone(ldd.PinPhysicalMemoryRO((TLinAddr)firstpage, PageSize));
       
   564 				break;
       
   565 			}
       
   566 		for (	TUint realtimeState = User::ERealtimeStateOff; 
       
   567 				realtimeState <= User::ERealtimeStateWarn; 
       
   568 				realtimeState++)
       
   569 			{
       
   570 			ThreadDie = EFalse;
       
   571 			RThread accessThread;
       
   572 			TRequestStatus s;
       
   573 			threadArgs.iRealtimeState = (User::TRealtimeState)realtimeState;
       
   574 			test_KErrNone(accessThread.Create(_L("Realtime Thread"), threadFunc, KDefaultStackSize, NULL, &threadArgs));
       
   575 			accessThread.Logon(s);
       
   576 			TRequestStatus threadInitialised;
       
   577 			accessThread.Rendezvous(threadInitialised);
       
   578 			accessThread.Resume();
       
   579 
       
   580 			_T_PRINTF(_L("wait for child\n"));
       
   581 			User::WaitForRequest(threadInitialised);
       
   582 			test_KErrNone(threadInitialised.Int());
       
   583 
       
   584 			_T_PRINTF(_L("Move page repeatedly\n"));
       
   585 			TBool success=EFalse, pagedOut=EFalse;
       
   586 			TUint inuse=0;
       
   587 			if (!aCode)
       
   588 				aArray[0] = aArray[0];	// Ensure the page of the first entry is paged in for the first move.
       
   589 			for (TInt i=0; i < Repitions; i++)
       
   590 				{
       
   591 				TInt r = aPagemove.TryMovingUserPage(firstpage, ETrue);
       
   592 				if (i == 0)
       
   593 					{
       
   594 					_T_PRINTF(_L("signal to child\n"));
       
   595 					RThread::Rendezvous(KErrNone);
       
   596 					}
       
   597 				switch (r)
       
   598 					{
       
   599 					case KErrInUse:
       
   600 						inuse++;
       
   601 						break;
       
   602 					case KErrArgument:
       
   603 						// The page was paged out, this should only happen for paged code.
       
   604 						test(aPaged);
       
   605 						pagedOut = ETrue;
       
   606 						break;
       
   607 					default:
       
   608 						test_KErrNone(r);
       
   609 						success=ETrue;
       
   610 						break;
       
   611 					}
       
   612 				}
       
   613 			ThreadDie = ETrue;
       
   614 			User::WaitForRequest(s);
       
   615 			test.Printf(_L("inuse %d\n"),inuse);
       
   616 			switch (state)
       
   617 				{
       
   618 				case ENoPinning :
       
   619 					test(success || aPaged);
       
   620 					if (aPaged && realtimeState == User::ERealtimeStateOn)
       
   621 						{
       
   622 						test_Equal(EExitPanic, accessThread.ExitType());
       
   623 						test(accessThread.ExitCategory()==_L("KERN-EXEC"));
       
   624 						test_Equal(EIllegalFunctionForRealtimeThread, accessThread.ExitReason());
       
   625 						}
       
   626 					else
       
   627 						{
       
   628 						test_Equal(EExitKill,accessThread.ExitType());
       
   629 						test_KErrNone(accessThread.ExitReason());
       
   630 						}
       
   631 					// Ensure the page is paged in before we attempt to move it again with a different realtime state.
       
   632 					if (aCode)
       
   633 						{
       
   634 						test_Equal(KArbitraryNumber, aFunc());
       
   635 						}
       
   636 					else
       
   637 						*aArray = *aArray;
       
   638 					break;				
       
   639 				case EVirtualPinning :
       
   640 					test(!aCode || !inuse);
       
   641 					test(success);
       
   642 					test(!pagedOut);
       
   643 					test_Equal(EExitKill,accessThread.ExitType());
       
   644 					test_KErrNone(accessThread.ExitReason());
       
   645 					break;
       
   646 				case EPhysicalPinning :
       
   647 					test(!success);
       
   648 					break;
       
   649 				}
       
   650 			accessThread.Close();
       
   651 			}
       
   652 		if (gPinningSupported)
       
   653 			{
       
   654 			// Unpin any pinned memory.
       
   655 			test_KErrNone(ldd.UnpinVirtualMemory());
       
   656 			test_KErrNone(ldd.UnpinPhysicalMemory());
       
   657 			}
       
   658 
       
   659 		_T_PRINTF(_L("Validate page data\n"));
       
   660 		if (aCode)
       
   661 			{
       
   662 			test_Equal(KArbitraryNumber, aFunc());
       
   663 			}
       
   664 		else
       
   665 			{
       
   666 			for (TInt i=0; i<aSize; i++)
       
   667 				test_Equal((TUint8)(i*i), aArray[i]);
       
   668 			}
       
   669 			
       
   670 		}
       
   671 	if (gPinningSupported)
       
   672 		{
       
   673 		test_KErrNone(ldd.DestroyVirtualPinObject());
       
   674 		test_KErrNone(ldd.DestroyPhysicalPinObject());
       
   675 		ldd.Close();
       
   676 		}
       
   677 	thread.Close();
       
   678 	}
       
   679 
       
   680 // Only commits and decommits the first page as that is the only page that is being moved.
       
   681 // Plus this ensures the page table and page directories of the chunk are always allocated
       
   682 // and therefore prevents Epoc::LinearToPhysical() from crashing the system.
       
   683 TInt CommitDecommit(TAny* aParam)
       
   684 	{
       
   685 	RChunk* chunk = (RChunk*) aParam;
       
   686 	volatile TUint8* byte = chunk->Base();
       
   687 	FOREVER
       
   688 		{
       
   689 		*byte = *byte;
       
   690 		User::AfterHighRes(0);
       
   691 		TInt r = chunk->Decommit(0, PageSize);
       
   692 		if (r != KErrNone)
       
   693 			return r;
       
   694 		User::AfterHighRes(0);
       
   695 		r = chunk->Commit(0, PageSize);
       
   696 		if (r != KErrNone)
       
   697 			return r;
       
   698 		}
       
   699 	}
       
   700 
       
   701 void TestCommitDecommit(RPageMove& pagemove, RChunk& aChunk)
       
   702 	{
       
   703 	test.Printf(_L("Attempt to move a page while it is being committed and decommited\n"));
       
   704 	RThread thread;
       
   705 	TRequestStatus s;
       
   706 	test_KErrNone(thread.Create(_L("CommitDecommit"), &CommitDecommit, KDefaultStackSize, NULL, (TAny*)&aChunk));
       
   707 	thread.Logon(s);
       
   708 	thread.SetPriority(EPriorityMore);
       
   709 	thread.Resume();
       
   710 
       
   711 	TUint8* firstpage=(TUint8*)_ALIGN_DOWN((TLinAddr)aChunk.Base(), PageSize);
       
   712 	for (TInt i=0; i < Repitions; i++)
       
   713 		{
       
   714 		TInt r = pagemove.TryMovingUserPage(firstpage, ETrue);
       
   715 		// Allow all valid return codes as we are only testing that this doesn't 
       
   716 		// crash the kernel and the page could be commited, paged out or decommited
       
   717 		// at any one time.
       
   718 		test_Value(r, r <= KErrNone);
       
   719 		}
       
   720 
       
   721 	thread.Kill(KErrNone);
       
   722 	User::WaitForRequest(s);
       
   723 	test_Equal(EExitKill,thread.ExitType());
       
   724 	test_KErrNone(thread.ExitReason());
       
   725 	thread.Close();
       
   726 	}
       
   727 
       
   728 
       
   729 void TestPageTableDiscard(RPageMove& pagemove, TUint8* array, TUint size)
       
   730 	{
       
   731 	_T_PRINTF(_L("Fill the array with some data\n"));
       
   732 	for (TUint i=0; i<size; i++) array[i] = i*i;
       
   733 
       
   734 	TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)array, PageSize);
       
   735 	RThread thread;
       
   736 	thread.Open(RThread().Id());
       
   737 	SPinThreadArgs threadArgs;
       
   738 	threadArgs.iLinAddr = (TLinAddr)array;
       
   739 	threadArgs.iParentThread = thread;
       
   740 	threadArgs.iRealtimeState = User::ERealtimeStateOff;
       
   741 
       
   742 	TMovingPinStage endStage = EMovingPinStages;
       
   743 	if (!gPinningSupported)
       
   744 		endStage = EVirtualPinning;
       
   745 	
       
   746 	for (TUint pageTableInfo = 0; pageTableInfo < 2; pageTableInfo++)
       
   747 		{
       
   748 		for (TUint state = ENoPinning; state < (TUint)endStage; state++)
       
   749 			{
       
   750 			TThreadFunction threadFunc = NULL;
       
   751 			if (!pageTableInfo)
       
   752 			{
       
   753 			switch (state)
       
   754 				{
       
   755 				case ENoPinning:
       
   756 					test.Printf(_L("Attempt to move page tables whilst the pages they map are being modified\n"));
       
   757 					threadFunc = &ReadWriteByte;
       
   758 					break;
       
   759 				case EVirtualPinning:
       
   760 					test.Printf(_L("Attempt to move page tables whilst the pages they map are being virtually pinned\n"));
       
   761 					threadFunc = &VirtualPinPage;
       
   762 					break;
       
   763 				case EPhysicalPinning:
       
   764 					test.Printf(_L("Attempt to move page tables whilst the pages they map are being physically pinned\n"));
       
   765 					threadFunc = &PhysicalPinPage;
       
   766 					break;
       
   767 				}
       
   768 			}
       
   769 			else
       
   770 			{
       
   771 			switch (state)
       
   772 				{
       
   773 				case ENoPinning:
       
   774 					test.Printf(_L("Attempt to move page table infos whilst pages they refer to are being modified\n"));
       
   775 					threadFunc = &ReadWriteByte;
       
   776 					break;
       
   777 				case EVirtualPinning:
       
   778 					test.Printf(_L("Attempt to move page table infos whilst pages they refer to are being virtually pinned\n"));
       
   779 					threadFunc = &VirtualPinPage;
       
   780 					break;
       
   781 				case EPhysicalPinning:
       
   782 					test.Printf(_L("Attempt to move page table infos whilst pages they refer to are being physically pinned\n"));
       
   783 					threadFunc = &PhysicalPinPage;
       
   784 					break;
       
   785 				}
       
   786 			}
       
   787 			ThreadDie = EFalse;
       
   788 			TUint numThreads = (NumberOfCpus > 1) ? NumberOfCpus - 1 : 1;
       
   789 			RThread* threads = new RThread[numThreads];
       
   790 			TRequestStatus* s = new TRequestStatus[numThreads];
       
   791 			StartThreads(numThreads, threads, s, threadFunc, threadArgs);
       
   792 
       
   793 			_T_PRINTF(_L("Move first array page repeatedly\n"));
       
   794 			TUint inuse = 0;
       
   795 			for (TInt i=0; i < Repitions; i++)
       
   796 				{
       
   797 				TInt r;
       
   798 				if (!pageTableInfo)
       
   799 					r = pagemove.TryMovingPageTable(firstpage);
       
   800 				else
       
   801 					r = pagemove.TryMovingPageTableInfo(firstpage);					
       
   802 				if (i == 0)
       
   803 					{// If this is the first run allow the pinning threads to 
       
   804 					// unpin the memory now that we've definitely done at least 
       
   805 					// one page move with the page pinned.
       
   806 					_T_PRINTF(_L("signal to child\n"));
       
   807 					RThread::Rendezvous(KErrNone);
       
   808 					}
       
   809 				switch (r)
       
   810 					{
       
   811 					case KErrInUse:
       
   812 						inuse++;
       
   813 						break;
       
   814 					case KErrNotFound:
       
   815 						// The page table or page table info page was paged out.
       
   816 						break;
       
   817 					default:
       
   818 						test_KErrNone(r);
       
   819 						break;
       
   820 					}
       
   821 				}
       
   822 			test.Printf(_L("inuse %d\n"),inuse);
       
   823 			// A virtually pinned page should always return KErrInUse at least once.
       
   824 			test(state != EVirtualPinning || inuse);
       
   825 
       
   826 			ThreadDie = ETrue;
       
   827 			EndThreads(numThreads, threads, s);
       
   828 
       
   829 			_T_PRINTF(_L("Validate page data\n"));
       
   830 			for (TUint i=0; i<size; i++)
       
   831 				test_Equal((TUint8)(i*i), array[i]);
       
   832 			}
       
   833 		}
       
   834 	thread.Close();
       
   835 	}
       
   836 
       
   837 // Basic testing of moving rom pages.
       
   838 void TestMovingRom(RPageMove& aPageMove)
       
   839 	{
       
   840 	TUint8* pPage=(TUint8*)User::Alloc(PageSize);
       
   841 	test(pPage!=NULL);
       
   842 
       
   843 	TUint romHdr = UserSvr::RomHeaderAddress();
       
   844 
       
   845 	if (gPinningSupported)
       
   846 		{
       
   847 		// Pin an unpaged rom page to get the physical address of the rom page.
       
   848 		// Pinning unpaged rom actually does nothing except return the physical 
       
   849 		// address of the page.
       
   850 		RMemoryTestLdd ldd;
       
   851 		test_KErrNone(ldd.Open());
       
   852 		test_KErrNone(ldd.CreatePhysicalPinObject());
       
   853 
       
   854 		// Save contents of rom page.
       
   855 		Mem::Move(pPage,(TAny*)romHdr,PageSize);
       
   856 
       
   857 		test_KErrNone(ldd.PinPhysicalMemoryRO(romHdr, PageSize));
       
   858 		test_KErrNone(ldd.UnpinPhysicalMemory());
       
   859 
       
   860 		// Now move the page, d_memorytest saves the address of the pinned page
       
   861 		// depsite it being unpinned.
       
   862 		// Will get KErrArgument as rom pages don't have an SPageInfo so memory
       
   863 		// model doesn't treat rom as though they are in ram, which in most cases 
       
   864 		// they are.
       
   865 		test_Equal(KErrArgument, ldd.MovePinnedPhysicalMemory(0));
       
   866 
       
   867 		test_KErrNone(Mem::Compare((TUint8*)romHdr,PageSize,pPage,PageSize));
       
   868 		test_KErrNone(ldd.DestroyPhysicalPinObject());
       
   869 		ldd.Close();
       
   870 		}
       
   871 
       
   872 	if (gRomPagingSupported)
       
   873 		{
       
   874 		// Use paged part of rom for testing
       
   875 		TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
       
   876 		test(romHeader->iPageableRomStart);
       
   877 		TUint romAddr = (TUint)((TUint8*)romHeader + romHeader->iPageableRomStart + 64 * PageSize);
       
   878 
       
   879 		// We will use the 64th pagable rom page so check that it exists.
       
   880 		test(romHeader->iPageableRomSize >= 65 * PageSize);
       
   881 	
       
   882 		// Page in the rom page and save it contents.
       
   883 		Mem::Move(pPage,(TAny*)romAddr,PageSize);
       
   884 		// This will actually discard the page not move it.
       
   885 		test_KErrNone(aPageMove.TryMovingUserPage(pPage));
       
   886 
       
   887 		test_KErrNone(Mem::Compare((TUint8*)romAddr,PageSize,pPage,PageSize));
       
   888 		}
       
   889 	}
       
   890 
       
   891 
       
   892 void TestMovingCodeChunk(RPageMove& pagemove, RChunk aChunk, TBool aPagedData)
       
   893 	{
       
   894 	TUint8* p = aChunk.Base();
       
   895 
       
   896 	TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)p, PageSize);
       
   897 	RThread thread;
       
   898 	thread.Open(RThread().Id());
       
   899 	SPinThreadArgs threadArgs;
       
   900 	threadArgs.iLinAddr = (TLinAddr)p;
       
   901 	threadArgs.iParentThread = thread;
       
   902 
       
   903 	test.Printf(_L("Attempt to move pages while they are being executed and modified\n"));
       
   904 	ThreadDie = EFalse;
       
   905 	RThread modCodeThread;
       
   906 	TRequestStatus s;
       
   907 	test_KErrNone(modCodeThread.Create(_L("User Data thread"), &ModifyCodeThread, KDefaultStackSize, NULL, &threadArgs));
       
   908 	modCodeThread.Logon(s);
       
   909 	TRequestStatus threadInitialised;
       
   910 	modCodeThread.Rendezvous(threadInitialised);
       
   911 	modCodeThread.Resume();
       
   912 
       
   913 	_T_PRINTF(_L("wait for child\n"));
       
   914 	User::WaitForRequest(threadInitialised);
       
   915 	test_KErrNone(threadInitialised.Int());
       
   916 
       
   917 	_T_PRINTF(_L("Move code chunk page repeatedly\n"));
       
   918 	TBool success=EFalse;
       
   919 	p[0] = p[0];	// Ensure the page of the first entry is paged in for the first move.
       
   920 	for (TInt i=0; i < Repitions; i++)
       
   921 		{
       
   922 		TInt r = pagemove.TryMovingUserPage(firstpage, ETrue);
       
   923 		if (i == 0)
       
   924 			{// If this is the first run allow the modifying thread to run now 
       
   925 			// we've done one move.
       
   926 			_T_PRINTF(_L("signal to child\n"));
       
   927 			RThread::Rendezvous(KErrNone);
       
   928 			}
       
   929 		switch (r)
       
   930 			{
       
   931 			case KErrInUse:
       
   932 				break;
       
   933 			case KErrArgument:
       
   934 				// The page was paged out, this should only happen for paged data.
       
   935 				test(aPagedData);
       
   936 				break;
       
   937 			default:
       
   938 				test_KErrNone(r);
       
   939 				success=ETrue;
       
   940 				break;
       
   941 			}
       
   942 		}
       
   943 	test(success || aPagedData);
       
   944 
       
   945 	ThreadDie = ETrue;
       
   946 	User::WaitForRequest(s);
       
   947 	test_Equal(EExitKill,modCodeThread.ExitType());
       
   948 	test_KErrNone(modCodeThread.ExitReason());
       
   949 	modCodeThread.Close();
       
   950 
       
   951 	thread.Close();
       
   952 	}
       
   953 
       
   954 GLDEF_C TInt E32Main()
       
   955     {
       
   956 	test.Title();
       
   957 	if (!HaveMMU())
       
   958 		{
       
   959 		test.Printf(_L("This test requires an MMU\n"));
       
   960 		return KErrNone;
       
   961 		}
       
   962 
       
   963 	test.Start(_L("Load test LDD"));
       
   964 	TInt r=User::LoadLogicalDevice(KLddFileName);
       
   965 	test(r==KErrNone || r==KErrAlreadyExists);
       
   966 
       
   967 	test_KErrNone(UserHal::PageSizeInBytes(PageSize));
       
   968 
       
   969 	// Determine which types of paging are supported
       
   970 	TUint32 attrs = DPTest::Attributes();
       
   971 	gRomPagingSupported = (attrs & DPTest::ERomPaging) != 0;
       
   972 	gCodePagingSupported = (attrs & DPTest::ECodePaging) != 0;
       
   973 	gDataPagingSupported = (attrs & DPTest::EDataPaging) != 0;
       
   974 
       
   975 	// Does this memory model support pinning.
       
   976 	TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
       
   977 	gPinningSupported = mm >= EMemModelTypeFlexible;
       
   978 
       
   979 	RPageMove pagemove;
       
   980 	test.Next(_L("Open test LDD"));
       
   981 	test_KErrNone(pagemove.Open());
       
   982 
       
   983 	// Determine whether this is a smp device.
       
   984 	NumberOfCpus = pagemove.NumberOfCpus();
       
   985 	if (NumberOfCpus > 1)
       
   986 		Repitions = 1000;	// SMP system therefore likely to get KErrInUse in less repitions.
       
   987 
       
   988 	test.Next(_L("Attempting to move regular local data pages"));
       
   989 		{
       
   990 		const TInt size=16384;
       
   991 		TUint8* array = new TUint8[size];
       
   992 		test_NotNull(array);
       
   993 
       
   994 		TestUserData(pagemove, array, size);
       
   995 
       
   996 		_T_PRINTF(_L("Walk heap\n"));
       
   997 		User::Check();
       
   998 
       
   999 		delete [] array;
       
  1000 		}
       
  1001 
       
  1002 	test.Next(_L("Attempting to move regular global coarse data pages"));
       
  1003 		{
       
  1004 		const TInt size=1<<20;	// Make this chunk multiple of 1MB so it is a coarse memory object on FMM
       
  1005 		RChunk chunk;
       
  1006 		test_KErrNone(chunk.CreateDisconnectedGlobal(_L("Dave"), 0, size, size));
       
  1007 		TUint8* array = chunk.Base();
       
  1008 
       
  1009 		TestUserData(pagemove, array, size);
       
  1010 		TestMovingRealtime(pagemove, array, size, NULL, EFalse);
       
  1011 		TestCommitDecommit(pagemove, chunk);
       
  1012 
       
  1013 		chunk.Close();
       
  1014 		}
       
  1015 
       
  1016 	if (gDataPagingSupported)
       
  1017 		{
       
  1018 		test.Next(_L("Attempting to move demand paged fine local user data pages"));
       
  1019 		const TInt size=16384;
       
  1020 		TChunkCreateInfo createInfo;
       
  1021 		createInfo.SetDisconnected(0, size, size);
       
  1022 		createInfo.SetPaging(TChunkCreateInfo::EPaged);
       
  1023 		RChunk chunk;
       
  1024 		test_KErrNone(chunk.Create(createInfo));
       
  1025 		TUint8* array = chunk.Base();
       
  1026 
       
  1027 		TestUserData(pagemove, array, size, ETrue);
       
  1028 		TestMovingRealtime(pagemove, array, size, NULL, EFalse, ETrue);
       
  1029 		TestPageTableDiscard(pagemove, array, size);
       
  1030 		TestCommitDecommit(pagemove, chunk);
       
  1031 		chunk.Close();
       
  1032 
       
  1033 		test.Next(_L("Attempting to move demand paged coarse global user data pages"));
       
  1034 		const TInt sizeCoarse = 1 << 20; // Make this chunk multiple of 1MB so it is a coarse memory object on FMM
       
  1035 		TChunkCreateInfo createInfoCoarse;
       
  1036 		createInfoCoarse.SetDisconnected(0, sizeCoarse, sizeCoarse);
       
  1037 		createInfoCoarse.SetGlobal(_L("Dave"));
       
  1038 		createInfoCoarse.SetPaging(TChunkCreateInfo::EPaged);
       
  1039 		RChunk chunkCoarse;
       
  1040 		test_KErrNone(chunkCoarse.Create(createInfoCoarse));
       
  1041 		array = chunkCoarse.Base();
       
  1042 
       
  1043 		TestUserData(pagemove, array, sizeCoarse, ETrue);
       
  1044 		TestMovingRealtime(pagemove, array, sizeCoarse, NULL, EFalse, ETrue);
       
  1045 		TestPageTableDiscard(pagemove, array, sizeCoarse);
       
  1046 		TestCommitDecommit(pagemove, chunkCoarse);
       
  1047 		chunkCoarse.Close();
       
  1048 		}
       
  1049 
       
  1050 	test.Next(_L("Attempting to move DLL writable static data pages"));
       
  1051 		{
       
  1052 		const TInt size=16384;
       
  1053 		TUint8* array = DllWsd::Address();
       
  1054 
       
  1055 		TestUserData(pagemove, array, size);
       
  1056 		}
       
  1057 
       
  1058 	test.Next(_L("Attempting to move user self-mod code chunk page when IMB'ing and executing"));
       
  1059 	RChunk codeChunk;
       
  1060 	test_KErrNone(codeChunk.CreateLocalCode(PageSize,PageSize));
       
  1061 	TestMovingCodeChunk(pagemove, codeChunk, EFalse);
       
  1062 	codeChunk.Close();
       
  1063 
       
  1064 	if (gDataPagingSupported)
       
  1065 		{
       
  1066 		test.Next(_L("Attempting to move paged user self-mod code chunk page when IMB'ing and executing"));
       
  1067 		TChunkCreateInfo createInfo;
       
  1068 		createInfo.SetCode(PageSize, PageSize);
       
  1069 		createInfo.SetPaging(TChunkCreateInfo::EPaged);
       
  1070 
       
  1071 		RChunk pagedCodeChunk;
       
  1072 		test_KErrNone(pagedCodeChunk.Create(createInfo));
       
  1073 		TestMovingCodeChunk(pagemove, pagedCodeChunk, ETrue);
       
  1074 		pagedCodeChunk.Close();
       
  1075 		}
       
  1076 
       
  1077 	test.Next(_L("Attempting to move RAM drive"));
       
  1078 	if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMultiple)
       
  1079 		{
       
  1080 		for (TInt i=0; i<Repitions; i++)
       
  1081 			test_KErrNone(pagemove.TryMovingUserPage((TAny*)0xA0000000));
       
  1082 		}
       
  1083 	else if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMoving)
       
  1084 		{
       
  1085 		for (TInt i=0; i<Repitions; i++)
       
  1086 			test_KErrNone(pagemove.TryMovingUserPage((TAny*)0x40000000));
       
  1087 		}
       
  1088 	else if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeFlexible)
       
  1089 		{
       
  1090 		// do nothing, RAM drive is not special
       
  1091 		}
       
  1092 	else
       
  1093 		{
       
  1094 		test.Printf(_L("Don't know where the RAM drive is!"));
       
  1095 		test(0);
       
  1096 		}
       
  1097 	
       
  1098 #if 0
       
  1099 	test.Next(_L("Attempting to move kernel heap pages"));
       
  1100 	for (TInt i=0; i<Repitions; i++)
       
  1101 		test_KErrNone(pagemove.TryMovingKHeap());
       
  1102 #endif
       
  1103 
       
  1104 	if ((MemModelAttributes()&EMemModelTypeMask) != EMemModelTypeFlexible)
       
  1105 		{// Only the moving and multiple memory models move kernel stack pages.
       
  1106 		test.Next(_L("Attempting to move kernel stack pages"));
       
  1107 		for (TInt i=0; i<Repitions; i++)
       
  1108 			test_KErrNone(pagemove.TryMovingKStack());
       
  1109 		}
       
  1110 
       
  1111 	test.Next(_L("Attempting to move ROM pages"));
       
  1112 	TestMovingRom(pagemove);
       
  1113 
       
  1114 	test.Next(_L("Attempting to move kernel code pages"));
       
  1115 	for (TInt i=0; i<Repitions; i++)
       
  1116 		test_KErrNone(pagemove.TryMovingKCode());
       
  1117 
       
  1118 	test.Next(_L("Attempting to move regular code pages"));
       
  1119 	TestMovingCode(pagemove, RamLoadedFunction);
       
  1120 	TestMovingRealtime(pagemove, NULL, 0, RamLoadedFunction, ETrue, EFalse);
       
  1121 
       
  1122 	if (gCodePagingSupported)
       
  1123 		{
       
  1124 		test.Next(_L("Attempting to move demand paged code pages"));
       
  1125 		TestMovingCode(pagemove, DllTestFunction, ETrue);
       
  1126 		TestMovingRealtime(pagemove, NULL, 0, DllTestFunction, ETrue, ETrue);
       
  1127 		}
       
  1128 
       
  1129 	/* Setup CodeModifier Test Driver */
       
  1130 	StartCodeModifierDriver();
       
  1131 	test(KErrNone==Device.InitialiseCodeModifier(/* Max break points */ 5 ));
       
  1132 
       
  1133 	test.Next(_L("Attempting to move code page being modified\n"));
       
  1134 	test_KErrNone(TestCodeModification(pagemove));
       
  1135 
       
  1136 	test.Next(_L("Attempting to move code (async) while page being modified"));
       
  1137 	test_KErrNone(TestCodeModificationAsync(pagemove));
       
  1138 
       
  1139 	StopCodeModifierDriver();
       
  1140 	
       
  1141 	test.Next(_L("Attempting to move ROM Locale DLL Page"));
       
  1142 	test_KErrNone(E32TestLocale(1));
       
  1143 
       
  1144 	test.Next(_L("Attempting to move RAM Locale DLL Page"));
       
  1145 	test_KErrNone(E32TestLocale(0));
       
  1146 
       
  1147 	test.Next(_L("Close test LDD"));
       
  1148 	pagemove.Close();
       
  1149 	User::FreeLogicalDevice(KLddFileName);
       
  1150 
       
  1151 	test.End();
       
  1152 	return(KErrNone);
       
  1153     }
       
  1154 
       
  1155 
       
  1156 void testUS(const TLocale& aLocale)
       
  1157 {
       
  1158 	test.Printf(_L("Test US\n"));
       
  1159 
       
  1160 	test(aLocale.CountryCode()==1);
       
  1161 	test(aLocale.DateFormat()==EDateAmerican);
       
  1162 	test(aLocale.TimeFormat()==ETime12);
       
  1163 	test(aLocale.CurrencySymbolPosition()==ELocaleBefore);
       
  1164 	test(aLocale.CurrencySpaceBetween()==FALSE);
       
  1165 	test(aLocale.CurrencyDecimalPlaces()==2);
       
  1166 	test(aLocale.CurrencyNegativeInBrackets()==EFalse);
       
  1167 	test(aLocale.CurrencyTriadsAllowed()==TRUE);
       
  1168 	test(aLocale.ThousandsSeparator()==',');
       
  1169 	test(aLocale.DecimalSeparator()=='.');
       
  1170 	test(aLocale.DateSeparator(0)==0);
       
  1171 	test(aLocale.DateSeparator(1)=='/');
       
  1172 	test(aLocale.DateSeparator(2)=='/');
       
  1173 	test(aLocale.DateSeparator(3)==0);
       
  1174 	test(aLocale.TimeSeparator(0)==0);
       
  1175 	test(aLocale.TimeSeparator(1)==':');
       
  1176 	test(aLocale.TimeSeparator(2)==':');
       
  1177 	test(aLocale.TimeSeparator(3)==0);
       
  1178 	test(aLocale.AmPmSymbolPosition()==TRUE);
       
  1179 	test(aLocale.AmPmSpaceBetween()==TRUE);
       
  1180 	test(aLocale.HomeDaylightSavingZone()==EDstNorthern);
       
  1181 	test(aLocale.WorkDays()==0x1f);
       
  1182 	test(aLocale.StartOfWeek()==ESunday);
       
  1183 	test(aLocale.ClockFormat()==EClockAnalog);
       
  1184 	test(aLocale.UnitsGeneral()==EUnitsImperial);
       
  1185 	test(aLocale.UnitsDistanceShort()==EUnitsImperial);
       
  1186 	test(aLocale.UnitsDistanceLong()==EUnitsImperial);
       
  1187 }
       
  1188 
       
  1189 
       
  1190 void testUK(const TLocale& aLocale)
       
  1191 {
       
  1192 //#ifdef __WINS__
       
  1193 	test(aLocale.CountryCode()==44);
       
  1194 	test(aLocale.DateFormat()==EDateEuropean);
       
  1195 	test(aLocale.TimeFormat()==ETime12);
       
  1196 	test(aLocale.CurrencySymbolPosition()==ELocaleBefore);
       
  1197 	test(aLocale.CurrencySpaceBetween()==FALSE);
       
  1198 	test(aLocale.CurrencyDecimalPlaces()==2);
       
  1199 	test(aLocale.CurrencyNegativeInBrackets()==EFalse);
       
  1200 	test(aLocale.CurrencyTriadsAllowed()==TRUE);
       
  1201 	test(aLocale.ThousandsSeparator()==',');
       
  1202 	test(aLocale.DecimalSeparator()=='.');
       
  1203 	test(aLocale.DateSeparator(0)==0);
       
  1204 	test(aLocale.DateSeparator(1)=='/');
       
  1205 	test(aLocale.DateSeparator(2)=='/');
       
  1206 	test(aLocale.DateSeparator(3)==0);
       
  1207 	test(aLocale.TimeSeparator(0)==0);
       
  1208 	test(aLocale.TimeSeparator(1)==':');
       
  1209 	test(aLocale.TimeSeparator(2)==':');
       
  1210 	test(aLocale.TimeSeparator(3)==0);
       
  1211 	test(aLocale.AmPmSymbolPosition()==TRUE);
       
  1212 	test(aLocale.AmPmSpaceBetween()==TRUE);
       
  1213 	test(aLocale.HomeDaylightSavingZone()==EDstEuropean);
       
  1214 	test(aLocale.WorkDays()==0x1f);
       
  1215 	test(aLocale.StartOfWeek()==EMonday);
       
  1216 	test(aLocale.ClockFormat()==EClockAnalog);
       
  1217 	test(aLocale.UnitsGeneral()==EUnitsImperial);
       
  1218 	test(aLocale.UnitsDistanceShort()==EUnitsImperial);
       
  1219 	test(aLocale.UnitsDistanceLong()==EUnitsImperial);
       
  1220 //#endif
       
  1221 }
       
  1222 
       
  1223 
       
  1224 void testChangeLocale(TInt isrom)
       
  1225 {
       
  1226 	TLocale locale;
       
  1227 	
       
  1228 #ifdef __WINS__
       
  1229 //We get a power-change notification 1 second after switch-on
       
  1230 //So we wait for a second on WINS.
       
  1231 //Should we fix this bug??
       
  1232 	User::After(1000000);
       
  1233 #endif
       
  1234 	RChangeNotifier notifier;
       
  1235 	TInt res=notifier.Create();
       
  1236 	test(res==KErrNone);
       
  1237 	TRequestStatus stat;
       
  1238 	res=notifier.Logon(stat);
       
  1239 	test(res==KErrNone);
       
  1240 	//initial pattern of stat is already tested by t_chnot
       
  1241 
       
  1242 	res=notifier.Logon(stat);
       
  1243 	test(res==KErrNone);
       
  1244 	test(stat==KRequestPending);
       
  1245 	if (isrom == 0) 
       
  1246 		{
       
  1247 		test.Printf(_L("Change to RAM US Locale\n")); 	
       
  1248 		res=UserSvr::ChangeLocale(ELOCLUS);
       
  1249 		}
       
  1250 	else
       
  1251 		{
       
  1252 		test.Printf(_L("Change to ROM US Locale\n")); 	
       
  1253 		res=UserSvr::ChangeLocale(ELOCLUS_ROM);
       
  1254 		}
       
  1255 	test.Printf(_L("res=%d\n"),res);
       
  1256 	test(res==KErrNone);
       
  1257 	test(stat.Int() & EChangesLocale);
       
  1258 	res=notifier.Logon(stat);
       
  1259 	test(res==KErrNone);
       
  1260 	test(stat==KRequestPending);
       
  1261 	
       
  1262 	locale.Refresh();
       
  1263 	testUS(locale);
       
  1264 }
       
  1265 
       
  1266 
       
  1267 LOCAL_C void LocaleLanguageGet(SLocaleLanguage& locale)
       
  1268 {
       
  1269 	TPckg<SLocaleLanguage> localeLanguageBuf(locale);
       
  1270 	TInt r = RProperty::Get(KUidSystemCategory, KLocaleLanguageKey, localeLanguageBuf);
       
  1271 	test(r == KErrNone || r == KErrNotFound);
       
  1272 }
       
  1273 
       
  1274 LOCAL_C TInt E32TestLocale(TInt isrom)
       
  1275 {
       
  1276 	TInt r;
       
  1277 	TAny *LocaleAddr;
       
  1278 	TLocale locale;
       
  1279 	
       
  1280 	/* Setup the US Locale DLL and ensure the Locale got modified (testUS) */
       
  1281 	testChangeLocale(isrom);
       
  1282  
       
  1283 	/* Now get a pointer to some data in the DLL. This will be used to move a
       
  1284 	** page from the dll 
       
  1285 	*/
       
  1286 	SLocaleLanguage localeLanguage;
       
  1287 	LocaleLanguageGet(localeLanguage);
       
  1288 	LocaleAddr = (TAny *) localeLanguage.iDateSuffixTable;
       
  1289 	test(LocaleAddr != NULL);
       
  1290 
       
  1291 	RPageMove pagemove;
       
  1292 	r=pagemove.Open();
       
  1293 	test_KErrNone(r);
       
  1294 
       
  1295 	r=pagemove.TryMovingLocaleDll(LocaleAddr);
       
  1296 	
       
  1297 	if (isrom == 0) 
       
  1298 		{
       
  1299 		test_KErrNone(r);
       
  1300 		}
       
  1301 	else
       
  1302 		{
       
  1303 		// When the locale is in rom it is in the unpaged part of rom and 
       
  1304 		// Epoc::LinearToPhysical() won't be able to find the address.
       
  1305 		test_Equal(KErrArgument, r)
       
  1306 		}
       
  1307 
       
  1308 	test.Printf(_L("Locale Test: Page move done\n"));
       
  1309 
       
  1310 	/* Test US again. The kernel should have cached the locale informaton, so this will not
       
  1311 	 * really be testing the pagmove.
       
  1312 	 */
       
  1313 	locale.Refresh();
       
  1314 	testUS(locale);
       
  1315 	
       
  1316 	/* Reload the Default Locale */
       
  1317 	test.Printf(_L("Locale Test: Change to UK Default\n"));
       
  1318 	r=UserSvr::ChangeLocale(ELOCL_DEFAULT);	
       
  1319 	test(r==KErrNone);
       
  1320 	locale.Refresh();
       
  1321 	testUK(locale);	
       
  1322 
       
  1323 	/* This will ACTUALLY test the page which was moved by making the kernel reload the Locale
       
  1324 	 * information from the DLL. 
       
  1325 	 */
       
  1326 	if (isrom == 0) 
       
  1327 		{
       
  1328 		test.Printf(_L("RAM Locale Test: Change to US Again\n"));
       
  1329 		r=UserSvr::ChangeLocale(ELOCLUS);	
       
  1330 		}
       
  1331 	else
       
  1332 		{
       
  1333 		test.Printf(_L("ROM Locale Test: Change to US Again\n"));
       
  1334 		r=UserSvr::ChangeLocale(ELOCLUS_ROM);	
       
  1335 		}
       
  1336 
       
  1337 
       
  1338 	test(r==KErrNone);
       
  1339 	locale.Refresh();
       
  1340 	testUS(locale);
       
  1341 
       
  1342 	/* Reset the Locale to the default */
       
  1343 	r=UserSvr::ChangeLocale(ELOCL_DEFAULT);	
       
  1344 	test(r==KErrNone);
       
  1345 	locale.Refresh();
       
  1346 	testUK(locale);	
       
  1347 	return(KErrNone);
       
  1348 }
       
  1349 
       
  1350 LOCAL_C void StartCodeModifierDriver()
       
  1351 	{
       
  1352 	test.Printf(_L("Start CodeModifier Driver\n"));
       
  1353 	TInt r = User::LoadLogicalDevice(KCodeModifierName);
       
  1354 	test( r==KErrNone || r==KErrAlreadyExists);
       
  1355 	if((r = Device.Open())!=KErrNone)	
       
  1356 		{
       
  1357 		User::FreeLogicalDevice(KCodeModifierName);
       
  1358 		test.Printf(_L("Could not open LDD"));
       
  1359 		test(0);
       
  1360 		}
       
  1361 	}
       
  1362 
       
  1363 
       
  1364 LOCAL_C void StopCodeModifierDriver()
       
  1365 	{
       
  1366 
       
  1367 	test.Printf(_L("Stop Code Modifier Driver\n"));
       
  1368 	test(KErrNone==Device.CloseCodeModifier());
       
  1369 	Device.Close();
       
  1370 	User::FreeLogicalDevice(KCodeModifierName);
       
  1371 	}
       
  1372 
       
  1373 
       
  1374 LOCAL_C void TestCodeSetupDrive(RThread &thread)
       
  1375 {
       
  1376 	/* The CodeModifier driver (look in ../debug/d_codemodifier) takes two threads, we just use the
       
  1377 	** first one */
       
  1378 	test(KErrNone==Device.ThreadId(0, thread.Id()));
       
  1379 }
       
  1380 
       
  1381 
       
  1382 LOCAL_C TUint GetCodeData(TInt *CodePtr, TInt& Ignore, TInt& FirstJump, TInt& SecondJump)
       
  1383 	{ 
       
  1384 	TUint ModAddr;
       
  1385 
       
  1386 	Ignore     = *CodePtr++;
       
  1387 	ModAddr    = (TUint)CodePtr;
       
  1388 	FirstJump  = *CodePtr++;
       
  1389 	SecondJump = *CodePtr++;
       
  1390 	return ModAddr;
       
  1391 	}
       
  1392 
       
  1393 LOCAL_C TInt TestCodeModification(RPageMove &pagemove)
       
  1394 	{
       
  1395 	TInt Ignore; 
       
  1396 	TUint ModAddr;
       
  1397 	TInt FirstJump;
       
  1398 	TInt SecondJump;
       
  1399 	RThread thread;
       
  1400 	
       
  1401 	ModAddr = GetCodeData((TInt *)TestCodeModFunc, Ignore, FirstJump, SecondJump); 
       
  1402 	
       
  1403 	test.Printf(_L("User Test code Returns = %d\n"), TestCodeModFunc());
       
  1404 	test.Printf(_L("Ignore = %x First Jump = %x Second = %x \n"), Ignore, FirstJump, SecondJump);
       
  1405 	
       
  1406 	TestCodeSetupDrive(thread);
       
  1407 
       
  1408 	for (TInt i=0; i<Repitions * 10; i++)
       
  1409 		{
       
  1410 		
       
  1411 		TInt r=Device.WriteCode(0, ModAddr,SecondJump,sizeof(TInt));
       
  1412 		test_KErrNone(r);
       
  1413 		r = TestCodeModFunc();
       
  1414 		test (2 == r);
       
  1415 
       
  1416 		test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
       
  1417 
       
  1418 		r = Device.RestoreCode(0, ModAddr);
       
  1419 		test_KErrNone(r);
       
  1420 		r = TestCodeModFunc();
       
  1421 		test (1 == r);
       
  1422 		
       
  1423 		test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
       
  1424 
       
  1425 		}
       
  1426 
       
  1427 	test.Printf(_L("User Test code = %d\n"), TestCodeModFunc());
       
  1428 	return KErrNone;
       
  1429 	}
       
  1430 
       
  1431 LOCAL_C int TestCodeAsync(TAny *NotUsed)
       
  1432 	{
       
  1433 	TInt Ignore; 
       
  1434 	TUint ModAddr;
       
  1435 	TInt FirstJump;
       
  1436 	TInt SecondJump;
       
  1437 
       
  1438 	ModAddr = GetCodeData((TInt *)TestCodeModFunc, Ignore, FirstJump, SecondJump); 
       
  1439 
       
  1440 	FOREVER
       
  1441 		{
       
  1442 		TInt r = Device.WriteCode(0, ModAddr,SecondJump,sizeof(TInt));
       
  1443 		test_KErrNone(r);
       
  1444 		
       
  1445 		r = TestCodeModFunc();
       
  1446 		test (2 == r);
       
  1447 
       
  1448 		r = Device.RestoreCode(0, ModAddr);
       
  1449 	
       
  1450 		test_KErrNone(r);
       
  1451 		r = TestCodeModFunc();
       
  1452 		test (1 == r);
       
  1453 		User::AfterHighRes(10);
       
  1454 		}
       
  1455 	}
       
  1456 
       
  1457 /* 
       
  1458  * Creates a Thread that modifies its code in a tight loop while the main
       
  1459  * thread moves the functions page around
       
  1460  */
       
  1461 LOCAL_C TInt TestCodeModificationAsync(RPageMove& pagemove)
       
  1462 	{
       
  1463 	TInt ret;
       
  1464 	RThread CodeThread;
       
  1465 	TRequestStatus s;
       
  1466 
       
  1467 	
       
  1468 	/* Create the Thread to modify the code segment */
       
  1469 	test_KErrNone(CodeThread.Create(_L("TestCodeAsync"), TestCodeAsync, KDefaultStackSize, NULL, NULL));
       
  1470 	CodeThread.Logon(s);
       
  1471 	CodeThread.SetPriority(EPriorityMore);
       
  1472 	CodeThread.Resume();
       
  1473 
       
  1474 	TestCodeSetupDrive(CodeThread);
       
  1475 
       
  1476 	/* Loop trying to move the code page while the thread (CodeThread) modifies it */
       
  1477 	for (TInt i=0; i<Repitions; i++)
       
  1478 		{
       
  1479 		test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
       
  1480 		}
       
  1481 
       
  1482 	CodeThread.Kill(KErrNone);
       
  1483 	User::WaitForRequest(s);
       
  1484 	test_Equal(EExitKill, CodeThread.ExitType());
       
  1485 	test_KErrNone(CodeThread.ExitReason());
       
  1486 	CodeThread.Close();
       
  1487 
       
  1488 	ret = TestCodeModFunc();
       
  1489 	test(ret == 1 || ret == 2);
       
  1490 
       
  1491 	return KErrNone;
       
  1492 	}