kerneltest/e32test/mmu/t_sharedio.cpp
changeset 0 a41df078684a
child 109 b3a1d9898418
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mmu/t_sharedio.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,673 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test\mmu\t_sharedio.cpp
+// Overview:
+// Verifies the correct implementation of Shared IO Buffers
+// API information:
+// DSharedIoBuffer
+// Details:
+// 1. Loading the shared IO buffer test device driver
+// 2. Create buffer of a specified size
+// - it passes a request to the device driver to create a buffer
+// - the driver creates a shared io buffer and it zero fills it
+// - it checks the size is as specified
+// 3. Map in buffer
+// - it passes a request to the device driver to map the buffer created at
+// step 1 into this user process
+// - the driver maps the buffer into this user process
+// - checks if UserToKernel and KernelToUser methods work as expected
+// - fills a buffer
+// - returns the user address and size to the user process
+// - using the address and size returned by the driver, the user process
+// checks the buffer is filled as expected
+// 4. Fill and check shared buffer
+// - user process fills the buffer and driver checks it
+// - driver fills the buffer and user process checks it
+// 5. Map Out Buffer
+// - requests to the driver that the buffer should be unmapped from this
+// process' address space
+// - the driver checks that iUserAddress becomes NULL after unmapping
+// 6. Destroy Buffer
+// - requests to the driver to destroy the buffer
+// 7. Create a buffer with a physical address
+// (not performed on WINS)
+// - requests to the driver to create a buffer by specifying a physical address
+// - the driver allocates a physical address
+// - creates a shared IO buffer over that physical address
+// - fills the buffer with a pattern
+// - destroys the buffer
+// - creates a hardware chunk over the same physical address
+// - checks the buffer contains the pattern
+// - closes the chunk
+// 8. Check using the same buffer by 2 different user processes
+// (not performed on WINS)
+// - process 1 maps a global buffer (the global buffer will be
+// created in the context of process 1)
+// - fills it
+// - unmaps it
+// - process 2 maps the global buffer
+// - checks if it's filled accordingly
+// - unmaps it
+// - destroys the global buffer
+// 9. Checking buffers are protected at context switching
+// (not relevant on WINS)
+// - creates a shared buffer and map it into this process
+// - creates a new process
+// - the new process tries to access the buffer mapped into the first process
+// by zeroing the raw buffer passed from the first process. This relies on the
+// fact that each shared buffer is created in the Home Section, so they will be
+// available at the same address
+// - tests if the new process was panicked due to access violation
+// - tests if the contents of the buffer haven't been changed
+// 10.Checking writing to unmapped buffer
+// (not performed on WINS)
+// - creates a new process
+// - the new process creates a buffer, maps it and unmaps it
+// - the new process tries to use the buffer after unmapping
+// - the parent process logs the exit type and reason and checks
+// these are EExitPanic and 3 (Kern 3 - access violation)
+// 11.Checking address lookup is implemented
+// (not relevant on WINS)
+// - creates a new process
+// - the new process will ask the device driver to read and write a descriptor
+// in the old process, the kernel will perform an address lookup before
+// reading or writing the descriptor, to make sure the address location does
+// belong to the old process. The descriptor is a TPtr pointing to a buffer
+// located in a shared io buffer.
+// - device driver will return an error in case address lookup fails or ThreadRead
+// or ThreadWrite fail
+// - the new process returns the error code returned by the device driver
+// - the old process tests for the exit code for the new process being KErrNone and
+// that the thread is not panicked, and also that the values written and read
+// are those expected.
+// 12.Closing test driver
+// - Trivial, but it will test if a created & mapped shared io buffer gets released
+// successfully when the logical channel is closed (which in turn will delete the
+// shared io buffer associated with the channel)
+// The test comes in 4 flavours, in order to test memory protection when context switching
+// between different types of processes.
+// T_SHAREDIO:
+// Main process is a moving process which creates another moving process.
+// T_SHAREDIO2:
+// Main process is a fixed process which creates a moving process.
+// T_SHAREDIO3:
+// Main process is a fixed process which creates another fixed process.
+// T_SHAREDIO4:
+// Main process is a moving process which creates a fixed process.
+// Platforms/Drives/Compatibility:
+// All (some steps will not be performed on emulator)
+// Assumptions/Requirement/Pre-requisites:
+// The test needs D_SHAREDIO.LDD, the device driver that actually operates the API. 
+// Failures and causes:
+// Failures of this test will indicate defects in the implementation of Shared Io Buffers.
+// Base Port information:
+// No?
+// 
+//
+
+#define __E32TEST_EXTENSION__
+
+#include <e32test.h>
+#include <e32math.h>
+#include "d_sharedio.h"
+#include <e32hal.h>
+#include "u32std.h"
+#include <u32hal.h>
+#include <e32svr.h>
+#include <f32dbg.h>
+#include <e32def.h>
+#include <e32def_private.h>
+#include "freeram.h"
+
+LOCAL_D RTest test(_L("T_SHAREDIO"));
+
+const TInt KTestBufferSize = 0x100000;
+
+TUint MemModelAttributes;
+TBool PhysicalCommitSupported;
+
+RTestLdd ldd;
+
+TUint32 TestBufferSizes[]={0x1000, 0x10453, 0x100000, 0x100001, 0x203000, 0};
+
+TInt checkBuffer(TAny* buffer, TUint32 aSize, TUint32 key)
+	{
+	TInt r=KErrNone;
+	TUint8* m=(TUint8*)buffer;
+	for(TUint32 size=0;size<aSize;size++,key+=5,m++)
+		{
+		if(*m!=(TUint8)(key%256))
+			{
+			r=KErrCorrupt;
+			break;
+			}
+		}
+	return r;
+	}
+
+TInt fillBuffer(TAny* buffer, TUint32 aSize, TUint32 key)
+	{
+	TUint8* m=(TUint8*)buffer;
+	for(TUint32 size=0;size<aSize;size++,key+=5,m++)
+		{
+		*m=(TUint8)(key%256);
+		}
+	return KErrNone;
+	}
+
+TBool CheckBuffer(TAny* aBuffer,TInt aSize)
+	{
+	TAny** p = (TAny**)aBuffer;
+	TAny** end = (TAny**)((TInt)p+aSize);
+	while(p<end)
+		{
+		if(*p!=p)
+			return EFalse;
+		++p;
+		}
+	return ETrue;
+	}
+
+enum TTestProcessFunctions
+	{
+	ETestProcess1,
+	ETestProcess2,
+	ETestProcess3,
+	};
+
+class RTestProcess : public RProcess
+	{
+public:
+	void Create(TTestProcessFunctions aFunction,TInt aArg1=-1,TInt aArg2=-1);
+	};
+
+void RTestProcess::Create(TTestProcessFunctions aFunction,TInt aArg1,TInt aArg2)
+	{
+	if(aArg1==-1)
+		aArg1 = RProcess().Id();
+	TBuf<512> commandLine;
+	commandLine.Num((TInt)aFunction);
+	commandLine.Append(_L(" "));
+	commandLine.AppendNum(aArg1);
+	commandLine.Append(_L(" "));
+	commandLine.AppendNum(aArg2);
+#ifdef __FIXED__
+	//fixed process creating a moving process
+	TFileName filename(RProcess().FileName());
+	TInt pos=filename.LocateReverse(TChar('\\'));
+	filename.SetLength(pos+1);
+	filename+=_L("T_SHAREDIO.EXE");
+	TInt r = RProcess::Create(filename,commandLine);
+#else
+#ifdef __SECOND_FIXED__
+	//fixed process creating another fixed process
+	TFileName filename(RProcess().FileName());
+	TInt pos=filename.LocateReverse(TChar('\\'));
+	filename.SetLength(pos+1);
+	filename+=_L("T_SHAREDIO2.EXE");
+	TInt r = RProcess::Create(filename,commandLine);
+#else
+#ifdef __MOVING_FIXED__
+	//moving process creating a fixed process
+	TFileName filename(RProcess().FileName());
+	TInt pos=filename.LocateReverse(TChar('\\'));
+	filename.SetLength(pos+1);
+	filename+=_L("T_SHAREDIO2.EXE");
+	TInt r = RProcess::Create(filename,commandLine);
+#else
+	//moving process creating a moving process
+	TInt r = RProcess::Create(RProcess().FileName(),commandLine);
+#endif
+#endif
+#endif
+	test(r==KErrNone);
+	SetJustInTime(EFalse);
+	}
+
+const TInt KProcessRendezvous = KRequestPending+1;
+
+TInt DoTestProcess(TInt aTestNum,TInt aArg1,TInt aArg2)
+	{
+	(void)aArg1;
+	(void)aArg2;
+
+	RTestLdd ldd;
+	TInt r;
+	r=User::LoadLogicalDevice(KSharedIoTestLddName);
+	if(r!=KErrNone && r!=KErrAlreadyExists)
+		return KErrGeneral;
+	r=ldd.Open();
+	if(r!=KErrNone)
+		return r;
+
+	switch(aTestNum)
+		{
+	case ETestProcess1:
+		{
+		TAny* gbuffer;
+		TUint32 gsize;
+		r=User::GetTIntParameter(1,(TInt&)gbuffer);
+		if(r!=KErrNone)
+			return r;
+		r=User::GetTIntParameter(2,(TInt&)gsize);
+		if(r!=KErrNone)
+			return r;
+
+		r=checkBuffer(gbuffer,gsize,23454);
+		if(r!=KErrNone)
+			return r;
+		r=ldd.MapOutGlobalBuffer();
+		if(r!=KErrNone)
+			return r;
+
+		r=ldd.CreateBuffer(KTestBufferSize);
+		if(r!=KErrNone)
+			return r;
+
+		TAny* buffer;
+		TUint32 size;
+		r=ldd.MapInBuffer(&buffer,&size);
+		if(r!=KErrNone)
+			return r;
+
+		if(!CheckBuffer(buffer,size))
+			return KErrGeneral;
+
+		r=ldd.MapOutBuffer();
+		if(r!=KErrNone)
+			return r;
+
+		RProcess::Rendezvous(KProcessRendezvous);
+
+		*(TInt*)buffer = 0;   // Should cause exception
+		break;
+		}
+	case ETestProcess2:
+		{
+		TInt size=aArg2;
+		TUint8* p=(TUint8*)aArg1;
+
+		RProcess::Rendezvous(KProcessRendezvous);
+		for(TInt i=0;i<size;i++)
+			p[i]=0; // Should cause exception
+		break;
+		}
+	case ETestProcess3:
+		{
+		TAny* buffer;
+		TUint32 size;
+
+		r=ldd.CreateBuffer(KTestBufferSize);
+		if(r!=KErrNone)
+			return r;
+
+		r=ldd.MapInBuffer(&buffer,&size);
+		if(r!=KErrNone)
+			return r;
+
+		if(!CheckBuffer(buffer,size))
+			return KErrGeneral;
+
+		*(TInt*)buffer=KMagic1;
+		TPckg<TInt> buf(*(TInt*)buffer);
+		r=ldd.ThreadRW(buf);
+		if(r!=KErrNone)
+			return r;
+
+		if(*(TInt*)buffer!=KMagic2)
+			return KErrCorrupt;
+
+		r=ldd.ThreadRW(*(TDes8*)aArg1,aArg2);
+		if(r!=KErrNone)
+			return r;
+		
+		r=ldd.MapOutBuffer();
+		if(r!=KErrNone)
+			return r;
+
+		break;
+		}
+	default:
+		User::Panic(_L("T_SHAREDIO"),1);
+		}
+
+	ldd.Close();	
+	return KErrNone;
+	}
+
+void CreateWithOOMCheck(TInt aSize, TBool aPhysicalAddress)
+	{
+	TInt failResult=KErrGeneral;
+
+	TInt freeRam = FreeRam(); //This will also add a delay
+
+	for(TInt failCount=1; failCount<1000; failCount++)
+		{
+		test.Printf(_L("alloc fail count = %d\n"),failCount);
+
+		User::__DbgSetAllocFail(ETrue,RAllocator::EFailNext,failCount);
+		__KHEAP_MARK;
+		
+		if (aPhysicalAddress)
+			failResult=ldd.CreateBufferPhysAddr(aSize);
+		else
+			failResult=ldd.CreateBuffer(aSize);
+
+		if(failResult==KErrNone)
+			break;
+
+		test(failResult==KErrNoMemory);
+		__KHEAP_MARKEND;
+
+		test(freeRam == FreeRam());  //This will also add a delay
+		}
+	User::__DbgSetAllocFail(ETrue,RAllocator::ENone,0);
+	__KHEAP_RESET;
+
+	test.Next(_L("Destroy buffer"));
+	if (aPhysicalAddress)
+		ldd.DestroyBufferPhysAddr();
+	else
+		ldd.DestroyBuffer();
+	
+	test(freeRam == FreeRam());  //This will also add a delay
+	}
+
+GLDEF_C TInt E32Main()
+    {
+	TBuf16<512> cmd;
+	User::CommandLine(cmd);
+	if(cmd.Length() && TChar(cmd[0]).IsDigit())
+		{
+		TInt function = -1;
+		TInt arg1 = -1;
+		TInt arg2 = -1;
+		TLex lex(cmd);
+		lex.Val(function);
+		lex.SkipSpace();
+		lex.Val(arg1);
+		lex.SkipSpace();
+		lex.Val(arg2);
+		return DoTestProcess(function,arg1,arg2);
+		}
+
+	MemModelAttributes=UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
+	TUint mm=MemModelAttributes&EMemModelTypeMask;
+	PhysicalCommitSupported = mm!=EMemModelTypeDirect && mm!=EMemModelTypeEmul;
+
+// Turn off lazy dll unloading
+	RLoader l;
+	test(l.Connect()==KErrNone);
+	test(l.CancelLazyDllUnload()==KErrNone);
+	l.Close();
+
+	test.Title();
+
+#if defined(__FIXED__) || defined(__SECOND_FIXED__) || defined(__MOVING_FIXED__)
+	if(mm!=EMemModelTypeMoving)
+		{
+		test.Printf(_L("TESTS NOT RUN - Only applicable to moving memory model\r\n"));
+		return 0;
+		}
+#endif
+
+	test.Start(_L("Loading test driver..."));
+
+	TInt r;
+	r=User::LoadLogicalDevice(KSharedIoTestLddName);
+	test(r==KErrNone || r==KErrAlreadyExists);
+	r=User::LoadLogicalDevice(KSharedIoTestLddName);
+	test(r==KErrAlreadyExists);
+	r=ldd.Open();
+	test(r==KErrNone);
+
+	TAny* buffer;
+	TUint32 size;
+	TUint32 key;
+
+	TInt testBufferSize=0;
+	for(; TestBufferSizes[testBufferSize]!=0; ++testBufferSize)
+		{
+		test.Printf(_L("Test buffer size = %08x\n"),TestBufferSizes[testBufferSize]);
+
+		test.Next(_L("Create buffer"));
+		r=ldd.CreateBuffer(TestBufferSizes[testBufferSize]);
+		if(r!=KErrNone)
+			test.Printf(_L("Creating buffer failed client r=%d"), r);
+		test(r==KErrNone);
+
+		test.Next(_L("Map In Buffer"));
+		r=ldd.MapInBuffer(&buffer,&size);
+		
+		test.Next(_L("CheckBuffer"));
+		test(CheckBuffer(buffer,size));
+		test(r==KErrNone);
+		test.Next(_L("Fill and check shared buffer"));
+		key=Math::Random();
+		fillBuffer(buffer,size,key);
+		test(ldd.CheckBuffer(key)==KErrNone);
+
+		key=Math::Random();
+		test(ldd.FillBuffer(key)==KErrNone);
+		test(checkBuffer(buffer,size,key)==KErrNone);
+
+		test.Next(_L("Map Out Buffer"));
+		r=ldd.MapOutBuffer();
+		test(r==KErrNone);
+
+		test.Next(_L("Destroy Buffer"));
+		r=ldd.DestroyBuffer();
+		test(r==KErrNone);
+
+		test.Next(_L("Create a buffer under OOM conditions"));
+		CreateWithOOMCheck(TestBufferSizes[testBufferSize], EFalse);
+
+		if(PhysicalCommitSupported)
+			{
+			test.Next(_L("Create a buffer with a physical address under OOM conditions"));
+			CreateWithOOMCheck(TestBufferSizes[testBufferSize], ETrue);
+
+			test.Next(_L("Create a buffer with a physical address"));
+			r=ldd.CreateBufferPhysAddr(0x1000);
+			test(r==KErrNone);
+
+			test.Next(_L("Map In physical address Buffer"));
+			r=ldd.MapInBuffer(&buffer,&size);
+			test(r==KErrNone);
+
+			test.Next(_L("Fill and check physical address shared buffer"));
+			key=Math::Random();
+			fillBuffer(buffer,size,key);
+			test(ldd.CheckBuffer(key)==KErrNone);
+
+			key=Math::Random();
+			test(ldd.FillBuffer(key)==KErrNone);
+			test(checkBuffer(buffer,size,key)==KErrNone);
+
+			test.Next(_L("Map Out physical address Buffer"));
+			r=ldd.MapOutBuffer();
+			test(r==KErrNone);
+
+			test.Next(_L("Destroy a buffer with a physical address"));
+			r=ldd.DestroyBufferPhysAddr();
+			test(r==KErrNone);
+		}
+
+		test.Next(_L("Check using the same buffer by 2 different user processes"));
+		TAny* gbuffer;
+		TUint32 gsize;
+		r=ldd.MapInGlobalBuffer(RProcess().Id(),gbuffer,gsize);
+		test(r==KErrNone);
+
+		fillBuffer(gbuffer,gsize,23454);
+
+		r=ldd.MapOutGlobalBuffer();
+		test(r==KErrNone);
+
+		r=ldd.CreateBuffer(TestBufferSizes[testBufferSize]);
+		test(r==KErrNone);
+
+		r=ldd.MapInBuffer(&buffer,&size);
+		test(r==KErrNone);
+
+		test(CheckBuffer(buffer,size));
+
+		key=Math::Random();
+		fillBuffer(buffer,size,key);
+		test(ldd.CheckBuffer(key)==KErrNone);
+
+		RTestProcess rogueP;
+		TRequestStatus rendezvous;
+		TRequestStatus logon;
+
+		if(MemModelAttributes&EMemModelAttrProcessProt)
+			{
+			test.Next(_L("Checking buffers are protected at context switching"));
+			rogueP.Create(ETestProcess2,(TInt)buffer,(TInt)size);
+			rogueP.Logon(logon);
+			rogueP.Rendezvous(rendezvous);
+			rogueP.Resume();
+			User::WaitForRequest(rendezvous);
+			test(rendezvous==KProcessRendezvous);
+			User::WaitForRequest(logon);
+			test(rogueP.ExitType()==EExitPanic);
+			test(logon==3);
+			test(ldd.CheckBuffer(key)==KErrNone);
+			}
+
+		r=ldd.MapOutBuffer();
+		test(r==KErrNone);
+
+		r=ldd.DestroyBuffer();
+		test(r==KErrNone);
+
+		RTestProcess process;
+
+		if((MemModelAttributes&EMemModelAttrKernProt) && (MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
+			{
+			test.Next(_L("Checking writing to unmapped buffer"));
+			process.Create(ETestProcess1);
+			process.Logon(logon);
+			process.Rendezvous(rendezvous);
+			test(ldd.MapInGlobalBuffer(process.Id(),gbuffer,gsize)==KErrNone);
+			test(process.SetParameter(1,(TInt)gbuffer)==KErrNone);
+			test(process.SetParameter(2,(TInt)gsize)==KErrNone);
+			process.Resume();
+			User::WaitForRequest(rendezvous);
+			test(rendezvous==KProcessRendezvous);
+			User::WaitForRequest(logon);
+			test(process.ExitType()==EExitPanic);
+			test(logon==3);
+			process.Close();
+			}
+
+		r=ldd.CreateBuffer(TestBufferSizes[testBufferSize]);
+		if(r!=KErrNone)
+			return r;
+
+		r=ldd.MapInBuffer(&buffer,&size);
+		if(r!=KErrNone)
+			return r;
+
+		if(!CheckBuffer(buffer,size))
+			return KErrGeneral;
+
+		*(TInt*)buffer=KMagic1;
+		TPckg<TInt> buf(*(TInt*)buffer);
+
+		RTestProcess proc;
+		test.Next(_L("Checking address lookup is implemented"));
+		proc.Create(ETestProcess3,(TInt)&buf,RThread().Id());
+		proc.Logon(logon);
+		proc.Resume();
+		User::WaitForRequest(logon);
+
+		test(proc.ExitType()==EExitKill);
+		test(logon==0);
+		test(*(TInt*)buffer==KMagic2);
+
+		ldd.DestroyBuffer();
+
+		// Check process death whilst buffer is mapped in
+		// Test case for defect DEF051851 - Shared IO Buffer fault when process dies
+		test.Next(_L("Checking process death whilst buffer is mapped in"));
+			process.Create(ETestProcess1);
+			process.Logon(logon);
+			test.Start(_L("Map buffer into another process"));
+			test(ldd.MapInGlobalBuffer(process.Id(),gbuffer,gsize)==KErrNone);
+			test.Next(_L("Kill other process"));
+			process.Kill(99);
+			User::WaitForRequest(logon);
+			test(process.ExitType()==EExitKill);
+			test(logon==99);
+			process.Close();
+			test.Next(_L("Map out buffer"));
+			r=ldd.MapOutGlobalBuffer();
+			test.Printf(_L("result = %d\n"),r);
+			test(r==KErrNone);
+
+			test.Next(_L("Map buffer into this process"));
+			test(ldd.MapInGlobalBuffer(RProcess().Id(),gbuffer,gsize)==KErrNone);
+			test.Next(_L("Map out buffer from this process"));
+			r=ldd.MapOutGlobalBuffer();
+			test.Printf(_L("result = %d\n"),r);
+			test(r==KErrNone);
+
+			process.Create(ETestProcess1);
+			process.Logon(logon);
+			test.Next(_L("Map buffer into another process"));
+			test(ldd.MapInGlobalBuffer(process.Id(),gbuffer,gsize)==KErrNone);
+			test.Next(_L("Kill other process"));
+			process.Kill(99);
+			User::WaitForRequest(logon);
+			test(process.ExitType()==EExitKill);
+			test(logon==99);
+			process.Close();
+			test.Next(_L("Map out buffer"));
+			r=ldd.MapOutGlobalBuffer();
+			test.Printf(_L("result = %d\n"),r);
+			test(r==KErrNone);
+			test.End();
+	} // loop for next buffer size
+
+	test.Next(_L("Create and map in buffer"));
+	r=ldd.CreateBuffer(KTestBufferSize);
+	test(r==KErrNone);
+	r=ldd.MapInBuffer(&buffer,&size);
+	test(r==KErrNone);
+
+//  Test for DEF053512 - Can't delete SharedIo buffers in DLogicalDevice destructor 
+
+	test.Next(_L("Map in global buffer"));
+	TAny* gbuffer;
+	TUint32 gsize;
+	test(ldd.MapInGlobalBuffer(RProcess().Id(),gbuffer,gsize)==KErrNone);
+
+	test.Next(_L("Closing channel (with a buffer still mapped in)"));
+	ldd.Close();
+
+//  Test for DEF053512 - Can't delete SharedIo buffers in DLogicalDevice destructor 
+
+	test.Next(_L("Unload driver (whilst global buffer still mapped in)"));
+	r=User::FreeLogicalDevice(KSharedIoTestLddName);
+	test(r==KErrNone);
+
+	test.End();
+
+
+
+	return(0);
+    }
+
+