kerneltest/e32test/mmu/t_pin.cpp
changeset 13 46fffbe7b5a7
parent 9 96e5fb8b040d
--- a/kerneltest/e32test/mmu/t_pin.cpp	Fri Jan 22 11:03:55 2010 +0200
+++ b/kerneltest/e32test/mmu/t_pin.cpp	Tue Jan 26 13:13:38 2010 +0200
@@ -115,7 +115,7 @@
 
 	test.Printf(_L("Allocate user chunk\n"));
 	TChunkCreateInfo createInfo;
-	createInfo.SetDisconnected(0,UCPageCount*PageSize,UCPageCount*PageSize);
+	createInfo.SetDisconnected(0,KUCPageCount*PageSize,KUCPageCount*PageSize);
 	createInfo.SetPaging(TChunkCreateInfo::EPaged);
 	test_KErrNone(chunk.Create(createInfo));
 	UCBase = (TInt8*)chunk.Base();
@@ -130,12 +130,12 @@
 	test_KErrNone(Ldd.UnpinPhysicalMemory());	
 
 	test.Printf(_L("Perform Physical pin operation on the chunk\n"));
-	test_KErrNone(Ldd.PinPhysicalMemory((TLinAddr)UCBase, UCPageCount*PageSize));	
+	test_KErrNone(Ldd.PinPhysicalMemory((TLinAddr)UCBase, KUCPageCount*PageSize));	
 
 	test.Printf(_L("Test that pinned physical memory preserves its mapping when recommited\n"));
-	test_KErrNone(chunk.Decommit(0,UCPageCount*PageSize));							 //Decommit all
-	for (i=UCPageCount-1;i>=0;i--) test_KErrNone(chunk.Commit(i*PageSize,PageSize)); //Commit in reverse order
-	for (i=0;i<UCPageCount;i++) // Recommited memory is not paged in. So, write into each page, before driver 
+	test_KErrNone(chunk.Decommit(0,KUCPageCount*PageSize));							 //Decommit all
+	for (i=KUCPageCount-1;i>=0;i--) test_KErrNone(chunk.Commit(i*PageSize,PageSize)); //Commit in reverse order
+	for (i=0;i<KUCPageCount;i++) // Recommited memory is not paged in. So, write into each page, before driver 
 		{						// calls Kern::LinearToPhysical or it will get KErrInvalidMemory in return.
 		volatile TInt8* ptr = (volatile TInt8*)(UCBase+i*PageSize);
 		*ptr = 10;
@@ -143,10 +143,10 @@
 	test_KErrNone(Ldd.CheckPageList(chunk.Base())); 					// Check that the mapping is preserved. 	
 	
 	test.Printf(_L("Sync cache & memory of User Chunk\n"));//Test Cache::SyncPhysicalMemoryBeforeDmaWrite
-	test_KErrNone(Ldd.SyncPinnedPhysicalMemory(0,UCPageCount*PageSize));
+	test_KErrNone(Ldd.SyncPinnedPhysicalMemory(0,KUCPageCount*PageSize));
 
 	test.Printf(_L("Invalidate cache of User Chunk\n"));//Test Cache::SyncPhysicalMemoryBefore/AfterDmaRead
-	test_KErrNone(Ldd.InvalidatePinnedPhysicalMemory(0,UCPageCount*PageSize));
+	test_KErrNone(Ldd.InvalidatePinnedPhysicalMemory(0,KUCPageCount*PageSize));
 	
 	test.Printf(_L("Try to move pinned phys. memory...\n")); //RAM defrag should return error code here.
 	i = Ldd.MovePinnedPhysicalMemory(0);
@@ -157,15 +157,15 @@
 	chunk.Close();						  // ... mapped to another virtual memory.
 
 	test.Printf(_L("Allocate & initilise the second chunk\n"));// Kernel sholudn't commit pinned physical memory ...
-	test_KErrNone(chunk.CreateLocal(2*PageSize,2*PageSize));   // ...that has been just decommited from the first chunk.
+	test_KErrNone(chunk.CreateLocal(KUCPageCount*PageSize,KUCPageCount*PageSize));   // ...that has been just decommited from the first chunk.
 	UCBase = (TInt8*)chunk.Base();
-	for (i=0;i<UCPageCount*PageSize;i++) UCBase[i]=0; //Initialise user buffer
+	for (i=0;i<KUCPageCount*PageSize;i++) UCBase[i]=0; //Initialise user buffer
 
 	test.Printf(_L("Invalidate cache of pinned memory\n"));//This shouldn't affect the second chunk.
-	test_KErrNone(Ldd.InvalidatePinnedPhysicalMemory(0,UCPageCount*PageSize));
+	test_KErrNone(Ldd.InvalidatePinnedPhysicalMemory(0,KUCPageCount*PageSize));
 
 	test.Printf(_L("Check data in the second chunk is unaffected\n"));
-	for (i=0;i<UCPageCount*PageSize;i++) test(UCBase[i]==0);
+	for (i=0;i<KUCPageCount*PageSize;i++) test(UCBase[i]==0);
 	
 	test.Printf(_L("Close the second chunk\n"));
 	chunk.Close();
@@ -199,7 +199,7 @@
 	RChunk chunk;
 
 	test.Printf(_L("Allocate user chunk\n"));
-	test_KErrNone(chunk.CreateDisconnectedLocal(0,UCPageCount*PageSize,UCPageCount*PageSize));
+	test_KErrNone(chunk.CreateDisconnectedLocal(0,KUCPageCount*PageSize,KUCPageCount*PageSize));
 	UCBase = (TInt8*)chunk.Base();
 	
 	const TInt KMaxKernelAllocations = 1024;
@@ -223,7 +223,7 @@
 		{
 		__KHEAP_FAILNEXT(i);
 		test.Printf(_L("Perform physical pin operation\n"));
-		r = Ldd.PinPhysicalMemory((TLinAddr)UCBase, UCPageCount*PageSize);
+		r = Ldd.PinPhysicalMemory((TLinAddr)UCBase, KUCPageCount*PageSize);
 		__KHEAP_RESET;
 		}
 	test.Printf(_L("Perform physical pin operation took %d tries\n"),i);
@@ -649,6 +649,163 @@
 	}
 
 
