1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/defrag/t_pagemove.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1502 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\defrag\t_pagemove.cpp
1.18 +
1.19 +//
1.20 +//--------------------------------------------------------------------------------------------------
1.21 +//! @SYMTestCaseID KBASE-T_PAGEMOVE-0572
1.22 +//! @SYMTestType UT
1.23 +//! @SYMPREQ PREQ308
1.24 +//! @SYMTestCaseDesc Test physical page moving
1.25 +//! t_pagemove loads and opens the logical device driver ("D_PAGEMOVE.LDD").
1.26 +//! Following this, it requests that the driver attempt to move
1.27 +//! various kinds of pages directly.
1.28 +//!
1.29 +//! API Information:
1.30 +//! RBusLogicalChannel
1.31 +//!
1.32 +//! Platforms/Drives/Compatibility:
1.33 +//! Hardware only. No defrag support on emulator.
1.34 +//!
1.35 +//! @SYMTestActions 1 - Move regular local data pages
1.36 +//! 2 - Move regular global data pages
1.37 +//! 3 - Move DLL writable static data pages
1.38 +//! 4 - Move user self-modifying code chunk pages
1.39 +//! 5 - Move RAM drive pages
1.40 +//! 6 - Move kernel heap pages (*********DISABLED************)
1.41 +//! 7 - Move kernel stack pages
1.42 +//! 8 - Move kernel code pages
1.43 +//! 9 - Move regular code pages
1.44 +//! 10 - Move code whilst the page is being modified
1.45 +//! 11 - Move code (async) whilst the page is being modified
1.46 +//! 12 - Move ROM locale DLL pages
1.47 +//! 13 - Move RAM locale DLL pages
1.48 +//! 14 - Moving pages whilst they are being virtually pinned and unpinned.
1.49 +//! 15 - Moving pages whilst they are being physically pinned and unpinned.
1.50 +//! @SYMTestExpectedResults All tests should pass.
1.51 +//! @SYMTestPriority High
1.52 +//! @SYMTestStatus Implemented
1.53 +//--------------------------------------------------------------------------------------------------
1.54 +//
1.55 +#define __E32TEST_EXTENSION__
1.56 +#include <e32test.h>
1.57 +#include <e32math.h>
1.58 +#include <e32uid.h>
1.59 +#include <e32hal.h>
1.60 +#include <e32std.h>
1.61 +#include <e32std_private.h>
1.62 +#include <dptest.h>
1.63 +#include "d_pagemove.h"
1.64 +#include "t_pagemove_dll.h"
1.65 +#include "t_pmwsd.h"
1.66 +#include "..\mmu\mmudetect.h"
1.67 +#include "..\debug\d_codemodifier.h"
1.68 +#include "..\mmu\d_memorytest.h"
1.69 +
1.70 +//#define _DEBUG_MSG
1.71 +#ifdef _DEBUG_MSG
1.72 +#define _R_PRINTF(x) RDebug::Printf(x)
1.73 +#define _T_PRINTF(x) test.Printf(x)
1.74 +#else
1.75 +#define _R_PRINTF(x)
1.76 +#define _T_PRINTF(x)
1.77 +#endif
1.78 +
1.79 +LOCAL_D RTest test(_L("T_PAGEMOVE"));
1.80 +
1.81 +_LIT(ELOCL_DEFAULT, "");
1.82 +_LIT(ELOCLUS, "T_LOCLUS_RAM");
1.83 +_LIT(ELOCLUS_ROM, "T_LOCLUS");
1.84 +LOCAL_C TInt E32TestLocale(TInt);
1.85 +
1.86 +RCodeModifierDevice Device;
1.87 +extern TInt TestCodeModFunc();
1.88 +
1.89 +extern TInt Increment(TInt);
1.90 +extern TUint Increment_Length();
1.91 +extern TInt Decrement(TInt);
1.92 +extern TUint Decrement_Length();
1.93 +typedef TInt (*PFI)(TInt);
1.94 +
1.95 +LOCAL_C void StartCodeModifierDriver();
1.96 +LOCAL_C void StopCodeModifierDriver();
1.97 +LOCAL_C TInt TestCodeModification(RPageMove &);
1.98 +LOCAL_C TInt TestCodeModificationAsync(RPageMove& pagemove);
1.99 +
1.100 +
1.101 +const TPtrC KLddFileName=_L("D_PAGEMOVE.LDD");
1.102 +TInt Repitions=4000;
1.103 +
1.104 +TInt PageSize;
1.105 +TUint NumberOfCpus;
1.106 +
1.107 +volatile TBool ThreadDie;
1.108 +
1.109 +TBool gDataPagingSupported;
1.110 +TBool gRomPagingSupported;
1.111 +TBool gCodePagingSupported;
1.112 +TBool gPinningSupported;
1.113 +
1.114 +// This executable is ram loaded (see mmp file) so this function will do fine
1.115 +// as a test of RAM-loaded code.
1.116 +TInt RamLoadedFunction()
1.117 + {
1.118 + return KArbitraryNumber;
1.119 + }
1.120 +
1.121 +struct SPinThreadArgs
1.122 + {
1.123 + TLinAddr iLinAddr;
1.124 + TTestFunction iTestFunc;
1.125 + RThread iParentThread;
1.126 + User::TRealtimeState iRealtimeState;
1.127 + };
1.128 +
1.129 +
1.130 +void StartThreads( TUint aNumThreads, RThread* aThreads, TRequestStatus* aStatus,
1.131 + TThreadFunction aThreadFunc, SPinThreadArgs& aThreadArgs)
1.132 + {
1.133 + for (TUint i = 0; i < aNumThreads; i++)
1.134 + {
1.135 + test_KErrNone(aThreads[i].Create(KNullDesC, aThreadFunc, KDefaultStackSize, NULL, &aThreadArgs));
1.136 + aThreads[i].Logon(aStatus[i]);
1.137 + TRequestStatus threadInitialised;
1.138 + aThreads[i].Rendezvous(threadInitialised);
1.139 + aThreads[i].Resume();
1.140 + _T_PRINTF(_L("wait for child\n"));
1.141 + User::WaitForRequest(threadInitialised);
1.142 + test_KErrNone(threadInitialised.Int());
1.143 + }
1.144 + }
1.145 +
1.146 +void EndThreads(TUint aNumThreads, RThread* aThreads, TRequestStatus* aStatus)
1.147 + {
1.148 + for (TUint i = 0; i < aNumThreads; i++)
1.149 + {
1.150 + User::WaitForRequest(aStatus[i]);
1.151 + test_Equal(EExitKill, aThreads[i].ExitType());
1.152 + test_KErrNone(aThreads[i].ExitReason());
1.153 + aThreads[i].Close();
1.154 + }
1.155 + }
1.156 +
1.157 +
1.158 +void Reschedule(TInt64& aSeed)
1.159 + {
1.160 + if (NumberOfCpus == 1)
1.161 + {
1.162 + TInt rand = Math::Rand(aSeed);
1.163 + if ((rand & 0x5) == 5)
1.164 + User::AfterHighRes(rand & 0x7);
1.165 + }
1.166 + }
1.167 +
1.168 +TInt ReadWriteByte(TAny* aParam)
1.169 + {
1.170 + SPinThreadArgs* args = (SPinThreadArgs*)aParam;
1.171 + volatile TUint8* byte = (volatile TUint8*)args->iLinAddr;
1.172 + TInt64 seed = Math::Random()*Math::Random();
1.173 +
1.174 + test_KErrNone(User::SetRealtimeState(args->iRealtimeState));
1.175 +
1.176 + // Ensure the the parentThread has moved the page at least once
1.177 + // before we start accessing it.
1.178 + TRequestStatus status;
1.179 + args->iParentThread.Rendezvous(status);
1.180 + RThread::Rendezvous(KErrNone);
1.181 + _R_PRINTF("wait for parent");
1.182 + User::WaitForRequest(status);
1.183 + _R_PRINTF("acesssing page");
1.184 +
1.185 + FOREVER
1.186 + {
1.187 + *byte = *byte;
1.188 + Reschedule(seed);
1.189 + if (ThreadDie)
1.190 + break;
1.191 + }
1.192 + return KErrNone;
1.193 + }
1.194 +
1.195 +
1.196 +TInt RunCodeThread(TAny* aParam)
1.197 + {
1.198 + TInt64 seed = Math::Random()*Math::Random();
1.199 + SPinThreadArgs* args = (SPinThreadArgs*)aParam;
1.200 +
1.201 + test_KErrNone(User::SetRealtimeState(args->iRealtimeState));
1.202 +
1.203 + // Ensure the the parentThread has moved the page at least once
1.204 + // before we start accessing it.
1.205 + TRequestStatus status;
1.206 + args->iParentThread.Rendezvous(status);
1.207 + RThread::Rendezvous(KErrNone);
1.208 + _R_PRINTF("wait for parent");
1.209 + User::WaitForRequest(status);
1.210 + _R_PRINTF("acesssing page");
1.211 +
1.212 + FOREVER
1.213 + {
1.214 + TInt r = args->iTestFunc();
1.215 + if (r != KArbitraryNumber)
1.216 + return KErrGeneral;
1.217 + Reschedule(seed);
1.218 + if (ThreadDie)
1.219 + break;
1.220 + }
1.221 + return KErrNone;
1.222 + }
1.223 +
1.224 +
1.225 +TInt VirtualPinPage(TAny* aParam)
1.226 + {
1.227 + TInt64 seed = Math::Random()*Math::Random();
1.228 + SPinThreadArgs* args = (SPinThreadArgs*)aParam;
1.229 + RMemoryTestLdd ldd;
1.230 + test_KErrNone(ldd.Open());
1.231 +
1.232 + test_KErrNone(ldd.CreateVirtualPinObject());
1.233 +
1.234 + TBool firstRun = ETrue;
1.235 + FOREVER
1.236 + {
1.237 + // Pin the page of aParam.
1.238 + test_KErrNone(ldd.PinVirtualMemory(args->iLinAddr, PageSize));
1.239 + if (firstRun)
1.240 + {// On the first run ensure that the page is definitely pinned when
1.241 + // the parent thread first attempts to move it.
1.242 + TRequestStatus status;
1.243 + args->iParentThread.Rendezvous(status);
1.244 + RThread::Rendezvous(KErrNone);
1.245 + User::WaitForRequest(status);
1.246 + test_KErrNone(status.Int());
1.247 + firstRun = EFalse;
1.248 + }
1.249 + Reschedule(seed);
1.250 + test_KErrNone(ldd.UnpinVirtualMemory());
1.251 + if (ThreadDie)
1.252 + break;
1.253 + }
1.254 + test_KErrNone(ldd.DestroyVirtualPinObject());
1.255 + ldd.Close();
1.256 + return KErrNone;
1.257 + }
1.258 +
1.259 +
1.260 +TInt PhysicalPinPage(TAny* aParam)
1.261 + {
1.262 + TInt64 seed = Math::Random()*Math::Random();
1.263 + SPinThreadArgs* args = (SPinThreadArgs*)aParam;
1.264 +
1.265 + RMemoryTestLdd ldd;
1.266 + test_KErrNone(ldd.Open());
1.267 +
1.268 + test_KErrNone(ldd.CreatePhysicalPinObject());
1.269 +
1.270 + TBool firstRun = ETrue;
1.271 + FOREVER
1.272 + {
1.273 + // Pin the page of aParam, use a read only pinning so that pinning code
1.274 + // doesn't return KErrAccessDenied as writable mappings not allowed on code.
1.275 + test_KErrNone(ldd.PinPhysicalMemoryRO(args->iLinAddr, PageSize));
1.276 + if (firstRun)
1.277 + {// On the first run ensure that the page is definitely pinned when
1.278 + // the parent thread first attempts to move it.
1.279 + TRequestStatus status;
1.280 + args->iParentThread.Rendezvous(status);
1.281 + RThread::Rendezvous(KErrNone);
1.282 + User::WaitForRequest(status);
1.283 + test_KErrNone(status.Int());
1.284 + firstRun = EFalse;
1.285 + }
1.286 + Reschedule(seed);
1.287 + test_KErrNone(ldd.UnpinPhysicalMemory());
1.288 + if (ThreadDie)
1.289 + break;
1.290 + }
1.291 + test_KErrNone(ldd.DestroyPhysicalPinObject());
1.292 + ldd.Close();
1.293 + return KErrNone;
1.294 + }
1.295 +
1.296 +TInt ModifyCodeThread(TAny* aParam)
1.297 + {
1.298 + SPinThreadArgs* args = (SPinThreadArgs*)aParam;
1.299 + TUint8* p = (TUint8*)args->iLinAddr;
1.300 + PFI func = (PFI)p;
1.301 +
1.302 + // Ensure the the parentThread has moved the page at least once
1.303 + // before we start accessing it.
1.304 + TRequestStatus status;
1.305 + args->iParentThread.Rendezvous(status);
1.306 + RThread::Rendezvous(KErrNone);
1.307 + _R_PRINTF("wait for parent");
1.308 + User::WaitForRequest(status);
1.309 + _R_PRINTF("modifiying page");
1.310 +
1.311 + while (!ThreadDie)
1.312 + {
1.313 + Mem::Copy(p, (TAny*)&Increment, Increment_Length());
1.314 + User::IMB_Range(p, p+Increment_Length());
1.315 + test_Equal(8, func(7));
1.316 +
1.317 + Mem::Copy(p, (TAny*)&Decrement, Decrement_Length());
1.318 + User::IMB_Range(p, p+Decrement_Length());
1.319 + test_Equal(6, func(7));
1.320 + }
1.321 + return KErrNone;
1.322 + }
1.323 +
1.324 +
1.325 +enum TMovingPinStage
1.326 + {
1.327 + ENoPinning,
1.328 + EVirtualPinning,
1.329 + EPhysicalPinning,
1.330 + EMovingPinStages,
1.331 + };
1.332 +
1.333 +void TestUserData(RPageMove& pagemove, TUint8* array, TInt size, TBool aPagedData=EFalse)
1.334 + {
1.335 + _T_PRINTF(_L("Fill the array with some data\n"));
1.336 + for (TInt i=0; i<size; i++) array[i] = i*i;
1.337 +
1.338 + TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)array, PageSize);
1.339 + RThread thread;
1.340 + thread.Open(RThread().Id());
1.341 + SPinThreadArgs threadArgs;
1.342 + threadArgs.iLinAddr = (TLinAddr)array;
1.343 + threadArgs.iParentThread = thread;
1.344 + threadArgs.iRealtimeState = User::ERealtimeStateOff;
1.345 +
1.346 + TMovingPinStage endStage = EMovingPinStages;
1.347 + if (!gPinningSupported)
1.348 + endStage = EVirtualPinning;
1.349 +
1.350 + for (TUint state = ENoPinning; state < (TUint)endStage; state++)
1.351 + {
1.352 + TThreadFunction threadFunc = NULL;
1.353 + switch (state)
1.354 + {
1.355 + case ENoPinning:
1.356 + test.Printf(_L("Attempt to move pages while they are being modified\n"));
1.357 + threadFunc = &ReadWriteByte;
1.358 + break;
1.359 + case EVirtualPinning:
1.360 + test.Printf(_L("Attempt to move pages while they are being virtually pinned\n"));
1.361 + threadFunc = &VirtualPinPage;
1.362 + break;
1.363 + case EPhysicalPinning:
1.364 + test.Printf(_L("Attempt to move pages while they are being physically pinned\n"));
1.365 + threadFunc = &PhysicalPinPage;
1.366 + break;
1.367 + }
1.368 + ThreadDie = EFalse;
1.369 + TUint numThreads = (NumberOfCpus > 1) ? NumberOfCpus - 1 : 1;
1.370 + RThread* userDataThread = new RThread[numThreads];
1.371 + TRequestStatus* s = new TRequestStatus[numThreads];
1.372 + StartThreads(numThreads, userDataThread, s, threadFunc, threadArgs);
1.373 +
1.374 + _T_PRINTF(_L("Move first array page repeatedly\n"));
1.375 + TBool success=EFalse;
1.376 + TUint inuse = 0;
1.377 + *(volatile TUint8*)array = *array; // Ensure the page of the first entry is paged in for the first move.
1.378 + for (TInt i=0; i < Repitions*2; i++)
1.379 + {
1.380 + TInt r = pagemove.TryMovingUserPage(firstpage, ETrue);
1.381 + if (i == 0)
1.382 + {// If this is the first run allow the pinning threads to
1.383 + // unpin the memory now that we've definitely done at least
1.384 + // one page move with the page pinned.
1.385 + _T_PRINTF(_L("signal to child\n"));
1.386 + RThread::Rendezvous(KErrNone);
1.387 + }
1.388 + switch (r)
1.389 + {
1.390 + case KErrInUse:
1.391 + inuse++;
1.392 + break;
1.393 + case KErrArgument:
1.394 + // The page was paged out, this should only happen for paged data.
1.395 + test(aPagedData);
1.396 + break;
1.397 + default:
1.398 + test_KErrNone(r);
1.399 + success=ETrue;
1.400 + break;
1.401 + }
1.402 + }
1.403 + // Can't guarantee that for paged data the page and its page tables will
1.404 + // be paged in, in most cases it will be at least once.
1.405 + // Pinning the page should always return KErrInUse except for virtually
1.406 + // pinned non-paged memory as virtual pinning is a nop for unpaged memory.
1.407 + test.Printf(_L("inuse test removed; inuse %d\n"),inuse);
1.408 + //test(inuse || aPagedData || state == EVirtualPinning);
1.409 + test(success || state == EPhysicalPinning);
1.410 +
1.411 + ThreadDie = ETrue;
1.412 + EndThreads(numThreads, userDataThread, s);
1.413 +
1.414 + _T_PRINTF(_L("Validate page data\n"));
1.415 + for (TInt i=0; i<size; i++)
1.416 + test_Equal((TUint8)(i*i), array[i]);
1.417 + }
1.418 + thread.Close();
1.419 + }
1.420 +
1.421 +
1.422 +void TestMovingCode(RPageMove& aPagemove, TTestFunction aFunc, TBool aPaged=EFalse)
1.423 + {
1.424 + TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)aFunc, PageSize);
1.425 + RThread thread;
1.426 + thread.Open(RThread().Id());
1.427 + SPinThreadArgs threadArgs;
1.428 + threadArgs.iLinAddr = (TLinAddr)firstpage;
1.429 + threadArgs.iTestFunc = aFunc;
1.430 + threadArgs.iParentThread = thread;
1.431 + threadArgs.iRealtimeState = User::ERealtimeStateOff;
1.432 +
1.433 + TMovingPinStage endStage = EMovingPinStages;
1.434 + if (!gPinningSupported)
1.435 + endStage = EVirtualPinning;
1.436 +
1.437 + for (TUint state = ENoPinning; state < (TUint)endStage; state++)
1.438 + {
1.439 + TThreadFunction threadFunc = NULL;
1.440 + switch (state)
1.441 + {
1.442 + case ENoPinning:
1.443 + test.Printf(_L("Attempt to move pages while they are being executed\n"));
1.444 + threadFunc = &RunCodeThread;
1.445 + test_Equal(KArbitraryNumber, aFunc()); // Ensure the page is paged in.
1.446 + break;
1.447 + case EVirtualPinning:
1.448 + test.Printf(_L("Attempt to move pages while they are being virtually pinned\n"));
1.449 + threadFunc = &VirtualPinPage;
1.450 + break;
1.451 + case EPhysicalPinning:
1.452 + test.Printf(_L("Attempt to move pages while they are being physically pinned\n"));
1.453 + threadFunc = &PhysicalPinPage;
1.454 + break;
1.455 + }
1.456 + ThreadDie = EFalse;
1.457 + TUint numThreads = (NumberOfCpus > 1) ? NumberOfCpus - 1 : 1;
1.458 + RThread* codeRunThread = new RThread[numThreads];
1.459 + TRequestStatus* s = new TRequestStatus[numThreads];
1.460 + StartThreads(numThreads, codeRunThread, s, threadFunc, threadArgs);
1.461 +
1.462 + _T_PRINTF(_L("Move first code page repeatedly\n"));
1.463 + test_Equal(KArbitraryNumber, aFunc());
1.464 + TBool inuse=EFalse, success=EFalse;
1.465 + for (TInt i=0; i < Repitions; i++)
1.466 + {
1.467 + TInt r = aPagemove.TryMovingUserPage(firstpage, ETrue);
1.468 + if (i == 0)
1.469 + {// If this is the first run allow the pinning threads to
1.470 + // unpin the memory now that we've definitely done at least
1.471 + // one page move with the page pinned.
1.472 + _T_PRINTF(_L("signal to child\n"));
1.473 + RThread::Rendezvous(KErrNone);
1.474 + }
1.475 + switch (r)
1.476 + {
1.477 + case KErrInUse:
1.478 + inuse=ETrue;
1.479 + break;
1.480 + case KErrArgument:
1.481 + // The page was paged out, this should only happen for paged code.
1.482 + test(aPaged);
1.483 + break;
1.484 + default:
1.485 + test_KErrNone(r);
1.486 + success=ETrue;
1.487 + break;
1.488 + }
1.489 + }
1.490 + // Physical pinning or adding a new pinning while a page is being moved
1.491 + // should prevent code pages being moved.
1.492 + switch (state)
1.493 + {
1.494 + case ENoPinning :
1.495 + test(!inuse || aPaged); // Stealing may get KErrInUse but this should only happen for paged code.
1.496 + case EVirtualPinning :
1.497 + test(success);
1.498 + break;
1.499 + case EPhysicalPinning :
1.500 + break;
1.501 + }
1.502 +
1.503 + ThreadDie = ETrue;
1.504 + EndThreads(numThreads, codeRunThread, s);
1.505 +
1.506 + _T_PRINTF(_L("Validate page data\n"));
1.507 + test_Equal(KArbitraryNumber, aFunc());
1.508 + }
1.509 + thread.Close();
1.510 + }
1.511 +
1.512 +
1.513 +void TestMovingRealtime(RPageMove& aPagemove, TUint8* aArray, TInt aSize, TTestFunction aFunc, TBool aCode, TBool aPaged=EFalse)
1.514 + {
1.515 + TThreadFunction threadFunc;
1.516 + TLinAddr pageAddr;
1.517 + RThread thread;
1.518 + TUint8* firstpage;
1.519 + thread.Open(RThread().Id());
1.520 + SPinThreadArgs threadArgs;
1.521 + threadArgs.iParentThread = thread;
1.522 + if (aCode)
1.523 + {
1.524 + pageAddr = (TLinAddr)aFunc;
1.525 + firstpage = (TUint8*)_ALIGN_DOWN(pageAddr, PageSize);
1.526 + threadArgs.iLinAddr = (TLinAddr)firstpage;
1.527 + threadFunc = RunCodeThread;
1.528 + threadArgs.iTestFunc = aFunc;
1.529 + test_Equal(KArbitraryNumber, aFunc());
1.530 + }
1.531 + else
1.532 + {
1.533 + pageAddr = (TLinAddr)aArray;
1.534 + firstpage = (TUint8*)_ALIGN_DOWN(pageAddr, PageSize);
1.535 + threadArgs.iLinAddr = (TLinAddr)aArray;
1.536 + threadFunc = ReadWriteByte;
1.537 + _T_PRINTF(_L("Fill the array with some data\n"));
1.538 + for (TInt i=0; i<aSize; i++) aArray[i] = i*i;
1.539 + }
1.540 +
1.541 + RMemoryTestLdd ldd;
1.542 +
1.543 + TMovingPinStage endStage = EMovingPinStages;
1.544 + if (gPinningSupported)
1.545 + {
1.546 + test_KErrNone(ldd.Open());
1.547 + test_KErrNone(ldd.CreateVirtualPinObject());
1.548 + test_KErrNone(ldd.CreatePhysicalPinObject());
1.549 + }
1.550 + else
1.551 + endStage = EVirtualPinning;
1.552 +
1.553 + for (TUint state = ENoPinning; state < (TUint)endStage; state++)
1.554 + {
1.555 + switch (state)
1.556 + {
1.557 + case ENoPinning:
1.558 + test.Printf(_L("Attempt to move pages while they are being accessed\n"));
1.559 + break;
1.560 + case EVirtualPinning:
1.561 + test.Printf(_L("Attempt to move pages while they are virtually pinned\n"));
1.562 + test_KErrNone(ldd.PinVirtualMemory((TLinAddr)firstpage, PageSize));
1.563 +
1.564 + break;
1.565 + case EPhysicalPinning:
1.566 + test.Printf(_L("Attempt to move pages while they are physically pinned\n"));
1.567 + test_KErrNone(ldd.PinPhysicalMemoryRO((TLinAddr)firstpage, PageSize));
1.568 + break;
1.569 + }
1.570 + for ( TUint realtimeState = User::ERealtimeStateOff;
1.571 + realtimeState <= User::ERealtimeStateWarn;
1.572 + realtimeState++)
1.573 + {
1.574 + ThreadDie = EFalse;
1.575 + RThread accessThread;
1.576 + TRequestStatus s;
1.577 + threadArgs.iRealtimeState = (User::TRealtimeState)realtimeState;
1.578 + test_KErrNone(accessThread.Create(_L("Realtime Thread"), threadFunc, KDefaultStackSize, NULL, &threadArgs));
1.579 + accessThread.Logon(s);
1.580 + TRequestStatus threadInitialised;
1.581 + accessThread.Rendezvous(threadInitialised);
1.582 + accessThread.Resume();
1.583 +
1.584 + _T_PRINTF(_L("wait for child\n"));
1.585 + User::WaitForRequest(threadInitialised);
1.586 + test_KErrNone(threadInitialised.Int());
1.587 +
1.588 + _T_PRINTF(_L("Move page repeatedly\n"));
1.589 + TBool success=EFalse, pagedOut=EFalse;
1.590 + TUint inuse=0;
1.591 + if (aCode)
1.592 + {
1.593 + test_Equal(KArbitraryNumber, aFunc());
1.594 + }
1.595 + else
1.596 + {
1.597 + *(volatile TUint8*)aArray = *aArray;
1.598 + }
1.599 +
1.600 + for (TInt i=0; i < Repitions; i++)
1.601 + {
1.602 + TInt r = aPagemove.TryMovingUserPage(firstpage, ETrue);
1.603 + if (i == 0)
1.604 + {
1.605 + _T_PRINTF(_L("signal to child\n"));
1.606 + RThread::Rendezvous(KErrNone);
1.607 + }
1.608 + switch (r)
1.609 + {
1.610 + case KErrInUse:
1.611 + inuse++;
1.612 + break;
1.613 + case KErrArgument:
1.614 + // The page was paged out, this should only happen for paged code.
1.615 + test(aPaged);
1.616 + pagedOut = ETrue;
1.617 + break;
1.618 + default:
1.619 + test_KErrNone(r);
1.620 + success=ETrue;
1.621 + break;
1.622 + }
1.623 + }
1.624 + ThreadDie = ETrue;
1.625 + User::WaitForRequest(s);
1.626 + test.Printf(_L("inuse %d\n"),inuse);
1.627 + switch (state)
1.628 + {
1.629 + case ENoPinning :
1.630 + test(success);
1.631 + if (EExitPanic == accessThread.ExitType())
1.632 + {
1.633 + test(accessThread.ExitCategory()==_L("KERN-EXEC"));
1.634 + test_Equal(EIllegalFunctionForRealtimeThread, accessThread.ExitReason());
1.635 + test(aPaged && realtimeState == User::ERealtimeStateOn);
1.636 + }
1.637 + else
1.638 + {
1.639 + test_Equal(EExitKill,accessThread.ExitType());
1.640 + test_KErrNone(accessThread.ExitReason());
1.641 + }
1.642 + // Ensure the page is paged in before we attempt to move it again with a different realtime state.
1.643 + if (aCode)
1.644 + {
1.645 + test_Equal(KArbitraryNumber, aFunc());
1.646 + }
1.647 + else
1.648 + {
1.649 + *(volatile TUint8*)aArray = *aArray;
1.650 + }
1.651 + break;
1.652 + case EVirtualPinning :
1.653 + test(!aCode || !inuse);
1.654 + test(success);
1.655 + test(!pagedOut);
1.656 + test_Equal(EExitKill,accessThread.ExitType());
1.657 + test_KErrNone(accessThread.ExitReason());
1.658 + break;
1.659 + case EPhysicalPinning :
1.660 + test(!success);
1.661 + break;
1.662 + }
1.663 + accessThread.Close();
1.664 + }
1.665 + if (gPinningSupported)
1.666 + {
1.667 + // Unpin any pinned memory.
1.668 + test_KErrNone(ldd.UnpinVirtualMemory());
1.669 + test_KErrNone(ldd.UnpinPhysicalMemory());
1.670 + }
1.671 +
1.672 + _T_PRINTF(_L("Validate page data\n"));
1.673 + if (aCode)
1.674 + {
1.675 + test_Equal(KArbitraryNumber, aFunc());
1.676 + }
1.677 + else
1.678 + {
1.679 + for (TInt i=0; i<aSize; i++)
1.680 + test_Equal((TUint8)(i*i), aArray[i]);
1.681 + }
1.682 +
1.683 + }
1.684 + if (gPinningSupported)
1.685 + {
1.686 + test_KErrNone(ldd.DestroyVirtualPinObject());
1.687 + test_KErrNone(ldd.DestroyPhysicalPinObject());
1.688 + ldd.Close();
1.689 + }
1.690 + thread.Close();
1.691 + }
1.692 +
1.693 +// Only commits and decommits the first page as that is the only page that is being moved.
1.694 +// Plus this ensures the page table and page directories of the chunk are always allocated
1.695 +// and therefore prevents Epoc::LinearToPhysical() from crashing the system.
1.696 +TInt CommitDecommit(TAny* aParam)
1.697 + {
1.698 + RChunk* chunk = (RChunk*) aParam;
1.699 + volatile TUint8* byte = chunk->Base();
1.700 + FOREVER
1.701 + {
1.702 + *byte = *byte;
1.703 + User::AfterHighRes(0);
1.704 + TInt r = chunk->Decommit(0, PageSize);
1.705 + if (r != KErrNone)
1.706 + return r;
1.707 + User::AfterHighRes(0);
1.708 + r = chunk->Commit(0, PageSize);
1.709 + if (r != KErrNone)
1.710 + return r;
1.711 + }
1.712 + }
1.713 +
1.714 +void TestCommitDecommit(RPageMove& pagemove, RChunk& aChunk)
1.715 + {
1.716 + test.Printf(_L("Attempt to move a page while it is being committed and decommited\n"));
1.717 + RThread thread;
1.718 + TRequestStatus s;
1.719 + test_KErrNone(thread.Create(_L("CommitDecommit"), &CommitDecommit, KDefaultStackSize, NULL, (TAny*)&aChunk));
1.720 + thread.Logon(s);
1.721 + thread.SetPriority(EPriorityMore);
1.722 + thread.Resume();
1.723 +
1.724 + TUint8* firstpage=(TUint8*)_ALIGN_DOWN((TLinAddr)aChunk.Base(), PageSize);
1.725 + for (TInt i=0; i < Repitions; i++)
1.726 + {
1.727 + TInt r = pagemove.TryMovingUserPage(firstpage, ETrue);
1.728 + // Allow all valid return codes as we are only testing that this doesn't
1.729 + // crash the kernel and the page could be commited, paged out or decommited
1.730 + // at any one time.
1.731 + test_Value(r, r <= KErrNone);
1.732 + }
1.733 +
1.734 + thread.Kill(KErrNone);
1.735 + User::WaitForRequest(s);
1.736 + test_Equal(EExitKill,thread.ExitType());
1.737 + test_KErrNone(thread.ExitReason());
1.738 + thread.Close();
1.739 + }
1.740 +
1.741 +
1.742 +void TestPageTableDiscard(RPageMove& pagemove, TUint8* array, TUint size)
1.743 + {
1.744 + _T_PRINTF(_L("Fill the array with some data\n"));
1.745 + for (TUint i=0; i<size; i++) array[i] = i*i;
1.746 +
1.747 + TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)array, PageSize);
1.748 + RThread thread;
1.749 + thread.Open(RThread().Id());
1.750 + SPinThreadArgs threadArgs;
1.751 + threadArgs.iLinAddr = (TLinAddr)array;
1.752 + threadArgs.iParentThread = thread;
1.753 + threadArgs.iRealtimeState = User::ERealtimeStateOff;
1.754 +
1.755 + TMovingPinStage endStage = EMovingPinStages;
1.756 + if (!gPinningSupported)
1.757 + endStage = EVirtualPinning;
1.758 +
1.759 + for (TUint pageTableInfo = 0; pageTableInfo < 2; pageTableInfo++)
1.760 + {
1.761 + for (TUint state = ENoPinning; state < (TUint)endStage; state++)
1.762 + {
1.763 + TThreadFunction threadFunc = NULL;
1.764 + if (!pageTableInfo)
1.765 + {
1.766 + switch (state)
1.767 + {
1.768 + case ENoPinning:
1.769 + test.Printf(_L("Attempt to move page tables whilst the pages they map are being modified\n"));
1.770 + threadFunc = &ReadWriteByte;
1.771 + break;
1.772 + case EVirtualPinning:
1.773 + test.Printf(_L("Attempt to move page tables whilst the pages they map are being virtually pinned\n"));
1.774 + threadFunc = &VirtualPinPage;
1.775 + break;
1.776 + case EPhysicalPinning:
1.777 + test.Printf(_L("Attempt to move page tables whilst the pages they map are being physically pinned\n"));
1.778 + threadFunc = &PhysicalPinPage;
1.779 + break;
1.780 + }
1.781 + }
1.782 + else
1.783 + {
1.784 + switch (state)
1.785 + {
1.786 + case ENoPinning:
1.787 + test.Printf(_L("Attempt to move page table infos whilst pages they refer to are being modified\n"));
1.788 + threadFunc = &ReadWriteByte;
1.789 + break;
1.790 + case EVirtualPinning:
1.791 + test.Printf(_L("Attempt to move page table infos whilst pages they refer to are being virtually pinned\n"));
1.792 + threadFunc = &VirtualPinPage;
1.793 + break;
1.794 + case EPhysicalPinning:
1.795 + test.Printf(_L("Attempt to move page table infos whilst pages they refer to are being physically pinned\n"));
1.796 + threadFunc = &PhysicalPinPage;
1.797 + break;
1.798 + }
1.799 + }
1.800 + ThreadDie = EFalse;
1.801 + TUint numThreads = (NumberOfCpus > 1) ? NumberOfCpus - 1 : 1;
1.802 + RThread* threads = new RThread[numThreads];
1.803 + TRequestStatus* s = new TRequestStatus[numThreads];
1.804 + StartThreads(numThreads, threads, s, threadFunc, threadArgs);
1.805 +
1.806 + _T_PRINTF(_L("Move first array page repeatedly\n"));
1.807 + TUint inuse = 0;
1.808 + for (TInt i=0; i < Repitions; i++)
1.809 + {
1.810 + TInt r;
1.811 + if (!pageTableInfo)
1.812 + r = pagemove.TryMovingPageTable(firstpage);
1.813 + else
1.814 + r = pagemove.TryMovingPageTableInfo(firstpage);
1.815 + if (i == 0)
1.816 + {// If this is the first run allow the pinning threads to
1.817 + // unpin the memory now that we've definitely done at least
1.818 + // one page move with the page pinned.
1.819 + _T_PRINTF(_L("signal to child\n"));
1.820 + RThread::Rendezvous(KErrNone);
1.821 + }
1.822 + switch (r)
1.823 + {
1.824 + case KErrInUse:
1.825 + inuse++;
1.826 + break;
1.827 + case KErrNotFound:
1.828 + // The page table or page table info page was paged out.
1.829 + break;
1.830 + default:
1.831 + test_KErrNone(r);
1.832 + break;
1.833 + }
1.834 + }
1.835 + test.Printf(_L("inuse %d\n"),inuse);
1.836 + // A virtually pinned page should always return KErrInUse at least once.
1.837 + test(state != EVirtualPinning || inuse);
1.838 +
1.839 + ThreadDie = ETrue;
1.840 + EndThreads(numThreads, threads, s);
1.841 +
1.842 + _T_PRINTF(_L("Validate page data\n"));
1.843 + for (TUint i=0; i<size; i++)
1.844 + test_Equal((TUint8)(i*i), array[i]);
1.845 + }
1.846 + }
1.847 + thread.Close();
1.848 + }
1.849 +
1.850 +// Basic testing of moving rom pages.
1.851 +void TestMovingRom(RPageMove& aPageMove)
1.852 + {
1.853 + TUint8* pPage=(TUint8*)User::Alloc(PageSize);
1.854 + test(pPage!=NULL);
1.855 +
1.856 + TUint romHdr = UserSvr::RomHeaderAddress();
1.857 +
1.858 + if (gPinningSupported)
1.859 + {
1.860 + // Pin an unpaged rom page to get the physical address of the rom page.
1.861 + // Pinning unpaged rom actually does nothing except return the physical
1.862 + // address of the page.
1.863 + RMemoryTestLdd ldd;
1.864 + test_KErrNone(ldd.Open());
1.865 + test_KErrNone(ldd.CreatePhysicalPinObject());
1.866 +
1.867 + // Save contents of rom page.
1.868 + Mem::Move(pPage,(TAny*)romHdr,PageSize);
1.869 +
1.870 + test_KErrNone(ldd.PinPhysicalMemoryRO(romHdr, PageSize));
1.871 + test_KErrNone(ldd.UnpinPhysicalMemory());
1.872 +
1.873 + // Now move the page, d_memorytest saves the address of the pinned page
1.874 + // depsite it being unpinned.
1.875 + // Will get KErrArgument as rom pages don't have an SPageInfo so memory
1.876 + // model doesn't treat rom as though they are in ram, which in most cases
1.877 + // they are.
1.878 + test_Equal(KErrArgument, ldd.MovePinnedPhysicalMemory(0));
1.879 +
1.880 + test_KErrNone(Mem::Compare((TUint8*)romHdr,PageSize,pPage,PageSize));
1.881 + test_KErrNone(ldd.DestroyPhysicalPinObject());
1.882 + ldd.Close();
1.883 + }
1.884 +
1.885 + if (gRomPagingSupported)
1.886 + {
1.887 + // Use paged part of rom for testing
1.888 + TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
1.889 + test(romHeader->iPageableRomStart);
1.890 + TUint romAddr = (TUint)((TUint8*)romHeader + romHeader->iPageableRomStart + 64 * PageSize);
1.891 +
1.892 + // We will use the 64th pagable rom page so check that it exists.
1.893 + test(romHeader->iPageableRomSize >= 65 * PageSize);
1.894 +
1.895 + // Page in the rom page and save it contents.
1.896 + Mem::Move(pPage,(TAny*)romAddr,PageSize);
1.897 + // This will actually discard the page not move it.
1.898 + test_KErrNone(aPageMove.TryMovingUserPage(pPage));
1.899 +
1.900 + test_KErrNone(Mem::Compare((TUint8*)romAddr,PageSize,pPage,PageSize));
1.901 + }
1.902 + }
1.903 +
1.904 +
1.905 +void TestMovingCodeChunk(RPageMove& pagemove, RChunk aChunk, TBool aPagedData)
1.906 + {
1.907 + TUint8* p = aChunk.Base();
1.908 +
1.909 + TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)p, PageSize);
1.910 + RThread thread;
1.911 + thread.Open(RThread().Id());
1.912 + SPinThreadArgs threadArgs;
1.913 + threadArgs.iLinAddr = (TLinAddr)p;
1.914 + threadArgs.iParentThread = thread;
1.915 +
1.916 + test.Printf(_L("Attempt to move pages while they are being executed and modified\n"));
1.917 + ThreadDie = EFalse;
1.918 + RThread modCodeThread;
1.919 + TRequestStatus s;
1.920 + test_KErrNone(modCodeThread.Create(_L("User Data thread"), &ModifyCodeThread, KDefaultStackSize, NULL, &threadArgs));
1.921 + modCodeThread.Logon(s);
1.922 + TRequestStatus threadInitialised;
1.923 + modCodeThread.Rendezvous(threadInitialised);
1.924 + modCodeThread.Resume();
1.925 +
1.926 + _T_PRINTF(_L("wait for child\n"));
1.927 + User::WaitForRequest(threadInitialised);
1.928 + test_KErrNone(threadInitialised.Int());
1.929 +
1.930 + _T_PRINTF(_L("Move code chunk page repeatedly\n"));
1.931 + TBool success=EFalse;
1.932 + *(volatile TUint8*)p = *p; // Ensure the page of the first entry is paged in for the first move.
1.933 + for (TInt i=0; i < Repitions; i++)
1.934 + {
1.935 + TInt r = pagemove.TryMovingUserPage(firstpage, ETrue);
1.936 + if (i == 0)
1.937 + {// If this is the first run allow the modifying thread to run now
1.938 + // we've done one move.
1.939 + _T_PRINTF(_L("signal to child\n"));
1.940 + RThread::Rendezvous(KErrNone);
1.941 + }
1.942 + switch (r)
1.943 + {
1.944 + case KErrInUse:
1.945 + break;
1.946 + case KErrArgument:
1.947 + // The page was paged out, this should only happen for paged data.
1.948 + test(aPagedData);
1.949 + break;
1.950 + default:
1.951 + test_KErrNone(r);
1.952 + success=ETrue;
1.953 + break;
1.954 + }
1.955 + }
1.956 + test(success);
1.957 +
1.958 + ThreadDie = ETrue;
1.959 + User::WaitForRequest(s);
1.960 + test_Equal(EExitKill,modCodeThread.ExitType());
1.961 + test_KErrNone(modCodeThread.ExitReason());
1.962 + modCodeThread.Close();
1.963 +
1.964 + thread.Close();
1.965 + }
1.966 +
1.967 +GLDEF_C TInt E32Main()
1.968 + {
1.969 + test.Title();
1.970 + if (!HaveMMU())
1.971 + {
1.972 + test.Printf(_L("This test requires an MMU\n"));
1.973 + return KErrNone;
1.974 + }
1.975 +
1.976 + test.Start(_L("Load test LDD"));
1.977 + TInt r=User::LoadLogicalDevice(KLddFileName);
1.978 + test(r==KErrNone || r==KErrAlreadyExists);
1.979 +
1.980 + test_KErrNone(UserHal::PageSizeInBytes(PageSize));
1.981 +
1.982 + // Determine which types of paging are supported
1.983 + TUint32 attrs = DPTest::Attributes();
1.984 + gRomPagingSupported = (attrs & DPTest::ERomPaging) != 0;
1.985 + gCodePagingSupported = (attrs & DPTest::ECodePaging) != 0;
1.986 + gDataPagingSupported = (attrs & DPTest::EDataPaging) != 0;
1.987 +
1.988 + // Does this memory model support pinning.
1.989 + TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
1.990 + gPinningSupported = mm >= EMemModelTypeFlexible;
1.991 +
1.992 + RPageMove pagemove;
1.993 + test.Next(_L("Open test LDD"));
1.994 + test_KErrNone(pagemove.Open());
1.995 +
1.996 + // Determine whether this is a smp device.
1.997 + NumberOfCpus = pagemove.NumberOfCpus();
1.998 + if (NumberOfCpus > 1)
1.999 + Repitions = 1000; // SMP system therefore likely to get KErrInUse in less repitions.
1.1000 +
1.1001 + test.Next(_L("Attempting to move regular local data pages"));
1.1002 + {
1.1003 + const TInt size=16384;
1.1004 + TUint8* array = new TUint8[size];
1.1005 + test_NotNull(array);
1.1006 +
1.1007 + TestUserData(pagemove, array, size);
1.1008 +
1.1009 + _T_PRINTF(_L("Walk heap\n"));
1.1010 + User::Check();
1.1011 +
1.1012 + delete [] array;
1.1013 + }
1.1014 +
1.1015 + test.Next(_L("Attempting to move regular global coarse data pages"));
1.1016 + {
1.1017 + const TInt size=1<<20; // Make this chunk multiple of 1MB so it is a coarse memory object on FMM
1.1018 + RChunk chunk;
1.1019 + test_KErrNone(chunk.CreateDisconnectedGlobal(_L("Dave"), 0, size, size));
1.1020 + TUint8* array = chunk.Base();
1.1021 +
1.1022 + TestUserData(pagemove, array, size);
1.1023 + TestMovingRealtime(pagemove, array, size, NULL, EFalse);
1.1024 + TestCommitDecommit(pagemove, chunk);
1.1025 +
1.1026 + chunk.Close();
1.1027 + }
1.1028 +
1.1029 + if (gDataPagingSupported)
1.1030 + {
1.1031 + test.Next(_L("Attempting to move demand paged fine local user data pages"));
1.1032 + const TInt size=16384;
1.1033 + TChunkCreateInfo createInfo;
1.1034 + createInfo.SetDisconnected(0, size, size);
1.1035 + createInfo.SetPaging(TChunkCreateInfo::EPaged);
1.1036 + RChunk chunk;
1.1037 + test_KErrNone(chunk.Create(createInfo));
1.1038 + TUint8* array = chunk.Base();
1.1039 +
1.1040 + TestUserData(pagemove, array, size, ETrue);
1.1041 + TestMovingRealtime(pagemove, array, size, NULL, EFalse, ETrue);
1.1042 + TestPageTableDiscard(pagemove, array, size);
1.1043 + TestCommitDecommit(pagemove, chunk);
1.1044 + chunk.Close();
1.1045 +
1.1046 + test.Next(_L("Attempting to move demand paged coarse global user data pages"));
1.1047 + const TInt sizeCoarse = 1 << 20; // Make this chunk multiple of 1MB so it is a coarse memory object on FMM
1.1048 + TChunkCreateInfo createInfoCoarse;
1.1049 + createInfoCoarse.SetDisconnected(0, sizeCoarse, sizeCoarse);
1.1050 + createInfoCoarse.SetGlobal(_L("Dave"));
1.1051 + createInfoCoarse.SetPaging(TChunkCreateInfo::EPaged);
1.1052 + RChunk chunkCoarse;
1.1053 + test_KErrNone(chunkCoarse.Create(createInfoCoarse));
1.1054 + array = chunkCoarse.Base();
1.1055 +
1.1056 + TestUserData(pagemove, array, sizeCoarse, ETrue);
1.1057 + TestMovingRealtime(pagemove, array, sizeCoarse, NULL, EFalse, ETrue);
1.1058 + TestPageTableDiscard(pagemove, array, sizeCoarse);
1.1059 + TestCommitDecommit(pagemove, chunkCoarse);
1.1060 + chunkCoarse.Close();
1.1061 + }
1.1062 +
1.1063 + test.Next(_L("Attempting to move DLL writable static data pages"));
1.1064 + {
1.1065 + const TInt size=16384;
1.1066 + TUint8* array = DllWsd::Address();
1.1067 +
1.1068 + TestUserData(pagemove, array, size);
1.1069 + }
1.1070 +
1.1071 + test.Next(_L("Attempting to move user self-mod code chunk page when IMB'ing and executing"));
1.1072 + RChunk codeChunk;
1.1073 + test_KErrNone(codeChunk.CreateLocalCode(PageSize,PageSize));
1.1074 + TestMovingCodeChunk(pagemove, codeChunk, EFalse);
1.1075 + codeChunk.Close();
1.1076 +
1.1077 + if (gDataPagingSupported)
1.1078 + {
1.1079 + test.Next(_L("Attempting to move paged user self-mod code chunk page when IMB'ing and executing"));
1.1080 + TChunkCreateInfo createInfo;
1.1081 + createInfo.SetCode(PageSize, PageSize);
1.1082 + createInfo.SetPaging(TChunkCreateInfo::EPaged);
1.1083 +
1.1084 + RChunk pagedCodeChunk;
1.1085 + test_KErrNone(pagedCodeChunk.Create(createInfo));
1.1086 + TestMovingCodeChunk(pagemove, pagedCodeChunk, ETrue);
1.1087 + pagedCodeChunk.Close();
1.1088 + }
1.1089 +
1.1090 + test.Next(_L("Attempting to move RAM drive"));
1.1091 + if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMultiple)
1.1092 + {
1.1093 + for (TInt i=0; i<Repitions; i++)
1.1094 + test_KErrNone(pagemove.TryMovingUserPage((TAny*)0xA0000000));
1.1095 + }
1.1096 + else if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMoving)
1.1097 + {
1.1098 + for (TInt i=0; i<Repitions; i++)
1.1099 + test_KErrNone(pagemove.TryMovingUserPage((TAny*)0x40000000));
1.1100 + }
1.1101 + else if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeFlexible)
1.1102 + {
1.1103 + // do nothing, RAM drive is not special
1.1104 + }
1.1105 + else
1.1106 + {
1.1107 + test.Printf(_L("Don't know where the RAM drive is!"));
1.1108 + test(0);
1.1109 + }
1.1110 +
1.1111 +#if 0
1.1112 + test.Next(_L("Attempting to move kernel heap pages"));
1.1113 + for (TInt i=0; i<Repitions; i++)
1.1114 + test_KErrNone(pagemove.TryMovingKHeap());
1.1115 +#endif
1.1116 +
1.1117 + if ((MemModelAttributes()&EMemModelTypeMask) != EMemModelTypeFlexible)
1.1118 + {// Only the moving and multiple memory models move kernel stack pages.
1.1119 + test.Next(_L("Attempting to move kernel stack pages"));
1.1120 + for (TInt i=0; i<Repitions; i++)
1.1121 + test_KErrNone(pagemove.TryMovingKStack());
1.1122 + }
1.1123 +
1.1124 + test.Next(_L("Attempting to move ROM pages"));
1.1125 + TestMovingRom(pagemove);
1.1126 +
1.1127 + test.Next(_L("Attempting to move kernel code pages"));
1.1128 + for (TInt i=0; i<Repitions; i++)
1.1129 + test_KErrNone(pagemove.TryMovingKCode());
1.1130 +
1.1131 + test.Next(_L("Attempting to move regular code pages"));
1.1132 + TestMovingCode(pagemove, RamLoadedFunction);
1.1133 + TestMovingRealtime(pagemove, NULL, 0, RamLoadedFunction, ETrue, EFalse);
1.1134 +
1.1135 + if (gCodePagingSupported)
1.1136 + {
1.1137 + test.Next(_L("Attempting to move demand paged code pages"));
1.1138 + TestMovingCode(pagemove, DllTestFunction, ETrue);
1.1139 + TestMovingRealtime(pagemove, NULL, 0, DllTestFunction, ETrue, ETrue);
1.1140 + }
1.1141 +
1.1142 + /* Setup CodeModifier Test Driver */
1.1143 + StartCodeModifierDriver();
1.1144 + test(KErrNone==Device.InitialiseCodeModifier(/* Max break points */ 5 ));
1.1145 +
1.1146 + test.Next(_L("Attempting to move code page being modified\n"));
1.1147 + test_KErrNone(TestCodeModification(pagemove));
1.1148 +
1.1149 + test.Next(_L("Attempting to move code (async) while page being modified"));
1.1150 + test_KErrNone(TestCodeModificationAsync(pagemove));
1.1151 +
1.1152 + StopCodeModifierDriver();
1.1153 +
1.1154 + test.Next(_L("Attempting to move ROM Locale DLL Page"));
1.1155 + test_KErrNone(E32TestLocale(1));
1.1156 +
1.1157 + test.Next(_L("Attempting to move RAM Locale DLL Page"));
1.1158 + test_KErrNone(E32TestLocale(0));
1.1159 +
1.1160 + test.Next(_L("Close test LDD"));
1.1161 + pagemove.Close();
1.1162 + User::FreeLogicalDevice(KLddFileName);
1.1163 +
1.1164 + test.End();
1.1165 + return(KErrNone);
1.1166 + }
1.1167 +
1.1168 +
1.1169 +void testUS(const TLocale& aLocale)
1.1170 +{
1.1171 + test.Printf(_L("Test US\n"));
1.1172 +
1.1173 + test(aLocale.CountryCode()==1);
1.1174 + test(aLocale.DateFormat()==EDateAmerican);
1.1175 + test(aLocale.TimeFormat()==ETime12);
1.1176 + test(aLocale.CurrencySymbolPosition()==ELocaleBefore);
1.1177 + test(aLocale.CurrencySpaceBetween()==FALSE);
1.1178 + test(aLocale.CurrencyDecimalPlaces()==2);
1.1179 + test(aLocale.CurrencyNegativeInBrackets()==EFalse);
1.1180 + test(aLocale.CurrencyTriadsAllowed()==TRUE);
1.1181 + test(aLocale.ThousandsSeparator()==',');
1.1182 + test(aLocale.DecimalSeparator()=='.');
1.1183 + test(aLocale.DateSeparator(0)==0);
1.1184 + test(aLocale.DateSeparator(1)=='/');
1.1185 + test(aLocale.DateSeparator(2)=='/');
1.1186 + test(aLocale.DateSeparator(3)==0);
1.1187 + test(aLocale.TimeSeparator(0)==0);
1.1188 + test(aLocale.TimeSeparator(1)==':');
1.1189 + test(aLocale.TimeSeparator(2)==':');
1.1190 + test(aLocale.TimeSeparator(3)==0);
1.1191 + test(aLocale.AmPmSymbolPosition()==TRUE);
1.1192 + test(aLocale.AmPmSpaceBetween()==TRUE);
1.1193 + test(aLocale.HomeDaylightSavingZone()==EDstNorthern);
1.1194 + test(aLocale.WorkDays()==0x1f);
1.1195 + test(aLocale.StartOfWeek()==ESunday);
1.1196 + test(aLocale.ClockFormat()==EClockAnalog);
1.1197 + test(aLocale.UnitsGeneral()==EUnitsImperial);
1.1198 + test(aLocale.UnitsDistanceShort()==EUnitsImperial);
1.1199 + test(aLocale.UnitsDistanceLong()==EUnitsImperial);
1.1200 +}
1.1201 +
1.1202 +
1.1203 +void testUK(const TLocale& aLocale)
1.1204 +{
1.1205 +//#ifdef __WINS__
1.1206 + test(aLocale.CountryCode()==44);
1.1207 + test(aLocale.DateFormat()==EDateEuropean);
1.1208 + test(aLocale.TimeFormat()==ETime12);
1.1209 + test(aLocale.CurrencySymbolPosition()==ELocaleBefore);
1.1210 + test(aLocale.CurrencySpaceBetween()==FALSE);
1.1211 + test(aLocale.CurrencyDecimalPlaces()==2);
1.1212 + test(aLocale.CurrencyNegativeInBrackets()==EFalse);
1.1213 + test(aLocale.CurrencyTriadsAllowed()==TRUE);
1.1214 + test(aLocale.ThousandsSeparator()==',');
1.1215 + test(aLocale.DecimalSeparator()=='.');
1.1216 + test(aLocale.DateSeparator(0)==0);
1.1217 + test(aLocale.DateSeparator(1)=='/');
1.1218 + test(aLocale.DateSeparator(2)=='/');
1.1219 + test(aLocale.DateSeparator(3)==0);
1.1220 + test(aLocale.TimeSeparator(0)==0);
1.1221 + test(aLocale.TimeSeparator(1)==':');
1.1222 + test(aLocale.TimeSeparator(2)==':');
1.1223 + test(aLocale.TimeSeparator(3)==0);
1.1224 + test(aLocale.AmPmSymbolPosition()==TRUE);
1.1225 + test(aLocale.AmPmSpaceBetween()==TRUE);
1.1226 + test(aLocale.HomeDaylightSavingZone()==EDstEuropean);
1.1227 + test(aLocale.WorkDays()==0x1f);
1.1228 + test(aLocale.StartOfWeek()==EMonday);
1.1229 + test(aLocale.ClockFormat()==EClockAnalog);
1.1230 + test(aLocale.UnitsGeneral()==EUnitsImperial);
1.1231 + test(aLocale.UnitsDistanceShort()==EUnitsImperial);
1.1232 + test(aLocale.UnitsDistanceLong()==EUnitsImperial);
1.1233 +//#endif
1.1234 +}
1.1235 +
1.1236 +
1.1237 +void testChangeLocale(TInt isrom)
1.1238 +{
1.1239 + TLocale locale;
1.1240 +
1.1241 +#ifdef __WINS__
1.1242 +//We get a power-change notification 1 second after switch-on
1.1243 +//So we wait for a second on WINS.
1.1244 +//Should we fix this bug??
1.1245 + User::After(1000000);
1.1246 +#endif
1.1247 + RChangeNotifier notifier;
1.1248 + TInt res=notifier.Create();
1.1249 + test(res==KErrNone);
1.1250 + TRequestStatus stat;
1.1251 + res=notifier.Logon(stat);
1.1252 + test(res==KErrNone);
1.1253 + //initial pattern of stat is already tested by t_chnot
1.1254 +
1.1255 + res=notifier.Logon(stat);
1.1256 + test(res==KErrNone);
1.1257 + test(stat==KRequestPending);
1.1258 + if (isrom == 0)
1.1259 + {
1.1260 + test.Printf(_L("Change to RAM US Locale\n"));
1.1261 + res=UserSvr::ChangeLocale(ELOCLUS);
1.1262 + }
1.1263 + else
1.1264 + {
1.1265 + test.Printf(_L("Change to ROM US Locale\n"));
1.1266 + res=UserSvr::ChangeLocale(ELOCLUS_ROM);
1.1267 + }
1.1268 + test.Printf(_L("res=%d\n"),res);
1.1269 + test(res==KErrNone);
1.1270 + test(stat.Int() & EChangesLocale);
1.1271 + res=notifier.Logon(stat);
1.1272 + test(res==KErrNone);
1.1273 + test(stat==KRequestPending);
1.1274 +
1.1275 + locale.Refresh();
1.1276 + testUS(locale);
1.1277 +}
1.1278 +
1.1279 +
1.1280 +LOCAL_C void LocaleLanguageGet(SLocaleLanguage& locale)
1.1281 +{
1.1282 + TPckg<SLocaleLanguage> localeLanguageBuf(locale);
1.1283 + TInt r = RProperty::Get(KUidSystemCategory, KLocaleLanguageKey, localeLanguageBuf);
1.1284 + test(r == KErrNone || r == KErrNotFound);
1.1285 +}
1.1286 +
1.1287 +LOCAL_C TInt E32TestLocale(TInt isrom)
1.1288 +{
1.1289 + TInt r;
1.1290 + TAny *LocaleAddr;
1.1291 + TLocale locale;
1.1292 +
1.1293 + /* Setup the US Locale DLL and ensure the Locale got modified (testUS) */
1.1294 + testChangeLocale(isrom);
1.1295 +
1.1296 + /* Now get a pointer to some data in the DLL. This will be used to move a
1.1297 + ** page from the dll
1.1298 + */
1.1299 + SLocaleLanguage localeLanguage;
1.1300 + LocaleLanguageGet(localeLanguage);
1.1301 + LocaleAddr = (TAny *) localeLanguage.iDateSuffixTable;
1.1302 + test(LocaleAddr != NULL);
1.1303 +
1.1304 + RPageMove pagemove;
1.1305 + r=pagemove.Open();
1.1306 + test_KErrNone(r);
1.1307 +
1.1308 + r=pagemove.TryMovingLocaleDll(LocaleAddr);
1.1309 +
1.1310 + if (isrom == 0)
1.1311 + {
1.1312 + test_KErrNone(r);
1.1313 + }
1.1314 + else
1.1315 + {
1.1316 + // When the locale is in rom it is in the unpaged part of rom and
1.1317 + // Epoc::LinearToPhysical() won't be able to find the address.
1.1318 + test_Equal(KErrArgument, r)
1.1319 + }
1.1320 +
1.1321 + test.Printf(_L("Locale Test: Page move done\n"));
1.1322 +
1.1323 + /* Test US again. The kernel should have cached the locale informaton, so this will not
1.1324 + * really be testing the pagmove.
1.1325 + */
1.1326 + locale.Refresh();
1.1327 + testUS(locale);
1.1328 +
1.1329 + /* Reload the Default Locale */
1.1330 + test.Printf(_L("Locale Test: Change to UK Default\n"));
1.1331 + r=UserSvr::ChangeLocale(ELOCL_DEFAULT);
1.1332 + test(r==KErrNone);
1.1333 + locale.Refresh();
1.1334 + testUK(locale);
1.1335 +
1.1336 + /* This will ACTUALLY test the page which was moved by making the kernel reload the Locale
1.1337 + * information from the DLL.
1.1338 + */
1.1339 + if (isrom == 0)
1.1340 + {
1.1341 + test.Printf(_L("RAM Locale Test: Change to US Again\n"));
1.1342 + r=UserSvr::ChangeLocale(ELOCLUS);
1.1343 + }
1.1344 + else
1.1345 + {
1.1346 + test.Printf(_L("ROM Locale Test: Change to US Again\n"));
1.1347 + r=UserSvr::ChangeLocale(ELOCLUS_ROM);
1.1348 + }
1.1349 +
1.1350 +
1.1351 + test(r==KErrNone);
1.1352 + locale.Refresh();
1.1353 + testUS(locale);
1.1354 +
1.1355 + /* Reset the Locale to the default */
1.1356 + r=UserSvr::ChangeLocale(ELOCL_DEFAULT);
1.1357 + test(r==KErrNone);
1.1358 + locale.Refresh();
1.1359 + testUK(locale);
1.1360 + return(KErrNone);
1.1361 +}
1.1362 +
1.1363 +LOCAL_C void StartCodeModifierDriver()
1.1364 + {
1.1365 + test.Printf(_L("Start CodeModifier Driver\n"));
1.1366 + TInt r = User::LoadLogicalDevice(KCodeModifierName);
1.1367 + test( r==KErrNone || r==KErrAlreadyExists);
1.1368 + if((r = Device.Open())!=KErrNone)
1.1369 + {
1.1370 + User::FreeLogicalDevice(KCodeModifierName);
1.1371 + test.Printf(_L("Could not open LDD"));
1.1372 + test(0);
1.1373 + }
1.1374 + }
1.1375 +
1.1376 +
1.1377 +LOCAL_C void StopCodeModifierDriver()
1.1378 + {
1.1379 +
1.1380 + test.Printf(_L("Stop Code Modifier Driver\n"));
1.1381 + test(KErrNone==Device.CloseCodeModifier());
1.1382 + Device.Close();
1.1383 + User::FreeLogicalDevice(KCodeModifierName);
1.1384 + }
1.1385 +
1.1386 +
1.1387 +LOCAL_C void TestCodeSetupDrive(RThread &thread)
1.1388 +{
1.1389 + /* The CodeModifier driver (look in ../debug/d_codemodifier) takes two threads, we just use the
1.1390 + ** first one */
1.1391 + test(KErrNone==Device.ThreadId(0, thread.Id()));
1.1392 +}
1.1393 +
1.1394 +
1.1395 +LOCAL_C TUint GetCodeData(TInt *CodePtr, TInt& Ignore, TInt& FirstJump, TInt& SecondJump)
1.1396 + {
1.1397 + TUint ModAddr;
1.1398 +
1.1399 + Ignore = *CodePtr++;
1.1400 + ModAddr = (TUint)CodePtr;
1.1401 + FirstJump = *CodePtr++;
1.1402 + SecondJump = *CodePtr++;
1.1403 + return ModAddr;
1.1404 + }
1.1405 +
1.1406 +LOCAL_C TInt TestCodeModification(RPageMove &pagemove)
1.1407 + {
1.1408 + TInt Ignore;
1.1409 + TUint ModAddr;
1.1410 + TInt FirstJump;
1.1411 + TInt SecondJump;
1.1412 + RThread thread;
1.1413 +
1.1414 + ModAddr = GetCodeData((TInt *)TestCodeModFunc, Ignore, FirstJump, SecondJump);
1.1415 +
1.1416 + test.Printf(_L("User Test code Returns = %d\n"), TestCodeModFunc());
1.1417 + test.Printf(_L("Ignore = %x First Jump = %x Second = %x \n"), Ignore, FirstJump, SecondJump);
1.1418 +
1.1419 + TestCodeSetupDrive(thread);
1.1420 +
1.1421 + for (TInt i=0; i<Repitions * 10; i++)
1.1422 + {
1.1423 +
1.1424 + TInt r=Device.WriteCode(0, ModAddr,SecondJump,sizeof(TInt));
1.1425 + test_KErrNone(r);
1.1426 + r = TestCodeModFunc();
1.1427 + test (2 == r);
1.1428 +
1.1429 + test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
1.1430 +
1.1431 + r = Device.RestoreCode(0, ModAddr);
1.1432 + test_KErrNone(r);
1.1433 + r = TestCodeModFunc();
1.1434 + test (1 == r);
1.1435 +
1.1436 + test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
1.1437 +
1.1438 + }
1.1439 +
1.1440 + test.Printf(_L("User Test code = %d\n"), TestCodeModFunc());
1.1441 + return KErrNone;
1.1442 + }
1.1443 +
1.1444 +LOCAL_C int TestCodeAsync(TAny *NotUsed)
1.1445 + {
1.1446 + TInt Ignore;
1.1447 + TUint ModAddr;
1.1448 + TInt FirstJump;
1.1449 + TInt SecondJump;
1.1450 +
1.1451 + ModAddr = GetCodeData((TInt *)TestCodeModFunc, Ignore, FirstJump, SecondJump);
1.1452 +
1.1453 + FOREVER
1.1454 + {
1.1455 + TInt r = Device.WriteCode(0, ModAddr,SecondJump,sizeof(TInt));
1.1456 + test_KErrNone(r);
1.1457 +
1.1458 + r = TestCodeModFunc();
1.1459 + test (2 == r);
1.1460 +
1.1461 + r = Device.RestoreCode(0, ModAddr);
1.1462 +
1.1463 + test_KErrNone(r);
1.1464 + r = TestCodeModFunc();
1.1465 + test (1 == r);
1.1466 + User::AfterHighRes(10);
1.1467 + }
1.1468 + }
1.1469 +
1.1470 +/*
1.1471 + * Creates a Thread that modifies its code in a tight loop while the main
1.1472 + * thread moves the functions page around
1.1473 + */
1.1474 +LOCAL_C TInt TestCodeModificationAsync(RPageMove& pagemove)
1.1475 + {
1.1476 + TInt ret;
1.1477 + RThread CodeThread;
1.1478 + TRequestStatus s;
1.1479 +
1.1480 +
1.1481 + /* Create the Thread to modify the code segment */
1.1482 + test_KErrNone(CodeThread.Create(_L("TestCodeAsync"), TestCodeAsync, KDefaultStackSize, NULL, NULL));
1.1483 + CodeThread.Logon(s);
1.1484 + CodeThread.SetPriority(EPriorityMore);
1.1485 + CodeThread.Resume();
1.1486 +
1.1487 + TestCodeSetupDrive(CodeThread);
1.1488 +
1.1489 + /* Loop trying to move the code page while the thread (CodeThread) modifies it */
1.1490 + for (TInt i=0; i<Repitions; i++)
1.1491 + {
1.1492 + test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
1.1493 + }
1.1494 +
1.1495 + CodeThread.Kill(KErrNone);
1.1496 + User::WaitForRequest(s);
1.1497 + test_Equal(EExitKill, CodeThread.ExitType());
1.1498 + test_KErrNone(CodeThread.ExitReason());
1.1499 + CodeThread.Close();
1.1500 +
1.1501 + ret = TestCodeModFunc();
1.1502 + test(ret == 1 || ret == 2);
1.1503 +
1.1504 + return KErrNone;
1.1505 + }