First public contribution.
1 // Copyright (c) 2008-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\mmu\t_pin.cpp
15 // Tests kernel APIs for logical pinning by pinning memory and using a realtime thread to check that
16 // no page faults are taken while accessing it.
20 #define __E32TEST_EXTENSION__
27 #include "d_memorytest.h"
28 #include "t_codepaging_dll.h"
29 #include "mmudetect.h"
32 RTest test(_L("T_PIN"));
34 _LIT(KTCodePagingDll4, "t_codepaging_dll4.dll");
35 const TInt KMinBufferSize = 16384;
39 RLibrary PagedLibrary;
40 const TUint8* PagedBuffer = NULL;
41 const TUint8* UnpagedBuffer = NULL;
46 TMemoryInfoV1Buf meminfo;
47 UserHal::MemoryInfo(meminfo);
48 return meminfo().iFreeRamInBytes;
51 void CheckMemoryPresent(const TUint8* aBuffer, TInt aSize, TBool aExpected)
54 test.Printf(_L(" Checking memory at %08x is present\n"), aBuffer);
56 test.Printf(_L(" Checking memory at %08x is not present\n"), aBuffer);
57 for (TInt i = 0 ; i < aSize ; i += PageSize)
58 test_Equal(aExpected, Ldd.IsMemoryPresent(aBuffer + i));
61 void FlushPagingCache()
63 test_KErrNone(DPTest::FlushCache());
66 void TestPinVirtualMemoryUnpaged()
68 test.Printf(_L("Create logical pin object\n"));
69 test_KErrNone(Ldd.CreateVirtualPinObject());
71 CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue);
72 test.Printf(_L("Perform logical pin operation on zero-length buffer\n"));
73 test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, 0));
74 CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue);
75 test.Printf(_L("Perform logical unpin operation\n"));
76 test_KErrNone(Ldd.UnpinVirtualMemory());
77 CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue);
78 test.Printf(_L("Perform logical pin operation on whole buffer\n"));
79 test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, KMinBufferSize));
80 CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue);
81 test.Printf(_L("Perform logical unpin operation\n"));
82 test_KErrNone(Ldd.UnpinVirtualMemory());
83 CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue);
85 // Don't check for memory presence on emulator as paging not supported.
86 test.Printf(_L("Perform logical pin operation on zero-length buffer\n"));
87 test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, 0));
88 test.Printf(_L("Perform logical unpin operation\n"));
89 test_KErrNone(Ldd.UnpinVirtualMemory());
90 test.Printf(_L("Perform logical pin operation on whole buffer\n"));
91 test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, KMinBufferSize));
92 test.Printf(_L("Perform logical unpin operation\n"));
93 test_KErrNone(Ldd.UnpinVirtualMemory());
95 test.Printf(_L("Perform logical unpin operation (again)\n"));
96 test_KErrNone(Ldd.UnpinVirtualMemory()); // test double unpin ok
97 test.Printf(_L("Destroy logical pin object\n"));
98 test_KErrNone(Ldd.DestroyVirtualPinObject());
99 test.Printf(_L("Destroy logical pin object (again)\n"));
100 test_KErrNone(Ldd.DestroyVirtualPinObject()); // test double destroy ok
103 void TestPinPhysicalMemory()
106 TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
107 if (mm < EMemModelTypeFlexible)
109 test.Printf(_L("Memory model (%d) doesn't support physical pining\n"),mm);
116 test.Printf(_L("Allocate user chunk\n"));
117 TChunkCreateInfo createInfo;
118 createInfo.SetDisconnected(0,KUCPageCount*PageSize,KUCPageCount*PageSize);
119 createInfo.SetPaging(TChunkCreateInfo::EPaged);
120 test_KErrNone(chunk.Create(createInfo));
121 UCBase = (TInt8*)chunk.Base();
123 test.Printf(_L("Create physical pin object\n"));
124 test_KErrNone(Ldd.CreatePhysicalPinObject());
126 test.Printf(_L("Perform physical pin operation on zero-length buffer\n"));
127 test_KErrNone(Ldd.PinPhysicalMemory((TLinAddr)UCBase, 0));
129 test.Printf(_L("Perform physical unpin operation\n"));
130 test_KErrNone(Ldd.UnpinPhysicalMemory());
132 test.Printf(_L("Perform Physical pin operation on the chunk\n"));
133 test_KErrNone(Ldd.PinPhysicalMemory((TLinAddr)UCBase, KUCPageCount*PageSize));
135 test.Printf(_L("Test that pinned physical memory preserves its mapping when recommited\n"));
136 test_KErrNone(chunk.Decommit(0,KUCPageCount*PageSize)); //Decommit all
137 for (i=KUCPageCount-1;i>=0;i--) test_KErrNone(chunk.Commit(i*PageSize,PageSize)); //Commit in reverse order
138 for (i=0;i<KUCPageCount;i++) // Recommited memory is not paged in. So, write into each page, before driver
139 { // calls Kern::LinearToPhysical or it will get KErrInvalidMemory in return.
140 volatile TInt8* ptr = (volatile TInt8*)(UCBase+i*PageSize);
143 test_KErrNone(Ldd.CheckPageList(chunk.Base())); // Check that the mapping is preserved.
145 test.Printf(_L("Sync cache & memory of User Chunk\n"));//Test Cache::SyncPhysicalMemoryBeforeDmaWrite
146 test_KErrNone(Ldd.SyncPinnedPhysicalMemory(0,KUCPageCount*PageSize));
148 test.Printf(_L("Invalidate cache of User Chunk\n"));//Test Cache::SyncPhysicalMemoryBefore/AfterDmaRead
149 test_KErrNone(Ldd.InvalidatePinnedPhysicalMemory(0,KUCPageCount*PageSize));
151 test.Printf(_L("Try to move pinned phys. memory...\n")); //RAM defrag should return error code here.
152 i = Ldd.MovePinnedPhysicalMemory(0);
153 test.Printf(_L("...returned %d\n"),i);
156 test.Printf(_L("Close the chunk\n")); // Phys. memory is pinned and shouldn't be ...
157 chunk.Close(); // ... mapped to another virtual memory.
159 test.Printf(_L("Allocate & initilise the second chunk\n"));// Kernel sholudn't commit pinned physical memory ...
160 test_KErrNone(chunk.CreateLocal(KUCPageCount*PageSize,KUCPageCount*PageSize)); // ...that has been just decommited from the first chunk.
161 UCBase = (TInt8*)chunk.Base();
162 for (i=0;i<KUCPageCount*PageSize;i++) UCBase[i]=0; //Initialise user buffer
164 test.Printf(_L("Invalidate cache of pinned memory\n"));//This shouldn't affect the second chunk.
165 test_KErrNone(Ldd.InvalidatePinnedPhysicalMemory(0,KUCPageCount*PageSize));
167 test.Printf(_L("Check data in the second chunk is unaffected\n"));
168 for (i=0;i<KUCPageCount*PageSize;i++) test(UCBase[i]==0);
170 test.Printf(_L("Close the second chunk\n"));
173 test.Printf(_L("Perform physical unpin operation\n"));
174 test_KErrNone(Ldd.UnpinPhysicalMemory());
176 test.Printf(_L("Perform physical unpin operation (again)\n"));
177 test_KErrNone(Ldd.UnpinPhysicalMemory()); // test double unpin ok
179 test.Printf(_L("Destroy physical pin object\n"));
180 test_KErrNone(Ldd.DestroyPhysicalPinObject());
182 test.Printf(_L("Destroy physical pin object (again)\n"));
183 test_KErrNone(Ldd.DestroyPhysicalPinObject()); // test double destroy ok
185 test.Printf(_L("Test phys. pinning and sync of kernel memory.\n"));
186 test_KErrNone(Ldd.PinKernelPhysicalMemory());// Simple test of phys. pinning of kernel memory
189 void TestPhysicalPinOutOfMemory()
191 TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
192 if (mm < EMemModelTypeFlexible)
194 test.Printf(_L("Memory model (%d) doesn't support physical pining\n"),mm);
201 test.Printf(_L("Allocate user chunk\n"));
202 test_KErrNone(chunk.CreateDisconnectedLocal(0,KUCPageCount*PageSize,KUCPageCount*PageSize));
203 UCBase = (TInt8*)chunk.Base();
205 const TInt KMaxKernelAllocations = 1024;
210 for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
213 test.Printf(_L("Create physical pin object\n"));
214 r = Ldd.CreatePhysicalPinObject();
217 test.Printf(_L("Create physical pin object took %d tries\n"),i);
222 for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
225 test.Printf(_L("Perform physical pin operation\n"));
226 r = Ldd.PinPhysicalMemory((TLinAddr)UCBase, KUCPageCount*PageSize);
229 test.Printf(_L("Perform physical pin operation took %d tries\n"),i);
232 test.Printf(_L("Perform physical unpin operation\n"));
233 Ldd.UnpinPhysicalMemory();
236 test.Printf(_L("Destroy physical pin object\n"));
237 Ldd.DestroyPhysicalPinObject();
239 // wait for any async cleanup in the supervisor to finish first...
240 UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
243 test.Printf(_L("Close the chunk\n"));
250 void TestPinVirtualMemoryInvalid()
252 test.Printf(_L("Create logical pin object\n"));
253 test_KErrNone(Ldd.CreateVirtualPinObject());
254 test.Printf(_L("Attempt logical pin on bad memory address\n"));
255 TLinAddr bad = (TLinAddr)0x10000;
256 TInt r = Ldd.PinVirtualMemory(bad,KMinBufferSize);
257 test.Printf(_L("%08x r=%d"),bad,r);
259 test_KErrNone(Ldd.UnpinVirtualMemory());
260 if ((MemModelAttributes() & EMemModelTypeMask) == EMemModelTypeMultiple)
262 // test unused part of code chunk...
263 bad = (TLinAddr)0x7f000000;
264 r = Ldd.PinVirtualMemory(bad,KMinBufferSize);
265 test.Printf(_L("%08x r=%d"),bad,r);
267 test_KErrNone(Ldd.UnpinVirtualMemory());
269 test.Printf(_L("Destroy logical pin object\n"));
270 test_KErrNone(Ldd.DestroyVirtualPinObject());
273 void TestPinVirtualMemoryPaged()
275 test.Printf(_L("Create logical pin object\n"));
276 test_KErrNone(Ldd.CreateVirtualPinObject());
278 CheckMemoryPresent(PagedBuffer, KMinBufferSize, EFalse);
279 test.Printf(_L("Perform logical pin operation on zero-length buffer\n"));
280 test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)PagedBuffer, 0));
281 CheckMemoryPresent(PagedBuffer, KMinBufferSize, EFalse);
282 test.Printf(_L("Perform logical unpin operation\n"));
283 test_KErrNone(Ldd.UnpinVirtualMemory());
284 CheckMemoryPresent(PagedBuffer, KMinBufferSize, EFalse);
285 test.Printf(_L("Perform logical pin operation on whole buffer\n"));
286 test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)PagedBuffer, KMinBufferSize));
287 CheckMemoryPresent(PagedBuffer, KMinBufferSize, ETrue);
289 CheckMemoryPresent(PagedBuffer, KMinBufferSize, ETrue);
290 test.Printf(_L("Perform logical unpin operation\n"));
291 test_KErrNone(Ldd.UnpinVirtualMemory());
292 CheckMemoryPresent(PagedBuffer, KMinBufferSize, ETrue);
294 CheckMemoryPresent(PagedBuffer, KMinBufferSize, EFalse);
295 test.Printf(_L("Perform logical unpin operation (again)\n"));
296 test_KErrNone(Ldd.UnpinVirtualMemory()); // test double unpin ok
297 test.Printf(_L("Destroy logical pin object\n"));
298 test_KErrNone(Ldd.DestroyVirtualPinObject());
299 test.Printf(_L("Destroy logical pin object (again)\n"));
300 test_KErrNone(Ldd.DestroyVirtualPinObject()); // test double destroy ok
304 volatile TBool SoakEnd = false;
309 TRandom(TUint32 aSeed)
311 inline TUint32 Next()
312 { iSeed = iSeed*69069+1; return iSeed; }
313 TUint32 operator()(TUint32 aRange)
314 { return (TUint32)((TUint64(Next())*TUint64(aRange))>>32); }
319 #define SOAK_CHECK(r) \
322 RDebug::Printf("SOAK_CHECK fail at line %d",__LINE__); \
326 TInt SoakThread(TAny*)
332 r = ldd.CreateVirtualPinObject();
335 TRandom random((TUint32)&ldd);
339 TUint start = random(KMinBufferSize);
340 TUint end = random(KMinBufferSize);
347 const TUint32 KPageMask = 0xfff;
349 end = (end+KPageMask)&~KPageMask;
351 r = ldd.PinVirtualMemory((TLinAddr)(PagedBuffer+start),end-start);
354 r = ldd.UnpinVirtualMemory();
358 r = ldd.DestroyVirtualPinObject();
366 void TestPinVirtualMemoryPagedSoak()
368 test.Start(_L("Create timer"));
370 test_KErrNone(timer.CreateLocal());
372 test.Next(_L("Create threads"));
373 const TUint KNumThreads = 4;
374 TRequestStatus status[KNumThreads];
375 RThread thread[KNumThreads];
377 for(i=0; i<KNumThreads; i++)
379 test_KErrNone(thread[i].Create(KNullDesC, SoakThread, 0x1000, NULL, 0));
380 thread[i].Logon(status[i]);
381 test(status[i].Int()==KRequestPending);
384 test.Next(_L("Start threads"));
385 RThread().SetPriority(EPriorityMore); // make sure we are higher priority than soak threads
386 for(i=0; i<KNumThreads; i++)
389 test.Next(_L("Wait..."));
390 TRequestStatus timeoutStatus;
391 timer.After(timeoutStatus,10*1000000);
392 User::WaitForAnyRequest();
393 test_KErrNone(timeoutStatus.Int()); // we should have timed out if soak threads are still running OK
395 test.Next(_L("Stop threads and check results"));
396 for(i=0; i<KNumThreads; i++)
397 test_Equal(KRequestPending,status[i].Int());
399 timer.After(timeoutStatus,10*1000000);
400 for(i=0; i<KNumThreads; i++)
402 User::WaitForAnyRequest();
403 test_Equal(KRequestPending,timeoutStatus.Int());
406 User::WaitForRequest(timeoutStatus);
407 RThread().SetPriority(EPriorityNormal); // restore thread priority
410 CLOSE_AND_WAIT(timer);
411 for(i=0; i<KNumThreads; i++)
412 CLOSE_AND_WAIT(thread[i]);
418 void TestPinVirtualMemoryDecommit()
420 const TInt KChunk = 4*1024*1024; // offset of page table boundary on X86 and ARM
421 const TInt KPage = PageSize;
422 const TInt TestData[][2] =
427 {KChunk-KPage, KPage},
428 {KChunk-2*KPage,2*KPage},
429 {KChunk-KPage, 2*KPage},
433 for(TInt i=0; TestData[i][1]; ++i)
435 TInt commitOffset = TestData[i][0];
436 TInt commitSize = TestData[i][1];
437 test.Printf(_L("Create chunk 0x%x+0x%x\n"),commitOffset,commitSize);
439 TChunkCreateInfo createInfo;
440 createInfo.SetDisconnected(commitOffset,commitOffset+commitSize,commitOffset+commitSize);
441 createInfo.SetPaging(TChunkCreateInfo::EPaged);
443 test_KErrNone(chunk.Create(createInfo));
444 TUint8* buffer = chunk.Base()+commitOffset;
445 TUint bufferSize = commitSize;
446 FlushPagingCache(); // start with blank slate as far as paged memory is concerned
448 test.Printf(_L("Create virtual pin object\n"));
449 test_KErrNone(Ldd.CreateVirtualPinObject());
450 test_KErrNone(Ldd2.CreateVirtualPinObject());
451 CheckMemoryPresent(buffer, bufferSize, EFalse);
452 TInt initialFreeRam = FreeRam();
454 test.Printf(_L("Pin memory\n"));
455 test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)buffer, bufferSize));
456 CheckMemoryPresent(buffer, bufferSize, ETrue);
457 TInt pinnedFreeRam = FreeRam();
458 test_Compare(pinnedFreeRam,<,initialFreeRam);
460 memset(buffer,~c,bufferSize); // invert memory
462 test.Printf(_L("Decommit pinned memory\n"));
463 test_KErrNone(chunk.Decommit(commitOffset,commitSize));
464 CheckMemoryPresent(buffer, bufferSize, EFalse);
465 test_Equal(pinnedFreeRam,FreeRam()); // decommited memory should not be freed as it is pinned
467 test.Printf(_L("Unpin memory\n"));
468 test_KErrNone(Ldd.UnpinVirtualMemory());
469 CheckMemoryPresent(buffer, bufferSize, EFalse);
470 test_Equal(initialFreeRam,FreeRam()); // memory should be now freed
473 // test recommitting decommitted pinned memory...
476 test.Printf(_L("Commit memory\n"));
477 test_KErrNone(chunk.Commit(commitOffset,commitSize));
478 CheckMemoryPresent(buffer, bufferSize, EFalse);
479 test_Equal(initialFreeRam,FreeRam());
481 test.Printf(_L("Read memory\n"));
482 volatile TUint8* p = buffer;
483 volatile TUint8* pEnd = buffer+bufferSize;
485 test_Equal(c,*p++); // memory should have been wiped
486 test_Equal(initialFreeRam,FreeRam()); // memory now paged in
488 test.Printf(_L("Pin memory which is already paged in\n"));
489 test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)buffer, bufferSize));
490 CheckMemoryPresent(buffer, bufferSize, ETrue);
491 test_Equal(pinnedFreeRam,FreeRam());
492 memset(buffer,~c,bufferSize); // invert memory
494 test.Printf(_L("Decommit pinned memory\n"));
495 test_KErrNone(chunk.Decommit(commitOffset,commitSize));
496 CheckMemoryPresent(buffer, bufferSize, EFalse);
497 test_Equal(pinnedFreeRam,FreeRam());
499 test.Printf(_L("Commit pinned memory again\n"));
500 test_KErrNone(chunk.Commit(commitOffset,commitSize));
501 CheckMemoryPresent(buffer, bufferSize, EFalse);
502 test_Equal(pinnedFreeRam,FreeRam());
504 pEnd = buffer+bufferSize;
506 test_Equal(c,*p++); // memory should have been wiped
508 test.Printf(_L("Unpin memory\n"));
509 test_KErrNone(Ldd.UnpinVirtualMemory());
510 CheckMemoryPresent(buffer, bufferSize, ETrue);
511 test_Equal(initialFreeRam,FreeRam());
513 test.Printf(_L("Decommit memory\n"));
514 test_KErrNone(chunk.Decommit(commitOffset,commitSize));
515 CheckMemoryPresent(buffer, bufferSize, EFalse);
516 test_Compare(FreeRam(),<=,initialFreeRam);
522 test.Printf(_L("Commit memory\n"));
523 test_KErrNone(chunk.Commit(commitOffset,commitSize));
524 CheckMemoryPresent(buffer, bufferSize, EFalse);
525 test_Equal(initialFreeRam,FreeRam());
527 test.Printf(_L("Pin memory\n"));
528 test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)buffer, bufferSize));
529 CheckMemoryPresent(buffer, bufferSize, ETrue);
530 test_Equal(pinnedFreeRam,FreeRam());
532 test.Printf(_L("Pin memory again\n"));
533 test_KErrNone(Ldd2.PinVirtualMemory((TLinAddr)buffer, bufferSize));
534 CheckMemoryPresent(buffer, bufferSize, ETrue);
535 test_Equal(pinnedFreeRam,FreeRam());
537 test.Printf(_L("Decommit pinned memory\n"));
538 test_KErrNone(chunk.Decommit(commitOffset,commitSize));
539 CheckMemoryPresent(buffer, bufferSize, EFalse);
540 test_Equal(pinnedFreeRam,FreeRam()); // decommited memory should not be freed as it is pinned
542 test.Printf(_L("Unpin memory\n"));
543 test_KErrNone(Ldd2.UnpinVirtualMemory());
544 CheckMemoryPresent(buffer, bufferSize, EFalse);
545 test_Equal(pinnedFreeRam,FreeRam()); // memory shouldn't be freed as another pin exists
547 test.Printf(_L("Unpin memory again\n"));
548 test_KErrNone(Ldd.UnpinVirtualMemory());
549 CheckMemoryPresent(buffer, bufferSize, EFalse);
550 test_Equal(initialFreeRam,FreeRam()); // memory should be now freed
553 // test page stealing of decommited memory
556 test.Printf(_L("Commit memory\n"));
557 test_KErrNone(chunk.Commit(commitOffset,commitSize));
558 CheckMemoryPresent(buffer, bufferSize, EFalse);
559 test_Equal(initialFreeRam,FreeRam());
561 test.Printf(_L("Pin memory\n"));
562 test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)buffer, bufferSize));
563 CheckMemoryPresent(buffer, bufferSize, ETrue);
564 test_Equal(pinnedFreeRam,FreeRam());
566 test.Printf(_L("Decommit pinned memory\n"));
567 test_KErrNone(chunk.Decommit(commitOffset,commitSize));
568 CheckMemoryPresent(buffer, bufferSize, EFalse);
569 test_Equal(pinnedFreeRam,FreeRam());
571 test.Printf(_L("Unpin memory a higher priority that supervisor thread\n"));
572 RThread().SetPriority(EPriorityRealTime);
573 test_KErrNone(Ldd.UnpinVirtualMemory());
574 // on single core system, supervisor thread can't run and free pages yet
575 // because we're a higher priority...
576 test.Printf(_L("memory freed = %d\n"),initialFreeRam==FreeRamNoWait());
578 test.Printf(_L("Force decommited unpinned pages out of live list\n"));
580 RThread().SetPriority(EPriorityNormal);
581 test_Equal(initialFreeRam,FreeRam()); // memory should be now freed
587 test.Printf(_L("Destroy pin object\n"));
588 test_KErrNone(Ldd.DestroyVirtualPinObject());
589 test_KErrNone(Ldd2.DestroyVirtualPinObject());
593 test.Printf(_L("Flush paging cache\n"));
594 FlushPagingCache(); // this is a test that has shown up bugs in the past
598 void TestPinOutOfMemory()
600 // Ensure that if pinning fails with KErrNoMemory,
601 // there isn't a memory leak
602 const TInt KMaxKernelAllocations = 1024;
605 const TUint8* buffer = NULL;
608 buffer = PagedBuffer;
612 buffer = UnpagedBuffer;
614 test_NotNull(buffer);
617 for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
620 test.Printf(_L("Create logical pin object\n"));
621 r = Ldd.CreateVirtualPinObject();
624 test.Printf(_L("Create logical pin object took %d tries\n"),i);
628 for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
631 test.Printf(_L("Perform logical pin operation\n"));
632 r = Ldd.PinVirtualMemory((TLinAddr)buffer, KMinBufferSize);
635 test.Printf(_L("Perform logical pin operation took %d tries\n"),i);
638 test.Printf(_L("Perform logical unpin operation\n"));
639 Ldd.UnpinVirtualMemory();
642 test.Printf(_L("Destroy logical pin object\n"));
643 Ldd.DestroyVirtualPinObject();
644 // wait for any async cleanup in the supervisor to finish first...
645 UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
652 TInt KernelModifyData(TAny*)
654 Ldd.KernelMapReadAndModifyMemory();
658 void TestMapAndPinMemory()
661 TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
662 if (mm < EMemModelTypeFlexible)
664 test.Printf(_L("Memory model (%d) doesn't support physical pining\n"),mm);
668 TUint KUCBytes = KUCPageCount * PageSize;
671 test.Printf(_L("Allocate user chunk\n"));
672 TChunkCreateInfo createInfo;
673 createInfo.SetDisconnected(0, KUCBytes, KUCBytes);
674 createInfo.SetPaging(TChunkCreateInfo::EPaged);
675 test_KErrNone(chunk.Create(createInfo));
676 TUint8* chunkBase = (TUint8*)chunk.Base();
678 test.Printf(_L("Create kernel map object\n"));
679 test_KErrNone(Ldd.CreateKernelMapObject(0));
681 test.Printf(_L("Perform kernel map operation on zero-length buffer\n"));
682 test_KErrNone(Ldd.KernelMapMemory((TLinAddr)chunkBase, 0));
684 test.Printf(_L("Perform kernel unmap operation\n"));
685 test_KErrNone(Ldd.KernelUnmapMemory());
687 test.Printf(_L("Perform kernel map operation on the chunk\n"));
688 test_KErrNone(Ldd.KernelMapMemory((TLinAddr)chunkBase, KUCBytes));
690 test.Printf(_L("Attempt to map the memory again while already mapped\n"));
691 test_Equal(KErrInUse, Ldd.KernelMapMemory((TLinAddr)chunkBase, KUCBytes));
693 test.Printf(_L("Use the kernel mapping to modify the data and verify it\n"));
694 TUint8* p = chunkBase;
695 for (i = 0; i < (TInt)KUCBytes; i++)
697 test_KErrNone(Ldd.KernelMapReadAndModifyMemory());
699 for (i = 0; i < (TInt)KUCBytes; i++)
700 test_Equal((TUint8)(i + 1), *p++);
702 test.Printf(_L("Test that kernel mapped memory preserves its mapping when recommited\n"));
703 test_KErrNone(chunk.Decommit(0,KUCPageCount*PageSize)); //Decommit all
704 for (i=KUCPageCount-1;i>=0;i--) test_KErrNone(chunk.Commit(i*PageSize,PageSize)); //Commit in reverse order
705 for (i=0;i<KUCPageCount;i++) // Recommited memory is not paged in. So, write into each page, before driver
706 { // calls Kern::LinearToPhysical or it will get KErrInvalidMemory in return.
707 volatile TInt8* ptr = (volatile TInt8*)(chunkBase+i*PageSize);
710 test_KErrNone(Ldd.KernelMapCheckPageList(chunkBase)); // Check that the mapping is preserved.
712 test.Printf(_L("Sync cache & memory of User Chunk\n")); //Test Cache::SyncMemoryBeforeDmaWrite
713 test_KErrNone(Ldd.KernelMapSyncMemory());
715 test.Printf(_L("Invalidate cache of User Chunk\n"));//Test Cache::SyncMemoryBefore/AfterDmaRead
716 test_KErrNone(Ldd.KernelMapInvalidateMemory());
718 test.Printf(_L("Try to move kernel map memory...\n")); //RAM defrag should return error code here.
719 for (i = 0; i < KUCPageCount; i++)
721 TInt r = Ldd.KernelMapMoveMemory(0);
722 test.Printf(_L("...[%d] returned %d\n"), i, r);
726 test.Printf(_L("Unmap the memory and attempt to map with invalid attributes\n"));
727 test_KErrNone(Ldd.KernelUnmapMemory());
728 test_Equal(KErrArgument, Ldd.KernelMapMemoryInvalid((TLinAddr)chunkBase, KUCBytes));
730 test.Printf(_L("Map the memory read only and attempt to modify it kernel side\n"));
731 test_KErrNone(Ldd.KernelMapMemoryRO((TLinAddr)chunkBase, KUCBytes));
732 // Reset the contents of the memory.
734 for (i = 0; i < (TInt)KUCBytes; i++)
738 test_KErrNone(modThread.Create(KNullDesC, KernelModifyData, PageSize, PageSize, PageSize, (TAny*)NULL));
739 TRequestStatus status;
740 modThread.Logon(status);
741 test_Equal(KRequestPending, status.Int());
743 User::WaitForRequest(status);
744 test_Equal(EExitPanic, modThread.ExitType());
745 test(modThread.ExitCategory() == _L("KERN-EXEC"));
746 test_Equal(ECausedException, modThread.ExitReason());
747 CLOSE_AND_WAIT(modThread);
749 test.Printf(_L("Close the chunk\n")); // Phys. memory is pinned and shouldn't be ...
750 chunk.Close(); // ... mapped to another virtual memory.
752 test.Printf(_L("Allocate & initilise the second chunk\n"));// Kernel shouldn't commit pinned physical memory ...
753 test_KErrNone(chunk.CreateLocal(KUCBytes, KUCBytes)); // ...that has just been decommited from the first chunk.
754 chunkBase = (TUint8*)chunk.Base();
755 for (i = 0; i < KUCPageCount * PageSize; i++)
756 chunkBase[i] = 0; //Initialise user buffer
758 test.Printf(_L("Invalidate cache of pinned memory\n"));//This shouldn't affect the second chunk.
759 test_KErrNone(Ldd.KernelMapInvalidateMemory());
761 test.Printf(_L("Check data in the second chunk is unaffected\n"));
762 for (i=0; i < KUCPageCount * PageSize; i++)
763 test(chunkBase[i]==0);
765 test.Printf(_L("Close the second chunk\n"));
768 test.Printf(_L("Perform kernel unmap operation\n"));
769 test_KErrNone(Ldd.KernelUnmapMemory());
771 test.Printf(_L("Perform physical unpin operation (again)\n"));
772 test_KErrNone(Ldd.KernelUnmapMemory()); // test double unpin ok
774 test.Printf(_L("Destroy physical pin object\n"));
775 test_KErrNone(Ldd.DestroyKernelMapObject());
777 test.Printf(_L("Destroy physical pin object (again)\n"));
778 test_KErrNone(Ldd.DestroyKernelMapObject()); // test double destroy ok
781 // Test a kernel mapping with preserved resources doesn't allocate when mapping and pinning.
783 test.Printf(_L("Create a pre-reserving kernel mapping object\n"));
784 TUint mappingSize = KUCBytes>>1;
785 // This test step relies on mapping objet being smaller than the user chunk
786 // and as mapping object will always be >=2 pages, user chunk must be at least 4.
787 __ASSERT_COMPILE(KUCPageCount >= 4);
788 test_KErrNone(Ldd.CreateKernelMapObject(mappingSize));
789 TChunkCreateInfo chunkInfo;
790 chunkInfo.SetNormal(KUCBytes, KUCBytes);
791 chunkInfo.SetPaging(TChunkCreateInfo::EUnpaged);
792 test_KErrNone(chunk.Create(chunkInfo));
794 test.Printf(_L("Map and pin an unpaged chunk with pre-reserved resources\n"));
795 __KHEAP_FAILNEXT(1); // Ensure any attempted kernel heap allocations fail.
796 test_KErrNone(Ldd.KernelMapMemory((TLinAddr)chunk.Base(), mappingSize));
797 test_KErrNone(Ldd.KernelUnmapMemory());
799 test.Printf(_L("Map more memory than we have pre-reserved resources for\n"));
800 test_Equal(KErrArgument, Ldd.KernelMapMemory((TLinAddr)chunk.Base(), mappingSize*2));
802 test.Printf(_L("Destroy the kernel map object with pre-reserved resources\n"));
803 test_KErrNone(Ldd.DestroyKernelMapObject()); // This will also unpin the memory.
804 // Clear the kernel heap fail next.
812 test.Start(_L("Test kernel pinning APIs"));
814 if (DPTest::Attributes() & DPTest::ERomPaging)
815 test.Printf(_L("Rom paging supported\n"));
816 if (DPTest::Attributes() & DPTest::ECodePaging)
817 test.Printf(_L("Code paging supported\n"));
818 if (DPTest::Attributes() & DPTest::EDataPaging)
819 test.Printf(_L("Data paging supported\n"));
821 test.Next(_L("Loading test drivers"));
822 test_KErrNone(Ldd.Open());
823 test_KErrNone(Ldd2.Open());
825 test.Next(_L("Getting page size"));
826 test_KErrNone(UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&PageSize,0));
828 test.Next(_L("Setting up paged and unpaged buffers"));
831 // Use unpaged rom for our unpaged buffer
832 TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
833 UnpagedBuffer = (TUint8*)romHeader;
834 TInt size = romHeader->iPageableRomStart ? romHeader->iPageableRomStart : romHeader->iUncompressedSize;
835 test(size >= KMinBufferSize);
837 if (DPTest::Attributes() & DPTest::ERomPaging)
839 // Use end of paged ROM for our paged buffer
840 test(romHeader->iPageableRomStart);
841 TInt offset = romHeader->iPageableRomStart + romHeader->iPageableRomSize - KMinBufferSize;
843 test(offset>=romHeader->iPageableRomStart);
844 PagedBuffer = (TUint8*)romHeader + offset;
846 else if (DPTest::Attributes() & DPTest::ECodePaging)
848 // Use code paged DLL for our paged buffer
849 test_KErrNone(PagedLibrary.Load(KTCodePagingDll4));
850 TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)PagedLibrary.Lookup(KGetAddressOfDataFunctionOrdinal);
852 PagedBuffer = (TUint8*)func(size);
853 test_NotNull(PagedBuffer);
854 test(size >= KMinBufferSize);
857 UnpagedBuffer = (TUint8*)User::Alloc(KMinBufferSize);
858 test_NotNull(UnpagedBuffer);
861 RDebug::Printf("UnpagedBuffer=%x\n",UnpagedBuffer);
862 RDebug::Printf("PagedBuffer=%x\n",PagedBuffer);
866 test.Next(_L("Logical pin unpaged memory"));
867 TestPinVirtualMemoryUnpaged();
869 test.Next(_L("Logical pin invalid memory"));
870 TestPinVirtualMemoryInvalid();
872 test.Next(_L("Physical pinning"));
873 TestPinPhysicalMemory();
875 test.Next(_L("Physical pinning OOM"));
876 TestPhysicalPinOutOfMemory();
878 test.Next(_L("Kernel pin mapping"));
879 TestMapAndPinMemory();
881 test.Next(_L("Pin OOM Tests"));
882 TestPinOutOfMemory();
886 test.Next(_L("Logical pin paged memory"));
887 TestPinVirtualMemoryPaged();
889 test.Next(_L("Logical pin paged memory soak test"));
890 TestPinVirtualMemoryPagedSoak();
893 if (DPTest::Attributes() & DPTest::EDataPaging)
895 test.Next(_L("Logical pin then decommit memory"));
896 TestPinVirtualMemoryDecommit();
899 // wait for any async cleanup in the supervisor to finish first...
900 UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
904 User::Free((TAny*)UnpagedBuffer);
907 PagedLibrary.Close();