os/kernelhwsrv/kerneltest/e32test/mmu/t_pin.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    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.
    17 // 
    18 //
    19 
    20 #define __E32TEST_EXTENSION__
    21 #include <e32test.h>
    22 #include <e32svr.h>
    23 #include <e32rom.h>
    24 #include <e32kpan.h>
    25 #include <u32hal.h>
    26 #include <dptest.h>
    27 #include "d_memorytest.h"
    28 #include "t_codepaging_dll.h"
    29 #include "mmudetect.h"
    30 #include "freeram.h"
    31 
    32 RTest test(_L("T_PIN"));
    33 
    34 _LIT(KTCodePagingDll4, "t_codepaging_dll4.dll");
    35 const TInt KMinBufferSize = 16384;
    36 
    37 RMemoryTestLdd Ldd;
    38 RMemoryTestLdd Ldd2;
    39 RLibrary PagedLibrary;
    40 const TUint8* PagedBuffer = NULL;
    41 const TUint8* UnpagedBuffer = NULL;
    42 TInt PageSize;
    43 
    44 TInt FreeRamNoWait()
    45 	{
    46 	TMemoryInfoV1Buf meminfo;
    47 	UserHal::MemoryInfo(meminfo);
    48 	return meminfo().iFreeRamInBytes;
    49 	}
    50 
    51 void CheckMemoryPresent(const TUint8* aBuffer, TInt aSize, TBool aExpected)
    52 	{
    53 	if (aExpected)
    54 		test.Printf(_L("  Checking memory at %08x is present\n"), aBuffer);
    55 	else
    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));
    59 	}
    60 
    61 void FlushPagingCache()
    62 	{
    63 	test_KErrNone(DPTest::FlushCache());
    64 	}
    65 
    66 void TestPinVirtualMemoryUnpaged()
    67 	{
    68 	test.Printf(_L("Create logical pin object\n"));
    69 	test_KErrNone(Ldd.CreateVirtualPinObject());
    70 #ifdef __EPOC32__
    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);
    84 #else
    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());
    94 #endif
    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
   101 	}
   102 
   103 void TestPinPhysicalMemory()
   104 	{
   105 	
   106 	TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
   107 	if (mm < EMemModelTypeFlexible)
   108 		{
   109 		test.Printf(_L("Memory model (%d) doesn't support physical pining\n"),mm);
   110 		return;
   111 		}
   112 	TInt i;
   113 	TInt8* UCBase;
   114 	RChunk chunk;
   115 
   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();
   122 	
   123 	test.Printf(_L("Create physical pin object\n"));
   124 	test_KErrNone(Ldd.CreatePhysicalPinObject());
   125 
   126 	test.Printf(_L("Perform physical pin operation on zero-length buffer\n"));
   127 	test_KErrNone(Ldd.PinPhysicalMemory((TLinAddr)UCBase, 0));	
   128 
   129 	test.Printf(_L("Perform physical unpin operation\n"));
   130 	test_KErrNone(Ldd.UnpinPhysicalMemory());	
   131 
   132 	test.Printf(_L("Perform Physical pin operation on the chunk\n"));
   133 	test_KErrNone(Ldd.PinPhysicalMemory((TLinAddr)UCBase, KUCPageCount*PageSize));	
   134 
   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);
   141 		*ptr = 10;
   142 		}
   143 	test_KErrNone(Ldd.CheckPageList(chunk.Base())); 					// Check that the mapping is preserved. 	
   144 	
   145 	test.Printf(_L("Sync cache & memory of User Chunk\n"));//Test Cache::SyncPhysicalMemoryBeforeDmaWrite
   146 	test_KErrNone(Ldd.SyncPinnedPhysicalMemory(0,KUCPageCount*PageSize));
   147 
   148 	test.Printf(_L("Invalidate cache of User Chunk\n"));//Test Cache::SyncPhysicalMemoryBefore/AfterDmaRead
   149 	test_KErrNone(Ldd.InvalidatePinnedPhysicalMemory(0,KUCPageCount*PageSize));
   150 	
   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);
   154 	test(i!=KErrNone);
   155 
   156 	test.Printf(_L("Close the chunk\n")); // Phys. memory is pinned and shouldn't be ...
   157 	chunk.Close();						  // ... mapped to another virtual memory.
   158 
   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
   163 
   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));
   166 
   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);
   169 	
   170 	test.Printf(_L("Close the second chunk\n"));
   171 	chunk.Close();
   172 
   173 	test.Printf(_L("Perform physical unpin operation\n"));
   174 	test_KErrNone(Ldd.UnpinPhysicalMemory());	
   175 
   176 	test.Printf(_L("Perform physical unpin operation (again)\n"));
   177 	test_KErrNone(Ldd.UnpinPhysicalMemory());	// test double unpin ok
   178 
   179 	test.Printf(_L("Destroy physical pin object\n"));
   180 	test_KErrNone(Ldd.DestroyPhysicalPinObject());
   181 
   182 	test.Printf(_L("Destroy physical pin object (again)\n"));
   183 	test_KErrNone(Ldd.DestroyPhysicalPinObject());  // test double destroy ok
   184 
   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
   187 	}
   188 
   189 void TestPhysicalPinOutOfMemory()
   190 	{
   191 	TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
   192 	if (mm < EMemModelTypeFlexible)
   193 		{
   194 		test.Printf(_L("Memory model (%d) doesn't support physical pining\n"),mm);
   195 		return;
   196 		}
   197 	
   198 	TInt8* UCBase;
   199 	RChunk chunk;
   200 
   201 	test.Printf(_L("Allocate user chunk\n"));
   202 	test_KErrNone(chunk.CreateDisconnectedLocal(0,KUCPageCount*PageSize,KUCPageCount*PageSize));
   203 	UCBase = (TInt8*)chunk.Base();
   204 	
   205 	const TInt KMaxKernelAllocations = 1024;
   206 	TInt r=KErrNoMemory;
   207 	TInt i;
   208 
   209 	__KHEAP_MARK;
   210 	for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
   211 		{
   212 		__KHEAP_FAILNEXT(i);
   213 		test.Printf(_L("Create physical pin object\n"));
   214 		r = Ldd.CreatePhysicalPinObject();
   215 		__KHEAP_RESET;
   216 		}
   217 	test.Printf(_L("Create physical pin object took %d tries\n"),i);
   218 	test_KErrNone(r);
   219 
   220 	r = KErrNoMemory;
   221 
   222 	for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
   223 		{
   224 		__KHEAP_FAILNEXT(i);
   225 		test.Printf(_L("Perform physical pin operation\n"));
   226 		r = Ldd.PinPhysicalMemory((TLinAddr)UCBase, KUCPageCount*PageSize);
   227 		__KHEAP_RESET;
   228 		}
   229 	test.Printf(_L("Perform physical pin operation took %d tries\n"),i);
   230 	if (r == KErrNone)
   231 		{
   232 		test.Printf(_L("Perform physical unpin operation\n"));
   233 		Ldd.UnpinPhysicalMemory();
   234 		}
   235 
   236 	test.Printf(_L("Destroy physical pin object\n"));
   237 	Ldd.DestroyPhysicalPinObject();
   238 
   239 	// wait for any async cleanup in the supervisor to finish first...
   240 	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);	
   241 	__KHEAP_MARKEND;
   242 
   243 	test.Printf(_L("Close the chunk\n"));
   244 	chunk.Close();
   245 	
   246 	test_KErrNone(r);
   247 	}
   248 
   249 
   250 void TestPinVirtualMemoryInvalid()
   251 	{
   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);
   258 	if(r==KErrNone)
   259 		test_KErrNone(Ldd.UnpinVirtualMemory());	
   260 	if ((MemModelAttributes() & EMemModelTypeMask) == EMemModelTypeMultiple)
   261 		{
   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);
   266 		if(r==KErrNone)
   267 			test_KErrNone(Ldd.UnpinVirtualMemory());	
   268 		}
   269 	test.Printf(_L("Destroy logical pin object\n"));
   270 	test_KErrNone(Ldd.DestroyVirtualPinObject());
   271 	}
   272 
   273 void TestPinVirtualMemoryPaged()
   274 	{
   275 	test.Printf(_L("Create logical pin object\n"));
   276 	test_KErrNone(Ldd.CreateVirtualPinObject());
   277 	FlushPagingCache();
   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);
   288 	FlushPagingCache();
   289 	CheckMemoryPresent(PagedBuffer, KMinBufferSize, ETrue);
   290 	test.Printf(_L("Perform logical unpin operation\n"));
   291 	test_KErrNone(Ldd.UnpinVirtualMemory());	
   292 	CheckMemoryPresent(PagedBuffer, KMinBufferSize, ETrue);
   293 	FlushPagingCache();
   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
   301 	}
   302 
   303 
   304 volatile TBool SoakEnd = false;
   305 
   306 class TRandom
   307 	{
   308 public:
   309 	TRandom(TUint32 aSeed)
   310 		: iSeed(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); }
   315 private:
   316 	TUint iSeed;
   317 	};
   318 
   319 #define SOAK_CHECK(r)												\
   320 	if(r!=KErrNone)													\
   321 		{															\
   322 		RDebug::Printf("SOAK_CHECK fail at line %d",__LINE__);		\
   323 		return r;													\
   324 		}															\
   325 
   326 TInt SoakThread(TAny*)
   327 	{
   328 	RMemoryTestLdd ldd;
   329 	TInt r = ldd.Open();
   330 	SOAK_CHECK(r)
   331 
   332 	r = ldd.CreateVirtualPinObject();
   333 	SOAK_CHECK(r)
   334 
   335 	TRandom random((TUint32)&ldd);
   336 
   337 	while(!SoakEnd)
   338 		{
   339 		TUint start = random(KMinBufferSize);
   340 		TUint end = random(KMinBufferSize);
   341 		if(start>end)
   342 			{
   343 			TUint temp = start;
   344 			start = end;
   345 			end = temp;
   346 			}
   347 		const TUint32 KPageMask = 0xfff;
   348 		start &= ~KPageMask;
   349 		end = (end+KPageMask)&~KPageMask;
   350 
   351 		r = ldd.PinVirtualMemory((TLinAddr)(PagedBuffer+start),end-start);
   352 		SOAK_CHECK(r)
   353 
   354 		r = ldd.UnpinVirtualMemory();
   355 		SOAK_CHECK(r)
   356 		}
   357 
   358 	r = ldd.DestroyVirtualPinObject();
   359 	SOAK_CHECK(r)
   360 
   361 	CLOSE_AND_WAIT(ldd);
   362 	return KErrNone;
   363 	}
   364 
   365 
   366 void TestPinVirtualMemoryPagedSoak()
   367 	{
   368 	test.Start(_L("Create timer"));
   369 	RTimer timer;
   370 	test_KErrNone(timer.CreateLocal());
   371 
   372 	test.Next(_L("Create threads"));
   373 	const TUint KNumThreads = 4;
   374 	TRequestStatus status[KNumThreads];
   375 	RThread thread[KNumThreads];
   376 	TUint i;
   377 	for(i=0; i<KNumThreads; i++)
   378 		{
   379 		test_KErrNone(thread[i].Create(KNullDesC, SoakThread, 0x1000, NULL, 0));
   380 		thread[i].Logon(status[i]);
   381 		test(status[i].Int()==KRequestPending);
   382 		}
   383 
   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++)
   387 		thread[i].Resume();
   388 
   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
   394 
   395 	test.Next(_L("Stop threads and check results"));
   396 	for(i=0; i<KNumThreads; i++)
   397 		test_Equal(KRequestPending,status[i].Int());
   398 	SoakEnd = true;
   399 	timer.After(timeoutStatus,10*1000000);
   400 	for(i=0; i<KNumThreads; i++)
   401 		{
   402 		User::WaitForAnyRequest();
   403 		test_Equal(KRequestPending,timeoutStatus.Int());
   404 		}
   405 	timer.Cancel();
   406 	User::WaitForRequest(timeoutStatus);
   407 	RThread().SetPriority(EPriorityNormal); // restore thread priority
   408 
   409 	// cleanup...
   410 	CLOSE_AND_WAIT(timer);
   411 	for(i=0; i<KNumThreads; i++)
   412 		CLOSE_AND_WAIT(thread[i]);
   413 
   414 	test.End();
   415 	}
   416 
   417 
   418 void TestPinVirtualMemoryDecommit()
   419 	{
   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] =
   423 		{
   424 			{0,				KPage},
   425 			{KPage,			KPage},
   426 			{KPage,			2*KPage},
   427 			{KChunk-KPage,	KPage},
   428 			{KChunk-2*KPage,2*KPage},
   429 			{KChunk-KPage,	2*KPage},
   430 			{0,0} // end marker
   431 		};
   432 
   433 	for(TInt i=0; TestData[i][1]; ++i)
   434 		{
   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);
   438 
   439 		TChunkCreateInfo createInfo;
   440 		createInfo.SetDisconnected(commitOffset,commitOffset+commitSize,commitOffset+commitSize);
   441 		createInfo.SetPaging(TChunkCreateInfo::EPaged);
   442 		RChunk chunk;
   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
   447 
   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();
   453 
   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);
   459 		TUint8 c = *buffer;
   460 		memset(buffer,~c,bufferSize); // invert memory
   461 
   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
   466 
   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
   471 
   472 		//
   473 		// test recommitting decommitted pinned memory...
   474 		//
   475 
   476 		test.Printf(_L("Commit memory\n"));
   477 		test_KErrNone(chunk.Commit(commitOffset,commitSize));	
   478 		CheckMemoryPresent(buffer, bufferSize, EFalse);
   479 		test_Equal(initialFreeRam,FreeRam());
   480 
   481 		test.Printf(_L("Read memory\n"));
   482 		volatile TUint8* p = buffer;
   483 		volatile TUint8* pEnd = buffer+bufferSize;
   484 		while(p<pEnd)
   485 			test_Equal(c,*p++); // memory should have been wiped
   486 		test_Equal(initialFreeRam,FreeRam()); // memory now paged in
   487 
   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
   493 
   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());
   498 
   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());
   503 		p = buffer;
   504 		pEnd = buffer+bufferSize;
   505 		while(p<pEnd)
   506 			test_Equal(c,*p++); // memory should have been wiped
   507 
   508 		test.Printf(_L("Unpin memory\n"));
   509 		test_KErrNone(Ldd.UnpinVirtualMemory());	
   510 		CheckMemoryPresent(buffer, bufferSize, ETrue);
   511 		test_Equal(initialFreeRam,FreeRam());
   512 
   513 		test.Printf(_L("Decommit memory\n"));
   514 		test_KErrNone(chunk.Decommit(commitOffset,commitSize));	
   515 		CheckMemoryPresent(buffer, bufferSize, EFalse);
   516 		test_Compare(FreeRam(),<=,initialFreeRam);
   517 
   518 		//
   519 		// test pin twice...
   520 		//
   521 
   522 		test.Printf(_L("Commit memory\n"));
   523 		test_KErrNone(chunk.Commit(commitOffset,commitSize));	
   524 		CheckMemoryPresent(buffer, bufferSize, EFalse);
   525 		test_Equal(initialFreeRam,FreeRam());
   526 
   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());
   531 
   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());
   536 
   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
   541 
   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
   546 
   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
   551 
   552 		//
   553 		// test page stealing of decommited memory
   554 		//
   555 
   556 		test.Printf(_L("Commit memory\n"));
   557 		test_KErrNone(chunk.Commit(commitOffset,commitSize));	
   558 		CheckMemoryPresent(buffer, bufferSize, EFalse);
   559 		test_Equal(initialFreeRam,FreeRam());
   560 
   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());
   565 
   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());
   570 
   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());
   577 
   578 		test.Printf(_L("Force decommited unpinned pages out of live list\n"));
   579 		FlushPagingCache();
   580 		RThread().SetPriority(EPriorityNormal);
   581 		test_Equal(initialFreeRam,FreeRam()); // memory should be now freed
   582 
   583 		//
   584 		// cleanup...
   585 		//
   586 
   587 		test.Printf(_L("Destroy pin object\n"));
   588 		test_KErrNone(Ldd.DestroyVirtualPinObject());
   589 		test_KErrNone(Ldd2.DestroyVirtualPinObject());
   590 		chunk.Close();
   591 		}
   592 
   593 	test.Printf(_L("Flush paging cache\n"));
   594 	FlushPagingCache(); // this is a test that has shown up bugs in the past
   595 	}
   596 
   597 
   598 void TestPinOutOfMemory()
   599 	{
   600 	// Ensure that if pinning fails with KErrNoMemory,
   601 	// there isn't a memory leak
   602 	const TInt KMaxKernelAllocations = 1024;
   603 	TInt r=KErrNoMemory;
   604 	TInt i;
   605 	const TUint8* buffer = NULL;
   606 	if (PagedBuffer)
   607 		{
   608 		buffer = PagedBuffer;
   609 		}
   610 	else
   611 		{
   612 		buffer = UnpagedBuffer;
   613 		}
   614 	test_NotNull(buffer);
   615 
   616 	__KHEAP_MARK;
   617 	for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
   618 		{
   619 		__KHEAP_FAILNEXT(i);
   620 		test.Printf(_L("Create logical pin object\n"));
   621 		r = Ldd.CreateVirtualPinObject();
   622 		__KHEAP_RESET;
   623 		}
   624 	test.Printf(_L("Create logical pin object took %d tries\n"),i);
   625 	test_KErrNone(r);
   626 
   627 	r = KErrNoMemory;
   628 	for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
   629 		{
   630 		__KHEAP_FAILNEXT(i);
   631 		test.Printf(_L("Perform logical pin operation\n"));
   632 		r = Ldd.PinVirtualMemory((TLinAddr)buffer, KMinBufferSize);
   633 		__KHEAP_RESET;
   634 		}
   635 	test.Printf(_L("Perform logical pin operation took %d tries\n"),i);
   636 	if (r == KErrNone)
   637 		{
   638 		test.Printf(_L("Perform logical unpin operation\n"));
   639 		Ldd.UnpinVirtualMemory();
   640 		}
   641 	
   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);	
   646 	__KHEAP_MARKEND;
   647 
   648 	test_KErrNone(r);
   649 	}
   650 
   651 
   652 TInt KernelModifyData(TAny*)
   653 	{
   654 	Ldd.KernelMapReadAndModifyMemory();
   655 	return KErrNone;
   656 	}
   657 
   658 void TestMapAndPinMemory()
   659 	{
   660 	
   661 	TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
   662 	if (mm < EMemModelTypeFlexible)
   663 		{
   664 		test.Printf(_L("Memory model (%d) doesn't support physical pining\n"),mm);
   665 		return;
   666 		}
   667 	TInt i;
   668 	TUint KUCBytes = KUCPageCount * PageSize;
   669 	RChunk chunk;
   670 
   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();
   677 	
   678 	test.Printf(_L("Create kernel map object\n"));
   679 	test_KErrNone(Ldd.CreateKernelMapObject(0));
   680 
   681 	test.Printf(_L("Perform kernel map operation on zero-length buffer\n"));
   682 	test_KErrNone(Ldd.KernelMapMemory((TLinAddr)chunkBase, 0));	
   683 
   684 	test.Printf(_L("Perform kernel unmap operation\n"));
   685 	test_KErrNone(Ldd.KernelUnmapMemory());	
   686 
   687 	test.Printf(_L("Perform kernel map operation on the chunk\n"));
   688 	test_KErrNone(Ldd.KernelMapMemory((TLinAddr)chunkBase, KUCBytes));
   689 
   690 	test.Printf(_L("Attempt to map the memory again while already mapped\n"));
   691 	test_Equal(KErrInUse, Ldd.KernelMapMemory((TLinAddr)chunkBase, KUCBytes));
   692 
   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++)
   696 		*p++ = (TUint8)i;
   697 	test_KErrNone(Ldd.KernelMapReadAndModifyMemory());
   698 	p = chunkBase;
   699 	for (i = 0; i < (TInt)KUCBytes; i++)
   700 		test_Equal((TUint8)(i + 1), *p++);	
   701 
   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);
   708 		*ptr = 10;
   709 		}
   710 	test_KErrNone(Ldd.KernelMapCheckPageList(chunkBase)); 	// Check that the mapping is preserved. 	
   711 	
   712 	test.Printf(_L("Sync cache & memory of User Chunk\n"));	//Test Cache::SyncMemoryBeforeDmaWrite
   713 	test_KErrNone(Ldd.KernelMapSyncMemory());
   714 
   715 	test.Printf(_L("Invalidate cache of User Chunk\n"));//Test Cache::SyncMemoryBefore/AfterDmaRead
   716 	test_KErrNone(Ldd.KernelMapInvalidateMemory());
   717 	
   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++)
   720 		{
   721 		TInt r = Ldd.KernelMapMoveMemory(0);
   722 		test.Printf(_L("...[%d] returned %d\n"), i, r);
   723 		test(r != KErrNone);
   724 		}
   725 
   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));
   729 
   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.
   733 	p = chunkBase;
   734 	for (i = 0; i < (TInt)KUCBytes; i++)
   735 		*p++ = (TUint8)i;
   736 
   737 	RThread modThread;
   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());
   742 	modThread.Resume();
   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);
   748 
   749 	test.Printf(_L("Close the chunk\n")); // Phys. memory is pinned and shouldn't be ...
   750 	chunk.Close();						  // ... mapped to another virtual memory.
   751 
   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
   757 
   758 	test.Printf(_L("Invalidate cache of pinned memory\n"));//This shouldn't affect the second chunk.
   759 	test_KErrNone(Ldd.KernelMapInvalidateMemory());
   760 
   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);
   764 	
   765 	test.Printf(_L("Close the second chunk\n"));
   766 	chunk.Close();
   767 
   768 	test.Printf(_L("Perform kernel unmap operation\n"));
   769 	test_KErrNone(Ldd.KernelUnmapMemory());	
   770 
   771 	test.Printf(_L("Perform physical unpin operation (again)\n"));
   772 	test_KErrNone(Ldd.KernelUnmapMemory());	// test double unpin ok
   773 
   774 	test.Printf(_L("Destroy physical pin object\n"));
   775 	test_KErrNone(Ldd.DestroyKernelMapObject());
   776 
   777 	test.Printf(_L("Destroy physical pin object (again)\n"));
   778 	test_KErrNone(Ldd.DestroyKernelMapObject());  // test double destroy ok
   779 
   780 	//
   781 	//	Test a kernel mapping with preserved resources doesn't allocate when mapping and pinning.
   782 	//
   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));
   793 
   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());
   798 
   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));
   801 
   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.
   805 	__KHEAP_RESET;
   806 	chunk.Close();
   807 	}
   808 
   809 TInt E32Main()
   810 	{
   811 	test.Title();
   812 	test.Start(_L("Test kernel pinning APIs"));
   813 
   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"));
   820 	
   821 	test.Next(_L("Loading test drivers"));
   822 	test_KErrNone(Ldd.Open());
   823 	test_KErrNone(Ldd2.Open());
   824 
   825 	test.Next(_L("Getting page size"));
   826 	test_KErrNone(UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&PageSize,0));
   827 	
   828 	test.Next(_L("Setting up paged and unpaged buffers"));
   829 
   830 #ifdef __EPOC32__
   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);
   836 	
   837 	if (DPTest::Attributes() & DPTest::ERomPaging)
   838 		{
   839 		// Use end of paged ROM for our paged buffer
   840 		test(romHeader->iPageableRomStart);
   841 		TInt offset = romHeader->iPageableRomStart + romHeader->iPageableRomSize - KMinBufferSize;
   842 		offset &= ~0xfff;
   843 		test(offset>=romHeader->iPageableRomStart);
   844 		PagedBuffer = (TUint8*)romHeader + offset;
   845 		}
   846 	else if (DPTest::Attributes() & DPTest::ECodePaging)
   847 		{
   848 		// Use code paged DLL for our paged buffer
   849 		test_KErrNone(PagedLibrary.Load(KTCodePagingDll4));		
   850 		TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)PagedLibrary.Lookup(KGetAddressOfDataFunctionOrdinal);
   851 		TInt size;
   852 		PagedBuffer = (TUint8*)func(size);
   853 		test_NotNull(PagedBuffer);
   854 		test(size >= KMinBufferSize);
   855 		}
   856 #else
   857 	UnpagedBuffer = (TUint8*)User::Alloc(KMinBufferSize);
   858 	test_NotNull(UnpagedBuffer);
   859 #endif
   860 
   861 	RDebug::Printf("UnpagedBuffer=%x\n",UnpagedBuffer);
   862 	RDebug::Printf("PagedBuffer=%x\n",PagedBuffer);
   863 
   864 	__KHEAP_MARK;
   865 	
   866 	test.Next(_L("Logical pin unpaged memory"));
   867 	TestPinVirtualMemoryUnpaged();
   868 
   869 	test.Next(_L("Logical pin invalid memory"));
   870 	TestPinVirtualMemoryInvalid();
   871 
   872 	test.Next(_L("Physical pinning"));
   873 	TestPinPhysicalMemory();
   874 	
   875 	test.Next(_L("Physical pinning OOM"));
   876 	TestPhysicalPinOutOfMemory();
   877 
   878 	test.Next(_L("Kernel pin mapping"));
   879 	TestMapAndPinMemory();
   880 
   881 	test.Next(_L("Pin OOM Tests"));
   882 	TestPinOutOfMemory();
   883 
   884 	if (PagedBuffer)
   885 		{
   886 		test.Next(_L("Logical pin paged memory"));
   887 		TestPinVirtualMemoryPaged();
   888 
   889 		test.Next(_L("Logical pin paged memory soak test"));
   890 		TestPinVirtualMemoryPagedSoak();
   891 		}
   892 
   893 	if (DPTest::Attributes() & DPTest::EDataPaging)
   894 		{
   895 		test.Next(_L("Logical pin then decommit memory"));
   896 		TestPinVirtualMemoryDecommit();
   897 		}
   898 
   899 	// wait for any async cleanup in the supervisor to finish first...
   900 	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);	
   901 	__KHEAP_MARKEND;
   902 
   903 #ifndef __EPOC32__
   904 	User::Free((TAny*)UnpagedBuffer);
   905 #endif
   906 
   907 	PagedLibrary.Close();
   908 	Ldd.Close();
   909 	Ldd2.Close();
   910 	test.End();
   911 
   912 	return KErrNone;
   913 	}