--- /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);
+ }
+
+