kerneltest/e32test/mmu/t_wsd_tst.cpp
branchRCL_3
changeset 21 e7d2d738d3c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mmu/t_wsd_tst.cpp	Mon Mar 15 12:45:50 2010 +0200
@@ -0,0 +1,466 @@
+// Copyright (c) 2006-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_wsd_tst.cpp
+// Test exporting and importing writable static data in DLLs.
+// This test relies on three dlls:
+// - t_wsd_dl1_[cx][pu]		Which is statically linked, and exports both code & data
+// - t_wsd_dl2_[cx][pu]		Which is dyanamically loaded, and imports code & writable static data from
+// - t_wsd_dl3_[cx][pu]		Which exports code and writable static data
+// The [cx] suffix indicates code-in-RAM vs XIP (ROM), and [pu] indicate paged or unpaged code.
+//
+
+//! @SYMTestCaseID			KBASE-T_CODEPAGING-0335
+//! @SYMTestType			UT
+//! @SYMPREQ				PREQ1110
+//! @SYMTestCaseDesc		Demand Paging Code Paging tests.
+//! @SYMTestActions			001 Code paging tests
+//! @SYMTestExpectedResults All tests should pass.
+//! @SYMTestPriority        High
+//! @SYMTestStatus          Implemented
+
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+#include <e32math.h>
+#include <f32file.h>
+#include <f32dbg.h>
+
+#include "mmudetect.h"
+#include "t_wsd_tst.h"
+
+// Global data /////////////////////////////////////////////////////////////////
+
+_LIT(KSearchPathTemplate, "%c:\\sys\\bin");		// drive letter
+_LIT(KLibraryName, "t_wsd_dl%d_%c%c");			// [23] [cx] [pu]
+
+TInt TheFailure = KErrNone;
+TChar CurrentDrive = 'Z';
+
+void SetCurrentDrive(TChar aDrive)
+	{
+	CurrentDrive = aDrive;
+	}
+
+class TPagingDriveInfo
+	{
+public:
+	TChar iDriveLetter;
+	TDriveInfo iDriveInfo;
+	};
+
+RArray<TPagingDriveInfo> SupportedDrives;
+
+// RTest stuff /////////////////////////////////////////////////////////////////
+
+RTest test(_L("T_WSD"));
+
+#define test_noError(x) { TInt _r = (x); if (_r < 0) HandleError(_r, __LINE__); }
+#define test_notNull(x) { TAny* _a = (TAny*)(x); if (_a == NULL) HandleNull(__LINE__); }
+#define test_equal(e, a) { TInt _e = TInt(e); TInt _a = TInt(a); if (_e != _a) HandleNotEqual(_e, _a, __LINE__); }
+
+void HandleError(TInt aError, TInt aLine)
+	{
+	test.Printf(_L("Error %d\n"), aError);
+	test.operator()(EFalse, aLine);
+	}
+
+void HandleNull(TInt aLine)
+	{
+	test.Printf(_L("Null value\n"));
+	test.operator()(EFalse, aLine);
+	}
+
+void HandleNotEqual(TInt aExpected, TInt aActual, TInt aLine)
+	{
+	test.Printf(_L("Expected 0x%x but got 0x%x\n"), aExpected, aActual);
+	test.operator()(EFalse, aLine);
+	}
+
+// Utility functions ///////////////////////////////////////////////////////////
+
+TPtrC16 GetMediaType(TInt aMediaType)
+	{
+	_LIT(KMediaNotPresent, "MediaNotPresent");
+	_LIT(KMediaUnknown, "MediaUnknown");
+	_LIT(KMediaFloppy, "MediaFloppy");
+	_LIT(KMediaHardDisk, "MediaHardDisk");
+	_LIT(KMediaCdRom, "MediaCdRom");
+	_LIT(KMediaRam, "MediaRam");
+	_LIT(KMediaFlash, "MediaFlash");
+	_LIT(KMediaRom, "MediaRom");
+	_LIT(KMediaRemote, "MediaRemote");
+	_LIT(KMediaNANDFlash, "MediaNANDFlash");
+	_LIT(KMediaUnKnown, "MediaUnKnown");
+
+	switch (aMediaType)
+		{
+	case EMediaNotPresent:
+		return KMediaNotPresent();
+	case EMediaUnknown:
+		return KMediaUnknown();
+	case EMediaFloppy:
+		return KMediaFloppy();
+	case EMediaHardDisk:
+		return KMediaHardDisk();
+	case EMediaCdRom:
+		return KMediaCdRom();
+	case EMediaRam:
+		return KMediaRam();
+	case EMediaFlash:
+		return KMediaFlash();
+	case EMediaRom:
+		return KMediaRom();
+	case EMediaRemote:
+		return KMediaRemote();
+	case EMediaNANDFlash:
+		return KMediaNANDFlash();
+	default:
+		return KMediaUnKnown();
+		}
+	}
+
+// Get the list of testable drives
+void GetSupportedDrives(TBool aVerbose = EFalse)
+	{
+	TUint32 memModelAttributes = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
+	TBool codePagingSupported = (memModelAttributes & EMemModelAttrCodePaging) != 0;
+	TUint32 pagingPolicy = E32Loader::PagingPolicy();
+	TBool pagingPolicyAllowsPaging = pagingPolicy != EKernelConfigCodePagingPolicyNoPaging;
+	test_Equal(codePagingSupported, pagingPolicyAllowsPaging);
+	if (codePagingSupported)
+		test.Printf(_L("Code paging is enabled.\n"));
+	else
+		test.Printf(_L("Code paging is NOT enabled.\n"));
+
+	if (aVerbose)
+		{
+		test.Printf(_L("Available drives:\n"));
+		test.Printf(_L("     Type             Attr     MedAttr  Filesystem\n"));
+		}
+
+	RFs fs;
+	test_noError(fs.Connect());
+
+	TDriveList driveList;
+	TInt r = fs.DriveList(driveList);
+	test_noError(r);
+
+	TBool NandPageableMediaFound = EFalse;
+	for (TInt drvNum=0; drvNum<KMaxDrives; ++drvNum)
+		{
+		if (!driveList[drvNum])
+			continue;   //-- skip unexisting drive
+
+		TDriveInfo driveInfo;
+		r = fs.Drive(driveInfo, drvNum);
+		test_noError(r);
+
+		TChar ch;
+		r = fs.DriveToChar(drvNum, ch);
+		test_noError(r);
+
+		TBuf<256> fileSystemName;
+		r = fs.FileSystemName(fileSystemName, drvNum);
+		test_noError(r);
+
+		// Decide which drives to exclude:
+		//		Locked/nonwritable drives, except the Z: ROM drive
+		//		Win32 drives on the emulator
+		//		Remote/nonlocal, removable/noninternal, redirected, substed drives
+		//	All others are included by default iff code paging is supported
+		//	If not, only the Z: ROM/XIP drive is tested
+		_LIT(KWin32FS, "Win32");
+		TBool include = codePagingSupported;
+		if (driveInfo.iDriveAtt & KDriveAttRom)
+			include = (ch == 'Z');
+		else if (driveInfo.iMediaAtt & (KMediaAttWriteProtected|KMediaAttLocked))
+			include = EFalse;
+		else if (fileSystemName == KWin32FS())
+			include = EFalse;
+		else if (driveInfo.iDriveAtt & (KDriveAttRedirected|KDriveAttSubsted|KDriveAttRemovable|KDriveAttRemote))
+			include = EFalse;
+		else if ((KDriveAttInternal|KDriveAttLocal) & ~driveInfo.iDriveAtt)
+			include = EFalse;
+
+		if (include)
+			{
+			TPagingDriveInfo pagingDriveInfo;
+			pagingDriveInfo.iDriveLetter = ch;
+			pagingDriveInfo.iDriveInfo = driveInfo;
+			r = SupportedDrives.Append(pagingDriveInfo);
+			test_noError(r);
+			}
+
+		TBool pageable = EFalse;
+		if (driveInfo.iDriveAtt & KDriveAttPageable)
+			{
+			pageable = ETrue;
+			if (driveInfo.iType == EMediaNANDFlash)
+				NandPageableMediaFound = ETrue;
+			}
+
+		// If we've already found a pageable NAND drive, then assume the
+		// Z: drive is pageable too if it's got a composite file system
+		_LIT(KCompositeName,"Composite");
+		if (NandPageableMediaFound && fileSystemName == KCompositeName())
+			pageable = ETrue;
+
+		if (aVerbose)
+			{
+			TPtrC16 mediaType = GetMediaType(driveInfo.iType);
+			_LIT(KPageable, "pageable");
+			test.Printf(_L("%c  %c: %16S %08x %08x %10S %S\n"),
+						include ? '*' : ' ', (TUint)ch, &mediaType,
+						driveInfo.iDriveAtt, driveInfo.iMediaAtt,
+			            &fileSystemName, (pageable ? &KPageable : &KNullDesC));
+			}
+		}
+
+	fs.Close();
+	}
+
+const TDesC& LibrarySearchPath(TChar aDrive)
+	{
+	static TBuf<64> path;
+	path.Format(KSearchPathTemplate, (TUint)aDrive);
+	return path;
+	}
+
+const TDesC& LibraryName(TChar aDrive, TInt aLibNo, TBool aRam, TBool aPaged)
+	{
+	// this gives DLL#2 a different name on each drive so we can be sure we're loading the right one
+	static TBuf<64> name;
+	name.Format(KLibraryName, aLibNo, aRam ? 'c' : 'x', aPaged ? 'p' : 'u');
+	if (aLibNo == 2 && aDrive != 'Z')
+		name.AppendFormat(_L("_%c"), (TUint)aDrive);
+	return name;
+	}
+
+const TDesC& LibraryFilename(TChar aDrive, TInt aLibNo, TBool aRam, TBool aPaged)
+	{
+	static TBuf<64> filename;
+	filename = LibrarySearchPath(aDrive);
+	filename.AppendFormat(_L("\\%S.dll"), &LibraryName(aDrive, aLibNo, aRam, aPaged));
+	return filename;
+	}
+
+TInt LoadSpecificLibrary(RLibrary& aLibrary, TChar aDrive, TInt aLibNo, TBool aRam, TBool aPaged)
+	{
+	const TDesC& path = LibrarySearchPath(aDrive);
+	const TDesC& name = LibraryName(aDrive, aLibNo, aRam, aPaged);
+	TInt err = aLibrary.Load(name, path);
+	TBuf<256> message;
+	message.Format(_L("Loading %S\\%S.dll returns %d\n"), &path, &name, err);
+	test.Printf(message);
+	return err;
+	}
+
+// Test functions //////////////////////////////////////////////////////////////
+
+void CopyDllToCurrentDrive(RFs& aFs, TBool aPaged, TInt aLibNo)
+	{
+	TBuf<64> source = LibraryFilename('Z', aLibNo, ETrue, aPaged);
+	TBuf<64> dest = LibraryFilename(CurrentDrive, aLibNo, ETrue, aPaged);
+	test.Printf(_L("Copying %S to %S\n"), &source, &dest);
+
+	TInt r = aFs.MkDirAll(dest);
+	test(r == KErrNone || r == KErrAlreadyExists);
+
+	TBuf<64> tempName(dest);
+	tempName.Append(_L(".tmp"));
+
+	RFile in, out, temp;
+	test_noError(in.Open(aFs, source, EFileRead));
+	test_noError(out.Replace(aFs, dest, EFileWrite));
+	test_noError(temp.Replace(aFs, tempName, EFileWrite));
+
+	const TInt KBufferSize = 3333;
+	TBuf8<KBufferSize> buffer;
+
+	test_noError(temp.Write(buffer));
+	test_noError(temp.Flush());
+
+	TInt size;
+	test_noError(in.Size(size));
+	TInt pos = 0;
+	while (pos < size)
+		{
+		test_noError(in.Read(buffer));
+		test_noError(out.Write(buffer));
+		test_noError(out.Flush());
+		test_noError(temp.Write(buffer));
+		test_noError(temp.Flush());
+		pos += buffer.Length();
+		}
+
+	out.SetAtt(KEntryAttNormal, KEntryAttReadOnly|
+								KEntryAttHidden|
+								KEntryAttSystem|
+								KEntryAttArchive|
+								KEntryAttXIP);
+
+	in.Close();
+	out.Close();
+	temp.Close();
+	}
+
+void CopyDllsToCurrentDrive()
+	{
+	RFs fs;
+	test_noError(fs.Connect());
+
+	CopyDllToCurrentDrive(fs, EFalse, 2);		// Unpaged library 2
+	CopyDllToCurrentDrive(fs, EFalse, 3);		// Unpaged library 3
+	CopyDllToCurrentDrive(fs, ETrue, 2);		// Paged library 2
+	CopyDllToCurrentDrive(fs, ETrue, 3);		// Paged library 3
+
+	fs.Close();
+	}
+
+void EraseDllsFromCurrentDrive()
+	{
+	RFs fs;
+	test_noError(fs.Connect());
+
+	CTrapCleanup* cleanup = CTrapCleanup::New();
+	test_notNull(cleanup);
+
+	CFileMan* fileMan = NULL;
+	TRAPD(r, fileMan = CFileMan::NewL(fs));
+	test_noError(r);
+
+	TBuf<64> libdir = LibrarySearchPath(CurrentDrive);
+	test.Printf(_L("Erasing %S\n"), &libdir);
+	fileMan->RmDir(libdir);
+
+	delete fileMan;
+	delete cleanup;
+	fs.Close();
+	}
+
+void CheckRelocatableData(RLibrary& library)
+	{
+	TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)library.Lookup(KGetAddressOfDataFunctionOrdinal);
+	test_notNull(func);
+
+	TInt size;
+	void* codeAddr;
+	void* dataAddr;
+	void*** dataPtrPtr = (void***)func(size, codeAddr, dataAddr);
+	void **dp = (void **)dataAddr;
+
+	for (TInt i = 0; i < size/4; i += 2)
+		{
+		test_equal(dp[i], codeAddr);
+		test_equal(dp[i+1], dataAddr);
+		}
+
+	test_equal(*dataPtrPtr, dp);
+	}
+
+void CheckWritableStaticData(RLibrary& library)
+	{
+	TInt (*func)(void) = (TInt (*)(void))library.Lookup(KCheckWritableStaticDataFunctionOrdinal);
+	RDebug::Printf("CheckWritableStaticData() is export %d at %08x", KCheckWritableStaticDataFunctionOrdinal, func);
+	test_notNull(func);
+	TInt err = func();
+	RDebug::Printf("CheckWritableStaticData() returned %d", err);
+	// test_noError(err);
+	if (TheFailure == KErrNone)
+		TheFailure = err;
+	}
+
+void RunPerDriveTests(TBool aPaged, TBool aRam)
+	{
+	TBuf<64> message = _L("Running ");
+	if (!aPaged)
+		message.Append(_L("un"));
+	message.AppendFormat(_L("paged R%cM tests on drive %c:"),
+		aRam ? 'A' : 'O', (TUint)CurrentDrive);
+	test.Next(message);
+
+	RFs fs;
+	test_noError(fs.Connect());
+	fs.SetDebugRegister(KFLDR);
+
+	// Explicitly loading dl2 will implicitly load dl3 as well
+	RLibrary dl2;
+	test_noError(LoadSpecificLibrary(dl2, CurrentDrive, 2, aRam, aPaged));
+	CheckRelocatableData(dl2);
+	CheckWritableStaticData(dl2);
+	dl2.Close();
+
+	fs.SetDebugRegister(0);
+	fs.Close();
+	}
+
+TInt E32Main()
+	{
+	test.Title();
+	test.Start(_L("WSD tests"));
+
+	// Check static linkage to dl1
+	test_noError(CheckExportedDataAddress(&ExportedData));
+
+	GetSupportedDrives(ETrue);
+	test(SupportedDrives.Count() > 0);
+
+	// Turn off evil lazy dll unloading
+	RLoader l;
+	test(l.Connect()==KErrNone);
+	test(l.CancelLazyDllUnload()==KErrNone);
+	l.Close();
+
+	// Make sure there aren't any DLLs left over from earlier tests
+	TInt i = SupportedDrives.Count();
+	while (--i >= 0)
+		{
+		SetCurrentDrive(SupportedDrives[i].iDriveLetter);
+		if (CurrentDrive != 'Z')
+				EraseDllsFromCurrentDrive();
+		}
+
+	// We want to test all supported drives in order of increasing priority, so
+	// that the CurrentDrive is always the hghest priority of those tested so far.
+	// Therefore, if Z (XIP ROM, lowest priority) is a valid test drive, do it first
+	i = SupportedDrives.Count();
+	if (--i >= 0)
+		{
+		SetCurrentDrive(SupportedDrives[i].iDriveLetter);
+		if (CurrentDrive == 'Z')
+			{
+			// ROM (XIP) tests can only be run from Z:
+			RunPerDriveTests(EFalse, EFalse);		// Unpaged ROM
+			RunPerDriveTests(ETrue, EFalse);		// Paged ROM
+			RunPerDriveTests(EFalse, ETrue);		// Unpaged RAM
+			RunPerDriveTests(ETrue, ETrue);			// Paged RAM
+			}
+		}
+
+	// Now run the RAM-based versions from each remaining drive in turn
+	for (i = 0; i < SupportedDrives.Count(); ++i)
+		{
+		SetCurrentDrive(SupportedDrives[i].iDriveLetter);
+		if (CurrentDrive != 'Z')
+			{
+			CopyDllsToCurrentDrive();
+			RunPerDriveTests(EFalse, ETrue);			// Unpaged RAM
+			RunPerDriveTests(ETrue, ETrue);				// Paged RAM
+			}
+		}
+
+	test_noError(TheFailure);
+	test.End();
+	return 0;
+	}
+