+TInt KernelModifyData(TAny*)
+	{
+	Ldd.KernelMapReadAndModifyMemory();
+	return KErrNone;
+	}
+
+void TestMapAndPinMemory()
+	{
+	
+	TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
+	if (mm < EMemModelTypeFlexible)
+		{
+		test.Printf(_L("Memory model (%d) doesn't support physical pining\n"),mm);
+		return;
+		}
+	TInt i;
+	TUint KUCBytes = KUCPageCount * PageSize;
+	RChunk chunk;
+
+	test.Printf(_L("Allocate user chunk\n"));
+	TChunkCreateInfo createInfo;
+	createInfo.SetDisconnected(0, KUCBytes, KUCBytes);
+	createInfo.SetPaging(TChunkCreateInfo::EPaged);
+	test_KErrNone(chunk.Create(createInfo));
+	TUint8* chunkBase = (TUint8*)chunk.Base();
+	
+	test.Printf(_L("Create kernel map object\n"));
+	test_KErrNone(Ldd.CreateKernelMapObject(0));
+
+	test.Printf(_L("Perform kernel map operation on zero-length buffer\n"));
+	test_KErrNone(Ldd.KernelMapMemory((TLinAddr)chunkBase, 0));	
+
+	test.Printf(_L("Perform kernel unmap operation\n"));
+	test_KErrNone(Ldd.KernelUnmapMemory());	
+
+	test.Printf(_L("Perform kernel map operation on the chunk\n"));
+	test_KErrNone(Ldd.KernelMapMemory((TLinAddr)chunkBase, KUCBytes));
+
+	test.Printf(_L("Attempt to map the memory again while already mapped\n"));
+	test_Equal(KErrInUse, Ldd.KernelMapMemory((TLinAddr)chunkBase, KUCBytes));
+
+	test.Printf(_L("Use the kernel mapping to modify the data and verify it\n"));
+	TUint8* p = chunkBase;
+	for (i = 0; i < (TInt)KUCBytes; i++)
+		*p++ = (TUint8)i;
+	test_KErrNone(Ldd.KernelMapReadAndModifyMemory());
+	p = chunkBase;
+	for (i = 0; i < (TInt)KUCBytes; i++)
+		test_Equal((TUint8)(i + 1), *p++);	
+
+	test.Printf(_L("Test that kernel mapped memory preserves its mapping when recommited\n"));
+	test_KErrNone(chunk.Decommit(0,KUCPageCount*PageSize));							 //Decommit all
+	for (i=KUCPageCount-1;i>=0;i--) test_KErrNone(chunk.Commit(i*PageSize,PageSize)); //Commit in reverse order
+	for (i=0;i<KUCPageCount;i++) // Recommited memory is not paged in. So, write into each page, before driver 
+		{						// calls Kern::LinearToPhysical or it will get KErrInvalidMemory in return.
+		volatile TInt8* ptr = (volatile TInt8*)(chunkBase+i*PageSize);
+		*ptr = 10;
+		}
+	test_KErrNone(Ldd.KernelMapCheckPageList(chunkBase)); 	// Check that the mapping is preserved. 	
+	
+	test.Printf(_L("Sync cache & memory of User Chunk\n"));	//Test Cache::SyncMemoryBeforeDmaWrite
+	test_KErrNone(Ldd.KernelMapSyncMemory());
+
+	test.Printf(_L("Invalidate cache of User Chunk\n"));//Test Cache::SyncMemoryBefore/AfterDmaRead
+	test_KErrNone(Ldd.KernelMapInvalidateMemory());
+	
+	test.Printf(_L("Try to move kernel map memory...\n")); //RAM defrag should return error code here.
+	for (i = 0; i < KUCPageCount; i++)
+		{
+		TInt r = Ldd.KernelMapMoveMemory(0);
+		test.Printf(_L("...[%d] returned %d\n"), i, r);
+		test(r != KErrNone);
+		}
+
+	test.Printf(_L("Unmap the memory and attempt to map with invalid attributes\n"));
+	test_KErrNone(Ldd.KernelUnmapMemory());
+	test_Equal(KErrArgument, Ldd.KernelMapMemoryInvalid((TLinAddr)chunkBase, KUCBytes));
+
+	test.Printf(_L("Map the memory read only and attempt to modify it kernel side\n"));
+	test_KErrNone(Ldd.KernelMapMemoryRO((TLinAddr)chunkBase, KUCBytes));
+	// Reset the contents of the memory.
+	p = chunkBase;
+	for (i = 0; i < (TInt)KUCBytes; i++)
+		*p++ = (TUint8)i;
+
+	RThread modThread;
+	test_KErrNone(modThread.Create(KNullDesC, KernelModifyData, PageSize, PageSize, PageSize, (TAny*)NULL));
+	TRequestStatus status;
+	modThread.Logon(status);
+	test_Equal(KRequestPending, status.Int());
+	modThread.Resume();
+	User::WaitForRequest(status);
+	test_Equal(EExitPanic, modThread.ExitType());
+	test(modThread.ExitCategory() == _L("KERN-EXEC"));
+	test_Equal(ECausedException, modThread.ExitReason());
+	CLOSE_AND_WAIT(modThread);
+
+	test.Printf(_L("Close the chunk\n")); // Phys. memory is pinned and shouldn't be ...
+	chunk.Close();						  // ... mapped to another virtual memory.
+
+	test.Printf(_L("Allocate & initilise the second chunk\n"));// Kernel shouldn't commit pinned physical memory ...
+	test_KErrNone(chunk.CreateLocal(KUCBytes, KUCBytes));   // ...that has just been decommited from the first chunk.
+	chunkBase = (TUint8*)chunk.Base();
+	for (i = 0; i < KUCPageCount * PageSize; i++) 
+		chunkBase[i] = 0; //Initialise user buffer
+
+	test.Printf(_L("Invalidate cache of pinned memory\n"));//This shouldn't affect the second chunk.
+	test_KErrNone(Ldd.KernelMapInvalidateMemory());
+
+	test.Printf(_L("Check data in the second chunk is unaffected\n"));
+	for (i=0; i < KUCPageCount * PageSize; i++) 
+		test(chunkBase[i]==0);
+	
+	test.Printf(_L("Close the second chunk\n"));
+	chunk.Close();
+
+	test.Printf(_L("Perform kernel unmap operation\n"));
+	test_KErrNone(Ldd.KernelUnmapMemory());	
+
+	test.Printf(_L("Perform physical unpin operation (again)\n"));
+	test_KErrNone(Ldd.KernelUnmapMemory());	// test double unpin ok
+
+	test.Printf(_L("Destroy physical pin object\n"));
+	test_KErrNone(Ldd.DestroyKernelMapObject());
+
+	test.Printf(_L("Destroy physical pin object (again)\n"));
+	test_KErrNone(Ldd.DestroyKernelMapObject());  // test double destroy ok
+
+	//
+	//	Test a kernel mapping with preserved resources doesn't allocate when mapping and pinning.
+	//
+	test.Printf(_L("Create a pre-reserving kernel mapping object\n"));
+	TUint mappingSize = KUCBytes>>1;
+	// This test step relies on mapping objet being smaller than the user chunk
+	// and as mapping object will always be >=2 pages, user chunk must be at least 4.
+	__ASSERT_COMPILE(KUCPageCount >= 4);
+	test_KErrNone(Ldd.CreateKernelMapObject(mappingSize));
+	TChunkCreateInfo chunkInfo;
+	chunkInfo.SetNormal(KUCBytes, KUCBytes);
+	chunkInfo.SetPaging(TChunkCreateInfo::EUnpaged);
+	test_KErrNone(chunk.Create(chunkInfo));
+
+	test.Printf(_L("Map and pin an unpaged chunk with pre-reserved resources\n"));
+	__KHEAP_FAILNEXT(1);	// Ensure any attempted kernel heap allocations fail.
+	test_KErrNone(Ldd.KernelMapMemory((TLinAddr)chunk.Base(), mappingSize));
+	test_KErrNone(Ldd.KernelUnmapMemory());
+
+	test.Printf(_L("Map more memory than we have pre-reserved resources for\n"));
+	test_Equal(KErrArgument, Ldd.KernelMapMemory((TLinAddr)chunk.Base(), mappingSize*2));
+
+	test.Printf(_L("Destroy the kernel map object with pre-reserved resources\n"));
+	test_KErrNone(Ldd.DestroyKernelMapObject());	// This will also unpin the memory.
+	// Clear the kernel heap fail next.
+	__KHEAP_RESET;
+	chunk.Close();
+	}
+
 TInt E32Main()
 	{
 	test.Title();
@@ -717,7 +874,10 @@
 	
 	test.Next(_L("Physical pinning OOM"));
 	TestPhysicalPinOutOfMemory();
-	
+
+	test.Next(_L("Kernel pin mapping"));
+	TestMapAndPinMemory();
+
 	test.Next(_L("Pin OOM Tests"));
 	TestPinOutOfMemory();