sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\demandpaging\t_pagingexample.cpp sl@0: // Test device driver migration examples sl@0: // sl@0: // sl@0: sl@0: #define __E32TEST_EXTENSION__ sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "../mmu/t_codepaging_dll.h" sl@0: #include "d_pagingexample.h" sl@0: sl@0: const TInt KBufferSize = KMaxTransferSize; sl@0: _LIT(KTCodePagingDll4, "t_codepaging_dll4.dll"); sl@0: sl@0: struct TTestData sl@0: { sl@0: TRequestStatus iStatus; sl@0: RPagingExample::TConfigData iConfig; sl@0: RPagingExample::TValueStruct iValue; sl@0: TInt iIntValue1; sl@0: TInt iIntValue2; sl@0: TPtr8 iPtr; sl@0: TUint8 iBuffer[KBufferSize]; sl@0: public: sl@0: TTestData() : iPtr(NULL, 0) { } sl@0: }; sl@0: sl@0: RTest test(_L("T_PAGINGEXAMPLE")); sl@0: TInt PageSize = 0; sl@0: RLibrary PagedLibrary; sl@0: TTestData* UnpagedInputData = NULL; sl@0: TTestData* UnpagedOutputData = NULL; sl@0: TTestData* PagedInputData = NULL; sl@0: TTestData* PagedOutputData = NULL; sl@0: sl@0: void InitInputData(TTestData* aData) sl@0: { sl@0: aData->iConfig.iParam1 = 2; sl@0: aData->iConfig.iParam2 = 3; sl@0: aData->iConfig.iParam3 = 5; sl@0: aData->iConfig.iParam4 = 7; sl@0: for (TInt i = 0 ; i < KBufferSize ; ++i) sl@0: aData->iBuffer[i] = (TUint8)(i + 123); sl@0: } sl@0: sl@0: void DoTestDriver(const TDesC& aDriverName, const TTestData* aInputData, TTestData* aOutputData) sl@0: { sl@0: test.Start(_L("Load logical device")); sl@0: TInt r = User::LoadLogicalDevice(aDriverName); sl@0: test(r==KErrNone || r==KErrAlreadyExists); sl@0: sl@0: test.Next(_L("Open logical device")); sl@0: RPagingExample ldd; sl@0: test_KErrNone(ldd.Open(aDriverName)); sl@0: sl@0: test.Next(_L("Set config")); sl@0: DPTest::FlushCache(); sl@0: test_KErrNone(ldd.SetConfig(aInputData->iConfig)); sl@0: sl@0: test.Next(_L("Get config")); sl@0: Mem::FillZ(&aOutputData->iConfig, sizeof(RPagingExample::TConfigData)); sl@0: DPTest::FlushCache(); sl@0: test_KErrNone(ldd.GetConfig(aOutputData->iConfig)); sl@0: test_Equal(0, Mem::Compare((TUint8*)&aInputData->iConfig, sizeof(RPagingExample::TConfigData), sl@0: (TUint8*)&aOutputData->iConfig, sizeof(RPagingExample::TConfigData))); sl@0: sl@0: TRequestStatus& status = aOutputData->iStatus; sl@0: sl@0: test.Next(_L("Notify")); sl@0: DPTest::FlushCache(); sl@0: ldd.Notify(status); sl@0: DPTest::FlushCache(); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrNone, status.Int()); sl@0: sl@0: test.Next(_L("Async get value")); sl@0: memclr(&aOutputData->iValue, sizeof(RPagingExample::TValueStruct)); sl@0: DPTest::FlushCache(); sl@0: ldd.AsyncGetValue(status, aOutputData->iValue); sl@0: DPTest::FlushCache(); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrNone, status.Int()); sl@0: test_Equal(1, aOutputData->iValue.iValue1); sl@0: test(aOutputData->iValue.iValue2 == _L8("shrt")); sl@0: sl@0: test.Next(_L("Cancel async get value")); sl@0: ldd.AsyncGetValue(status, aOutputData->iValue); sl@0: ldd.Cancel(); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrCancel, status.Int()); sl@0: sl@0: test.Next(_L("Async get value 2")); sl@0: aOutputData->iIntValue1 = 0; sl@0: aOutputData->iIntValue2 = 0; sl@0: DPTest::FlushCache(); sl@0: ldd.AsyncGetValue2(status, aOutputData->iIntValue1, aOutputData->iIntValue2); sl@0: DPTest::FlushCache(); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrNone, status.Int()); sl@0: test_Equal(1, aOutputData->iIntValue1); sl@0: test_Equal(2, aOutputData->iIntValue2); sl@0: sl@0: test.Next(_L("Cancel async get value 2")); sl@0: ldd.AsyncGetValue2(status, aOutputData->iIntValue1, aOutputData->iIntValue2); sl@0: ldd.Cancel(); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrCancel, status.Int()); sl@0: sl@0: test.Next(_L("Write buffer too short")); sl@0: ldd.Write(status, NULL, 0); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrArgument, status.Int()); sl@0: sl@0: test.Next(_L("Write buffer too long")); sl@0: ldd.Write(status, NULL, KMaxTransferSize + 1); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrArgument, status.Int()); sl@0: sl@0: test.Next(_L("Write")); sl@0: DPTest::FlushCache(); sl@0: ldd.Write(status, aInputData->iBuffer, KBufferSize); sl@0: DPTest::FlushCache(); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: sl@0: test.Next(_L("Cancel write")); sl@0: ldd.Write(status, aInputData->iBuffer, KBufferSize); sl@0: ldd.Cancel(); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrCancel, status.Int()); sl@0: sl@0: test.Next(_L("Read buffer too short")); sl@0: ldd.Read(status, NULL, 0); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrArgument, status.Int()); sl@0: sl@0: test.Next(_L("Read buffer too long")); sl@0: ldd.Read(status, NULL, KMaxTransferSize + 1); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrArgument, status.Int()); sl@0: sl@0: test.Next(_L("Read")); sl@0: Mem::FillZ(aOutputData->iBuffer, KBufferSize); sl@0: DPTest::FlushCache(); sl@0: ldd.Read(status, aOutputData->iBuffer, KBufferSize); sl@0: DPTest::FlushCache(); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: test_Equal(0, Mem::Compare(aInputData->iBuffer, KBufferSize, sl@0: aOutputData->iBuffer, KBufferSize)); sl@0: sl@0: test.Next(_L("Cancel read")); sl@0: ldd.Read(status, aOutputData->iBuffer, KBufferSize); sl@0: ldd.Cancel(); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrCancel, status.Int()); sl@0: sl@0: test.Next(_L("Cancel nothing")); sl@0: ldd.Cancel(); sl@0: sl@0: test.Next(_L("Write while write pending")); sl@0: TRequestStatus status2; sl@0: ldd.Write(status, aInputData->iBuffer, KBufferSize); sl@0: ldd.Write(status2, aInputData->iBuffer, KBufferSize); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: User::WaitForRequest(status2); sl@0: test_Equal(KErrInUse, status2.Int()); sl@0: sl@0: test.Next(_L("Read while read pending")); sl@0: ldd.Read(status, aOutputData->iBuffer, KBufferSize); sl@0: ldd.Read(status2, aOutputData->iBuffer, KBufferSize); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: User::WaitForRequest(status2); sl@0: test_Equal(KErrInUse, status2.Int()); sl@0: sl@0: test.Next(_L("Write des")); sl@0: TPtrC8 writeDes(aInputData->iBuffer + 1, KBufferSize - 1); sl@0: DPTest::FlushCache(); sl@0: ldd.WriteDes(status, writeDes); sl@0: DPTest::FlushCache(); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: sl@0: test.Next(_L("Cancel write des")); sl@0: ldd.WriteDes(status, writeDes); sl@0: ldd.Cancel(); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrCancel, status.Int()); sl@0: sl@0: test.Next(_L("Read des")); sl@0: TPtr8 readDes(aOutputData->iBuffer, KBufferSize - 1); sl@0: Mem::FillZ(aOutputData->iBuffer, KBufferSize); sl@0: DPTest::FlushCache(); sl@0: ldd.ReadDes(status, readDes); sl@0: DPTest::FlushCache(); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: test(readDes == writeDes); sl@0: sl@0: test.Next(_L("Read des 2")); // has paged header but unpaged contnet, if output data is paged sl@0: aOutputData->iPtr.Set(UnpagedOutputData->iBuffer, 0, KBufferSize - 1); sl@0: Mem::FillZ(UnpagedOutputData->iBuffer, KBufferSize); sl@0: DPTest::FlushCache(); sl@0: ldd.ReadDes(status, aOutputData->iPtr); sl@0: DPTest::FlushCache(); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: test(aOutputData->iPtr == writeDes); sl@0: sl@0: test.Next(_L("Cancel read des")); sl@0: ldd.ReadDes(status, readDes); sl@0: ldd.Cancel(); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrCancel, status.Int()); sl@0: sl@0: test.Next(_L("Read and write at the same time")); sl@0: ldd.Write(status, aInputData->iBuffer, KBufferSize); sl@0: ldd.Read(status2, aOutputData->iBuffer, KBufferSize); sl@0: DPTest::FlushCache(); sl@0: User::WaitForRequest(status); sl@0: test_KErrNone(status.Int()); sl@0: User::WaitForRequest(status2); sl@0: test_KErrNone(status2.Int()); sl@0: sl@0: test.Next(_L("Cancel read and write")); sl@0: ldd.Write(status, aInputData->iBuffer, KBufferSize); sl@0: ldd.Read(status2, aOutputData->iBuffer, KBufferSize); sl@0: ldd.Cancel(); sl@0: User::WaitForRequest(status); sl@0: test_Equal(KErrCancel, status.Int()); sl@0: User::WaitForRequest(status2); sl@0: test_Equal(KErrCancel, status2.Int()); sl@0: sl@0: test.Next(_L("Close and free logical device")); sl@0: ldd.Close(); sl@0: test_KErrNone(User::FreeLogicalDevice(aDriverName)); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: void TestDriver(const TDesC& aDriverName, TBool aMigrated) sl@0: { sl@0: TBuf<64> string; sl@0: string.Format(_L("Testing driver %S"), &aDriverName); sl@0: test.Next(string); sl@0: sl@0: test.Start(_L("Test reading from unpaged memory and writing to unpaged memory")); sl@0: DoTestDriver(aDriverName, UnpagedInputData, UnpagedOutputData); sl@0: sl@0: if (aMigrated && PagedInputData) sl@0: { sl@0: if (PagedOutputData) sl@0: { sl@0: test.Next(_L("Test reading from paged memory and writing to paged memory")); sl@0: DoTestDriver(aDriverName, PagedInputData, PagedOutputData); sl@0: } sl@0: else sl@0: { sl@0: test.Next(_L("Test reading from paged memory and writing to unpaged memory")); sl@0: DoTestDriver(aDriverName, PagedInputData, UnpagedOutputData); sl@0: } sl@0: } sl@0: sl@0: // todo: test pinning failures sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: enum TTestAction sl@0: { sl@0: ETestRequestComplete, sl@0: ETestRawRead, sl@0: ETestRawWrite, sl@0: ETestDesRead, sl@0: ETestDesWrite sl@0: }; sl@0: sl@0: enum TTestAccess sl@0: { sl@0: EAccessUnpaged, sl@0: EAccessPaged sl@0: }; sl@0: sl@0: enum TTestOutcome sl@0: { sl@0: EOutcomeSuccess, sl@0: EOutcomeRealtimePanic sl@0: }; sl@0: sl@0: TInt RealtimeTestFunc(TAny* aArg) sl@0: { sl@0: TTestAction action = (TTestAction)((TUint)aArg & 255); sl@0: TTestAccess access = (TTestAccess)((TUint)aArg >> 8); sl@0: sl@0: TTestData* inputData = access == EAccessPaged ? PagedInputData : UnpagedInputData; sl@0: TTestData* outputData = access == EAccessPaged ? PagedOutputData : UnpagedOutputData; sl@0: sl@0: RPagingExample ldd; sl@0: TInt r = ldd.Open(KPagingExample1PreLdd); sl@0: if (r != KErrNone) sl@0: return r; sl@0: ldd.SetDfcThreadRealtimeState(ETrue); sl@0: sl@0: TRequestStatus unpagedStatus; sl@0: TRequestStatus* status = &unpagedStatus; sl@0: sl@0: switch(action) sl@0: { sl@0: case ETestRequestComplete: sl@0: { sl@0: RDebug::Printf("Test RequestComplete"); sl@0: status = &outputData->iStatus; sl@0: RPagingExample::TValueStruct value; sl@0: DPTest::FlushCache(); sl@0: ldd.AsyncGetValue(*status, value); sl@0: DPTest::FlushCache(); sl@0: } sl@0: break; sl@0: sl@0: case ETestRawRead: sl@0: RDebug::Printf("Test ThreadRawRead"); sl@0: ldd.Write(*status, inputData->iBuffer, KBufferSize); sl@0: DPTest::FlushCache(); sl@0: break; sl@0: sl@0: case ETestRawWrite: sl@0: RDebug::Printf("Test ThreadRawWrite"); sl@0: ldd.Read(*status, outputData->iBuffer, KBufferSize); sl@0: DPTest::FlushCache(); sl@0: break; sl@0: sl@0: case ETestDesRead: sl@0: { sl@0: RDebug::Printf("Test ThreadDesRead"); sl@0: TPtrC8 writeDes(inputData->iBuffer, KBufferSize); sl@0: ldd.WriteDes(*status, writeDes); sl@0: DPTest::FlushCache(); sl@0: } sl@0: break; sl@0: sl@0: case ETestDesWrite: sl@0: { sl@0: RDebug::Printf("Test ThreadDesWrite"); sl@0: TPtr8 readDes(outputData->iBuffer, KBufferSize); sl@0: ldd.ReadDes(*status, readDes); sl@0: DPTest::FlushCache(); sl@0: } sl@0: break; sl@0: default: sl@0: return KErrArgument; sl@0: } sl@0: User::WaitForAnyRequest(); sl@0: r = status->Int(); sl@0: ldd.Close(); sl@0: return r; sl@0: } sl@0: sl@0: void RunRealtimeTestThread(TTestAction aTestAction, TTestAccess aAccess, TTestOutcome aExpectedOutcome) sl@0: { sl@0: RThread thread; sl@0: TUint arg = aTestAction | (aAccess << 8); sl@0: test_KErrNone(thread.Create(KNullDesC, RealtimeTestFunc, 4096, NULL, (TAny*)arg)); sl@0: TRequestStatus status; sl@0: thread.Logon(status); sl@0: thread.Resume(); sl@0: User::WaitForRequest(status); sl@0: switch (aExpectedOutcome) sl@0: { sl@0: case EOutcomeSuccess: sl@0: test_Equal(EExitKill, thread.ExitType()); sl@0: test_Equal(KErrNone, thread.ExitReason()); sl@0: break; sl@0: sl@0: case EOutcomeRealtimePanic: sl@0: test_Equal(EExitPanic, thread.ExitType()); sl@0: test_Equal(EIllegalFunctionForRealtimeThread, thread.ExitReason()); sl@0: break; sl@0: sl@0: default: sl@0: test(EFalse); sl@0: } sl@0: CLOSE_AND_WAIT(thread); sl@0: } sl@0: sl@0: void TestPagedAccessInRealtimeThread() sl@0: { sl@0: // Test driver access to paged memory from realtime DFC thread. This can happen if a client sl@0: // passes paged memory to a driver that doesn't expect it, and has set its realtime state to sl@0: // enfore this. The client should be panicked in this case. sl@0: sl@0: test.Start(_L("Test memory access from realtime threads")); sl@0: test.Next(_L("Load logical device")); sl@0: TInt r = User::LoadLogicalDevice(KPagingExample1PreLdd); sl@0: test(r==KErrNone || r==KErrAlreadyExists); sl@0: sl@0: test.Next(_L("Test access to unpaged memory from realtime thread")); sl@0: RunRealtimeTestThread(ETestRequestComplete, EAccessUnpaged, EOutcomeSuccess); sl@0: RunRealtimeTestThread(ETestRawRead, EAccessUnpaged, EOutcomeSuccess); sl@0: RunRealtimeTestThread(ETestRawWrite, EAccessUnpaged, EOutcomeSuccess); sl@0: RunRealtimeTestThread(ETestDesRead, EAccessUnpaged, EOutcomeSuccess); sl@0: RunRealtimeTestThread(ETestDesWrite, EAccessUnpaged, EOutcomeSuccess); sl@0: sl@0: test.Next(_L("Test access to paged memory from realtime thread")); sl@0: if (PagedInputData) sl@0: { sl@0: RunRealtimeTestThread(ETestRawRead, EAccessPaged, EOutcomeRealtimePanic); sl@0: RunRealtimeTestThread(ETestDesRead, EAccessPaged, EOutcomeRealtimePanic); sl@0: } sl@0: if (PagedOutputData) sl@0: { sl@0: RunRealtimeTestThread(ETestRequestComplete, EAccessPaged, EOutcomeRealtimePanic); sl@0: RunRealtimeTestThread(ETestRawWrite, EAccessPaged, EOutcomeRealtimePanic); sl@0: RunRealtimeTestThread(ETestDesWrite, EAccessPaged, EOutcomeRealtimePanic); sl@0: } sl@0: sl@0: test.Next(_L("Close and free logical device")); sl@0: test_KErrNone(User::FreeLogicalDevice(KPagingExample1PreLdd)); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: TInt E32Main() sl@0: { sl@0: test.Title(); sl@0: sl@0: test.Start(_L("Test device driver migration examples")); sl@0: sl@0: UnpagedInputData = (TTestData*)User::Alloc(sizeof(TTestData)); sl@0: test_NotNull(UnpagedInputData); sl@0: UnpagedOutputData = (TTestData*)User::Alloc(sizeof(TTestData)); sl@0: test_NotNull(UnpagedOutputData); sl@0: sl@0: test_KErrNone(UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&PageSize,0)); sl@0: sl@0: RChunk chunk; sl@0: if (DPTest::Attributes() & DPTest::EDataPaging) sl@0: { sl@0: TChunkCreateInfo info; sl@0: TInt size = (sizeof(TTestData) + PageSize - 1) & ~(PageSize - 1); sl@0: info.SetNormal(size, size); sl@0: info.SetPaging(TChunkCreateInfo::EPaged); sl@0: test_KErrNone(chunk.Create(info)); sl@0: test(chunk.IsPaged()); sl@0: PagedOutputData = (TTestData*)chunk.Base(); sl@0: test.Printf(_L("Using data pagd output buffer at %08x\n"), PagedOutputData); sl@0: } sl@0: sl@0: if (DPTest::Attributes() & DPTest::ERomPaging) sl@0: { sl@0: // use paged part of rom for read-only data sl@0: TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); sl@0: test(romHeader->iPageableRomStart); sl@0: // todo: for some reason the first part of page of paged rom doesn't seem to get paged out sl@0: // when we flush the paging cache, hence PagedInputData starts some way into this sl@0: PagedInputData = (TTestData*)((TUint8*)romHeader + romHeader->iPageableRomStart + 64 * PageSize); sl@0: TInt romDataSize = romHeader->iPageableRomSize - 64 * PageSize; sl@0: test(romDataSize >= (TInt)sizeof(TTestData)); sl@0: test.Printf(_L("Using rom paged input data at %08x\n"), PagedInputData); sl@0: } sl@0: else if (DPTest::Attributes() & DPTest::ECodePaging) sl@0: { sl@0: // use code paged DLL for read-only buffer sl@0: test_KErrNone(PagedLibrary.Load(KTCodePagingDll4)); sl@0: TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)PagedLibrary.Lookup(KGetAddressOfDataFunctionOrdinal); sl@0: TInt codeDataSize; sl@0: PagedInputData = (TTestData*)func(codeDataSize); sl@0: test_NotNull(PagedInputData); sl@0: test(codeDataSize >= (TInt)sizeof(TTestData)); sl@0: test.Printf(_L("Using code paged input data at %08x\n"), PagedInputData); sl@0: } sl@0: sl@0: InitInputData(UnpagedInputData); sl@0: sl@0: TestDriver(KPagingExample1PreLdd, EFalse); sl@0: TestDriver(KPagingExample1PostLdd, ETrue); sl@0: TestDriver(KPagingExample2PreLdd, EFalse); sl@0: TestDriver(KPagingExample2PostLdd, ETrue); sl@0: TestPagedAccessInRealtimeThread(); sl@0: sl@0: PagedLibrary.Close(); sl@0: User::Free(UnpagedInputData); sl@0: User::Free(UnpagedOutputData); sl@0: sl@0: test.End(); sl@0: return 0; sl@0: }