Update contrib.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\defrag\t_pagemove.cpp
17 //--------------------------------------------------------------------------------------------------
18 //! @SYMTestCaseID KBASE-T_PAGEMOVE-0572
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.
27 //! RBusLogicalChannel
29 //! Platforms/Drives/Compatibility:
30 //! Hardware only. No defrag support on emulator.
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 //--------------------------------------------------------------------------------------------------
52 #define __E32TEST_EXTENSION__
58 #include <e32std_private.h>
60 #include "d_pagemove.h"
61 #include "t_pagemove_dll.h"
63 #include "..\mmu\mmudetect.h"
64 #include "..\debug\d_codemodifier.h"
65 #include "..\mmu\d_memorytest.h"
69 #define _R_PRINTF(x) RDebug::Printf(x)
70 #define _T_PRINTF(x) test.Printf(x)
76 LOCAL_D RTest test(_L("T_PAGEMOVE"));
78 _LIT(ELOCL_DEFAULT, "");
79 _LIT(ELOCLUS, "T_LOCLUS_RAM");
80 _LIT(ELOCLUS_ROM, "T_LOCLUS");
81 LOCAL_C TInt E32TestLocale(TInt);
83 RCodeModifierDevice Device;
84 extern TInt TestCodeModFunc();
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);
92 LOCAL_C void StartCodeModifierDriver();
93 LOCAL_C void StopCodeModifierDriver();
94 LOCAL_C TInt TestCodeModification(RPageMove &);
95 LOCAL_C TInt TestCodeModificationAsync(RPageMove& pagemove);
98 const TPtrC KLddFileName=_L("D_PAGEMOVE.LDD");
104 volatile TBool ThreadDie;
106 TBool gDataPagingSupported;
107 TBool gRomPagingSupported;
108 TBool gCodePagingSupported;
109 TBool gPinningSupported;
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()
115 return KArbitraryNumber;
118 struct SPinThreadArgs
121 TTestFunction iTestFunc;
122 RThread iParentThread;
123 User::TRealtimeState iRealtimeState;
127 void StartThreads( TUint aNumThreads, RThread* aThreads, TRequestStatus* aStatus,
128 TThreadFunction aThreadFunc, SPinThreadArgs& aThreadArgs)
130 for (TUint i = 0; i < aNumThreads; i++)
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());
143 void EndThreads(TUint aNumThreads, RThread* aThreads, TRequestStatus* aStatus)
145 for (TUint i = 0; i < aNumThreads; i++)
147 User::WaitForRequest(aStatus[i]);
148 test_Equal(EExitKill, aThreads[i].ExitType());
149 test_KErrNone(aThreads[i].ExitReason());
155 void Reschedule(TInt64& aSeed)
157 if (NumberOfCpus == 1)
159 TInt rand = Math::Rand(aSeed);
160 if ((rand & 0x5) == 5)
161 User::AfterHighRes(rand & 0x7);
165 TInt ReadWriteByte(TAny* aParam)
167 SPinThreadArgs* args = (SPinThreadArgs*)aParam;
168 volatile TUint8* byte = (volatile TUint8*)args->iLinAddr;
169 TInt64 seed = Math::Random()*Math::Random();
171 test_KErrNone(User::SetRealtimeState(args->iRealtimeState));
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");
193 TInt RunCodeThread(TAny* aParam)
195 TInt64 seed = Math::Random()*Math::Random();
196 SPinThreadArgs* args = (SPinThreadArgs*)aParam;
198 test_KErrNone(User::SetRealtimeState(args->iRealtimeState));
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");
211 TInt r = args->iTestFunc();
212 if (r != KArbitraryNumber)
222 TInt VirtualPinPage(TAny* aParam)
224 TInt64 seed = Math::Random()*Math::Random();
225 SPinThreadArgs* args = (SPinThreadArgs*)aParam;
227 test_KErrNone(ldd.Open());
229 test_KErrNone(ldd.CreateVirtualPinObject());
231 TBool firstRun = ETrue;
234 // Pin the page of aParam.
235 test_KErrNone(ldd.PinVirtualMemory(args->iLinAddr, PageSize));
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());
247 test_KErrNone(ldd.UnpinVirtualMemory());
251 test_KErrNone(ldd.DestroyVirtualPinObject());
257 TInt PhysicalPinPage(TAny* aParam)
259 TInt64 seed = Math::Random()*Math::Random();
260 SPinThreadArgs* args = (SPinThreadArgs*)aParam;
263 test_KErrNone(ldd.Open());
265 test_KErrNone(ldd.CreatePhysicalPinObject());
267 TBool firstRun = ETrue;
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));
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());
284 test_KErrNone(ldd.UnpinPhysicalMemory());
288 test_KErrNone(ldd.DestroyPhysicalPinObject());
293 TInt ModifyCodeThread(TAny* aParam)
295 SPinThreadArgs* args = (SPinThreadArgs*)aParam;
296 TUint8* p = (TUint8*)args->iLinAddr;
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");
310 Mem::Copy(p, (TAny*)&Increment, Increment_Length());
311 User::IMB_Range(p, p+Increment_Length());
312 test_Equal(8, func(7));
314 Mem::Copy(p, (TAny*)&Decrement, Decrement_Length());
315 User::IMB_Range(p, p+Decrement_Length());
316 test_Equal(6, func(7));
330 void TestUserData(RPageMove& pagemove, TUint8* array, TInt size, TBool aPagedData=EFalse)
332 _T_PRINTF(_L("Fill the array with some data\n"));
333 for (TInt i=0; i<size; i++) array[i] = i*i;
335 TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)array, PageSize);
337 thread.Open(RThread().Id());
338 SPinThreadArgs threadArgs;
339 threadArgs.iLinAddr = (TLinAddr)array;
340 threadArgs.iParentThread = thread;
341 threadArgs.iRealtimeState = User::ERealtimeStateOff;
343 TMovingPinStage endStage = EMovingPinStages;
344 if (!gPinningSupported)
345 endStage = EVirtualPinning;
347 for (TUint state = ENoPinning; state < (TUint)endStage; state++)
349 TThreadFunction threadFunc = NULL;
353 test.Printf(_L("Attempt to move pages while they are being modified\n"));
354 threadFunc = &ReadWriteByte;
356 case EVirtualPinning:
357 test.Printf(_L("Attempt to move pages while they are being virtually pinned\n"));
358 threadFunc = &VirtualPinPage;
360 case EPhysicalPinning:
361 test.Printf(_L("Attempt to move pages while they are being physically pinned\n"));
362 threadFunc = &PhysicalPinPage;
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);
371 _T_PRINTF(_L("Move first array page repeatedly\n"));
372 TBool success=EFalse;
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++)
377 TInt r = pagemove.TryMovingUserPage(firstpage, ETrue);
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);
391 // The page was paged out, this should only happen for paged data.
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);
409 EndThreads(numThreads, userDataThread, s);
411 _T_PRINTF(_L("Validate page data\n"));
412 for (TInt i=0; i<size; i++)
413 test_Equal((TUint8)(i*i), array[i]);
419 void TestMovingCode(RPageMove& aPagemove, TTestFunction aFunc, TBool aPaged=EFalse)
421 TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)aFunc, PageSize);
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;
430 TMovingPinStage endStage = EMovingPinStages;
431 if (!gPinningSupported)
432 endStage = EVirtualPinning;
434 for (TUint state = ENoPinning; state < (TUint)endStage; state++)
436 TThreadFunction threadFunc = NULL;
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.
444 case EVirtualPinning:
445 test.Printf(_L("Attempt to move pages while they are being virtually pinned\n"));
446 threadFunc = &VirtualPinPage;
448 case EPhysicalPinning:
449 test.Printf(_L("Attempt to move pages while they are being physically pinned\n"));
450 threadFunc = &PhysicalPinPage;
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);
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++)
464 TInt r = aPagemove.TryMovingUserPage(firstpage, ETrue);
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);
478 // The page was paged out, this should only happen for paged code.
487 // Physical pinning or adding a new pinning while a page is being moved
488 // should prevent code pages being moved.
492 test(!inuse || aPaged); // Stealing may get KErrInUse but this should only happen for paged code.
493 case EVirtualPinning :
496 case EPhysicalPinning :
501 EndThreads(numThreads, codeRunThread, s);
503 _T_PRINTF(_L("Validate page data\n"));
504 test_Equal(KArbitraryNumber, aFunc());
510 void TestMovingRealtime(RPageMove& aPagemove, TUint8* aArray, TInt aSize, TTestFunction aFunc, TBool aCode, TBool aPaged=EFalse)
512 TThreadFunction threadFunc;
516 thread.Open(RThread().Id());
517 SPinThreadArgs threadArgs;
518 threadArgs.iParentThread = thread;
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());
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;
540 TMovingPinStage endStage = EMovingPinStages;
541 if (gPinningSupported)
543 test_KErrNone(ldd.Open());
544 test_KErrNone(ldd.CreateVirtualPinObject());
545 test_KErrNone(ldd.CreatePhysicalPinObject());
548 endStage = EVirtualPinning;
550 for (TUint state = ENoPinning; state < (TUint)endStage; state++)
555 test.Printf(_L("Attempt to move pages while they are being accessed\n"));
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));
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));
567 for ( TUint realtimeState = User::ERealtimeStateOff;
568 realtimeState <= User::ERealtimeStateWarn;
572 RThread accessThread;
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();
581 _T_PRINTF(_L("wait for child\n"));
582 User::WaitForRequest(threadInitialised);
583 test_KErrNone(threadInitialised.Int());
585 _T_PRINTF(_L("Move page repeatedly\n"));
586 TBool success=EFalse, pagedOut=EFalse;
590 test_Equal(KArbitraryNumber, aFunc());
594 *(volatile TUint8*)aArray = *aArray;
597 for (TInt i=0; i < Repitions; i++)
599 TInt r = aPagemove.TryMovingUserPage(firstpage, ETrue);
602 _T_PRINTF(_L("signal to child\n"));
603 RThread::Rendezvous(KErrNone);
611 // The page was paged out, this should only happen for paged code.
622 User::WaitForRequest(s);
623 test.Printf(_L("inuse %d\n"),inuse);
628 if (EExitPanic == accessThread.ExitType())
630 test(accessThread.ExitCategory()==_L("KERN-EXEC"));
631 test_Equal(EIllegalFunctionForRealtimeThread, accessThread.ExitReason());
632 test(aPaged && realtimeState == User::ERealtimeStateOn);
636 test_Equal(EExitKill,accessThread.ExitType());
637 test_KErrNone(accessThread.ExitReason());
639 // Ensure the page is paged in before we attempt to move it again with a different realtime state.
642 test_Equal(KArbitraryNumber, aFunc());
646 *(volatile TUint8*)aArray = *aArray;
649 case EVirtualPinning :
650 test(!aCode || !inuse);
653 test_Equal(EExitKill,accessThread.ExitType());
654 test_KErrNone(accessThread.ExitReason());
656 case EPhysicalPinning :
660 accessThread.Close();
662 if (gPinningSupported)
664 // Unpin any pinned memory.
665 test_KErrNone(ldd.UnpinVirtualMemory());
666 test_KErrNone(ldd.UnpinPhysicalMemory());
669 _T_PRINTF(_L("Validate page data\n"));
672 test_Equal(KArbitraryNumber, aFunc());
676 for (TInt i=0; i<aSize; i++)
677 test_Equal((TUint8)(i*i), aArray[i]);
681 if (gPinningSupported)
683 test_KErrNone(ldd.DestroyVirtualPinObject());
684 test_KErrNone(ldd.DestroyPhysicalPinObject());
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)
695 RChunk* chunk = (RChunk*) aParam;
696 volatile TUint8* byte = chunk->Base();
700 User::AfterHighRes(0);
701 TInt r = chunk->Decommit(0, PageSize);
704 User::AfterHighRes(0);
705 r = chunk->Commit(0, PageSize);
711 void TestCommitDecommit(RPageMove& pagemove, RChunk& aChunk)
713 test.Printf(_L("Attempt to move a page while it is being committed and decommited\n"));
716 test_KErrNone(thread.Create(_L("CommitDecommit"), &CommitDecommit, KDefaultStackSize, NULL, (TAny*)&aChunk));
718 thread.SetPriority(EPriorityMore);
721 TUint8* firstpage=(TUint8*)_ALIGN_DOWN((TLinAddr)aChunk.Base(), PageSize);
722 for (TInt i=0; i < Repitions; i++)
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
728 test_Value(r, r <= KErrNone);
731 thread.Kill(KErrNone);
732 User::WaitForRequest(s);
733 test_Equal(EExitKill,thread.ExitType());
734 test_KErrNone(thread.ExitReason());
739 void TestPageTableDiscard(RPageMove& pagemove, TUint8* array, TUint size)
741 _T_PRINTF(_L("Fill the array with some data\n"));
742 for (TUint i=0; i<size; i++) array[i] = i*i;
744 TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)array, PageSize);
746 thread.Open(RThread().Id());
747 SPinThreadArgs threadArgs;
748 threadArgs.iLinAddr = (TLinAddr)array;
749 threadArgs.iParentThread = thread;
750 threadArgs.iRealtimeState = User::ERealtimeStateOff;
752 TMovingPinStage endStage = EMovingPinStages;
753 if (!gPinningSupported)
754 endStage = EVirtualPinning;
756 for (TUint pageTableInfo = 0; pageTableInfo < 2; pageTableInfo++)
758 for (TUint state = ENoPinning; state < (TUint)endStage; state++)
760 TThreadFunction threadFunc = NULL;
766 test.Printf(_L("Attempt to move page tables whilst the pages they map are being modified\n"));
767 threadFunc = &ReadWriteByte;
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;
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;
784 test.Printf(_L("Attempt to move page table infos whilst pages they refer to are being modified\n"));
785 threadFunc = &ReadWriteByte;
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;
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;
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);
803 _T_PRINTF(_L("Move first array page repeatedly\n"));
805 for (TInt i=0; i < Repitions; i++)
809 r = pagemove.TryMovingPageTable(firstpage);
811 r = pagemove.TryMovingPageTableInfo(firstpage);
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);
825 // The page table or page table info page was paged out.
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);
837 EndThreads(numThreads, threads, s);
839 _T_PRINTF(_L("Validate page data\n"));
840 for (TUint i=0; i<size; i++)
841 test_Equal((TUint8)(i*i), array[i]);
847 // Basic testing of moving rom pages.
848 void TestMovingRom(RPageMove& aPageMove)
850 TUint8* pPage=(TUint8*)User::Alloc(PageSize);
853 TUint romHdr = UserSvr::RomHeaderAddress();
855 if (gPinningSupported)
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.
861 test_KErrNone(ldd.Open());
862 test_KErrNone(ldd.CreatePhysicalPinObject());
864 // Save contents of rom page.
865 Mem::Move(pPage,(TAny*)romHdr,PageSize);
867 test_KErrNone(ldd.PinPhysicalMemoryRO(romHdr, PageSize));
868 test_KErrNone(ldd.UnpinPhysicalMemory());
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
875 test_Equal(KErrArgument, ldd.MovePinnedPhysicalMemory(0));
877 test_KErrNone(Mem::Compare((TUint8*)romHdr,PageSize,pPage,PageSize));
878 test_KErrNone(ldd.DestroyPhysicalPinObject());
882 if (gRomPagingSupported)
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);
889 // We will use the 64th pagable rom page so check that it exists.
890 test(romHeader->iPageableRomSize >= 65 * PageSize);
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));
897 test_KErrNone(Mem::Compare((TUint8*)romAddr,PageSize,pPage,PageSize));
902 void TestMovingCodeChunk(RPageMove& pagemove, RChunk aChunk, TBool aPagedData)
904 TUint8* p = aChunk.Base();
906 TUint8* firstpage = (TUint8*)_ALIGN_DOWN((TLinAddr)p, PageSize);
908 thread.Open(RThread().Id());
909 SPinThreadArgs threadArgs;
910 threadArgs.iLinAddr = (TLinAddr)p;
911 threadArgs.iParentThread = thread;
913 test.Printf(_L("Attempt to move pages while they are being executed and modified\n"));
915 RThread modCodeThread;
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();
923 _T_PRINTF(_L("wait for child\n"));
924 User::WaitForRequest(threadInitialised);
925 test_KErrNone(threadInitialised.Int());
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++)
932 TInt r = pagemove.TryMovingUserPage(firstpage, ETrue);
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);
944 // The page was paged out, this should only happen for paged data.
956 User::WaitForRequest(s);
957 test_Equal(EExitKill,modCodeThread.ExitType());
958 test_KErrNone(modCodeThread.ExitReason());
959 modCodeThread.Close();
964 GLDEF_C TInt E32Main()
969 test.Printf(_L("This test requires an MMU\n"));
973 test.Start(_L("Load test LDD"));
974 TInt r=User::LoadLogicalDevice(KLddFileName);
975 test(r==KErrNone || r==KErrAlreadyExists);
977 test_KErrNone(UserHal::PageSizeInBytes(PageSize));
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;
985 // Does this memory model support pinning.
986 TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
987 gPinningSupported = mm >= EMemModelTypeFlexible;
990 test.Next(_L("Open test LDD"));
991 test_KErrNone(pagemove.Open());
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.
998 test.Next(_L("Attempting to move regular local data pages"));
1000 const TInt size=16384;
1001 TUint8* array = new TUint8[size];
1002 test_NotNull(array);
1004 TestUserData(pagemove, array, size);
1006 _T_PRINTF(_L("Walk heap\n"));
1012 test.Next(_L("Attempting to move regular global coarse data pages"));
1014 const TInt size=1<<20; // Make this chunk multiple of 1MB so it is a coarse memory object on FMM
1016 test_KErrNone(chunk.CreateDisconnectedGlobal(_L("Dave"), 0, size, size));
1017 TUint8* array = chunk.Base();
1019 TestUserData(pagemove, array, size);
1020 TestMovingRealtime(pagemove, array, size, NULL, EFalse);
1021 TestCommitDecommit(pagemove, chunk);
1026 if (gDataPagingSupported)
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);
1034 test_KErrNone(chunk.Create(createInfo));
1035 TUint8* array = chunk.Base();
1037 TestUserData(pagemove, array, size, ETrue);
1038 TestMovingRealtime(pagemove, array, size, NULL, EFalse, ETrue);
1039 TestPageTableDiscard(pagemove, array, size);
1040 TestCommitDecommit(pagemove, chunk);
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);
1050 test_KErrNone(chunkCoarse.Create(createInfoCoarse));
1051 array = chunkCoarse.Base();
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();
1060 test.Next(_L("Attempting to move DLL writable static data pages"));
1062 const TInt size=16384;
1063 TUint8* array = DllWsd::Address();
1065 TestUserData(pagemove, array, size);
1068 test.Next(_L("Attempting to move user self-mod code chunk page when IMB'ing and executing"));
1070 test_KErrNone(codeChunk.CreateLocalCode(PageSize,PageSize));
1071 TestMovingCodeChunk(pagemove, codeChunk, EFalse);
1074 if (gDataPagingSupported)
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);
1081 RChunk pagedCodeChunk;
1082 test_KErrNone(pagedCodeChunk.Create(createInfo));
1083 TestMovingCodeChunk(pagemove, pagedCodeChunk, ETrue);
1084 pagedCodeChunk.Close();
1087 test.Next(_L("Attempting to move RAM drive"));
1088 if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMultiple)
1090 for (TInt i=0; i<Repitions; i++)
1091 test_KErrNone(pagemove.TryMovingUserPage((TAny*)0xA0000000));
1093 else if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMoving)
1095 for (TInt i=0; i<Repitions; i++)
1096 test_KErrNone(pagemove.TryMovingUserPage((TAny*)0x40000000));
1098 else if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeFlexible)
1100 // do nothing, RAM drive is not special
1104 test.Printf(_L("Don't know where the RAM drive is!"));
1109 test.Next(_L("Attempting to move kernel heap pages"));
1110 for (TInt i=0; i<Repitions; i++)
1111 test_KErrNone(pagemove.TryMovingKHeap());
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());
1121 test.Next(_L("Attempting to move ROM pages"));
1122 TestMovingRom(pagemove);
1124 test.Next(_L("Attempting to move kernel code pages"));
1125 for (TInt i=0; i<Repitions; i++)
1126 test_KErrNone(pagemove.TryMovingKCode());
1128 test.Next(_L("Attempting to move regular code pages"));
1129 TestMovingCode(pagemove, RamLoadedFunction);
1130 TestMovingRealtime(pagemove, NULL, 0, RamLoadedFunction, ETrue, EFalse);
1132 if (gCodePagingSupported)
1134 test.Next(_L("Attempting to move demand paged code pages"));
1135 TestMovingCode(pagemove, DllTestFunction, ETrue);
1136 TestMovingRealtime(pagemove, NULL, 0, DllTestFunction, ETrue, ETrue);
1139 /* Setup CodeModifier Test Driver */
1140 StartCodeModifierDriver();
1141 test(KErrNone==Device.InitialiseCodeModifier(/* Max break points */ 5 ));
1143 test.Next(_L("Attempting to move code page being modified\n"));
1144 test_KErrNone(TestCodeModification(pagemove));
1146 test.Next(_L("Attempting to move code (async) while page being modified"));
1147 test_KErrNone(TestCodeModificationAsync(pagemove));
1149 StopCodeModifierDriver();
1151 test.Next(_L("Attempting to move ROM Locale DLL Page"));
1152 test_KErrNone(E32TestLocale(1));
1154 test.Next(_L("Attempting to move RAM Locale DLL Page"));
1155 test_KErrNone(E32TestLocale(0));
1157 test.Next(_L("Close test LDD"));
1159 User::FreeLogicalDevice(KLddFileName);
1166 void testUS(const TLocale& aLocale)
1168 test.Printf(_L("Test US\n"));
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);
1200 void testUK(const TLocale& aLocale)
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);
1234 void testChangeLocale(TInt isrom)
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);
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
1252 res=notifier.Logon(stat);
1253 test(res==KErrNone);
1254 test(stat==KRequestPending);
1257 test.Printf(_L("Change to RAM US Locale\n"));
1258 res=UserSvr::ChangeLocale(ELOCLUS);
1262 test.Printf(_L("Change to ROM US Locale\n"));
1263 res=UserSvr::ChangeLocale(ELOCLUS_ROM);
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);
1277 LOCAL_C void LocaleLanguageGet(SLocaleLanguage& locale)
1279 TPckg<SLocaleLanguage> localeLanguageBuf(locale);
1280 TInt r = RProperty::Get(KUidSystemCategory, KLocaleLanguageKey, localeLanguageBuf);
1281 test(r == KErrNone || r == KErrNotFound);
1284 LOCAL_C TInt E32TestLocale(TInt isrom)
1290 /* Setup the US Locale DLL and ensure the Locale got modified (testUS) */
1291 testChangeLocale(isrom);
1293 /* Now get a pointer to some data in the DLL. This will be used to move a
1294 ** page from the dll
1296 SLocaleLanguage localeLanguage;
1297 LocaleLanguageGet(localeLanguage);
1298 LocaleAddr = (TAny *) localeLanguage.iDateSuffixTable;
1299 test(LocaleAddr != NULL);
1305 r=pagemove.TryMovingLocaleDll(LocaleAddr);
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)
1318 test.Printf(_L("Locale Test: Page move done\n"));
1320 /* Test US again. The kernel should have cached the locale informaton, so this will not
1321 * really be testing the pagmove.
1326 /* Reload the Default Locale */
1327 test.Printf(_L("Locale Test: Change to UK Default\n"));
1328 r=UserSvr::ChangeLocale(ELOCL_DEFAULT);
1333 /* This will ACTUALLY test the page which was moved by making the kernel reload the Locale
1334 * information from the DLL.
1338 test.Printf(_L("RAM Locale Test: Change to US Again\n"));
1339 r=UserSvr::ChangeLocale(ELOCLUS);
1343 test.Printf(_L("ROM Locale Test: Change to US Again\n"));
1344 r=UserSvr::ChangeLocale(ELOCLUS_ROM);
1352 /* Reset the Locale to the default */
1353 r=UserSvr::ChangeLocale(ELOCL_DEFAULT);
1360 LOCAL_C void StartCodeModifierDriver()
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)
1367 User::FreeLogicalDevice(KCodeModifierName);
1368 test.Printf(_L("Could not open LDD"));
1374 LOCAL_C void StopCodeModifierDriver()
1377 test.Printf(_L("Stop Code Modifier Driver\n"));
1378 test(KErrNone==Device.CloseCodeModifier());
1380 User::FreeLogicalDevice(KCodeModifierName);
1384 LOCAL_C void TestCodeSetupDrive(RThread &thread)
1386 /* The CodeModifier driver (look in ../debug/d_codemodifier) takes two threads, we just use the
1388 test(KErrNone==Device.ThreadId(0, thread.Id()));
1392 LOCAL_C TUint GetCodeData(TInt *CodePtr, TInt& Ignore, TInt& FirstJump, TInt& SecondJump)
1396 Ignore = *CodePtr++;
1397 ModAddr = (TUint)CodePtr;
1398 FirstJump = *CodePtr++;
1399 SecondJump = *CodePtr++;
1403 LOCAL_C TInt TestCodeModification(RPageMove &pagemove)
1411 ModAddr = GetCodeData((TInt *)TestCodeModFunc, Ignore, FirstJump, SecondJump);
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);
1416 TestCodeSetupDrive(thread);
1418 for (TInt i=0; i<Repitions * 10; i++)
1421 TInt r=Device.WriteCode(0, ModAddr,SecondJump,sizeof(TInt));
1423 r = TestCodeModFunc();
1426 test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
1428 r = Device.RestoreCode(0, ModAddr);
1430 r = TestCodeModFunc();
1433 test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
1437 test.Printf(_L("User Test code = %d\n"), TestCodeModFunc());
1441 LOCAL_C int TestCodeAsync(TAny *NotUsed)
1448 ModAddr = GetCodeData((TInt *)TestCodeModFunc, Ignore, FirstJump, SecondJump);
1452 TInt r = Device.WriteCode(0, ModAddr,SecondJump,sizeof(TInt));
1455 r = TestCodeModFunc();
1458 r = Device.RestoreCode(0, ModAddr);
1461 r = TestCodeModFunc();
1463 User::AfterHighRes(10);
1468 * Creates a Thread that modifies its code in a tight loop while the main
1469 * thread moves the functions page around
1471 LOCAL_C TInt TestCodeModificationAsync(RPageMove& pagemove)
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();
1484 TestCodeSetupDrive(CodeThread);
1486 /* Loop trying to move the code page while the thread (CodeThread) modifies it */
1487 for (TInt i=0; i<Repitions; i++)
1489 test_KErrNone(pagemove.TryMovingUserPage((TAny*)TestCodeModFunc));
1492 CodeThread.Kill(KErrNone);
1493 User::WaitForRequest(s);
1494 test_Equal(EExitKill, CodeThread.ExitType());
1495 test_KErrNone(CodeThread.ExitReason());
1498 ret = TestCodeModFunc();
1499 test(ret == 1 || ret == 2);