kerneltest/e32test/defrag/t_pagemove.cpp
changeset 43 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 43:96e5fb8b040d
       
     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 		*(volatile TUint8*)array = *array;	// 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);
       
   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 		test_Equal(KArbitraryNumber, aFunc());	
       
   461 		TBool inuse=EFalse, success=EFalse;
       
   462 		for (TInt i=0; i < Repitions; i++)
       
   463 			{
       
   464 			TInt r = aPagemove.TryMovingUserPage(firstpage, ETrue);
       
   465 			if (i == 0)
       
   466 				{// If this is the first run allow the pinning threads to 
       
   467 				// unpin the memory now that we've definitely done at least 
       
   468 				// one page move with the page pinned.
       
   469 				_T_PRINTF(_L("signal to child\n"));
       
   470 				RThread::Rendezvous(KErrNone);
       
   471 				}
       
   472 			switch (r)
       
   473 				{
       
   474 				case KErrInUse:
       
   475 					inuse=ETrue;
       
   476 					break;
       
   477 				case KErrArgument:
       
   478 					// The page was paged out, this should only happen for paged code.
       
   479 					test(aPaged);
       
   480 					break;
       
   481 				default:
       
   482 					test_KErrNone(r);
       
   483 					success=ETrue;
       
   484 					break;
       
   485 				}
       
   486 			}
       
   487 		// Physical pinning or adding a new pinning while a page is being moved
       
   488 		// should prevent code pages being moved.
       
   489 		switch (state)
       
   490 		{
       
   491 			case ENoPinning :			
       
   492 				test(!inuse || aPaged);	// Stealing may get KErrInUse but this should only happen for paged code.
       
   493 			case EVirtualPinning :
       
   494 				test(success);
       
   495 				break;
       
   496 			case EPhysicalPinning :
       
   497 				break;
       
   498 		}
       
   499 
       
   500 		ThreadDie = ETrue;
       
   501 		EndThreads(numThreads, codeRunThread, s);
       
   502 
       
   503 		_T_PRINTF(_L("Validate page data\n"));
       
   504 		test_Equal(KArbitraryNumber, aFunc());		
       
   505 		}
       
   506 	thread.Close();
       
   507 	}
       
   508 
       
   509 
       
   510 void TestMovingRealtime(RPageMove& aPagemove, TUint8* aArray, TInt aSize, TTestFunction aFunc, TBool aCode, TBool aPaged=EFalse)
       
   511 	{
       
   512 	TThreadFunction threadFunc;
       
   513 	TLinAddr pageAddr;
       
   514 	RThread thread;
       
   515 	TUint8* firstpage;
       
   516 	thread.Open(RThread().Id());
       
   517 	SPinThreadArgs threadArgs;
       
   518 	threadArgs.iParentThread = thread;
       
   519 	if (aCode)
       
   520 		{
       
   521 		pageAddr = (TLinAddr)aFunc;
       
   522 		firstpage = (TUint8*)_ALIGN_DOWN(pageAddr, PageSize);
       
   523 		threadArgs.iLinAddr = (TLinAddr)firstpage;
       
   524 		threadFunc = RunCodeThread;
       
   525 		threadArgs.iTestFunc = aFunc;
       
   526 		test_Equal(KArbitraryNumber, aFunc());
       
   527 		}
       
   528 	else
       
   529 		{
       
   530 		pageAddr = (TLinAddr)aArray;
       
   531 		firstpage = (TUint8*)_ALIGN_DOWN(pageAddr, PageSize);
       
   532 		threadArgs.iLinAddr = (TLinAddr)aArray;
       
   533 		threadFunc = ReadWriteByte;
       
   534 		_T_PRINTF(_L("Fill the array with some data\n"));
       
   535 		for (TInt i=0; i<aSize; i++) aArray[i] = i*i;
       
   536 		}
       
   537 
       
   538 	RMemoryTestLdd ldd;
       
   539 
       
   540 	TMovingPinStage endStage = EMovingPinStages;
       
   541 	if (gPinningSupported)
       
   542 		{
       
   543 		test_KErrNone(ldd.Open());
       
   544 		test_KErrNone(ldd.CreateVirtualPinObject());
       
   545 		test_KErrNone(ldd.CreatePhysicalPinObject());
       
   546 		}
       
   547 	else
       
   548 		endStage = EVirtualPinning;
       
   549 
       
   550 	for (TUint state = ENoPinning; state < (TUint)endStage; state++)
       
   551 		{
       
   552 		switch (state)
       
   553 			{
       
   554 			case ENoPinning:
       
   555 				test.Printf(_L("Attempt to move pages while they are being accessed\n"));
       
   556 				break;
       
   557 			case EVirtualPinning:
       
   558 				test.Printf(_L("Attempt to move pages while they are virtually pinned\n"));
       
   559 				test_KErrNone(ldd.PinVirtualMemory((TLinAddr)firstpage, PageSize));
       
   560 
       
   561 				break;
       
   562 			case EPhysicalPinning:
       
   563 				test.Printf(_L("Attempt to move pages while they are physically pinned\n"));
       
   564 				test_KErrNone(ldd.PinPhysicalMemoryRO((TLinAddr)firstpage, PageSize));
       
   565 				break;
       
   566 			}
       
   567 		for (	TUint realtimeState = User::ERealtimeStateOff; 
       
   568 				realtimeState <= User::ERealtimeStateWarn; 
       
   569 				realtimeState++)
       
   570 			{
       
   571 			ThreadDie = EFalse;
       
   572 			RThread accessThread;
       
   573 			TRequestStatus s;
       
   574 			threadArgs.iRealtimeState = (User::TRealtimeState)realtimeState;
       
   575 			test_KErrNone(accessThread.Create(_L("Realtime Thread"), threadFunc, KDefaultStackSize, NULL, &threadArgs));
       
   576 			accessThread.Logon(s);
       
   577 			TRequestStatus threadInitialised;
       
   578 			accessThread.Rendezvous(threadInitialised);
       
   579 			accessThread.Resume();
       
   580 
       
   581 			_T_PRINTF(_L("wait for child\n"));
       
   582 			User::WaitForRequest(threadInitialised);
       
   583 			test_KErrNone(threadInitialised.Int());
       
   584 
       
   585 			_T_PRINTF(_L("Move page repeatedly\n"));
       
   586 			TBool success=EFalse, pagedOut=EFalse;
       
   587 			TUint inuse=0;
       
   588 			if (aCode)
       
   589 				{
       
   590 				test_Equal(KArbitraryNumber, aFunc());
       
   591 				}
       
   592 			else
       
   593 				{
       
   594 				*(volatile TUint8*)aArray = *aArray;
       
   595 				}
       
   596 
       
   597 			for (TInt i=0; i < Repitions; i++)
       
   598 				{
       
   599 				TInt r = aPagemove.TryMovingUserPage(firstpage, ETrue);
       
   600 				if (i == 0)
       
   601 					{
       
   602 					_T_PRINTF(_L("signal to child\n"));
       
   603 					RThread::Rendezvous(KErrNone);
       
   604 					}
       
   605 				switch (r)
       
   606 					{
       
   607 					case KErrInUse:
       
   608 						inuse++;
       
   609 						break;
       
   610 					case KErrArgument:
       
   611 						// The page was paged out, this should only happen for paged code.
       
   612 						test(aPaged);
       
   613 						pagedOut = ETrue;
       
   614 						break;
       
   615 					default:
       
   616 						test_KErrNone(r);
       
   617 						success=ETrue;
       
   618 						break;
       
   619 					}
       
   620 				}
       
   621 			ThreadDie = ETrue;
       
   622 			User::WaitForRequest(s);
       
   623 			test.Printf(_L("inuse %d\n"),inuse);
       
   624 			switch (state)
       
   625 				{
       
   626 				case ENoPinning :
       
   627 					test(success);
       
   628 					if (EExitPanic == accessThread.ExitType())
       
   629 						{
       
   630 						test(accessThread.ExitCategory()==_L("KERN-EXEC"));
       
   631 						test_Equal(EIllegalFunctionForRealtimeThread, accessThread.ExitReason());
       
   632 						test(aPaged && realtimeState == User::ERealtimeStateOn);
       
   633 						}
       
   634 					else
       
   635 						{
       
   636 						test_Equal(EExitKill,accessThread.ExitType());
       
   637 						test_KErrNone(accessThread.ExitReason());
       
   638 						}
       
   639 					// Ensure the page is paged in before we attempt to move it again with a different realtime state.
       
   640 					if (aCode)
       
   641 						{
       
   642 						test_Equal(KArbitraryNumber, aFunc());
       
   643 						}
       
   644 					else
       
   645 						{
       
   646 						*(volatile TUint8*)aArray = *aArray;
       
   647 						}
       
   648 					break;				
       
   649 				case EVirtualPinning :
       
   650 					test(!aCode || !inuse);
       
   651 					test(success);
       
   652 					test(!pagedOut);
       
   653 					test_Equal(EExitKill,accessThread.ExitType());
       
   654 					test_KErrNone(accessThread.ExitReason());
       
   655 					break;
       
   656 				case EPhysicalPinning :
       
   657 					test(!success);
       
   658 					break;
       
   659 				}
       
   660 			accessThread.Close();
       
   661 			}
       
   662 		if (gPinningSupported)
       
   663 			{
       
   664 			// Unpin any pinned memory.
       
   665 			test_KErrNone(ldd.UnpinVirtualMemory());
       
   666 			test_KErrNone(ldd.UnpinPhysicalMemory());
       
   667 			}
       
   668 
       
   669 		_T_PRINTF(_L("Validate page data\n"));
       
   670 		if (aCode)
       
   671 			{
       
   672 			test_Equal(KArbitraryNumber, aFunc());
       
   673 			}
       
   674 		else
       
   675 			{
       
   676 			for (TInt i=0; i<aSize; i++)
       
   677 				test_Equal((TUint8)(i*i), aArray[i]);
       
   678 			}
       
   679 			
       
   680 		}
       
   681 	if (gPinningSupported)
       
   682 		{
       
   683 		test_KErrNone(ldd.DestroyVirtualPinObject());
       
   684 		test_KErrNone(ldd.DestroyPhysicalPinObject());
       
   685 		ldd.Close();
       
   686 		}
       
   687 	thread.Close();
       
   688 	}
       
   689 
       
   690 // Only commits and decommits the first page as that is the only page that is being moved.
       
   691 // Plus this ensures the page table and page directories of the chunk are always allocated
       
   692 // and therefore prevents Epoc::LinearToPhysical() from crashing the system.
       
   693 TInt CommitDecommit(TAny* aParam)
       
   694 	{
       
   695 	RChunk* chunk = (RChunk*) aParam;
       
   696 	volatile TUint8* byte = chunk->Base();
       
   697 	FOREVER
       
   698 		{
       
   699 		*byte = *byte;
       
   700 		User::AfterHighRes(0);
       
   701 		TInt r = chunk->Decommit(0, PageSize);
       
   702 		if (r != KErrNone)
       
   703 			return r;
       
   704 		User::AfterHighRes(0);
       
   705 		r = chunk->Commit(0, PageSize);
       
   706 		if (r != KErrNone)
       
   707 			return r;
       
   708 		}
       
   709 	}
       
   710 
       
   711 void TestCommitDecommit(RPageMove& pagemove, RChunk& aChunk)
       
   712 	{
       
   713 	test.Printf(_L("Attempt to move a page while it is being committed and decommited\n"));
       
   714 	RThread thread;
       
   715 	TRequestStatus s;
       
   716 	test_KErrNone(thread.Create(_L("CommitDecommit"), &CommitDecommit, KDefaultStackSize, NULL, (TAny*)&aChunk));
       
   717 	thread.Logon(s);
       
   718 	thread.SetPriority(EPriorityMore);
       
   719 	thread.Resume();
       
   720 
       
   721 	TUint8* firstpage=(TUint8*)_ALIGN_DOWN((TLinAddr)aChunk.Base(), PageSize);
       
   722 	for (TInt i=0; i < Repitions; i++)
       
   723 		{
       
   724 		TInt r = pagemove.TryMovingUserPage(firstpage, ETrue);
       
   725 		// Allow all valid return codes as we are only testing that this doesn't 
       
   726 		// crash the kernel and the page could be commited, paged out or decommited
       
   727 		// at any one time.
       
   728 		test_Value(r, r <= KErrNone);
       
   729 		}
       
   730 
       
   731 	thread.Kill(KErrNone);
       
   732 	User::WaitForRequest(s);
       
   733 	test_Equal(EExitKill,thread.ExitType());
       
   734 	test_KErrNone(thread.ExitReason());
       
   735 	thread.Close();
       
   736 	}
       
   737 
       
   738 
       
   739 void TestPageTableDiscard(RPageMove& pagemove, TUint8* array, TUint size)
       
   740 	{
       
   741 	_T_PRINTF(_L("Fill the array with some data\n"));
       
   742 	for (TUint i=0; i<size; i++) array[i] = i*i;
       
   743 
       
   744 	TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)array, PageSize);
       
   745 	RThread thread;
       
   746 	thread.Open(RThread().Id());
       
   747 	SPinThreadArgs threadArgs;
       
   748 	threadArgs.iLinAddr = (TLinAddr)array;
       
   749 	threadArgs.iParentThread = thread;
       
   750 	threadArgs.iRealtimeState = User::ERealtimeStateOff;
       
   751 
       
   752 	TMovingPinStage endStage = EMovingPinStages;
       
   753 	if (!gPinningSupported)
       
   754 		endStage = EVirtualPinning;
       
   755 	
       
   756 	for (TUint pageTableInfo = 0; pageTableInfo < 2; pageTableInfo++)
       
   757 		{
       
   758 		for (TUint state = ENoPinning; state < (TUint)endStage; state++)
       
   759 			{
       
   760 			TThreadFunction threadFunc = NULL;
       
   761 			if (!pageTableInfo)
       
   762 			{
       
   763 			switch (state)
       
   764 				{
       
   765 				case ENoPinning:
       
   766 					test.Printf(_L("Attempt to move page tables whilst the pages they map are being modified\n"));
       
   767 					threadFunc = &ReadWriteByte;
       
   768 					break;
       
   769 				case EVirtualPinning:
       
   770 					test.Printf(_L("Attempt to move page tables whilst the pages they map are being virtually pinned\n"));
       
   771 					threadFunc = &VirtualPinPage;
       
   772 					break;
       
   773 				case EPhysicalPinning:
       
   774 					test.Printf(_L("Attempt to move page tables whilst the pages they map are being physically pinned\n"));
       
   775 					threadFunc = &PhysicalPinPage;
       
   776 					break;
       
   777 				}
       
   778 			}
       
   779 			else
       
   780 			{
       
   781 			switch (state)
       
   782 				{
       
   783 				case ENoPinning:
       
   784 					test.Printf(_L("Attempt to move page table infos whilst pages they refer to are being modified\n"));
       
   785 					threadFunc = &ReadWriteByte;
       
   786 					break;
       
   787 				case EVirtualPinning:
       
   788 					test.Printf(_L("Attempt to move page table infos whilst pages they refer to are being virtually pinned\n"));
       
   789 					threadFunc = &VirtualPinPage;
       
   790 					break;
       
   791 				case EPhysicalPinning:
       
   792 					test.Printf(_L("Attempt to move page table infos whilst pages they refer to are being physically pinned\n"));
       
   793 					threadFunc = &PhysicalPinPage;
       
   794 					break;
       
   795 				}
       
   796 			}
       
   797 			ThreadDie = EFalse;
       
   798 			TUint numThreads = (NumberOfCpus > 1) ? NumberOfCpus - 1 : 1;
       
   799 			RThread* threads = new RThread[numThreads];
       
   800 			TRequestStatus* s = new TRequestStatus[numThreads];
       
   801 			StartThreads(numThreads, threads, s, threadFunc, threadArgs);
       
   802 
       
   803 			_T_PRINTF(_L("Move first array page repeatedly\n"));
       
   804 			TUint inuse = 0;
       
   805 			for (TInt i=0; i < Repitions; i++)
       
   806 				{
       
   807 				TInt r;
       
   808 				if (!pageTableInfo)
       
   809 					r = pagemove.TryMovingPageTable(firstpage);
       
   810 				else
       
   811 					r = pagemove.TryMovingPageTableInfo(firstpage);					
       
   812 				if (i == 0)
       
   813 					{// If this is the first run allow the pinning threads to 
       
   814 					// unpin the memory now that we've definitely done at least 
       
   815 					// one page move with the page pinned.
       
   816 					_T_PRINTF(_L("signal to child\n"));
       
   817 					RThread::Rendezvous(KErrNone);
       
   818 					}
       
   819 				switch (r)
       
   820 					{
       
   821 					case KErrInUse:
       
   822 						inuse++;
       
   823 						break;
       
   824 					case KErrNotFound:
       
   825 						// The page table or page table info page was paged out.
       
   826 						break;
       
   827 					default:
       
   828 						test_KErrNone(r);
       
   829 						break;
       
   830 					}
       
   831 				}
       
   832 			test.Printf(_L("inuse %d\n"),inuse);
       
   833 			// A virtually pinned page should always return KErrInUse at least once.
       
   834 			test(state != EVirtualPinning || inuse);
       
   835 
       
   836 			ThreadDie = ETrue;
       
   837 			EndThreads(numThreads, threads, s);
       
   838 
       
   839 			_T_PRINTF(_L("Validate page data\n"));
       
   840 			for (TUint i=0; i<size; i++)
       
   841 				test_Equal((TUint8)(i*i), array[i]);
       
   842 			}
       
   843 		}
       
   844 	thread.Close();
       
   845 	}
       
   846 
       
   847 // Basic testing of moving rom pages.
       
   848 void TestMovingRom(RPageMove& aPageMove)
       
   849 	{
       
   850 	TUint8* pPage=(TUint8*)User::Alloc(PageSize);
       
   851 	test(pPage!=NULL);
       
   852 
       
   853 	TUint romHdr = UserSvr::RomHeaderAddress();
       
   854 
       
   855 	if (gPinningSupported)
       
   856 		{
       
   857 		// Pin an unpaged rom page to get the physical address of the rom page.
       
   858 		// Pinning unpaged rom actually does nothing except return the physical 
       
   859 		// address of the page.
       
   860 		RMemoryTestLdd ldd;
       
   861 		test_KErrNone(ldd.Open());
       
   862 		test_KErrNone(ldd.CreatePhysicalPinObject());
       
   863 
       
   864 		// Save contents of rom page.
       
   865 		Mem::Move(pPage,(TAny*)romHdr,PageSize);
       
   866 
       
   867 		test_KErrNone(ldd.PinPhysicalMemoryRO(romHdr, PageSize));
       
   868 		test_KErrNone(ldd.UnpinPhysicalMemory());
       
   869 
       
   870 		// Now move the page, d_memorytest saves the address of the pinned page
       
   871 		// depsite it being unpinned.
       
   872 		// Will get KErrArgument as rom pages don't have an SPageInfo so memory
       
   873 		// model doesn't treat rom as though they are in ram, which in most cases 
       
   874 		// they are.
       
   875 		test_Equal(KErrArgument, ldd.MovePinnedPhysicalMemory(0));
       
   876 
       
   877 		test_KErrNone(Mem::Compare((TUint8*)romHdr,PageSize,pPage,PageSize));
       
   878 		test_KErrNone(ldd.DestroyPhysicalPinObject());
       
   879 		ldd.Close();
       
   880 		}
       
   881 
       
   882 	if (gRomPagingSupported)
       
   883 		{
       
   884 		// Use paged part of rom for testing
       
   885 		TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
       
   886 		test(romHeader->iPageableRomStart);
       
   887 		TUint romAddr = (TUint)((TUint8*)romHeader + romHeader->iPageableRomStart + 64 * PageSize);
       
   888 
       
   889 		// We will use the 64th pagable rom page so check that it exists.
       
   890 		test(romHeader->iPageableRomSize >= 65 * PageSize);
       
   891 	
       
   892 		// Page in the rom page and save it contents.
       
   893 		Mem::Move(pPage,(TAny*)romAddr,PageSize);
       
   894 		// This will actually discard the page not move it.
       
   895 		test_KErrNone(aPageMove.TryMovingUserPage(pPage));
       
   896 
       
   897 		test_KErrNone(Mem::Compare((TUint8*)romAddr,PageSize,pPage,PageSize));
       
   898 		}
       
   899 	}
       
   900 
       
   901 
       
   902 void TestMovingCodeChunk(RPageMove& pagemove, RChunk aChunk, TBool aPagedData)
       
   903 	{
       
   904 	TUint8* p = aChunk.Base();
       
   905 
       
   906 	TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)p, PageSize);
       
   907 	RThread thread;
       
   908 	thread.Open(RThread().Id());
       
   909 	SPinThreadArgs threadArgs;
       
   910 	threadArgs.iLinAddr = (TLinAddr)p;
       
   911 	threadArgs.iParentThread = thread;
       
   912 
       
   913 	test.Printf(_L("Attempt to move pages while they are being executed and modified\n"));
       
   914 	ThreadDie = EFalse;
       
   915 	RThread modCodeThread;
       
   916 	TRequestStatus s;
       
   917 	test_KErrNone(modCodeThread.Create(_L("User Data thread"), &ModifyCodeThread, KDefaultStackSize, NULL, &threadArgs));
       
   918 	modCodeThread.Logon(s);
       
   919 	TRequestStatus threadInitialised;
       
   920 	modCodeThread.Rendezvous(threadInitialised);
       
   921 	modCodeThread.Resume();
       
   922 
       
   923 	_T_PRINTF(_L("wait for child\n"));
       
   924 	User::WaitForRequest(threadInitialised);
       
   925 	test_KErrNone(threadInitialised.Int());
       
   926 
       
   927 	_T_PRINTF(_L("Move code chunk page repeatedly\n"));
       
   928 	TBool success=EFalse;
       
   929 	*(volatile TUint8*)p = *p; // Ensure the page of the first entry is paged in for the first move.
       
   930 	for (TInt i=0; i < Repitions; i++)
       
   931 		{
       
   932 		TInt r = pagemove.TryMovingUserPage(firstpage, ETrue);
       
   933 		if (i == 0)
       
   934 			{// If this is the first run allow the modifying thread to run now 
       
   935 			// we've done one move.
       
   936 			_T_PRINTF(_L("signal to child\n"));
       
   937 			RThread::Rendezvous(KErrNone);
       
   938 			}
       
   939 		switch (r)
       
   940 			{
       
   941 			case KErrInUse:
       
   942 				break;
       
   943 			case KErrArgument:
       
   944 				// The page was paged out, this should only happen for paged data.
       
   945 				test(aPagedData);
       
   946 				break;
       
   947 			default:
       
   948 				test_KErrNone(r);
       
   949 				success=ETrue;
       
   950 				break;
       
   951 			}
       
   952 		}
       
   953 	test(success);
       
   954 
       
   955 	ThreadDie = ETrue;
       
   956 	User::WaitForRequest(s);
       
   957 	test_Equal(EExitKill,modCodeThread.ExitType());
       
   958 	test_KErrNone(modCodeThread.ExitReason());
       
   959 	modCodeThread.Close();
       
   960 
       
   961 	thread.Close();
       
   962 	}
       
   963 
       
   964 GLDEF_C TInt E32Main()
       
   965     {
       
   966 	test.Title();
       
   967 	if (!HaveMMU())
       
   968 		{
       
   969 		test.Printf(_L("This test requires an MMU\n"));
       
   970 		return KErrNone;
       
   971 		}
       
   972 
       
   973 	test.Start(_L("Load test LDD"));
       
   974 	TInt r=User::LoadLogicalDevice(KLddFileName);
       
   975 	test(r==KErrNone || r==KErrAlreadyExists);
       
   976 
       
   977 	test_KErrNone(UserHal::PageSizeInBytes(PageSize));
       
   978 
       
   979 	// Determine which types of paging are supported
       
   980 	TUint32 attrs = DPTest::Attributes();
       
   981 	gRomPagingSupported = (attrs & DPTest::ERomPaging) != 0;
       
   982 	gCodePagingSupported = (attrs & DPTest::ECodePaging) != 0;
       
   983 	gDataPagingSupported = (attrs & DPTest::EDataPaging) != 0;
       
   984 
       
   985 	// Does this memory model support pinning.
       
   986 	TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
       
   987 	gPinningSupported = mm >= EMemModelTypeFlexible;
       
   988 
       
   989 	RPageMove pagemove;
       
   990 	test.Next(_L("Open test LDD"));
       
   991 	test_KErrNone(pagemove.Open());
       
   992 
       
   993 	// Determine whether this is a smp device.
       
   994 	NumberOfCpus = pagemove.NumberOfCpus();
       
   995 	if (NumberOfCpus > 1)
       
   996 		Repitions = 1000;	// SMP system therefore likely to get KErrInUse in less repitions.
       
   997 
       
   998 	test.Next(_L("Attempting to move regular local data pages"));
       
   999 		{
       
  1000 		const TInt size=16384;
       
  1001 		TUint8* array = new TUint8[size];
       
  1002 		test_NotNull(array);
       
  1003 
       
  1004 		TestUserData(pagemove, array, size);
       
  1005 
       
  1006 		_T_PRINTF(_L("Walk heap\n"));
       
  1007 		User::Check();
       
  1008 
       
  1009 		delete [] array;
       
  1010 		}
       
  1011 
       
  1012 	test.Next(_L("Attempting to move regular global coarse data pages"));
       
  1013 		{
       
  1014 		const TInt size=1<<20;	// Make this chunk multiple of 1MB so it is a coarse memory object on FMM
       
  1015 		RChunk chunk;
       
  1016 		test_KErrNone(chunk.CreateDisconnectedGlobal(_L("Dave"), 0, size, size));
       
  1017 		TUint8* array = chunk.Base();
       
  1018 
       
  1019 		TestUserData(pagemove, array, size);
       
  1020 		TestMovingRealtime(pagemove, array, size, NULL, EFalse);
       
  1021 		TestCommitDecommit(pagemove, chunk);
       
  1022 
       
  1023 		chunk.Close();
       
  1024 		}
       
  1025 
       
  1026 	if (gDataPagingSupported)
       
  1027 		{
       
  1028 		test.Next(_L("Attempting to move demand paged fine local user data pages"));
       
  1029 		const TInt size=16384;
       
  1030 		TChunkCreateInfo createInfo;
       
  1031 		createInfo.SetDisconnected(0, size, size);
       
  1032 		createInfo.SetPaging(TChunkCreateInfo::EPaged);
       
  1033 		RChunk chunk;
       
  1034 		test_KErrNone(chunk.Create(createInfo));
       
  1035 		TUint8* array = chunk.Base();
       
  1036 
       
  1037 		TestUserData(pagemove, array, size, ETrue);
       
  1038 		TestMovingRealtime(pagemove, array, size, NULL, EFalse, ETrue);
       
  1039 		TestPageTableDiscard(pagemove, array, size);
       
  1040 		TestCommitDecommit(pagemove, chunk);
       
  1041 		chunk.Close();
       
  1042 
       
  1043 		test.Next(_L("Attempting to move demand paged coarse global user data pages"));
       
  1044 		const TInt sizeCoarse = 1 << 20; // Make this chunk multiple of 1MB so it is a coarse memory object on FMM
       
  1045 		TChunkCreateInfo createInfoCoarse;
       
  1046 		createInfoCoarse.SetDisconnected(0, sizeCoarse, sizeCoarse);
       
  1047 		createInfoCoarse.SetGlobal(_L("Dave"));
       
  1048 		createInfoCoarse.SetPaging(TChunkCreateInfo::EPaged);
       
  1049 		RChunk chunkCoarse;
       
  1050 		test_KErrNone(chunkCoarse.Create(createInfoCoarse));
       
  1051 		array = chunkCoarse.Base();
       
  1052 
       
  1053 		TestUserData(pagemove, array, sizeCoarse, ETrue);
       
  1054 		TestMovingRealtime(pagemove, array, sizeCoarse, NULL, EFalse, ETrue);
       
  1055 		TestPageTableDiscard(pagemove, array, sizeCoarse);
       
  1056 		TestCommitDecommit(pagemove, chunkCoarse);
       
  1057 		chunkCoarse.Close();
       
  1058 		}
       
  1059 
       
  1060 	test.Next(_L("Attempting to move DLL writable static data pages"));
       
  1061 		{
       
  1062 		const TInt size=16384;
       
  1063 		TUint8* array = DllWsd::Address();
       
  1064 
       
  1065 		TestUserData(pagemove, array, size);
       
  1066 		}
       
  1067 
       
  1068 	test.Next(_L("Attempting to move user self-mod code chunk page when IMB'ing and executing"));
       
  1069 	RChunk codeChunk;
       
  1070 	test_KErrNone(codeChunk.CreateLocalCode(PageSize,PageSize));
       
  1071 	TestMovingCodeChunk(pagemove, codeChunk, EFalse);
       
  1072 	codeChunk.Close();
       
  1073 
       
  1074 	if (gDataPagingSupported)
       
  1075 		{
       
  1076 		test.Next(_L("Attempting to move paged user self-mod code chunk page when IMB'ing and executing"));
       
  1077 		TChunkCreateInfo createInfo;
       
  1078 		createInfo.SetCode(PageSize, PageSize);
       
  1079 		createInfo.SetPaging(TChunkCreateInfo::EPaged);
       
  1080 
       
  1081 		RChunk pagedCodeChunk;
       
  1082 		test_KErrNone(pagedCodeChunk.Create(createInfo));
       
  1083 		TestMovingCodeChunk(pagemove, pagedCodeChunk, ETrue);
       
  1084 		pagedCodeChunk.Close();
       
  1085 		}
       
  1086 
       
  1087 	test.Next(_L("Attempting to move RAM drive"));
       
  1088 	if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMultiple)
       
  1089 		{
       
  1090 		for (TInt i=0; i<Repitions; i++)
       
  1091 			test_KErrNone(pagemove.TryMovingUserPage((TAny*)0xA0000000));
       
  1092 		}
       
  1093 	else if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMoving)
       
  1094 		{
       
  1095 		for (TInt i=0; i<Repitions; i++)
       
  1096 			test_KErrNone(pagemove.TryMovingUserPage((TAny*)0x40000000));
       
  1097 		}
       
  1098 	else if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeFlexible)
       
  1099 		{
       
  1100 		// do nothing, RAM drive is not special
       
  1101 		}
       
  1102 	else
       
  1103 		{
       
  1104 		test.Printf(_L("Don't know where the RAM drive is!"));
       
  1105 		test(0);
       
  1106 		}
       
  1107 	
       
  1108 #if 0
       
  1109 	test.Next(_L("Attempting to move kernel heap pages"));
       
  1110 	for (TInt i=0; i<Repitions; i++)
       
  1111 		test_KErrNone(pagemove.TryMovingKHeap());
       
  1112 #endif
       
  1113 
       
  1114 	if ((MemModelAttributes()&EMemModelTypeMask) != EMemModelTypeFlexible)
       
  1115 		{// Only the moving and multiple memory models move kernel stack pages.
       
  1116 		test.Next(_L("Attempting to move kernel stack pages"));
       
  1117 		for (TInt i=0; i<Repitions; i++)
       
  1118 			test_KErrNone(pagemove.TryMovingKStack());
       
  1119 		}
       
  1120 
       
  1121 	test.Next(_L("Attempting to move ROM pages"));
       
  1122 	TestMovingRom(pagemove);
       
  1123 
       
  1124 	test.Next(_L("Attempting to move kernel code pages"));
       
  1125 	for (TInt i=0; i<Repitions; i++)
       
  1126 		test_KErrNone(pagemove.TryMovingKCode());
       
  1127 
       
  1128 	test.Next(_L("Attempting to move regular code pages"));
       
  1129 	TestMovingCode(pagemove, RamLoadedFunction);
       
  1130 	TestMovingRealtime(pagemove, NULL, 0, RamLoadedFunction, ETrue, EFalse);
       
  1131 
       
  1132 	if (gCodePagingSupported)
       
  1133 		{
       
  1134 		test.Next(_L("Attempting to move demand paged code pages"));
       
  1135 		TestMovingCode(pagemove, DllTestFunction, ETrue);
       
  1136 		TestMovingRealtime(pagemove, NULL, 0, DllTestFunction, ETrue, ETrue);
       
  1137 		}
       
  1138 
       
  1139 	/* Setup CodeModifier Test Driver */
       
  1140 	StartCodeModifierDriver();
       
  1141 	test(KErrNone==Device.InitialiseCodeModifier(/* Max break points */ 5 ));
       
  1142 
       
  1143 	test.Next(_L("Attempting to move code page being modified\n"));
       
  1144 	test_KErrNone(TestCodeModification(pagemove));
       
  1145 
       
  1146 	test.Next(_L("Attempting to move code (async) while page being modified"));
       
  1147 	test_KErrNone(TestCodeModificationAsync(pagemove));
       
  1148 
       
  1149 	StopCodeModifierDriver();
       
  1150 	
       
  1151 	test.Next(_L("Attempting to move ROM Locale DLL Page"));
       
  1152 	test_KErrNone(E32TestLocale(1));
       
  1153 
       
  1154 	test.Next(_L("Attempting to move RAM Locale DLL Page"));
       
  1155 	test_KErrNone(E32TestLocale(0));
       
  1156 
       
  1157 	test.Next(_L("Close test LDD"));
       
  1158 	pagemove.Close();
       
  1159 	User::FreeLogicalDevice(KLddFileName);
       
  1160 
       
  1161 	test.End();
       
  1162 	return(KErrNone);
       
  1163     }
       
  1164 
       
  1165 
       
  1166 void testUS(const TLocale& aLocale)
       
  1167 {
       
  1168 	test.Printf(_L("Test US\n"));
       
  1169 
       
  1170 	test(aLocale.CountryCode()==1);
       
  1171 	test(aLocale.DateFormat()==EDateAmerican);
       
  1172 	test(aLocale.TimeFormat()==ETime12);
       
  1173 	test(aLocale.CurrencySymbolPosition()==ELocaleBefore);
       
  1174 	test(aLocale.CurrencySpaceBetween()==FALSE);
       
  1175 	test(aLocale.CurrencyDecimalPlaces()==2);
       
  1176 	test(aLocale.CurrencyNegativeInBrackets()==EFalse);
       
  1177 	test(aLocale.CurrencyTriadsAllowed()==TRUE);
       
  1178 	test(aLocale.ThousandsSeparator()==',');
       
  1179 	test(aLocale.DecimalSeparator()=='.');
       
  1180 	test(aLocale.DateSeparator(0)==0);
       
  1181 	test(aLocale.DateSeparator(1)=='/');
       
  1182 	test(aLocale.DateSeparator(2)=='/');
       
  1183 	test(aLocale.DateSeparator(3)==0);
       
  1184 	test(aLocale.TimeSeparator(0)==0);
       
  1185 	test(aLocale.TimeSeparator(1)==':');
       
  1186 	test(aLocale.TimeSeparator(2)==':');
       
  1187 	test(aLocale.TimeSeparator(3)==0);
       
  1188 	test(aLocale.AmPmSymbolPosition()==TRUE);
       
  1189 	test(aLocale.AmPmSpaceBetween()==TRUE);
       
  1190 	test(aLocale.HomeDaylightSavingZone()==EDstNorthern);
       
  1191 	test(aLocale.WorkDays()==0x1f);
       
  1192 	test(aLocale.StartOfWeek()==ESunday);
       
  1193 	test(aLocale.ClockFormat()==EClockAnalog);
       
  1194 	test(aLocale.UnitsGeneral()==EUnitsImperial);
       
  1195 	test(aLocale.UnitsDistanceShort()==EUnitsImperial);
       
  1196 	test(aLocale.UnitsDistanceLong()==EUnitsImperial);
       
  1197 }
       
  1198 
       
  1199 
       
  1200 void testUK(const TLocale& aLocale)
       
  1201 {
       
  1202 //#ifdef __WINS__
       
  1203 	test(aLocale.CountryCode()==44);
       
  1204 	test(aLocale.DateFormat()==EDateEuropean);
       
  1205 	test(aLocale.TimeFormat()==ETime12);
       
  1206 	test(aLocale.CurrencySymbolPosition()==ELocaleBefore);
       
  1207 	test(aLocale.CurrencySpaceBetween()==FALSE);
       
  1208 	test(aLocale.CurrencyDecimalPlaces()==2);
       
  1209 	test(aLocale.CurrencyNegativeInBrackets()==EFalse);
       
  1210 	test(aLocale.CurrencyTriadsAllowed()==TRUE);
       
  1211 	test(aLocale.ThousandsSeparator()==',');
       
  1212 	test(aLocale.DecimalSeparator()=='.');
       
  1213 	test(aLocale.DateSeparator(0)==0);
       
  1214 	test(aLocale.DateSeparator(1)=='/');
       
  1215 	test(aLocale.DateSeparator(2)=='/');
       
  1216 	test(aLocale.DateSeparator(3)==0);
       
  1217 	test(aLocale.TimeSeparator(0)==0);
       
  1218 	test(aLocale.TimeSeparator(1)==':');
       
  1219 	test(aLocale.TimeSeparator(2)==':');
       
  1220 	test(aLocale.TimeSeparator(3)==0);
       
  1221 	test(aLocale.AmPmSymbolPosition()==TRUE);
       
  1222 	test(aLocale.AmPmSpaceBetween()==TRUE);
       
  1223 	test(aLocale.HomeDaylightSavingZone()==EDstEuropean);
       
  1224 	test(aLocale.WorkDays()==0x1f);
       
  1225 	test(aLocale.StartOfWeek()==EMonday);
       
  1226 	test(aLocale.ClockFormat()==EClockAnalog);
       
  1227 	test(aLocale.UnitsGeneral()==EUnitsImperial);
       
  1228 	test(aLocale.UnitsDistanceShort()==EUnitsImperial);
       
  1229 	test(aLocale.UnitsDistanceLong()==EUnitsImperial);
       
  1230 //#endif
       
  1231 }
       
  1232 
       
  1233 
       
  1234 void testChangeLocale(TInt isrom)
       
  1235 {
       
  1236 	TLocale locale;
       
  1237 	
       
  1238 #ifdef __WINS__
       
  1239 //We get a power-change notification 1 second after switch-on
       
  1240 //So we wait for a second on WINS.
       
  1241 //Should we fix this bug??
       
  1242 	User::After(1000000);
       
  1243 #endif
       
  1244 	RChangeNotifier notifier;
       
  1245 	TInt res=notifier.Create();
       
  1246 	test(res==KErrNone);
       
  1247 	TRequestStatus stat;
       
  1248 	res=notifier.Logon(stat);
       
  1249 	test(res==KErrNone);
       
  1250 	//initial pattern of stat is already tested by t_chnot
       
  1251 
       
  1252 	res=notifier.Logon(stat);
       
  1253 	test(res==KErrNone);
       
  1254 	test(stat==KRequestPending);
       
  1255 	if (isrom == 0) 
       
  1256 		{
       
  1257 		test.Printf(_L("Change to RAM US Locale\n")); 	
       
  1258 		res=UserSvr::ChangeLocale(ELOCLUS);
       
  1259 		}
       
  1260 	else
       
  1261 		{
       
  1262 		test.Printf(_L("Change to ROM US Locale\n")); 	
       
  1263 		res=UserSvr::ChangeLocale(ELOCLUS_ROM);
       
  1264 		}
       
  1265 	test.Printf(_L("res=%d\n"),res);
       
  1266 	test(res==KErrNone);
       
  1267 	test(stat.Int() & EChangesLocale);
       
  1268 	res=notifier.Logon(stat);
       
  1269 	test(res==KErrNone);
       
  1270 	test(stat==KRequestPending);
       
  1271 	
       
  1272 	locale.Refresh();
       
  1273 	testUS(locale);
       
  1274 }
       
  1275 
       
  1276 
       
  1277 LOCAL_C void LocaleLanguageGet(SLocaleLanguage& locale)
       
  1278 {
       
  1279 	TPckg<SLocaleLanguage> localeLanguageBuf(locale);
       
  1280 	TInt r = RProperty::Get(KUidSystemCategory, KLocaleLanguageKey, localeLanguageBuf);
       
  1281 	test(r == KErrNone || r == KErrNotFound);
       
  1282 }
       
  1283 
       
  1284 LOCAL_C TInt E32TestLocale(TInt isrom)
       
  1285 {
       
  1286 	TInt r;
       
  1287 	TAny *LocaleAddr;
       
  1288 	TLocale locale;
       
  1289 	
       
  1290 	/* Setup the US Locale DLL and ensure the Locale got modified (testUS) */
       
  1291 	testChangeLocale(isrom);
       
  1292  
       
  1293 	/* Now get a pointer to some data in the DLL. This will be used to move a
       
  1294 	** page from the dll 
       
  1295 	*/
       
  1296 	SLocaleLanguage localeLanguage;
       
  1297 	LocaleLanguageGet(localeLanguage);
       
  1298 	LocaleAddr = (TAny *) localeLanguage.iDateSuffixTable;
       
  1299 	test(LocaleAddr != NULL);
       
  1300 
       
  1301 	RPageMove pagemove;
       
  1302 	r=pagemove.Open();
       
  1303 	test_KErrNone(r);
       
  1304 
       
  1305 	r=pagemove.TryMovingLocaleDll(LocaleAddr);
       
  1306 	
       
  1307 	if (isrom == 0) 
       
  1308 		{
       
  1309 		test_KErrNone(r);
       
  1310 		}
       
  1311 	else
       
  1312 		{
       
  1313 		// When the locale is in rom it is in the unpaged part of rom and 
       
  1314 		// Epoc::LinearToPhysical() won't be able to find the address.
       
  1315 		test_Equal(KErrArgument, r)
       
  1316 		}
       
  1317 
       
  1318 	test.Printf(_L("Locale Test: Page move done\n"));
       
  1319 
       
  1320 	/* Test US again. The kernel should have cached the locale informaton, so this will not
       
  1321 	 * really be testing the pagmove.
       
  1322 	 */
       
  1323 	locale.Refresh();
       
  1324 	testUS(locale);
       
  1325 	
       
  1326 	/* Reload the Default Locale */
       
  1327 	test.Printf(_L("Locale Test: Change to UK Default\n"));
       
  1328 	r=UserSvr::ChangeLocale(ELOCL_DEFAULT);	
       
  1329 	test(r==KErrNone);
       
  1330 	locale.Refresh();
       
  1331 	testUK(locale);	
       
  1332 
       
  1333 	/* This will ACTUALLY test the page which was moved by making the kernel reload the Locale
       
  1334 	 * information from the DLL. 
       
  1335 	 */
       
  1336 	if (isrom == 0) 
       
  1337 		{
       
  1338 		test.Printf(_L("RAM Locale Test: Change to US Again\n"));
       
  1339 		r=UserSvr::ChangeLocale(ELOCLUS);	
       
  1340 		}
       
  1341 	else
       
  1342 		{
       
  1343 		test.Printf(_L("ROM Locale Test: Change to US Again\n"));
       
  1344 		r=UserSvr::ChangeLocale(ELOCLUS_ROM);	
       
  1345 		}
       
  1346 
       
  1347 
       
  1348 	test(r==KErrNone);
       
  1349 	locale.Refresh();
       
  1350 	testUS(locale);
       
  1351 
       
  1352 	/* Reset the Locale to the default */
       
  1353 	r=UserSvr::ChangeLocale(ELOCL_DEFAULT);	
       
  1354 	test(r==KErrNone);
       
  1355 	locale.Refresh();
       
  1356 	testUK(locale);	
       
  1357 	return(KErrNone);
       
  1358 }
       
  1359 
       
  1360 LOCAL_C void StartCodeModifierDriver()
       
  1361 	{
       
  1362 	test.Printf(_L("Start CodeModifier Driver\n"));
       
  1363 	TInt r = User::LoadLogicalDevice(KCodeModifierName);
       
  1364 	test( r==KErrNone || r==KErrAlreadyExists);
       
  1365 	if((r = Device.Open())!=KErrNone)	
       
  1366 		{
       
  1367 		User::FreeLogicalDevice(KCodeModifierName);
       
  1368 		test.Printf(_L("Could not open LDD"));
       
  1369 		test(0);
       
  1370 		}
       
  1371 	}
       
  1372 
       
  1373 
       
  1374 LOCAL_C void StopCodeModifierDriver()
       
  1375 	{
       
  1376 
       
  1377 	test.Printf(_L("Stop Code Modifier Driver\n"));
       
  1378 	test(KErrNone==Device.CloseCodeModifier());
       
  1379 	Device.Close();
       
  1380 	User::FreeLogicalDevice(KCodeModifierName);
       
  1381 	}
       
  1382 
       
  1383 
       
  1384 LOCAL_C void TestCodeSetupDrive(RThread &thread)
       
  1385 {
       
  1386 	/* The CodeModifier driver (look in ../debug/d_codemodifier) takes two threads, we just use the
       
  1387 	** first one */
       
  1388 	test(KErrNone==Device.ThreadId(0, thread.Id()));
       
  1389 }
       
  1390 
       
  1391 
       
  1392 LOCAL_C TUint GetCodeData(TInt *CodePtr, TInt& Ignore, TInt& FirstJump, TInt& SecondJump)
       
  1393 	{ 
       
  1394 	TUint ModAddr;
       
  1395 
       
  1396 	Ignore     = *CodePtr++;
       
  1397 	ModAddr    = (TUint)CodePtr;
       
  1398 	FirstJump  = *CodePtr++;
       
  1399 	SecondJump = *CodePtr++;
       
  1400 	return ModAddr;
       
  1401 	}
       
  1402 
       
  1403 LOCAL_C TInt TestCodeModification(RPageMove &pagemove)
       
  1404 	{
       
  1405 	TInt Ignore; 
       
  1406 	TUint ModAddr;
       
  1407 	TInt FirstJump;
       
  1408 	TInt SecondJump;
       
  1409 	RThread thread;
       
  1410 	
       
  1411 	ModAddr = GetCodeData((TInt *)TestCodeModFunc, Ignore, FirstJump, SecondJump); 
       
  1412 	
       
  1413 	test.Printf(_L("User Test code Returns = %d\n"), TestCodeModFunc());
       
  1414 	test.Printf(_L("Ignore = %x First Jump = %x Second = %x \n"), Ignore, FirstJump, SecondJump);
       
  1415 	
       
  1416 	TestCodeSetupDrive(thread);
       
  1417 
       
  1418 	for (TInt i=0; i<Repitions * 10; i++)
       
  1419 		{
       
  1420 		
       
  1421 		TInt r=Device.WriteCode(0, ModAddr,SecondJump,sizeof(TInt));
       
  1422 		test_KErrNone(r);
       
  1423 		r = TestCodeModFunc();
       
  1424 		test (2 == r);
       
  1425 
       
  1426 		test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
       
  1427 
       
  1428 		r = Device.RestoreCode(0, ModAddr);
       
  1429 		test_KErrNone(r);
       
  1430 		r = TestCodeModFunc();
       
  1431 		test (1 == r);
       
  1432 		
       
  1433 		test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
       
  1434 
       
  1435 		}
       
  1436 
       
  1437 	test.Printf(_L("User Test code = %d\n"), TestCodeModFunc());
       
  1438 	return KErrNone;
       
  1439 	}
       
  1440 
       
  1441 LOCAL_C int TestCodeAsync(TAny *NotUsed)
       
  1442 	{
       
  1443 	TInt Ignore; 
       
  1444 	TUint ModAddr;
       
  1445 	TInt FirstJump;
       
  1446 	TInt SecondJump;
       
  1447 
       
  1448 	ModAddr = GetCodeData((TInt *)TestCodeModFunc, Ignore, FirstJump, SecondJump); 
       
  1449 
       
  1450 	FOREVER
       
  1451 		{
       
  1452 		TInt r = Device.WriteCode(0, ModAddr,SecondJump,sizeof(TInt));
       
  1453 		test_KErrNone(r);
       
  1454 		
       
  1455 		r = TestCodeModFunc();
       
  1456 		test (2 == r);
       
  1457 
       
  1458 		r = Device.RestoreCode(0, ModAddr);
       
  1459 	
       
  1460 		test_KErrNone(r);
       
  1461 		r = TestCodeModFunc();
       
  1462 		test (1 == r);
       
  1463 		User::AfterHighRes(10);
       
  1464 		}
       
  1465 	}
       
  1466 
       
  1467 /* 
       
  1468  * Creates a Thread that modifies its code in a tight loop while the main
       
  1469  * thread moves the functions page around
       
  1470  */
       
  1471 LOCAL_C TInt TestCodeModificationAsync(RPageMove& pagemove)
       
  1472 	{
       
  1473 	TInt ret;
       
  1474 	RThread CodeThread;
       
  1475 	TRequestStatus s;
       
  1476 
       
  1477 	
       
  1478 	/* Create the Thread to modify the code segment */
       
  1479 	test_KErrNone(CodeThread.Create(_L("TestCodeAsync"), TestCodeAsync, KDefaultStackSize, NULL, NULL));
       
  1480 	CodeThread.Logon(s);
       
  1481 	CodeThread.SetPriority(EPriorityMore);
       
  1482 	CodeThread.Resume();
       
  1483 
       
  1484 	TestCodeSetupDrive(CodeThread);
       
  1485 
       
  1486 	/* Loop trying to move the code page while the thread (CodeThread) modifies it */
       
  1487 	for (TInt i=0; i<Repitions; i++)
       
  1488 		{
       
  1489 		test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
       
  1490 		}
       
  1491 
       
  1492 	CodeThread.Kill(KErrNone);
       
  1493 	User::WaitForRequest(s);
       
  1494 	test_Equal(EExitKill, CodeThread.ExitType());
       
  1495 	test_KErrNone(CodeThread.ExitReason());
       
  1496 	CodeThread.Close();
       
  1497 
       
  1498 	ret = TestCodeModFunc();
       
  1499 	test(ret == 1 || ret == 2);
       
  1500 
       
  1501 	return KErrNone;
       
  1502 	}