diff -r a77889bee936 -r 647ab20fee2e kerneltest/e32test/mmu/t_demandpaging.cpp --- a/kerneltest/e32test/mmu/t_demandpaging.cpp Thu Aug 12 11:55:14 2010 +0100 +++ b/kerneltest/e32test/mmu/t_demandpaging.cpp Thu Aug 12 12:51:24 2010 +0100 @@ -75,6 +75,7 @@ #include #include #include +#include #include "d_memorytest.h" #include "d_demandpaging.h" #include "d_gobble.h" @@ -108,6 +109,14 @@ // A descriptor whose header is in paged memory (actually just a pointer to a zero word) TDesC8* PagedHeaderDes = NULL; +// An area of paged rom if rom paging is supported, or zero +TUint8* RomPagedBuffer = NULL; +TInt RomPagedBufferSize = 0; + +// An area of paged code if code paging is supported, or zero +TUint8* CodePagedBuffer = NULL; +TInt CodePagedBufferSize = 0; + // A data paged chunk used as a buffer, if data paging is supported _LIT(KChunkName, "t_demandpaging chunk"); RChunk DataPagedChunk; @@ -119,7 +128,13 @@ return *aPtr; } +TUint8 WriteByte(volatile TUint8* aPtr) + { + return *aPtr = 1; + } + #define READ(a) ReadByte((volatile TUint8*)(a)) +#define WRITE(a) WriteByte((volatile TUint8*)(a)) void ThrashPaging(TUint aBytes) { @@ -435,12 +450,13 @@ EDesContentPaged }; -enum TRealtimeOutcome +enum TThreadOutcome { ENoError, EBadDescriptor, EServerTerminated, - ERealtimePanic + ERealtimePanic, + EAbortPanic }; class RTestSession : public RSessionBase @@ -626,7 +642,7 @@ return r; } -void TestRealtimeOutcome(RThread aThread, TRealtimeOutcome aOutcome) +void TestThreadOutcome(RThread aThread, TThreadOutcome aOutcome) { switch(aOutcome) { @@ -651,6 +667,12 @@ test_Equal(EIllegalFunctionForRealtimeThread, aThread.ExitReason()); break; + case EAbortPanic: + test_Equal(EExitPanic, aThread.ExitType()); + // category for paging errors tested elsewhere + test_Equal(KErrAbort, aThread.ExitReason()); + break; + default: test(EFalse); } @@ -661,8 +683,9 @@ TIpcObjectPaged aServerPaged, User::TRealtimeState aClientState, User::TRealtimeState aServerState, - TRealtimeOutcome aClientOutcome, - TRealtimeOutcome aServerOutcome) + TThreadOutcome aClientOutcome, + TThreadOutcome aServerOutcome, + TPagingErrorContext aSimulatedError = EPagingErrorContextNone) { test.Printf(_L("TestPagedIpc %d %d %d %d %d %d %d\n"), aIpcDir, aClientPaged, aServerPaged, aClientState, aServerState, aClientOutcome, aServerOutcome); @@ -688,6 +711,11 @@ name = clientThread.Name(); test.Printf(_L(" client: %S\n"), &name); clientThread.Logon(clientStatus); + + // set up simulated failure if specifed + if (aSimulatedError != EPagingErrorContextNone) + test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalDebugSetFail, (TAny*)aSimulatedError, 0)); + clientThread.Resume(); User::WaitForRequest(serverStatus); @@ -696,9 +724,13 @@ User::WaitForRequest(clientStatus); test.Printf(_L(" client exit type is %d %d\n"), clientThread.ExitType(), clientThread.ExitReason()); + + // cancel any simulated failure + if (aSimulatedError != EPagingErrorContextNone) + test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalDebugSetFail, (TAny*)EPagingErrorContextNone, 0)); - TestRealtimeOutcome(serverThread, aServerOutcome); - TestRealtimeOutcome(clientThread, aClientOutcome); + TestThreadOutcome(serverThread, aServerOutcome); + TestThreadOutcome(clientThread, aClientOutcome); CLOSE_AND_WAIT(serverThread); CLOSE_AND_WAIT(clientThread); @@ -717,7 +749,7 @@ return KErrNone; } -TInt RunTestThread(User::TRealtimeState aType, TRealtimeOutcome aOutcome) +TInt RunTestThread(User::TRealtimeState aType, TThreadOutcome aOutcome) { RThread thread; TInt r=thread.Create(KNullDesC, &TestThreadFunction, 0x1000, NULL, (TAny*)aType); @@ -729,7 +761,7 @@ return s.Int(); thread.Resume(); User::WaitForRequest(s); - TestRealtimeOutcome(thread, aOutcome); + TestThreadOutcome(thread, aOutcome); CLOSE_AND_WAIT(thread); return KErrNone; } @@ -811,6 +843,141 @@ test(KErrNone==DPTest::SetCacheSize(0,0)); } +enum TPageFaultType + { + EPageFaultRomRead, + EPageFaultCodeRead, + EPageFaultDataRead, + EPageFaultDataWrite, + }; + + +TInt TestPagingErrorThreadFunction(TAny* aArg) + { + TUint8* ptr = (TUint8*)((TUint)aArg & ~1); + TBool write = ((TUint)aArg & 1) != 0; + + if (write) + { + WRITE(ptr); + return DPTest::FlushCache(); + } + else + { + READ(ptr); + return KErrNone; + } + } + +void TestPagingError(TPageFaultType aPageFaultType, + TPagingErrorContext aSimulatedError, + TExitType aExpectedExitType, + const TDesC& aExpectedExitCategory, + TInt aExpectedExitReason) + { + test.Printf(_L("TestPagingError %d %d %d \"%S\" %d\n"), aPageFaultType, aSimulatedError, + aExpectedExitType, &aExpectedExitCategory, aExpectedExitReason); + + TUint8* ptr; + TBool write; + + switch(aPageFaultType) + { + case EPageFaultRomRead: ptr = RomPagedBuffer; write = EFalse; break; + case EPageFaultCodeRead: ptr = CodePagedBuffer; write = EFalse; break; + case EPageFaultDataRead: ptr = DataPagedBuffer; write = EFalse; break; + case EPageFaultDataWrite: ptr = DataPagedBuffer; write = ETrue; break; + default: test(EFalse); return; + } + + if (ptr == NULL) return; // specified type of paging is not enabled + + if (write) + READ(ptr); // ensure data to be written is paged in + else + test_KErrNone(DPTest::FlushCache()); // ensure data to be read is paged out + + // set up simulated failure + test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalDebugSetFail, (TAny*)aSimulatedError, 0)); + + RThread thread; + TAny* arg = (TAny*)((TUint)ptr | (write ? 1 : 0)); + test_KErrNone(thread.Create(KNullDesC, &TestPagingErrorThreadFunction, 0x1000, NULL, arg)); + TRequestStatus s; + thread.Logon(s); + test_Equal(KRequestPending, s.Int()); + thread.Resume(); + User::WaitForRequest(s); + + // cancel any simulated failure + test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalDebugSetFail, (TAny*)EPagingErrorContextNone, 0)); + + TExitCategoryName exitCategory = thread.ExitCategory(); + test.Printf(_L(" thread exit type is %d \"%S\" %d\n"), + thread.ExitType(), &exitCategory, thread.ExitReason()); + + test_Equal(aExpectedExitType, thread.ExitType()); + if (aExpectedExitType == EExitPanic) + test_Equal(0, aExpectedExitCategory.Compare(exitCategory)); + test_Equal(aExpectedExitReason, thread.ExitReason()); + + CLOSE_AND_WAIT(thread); + } + +void CreateDataPagedChunk() + { + TChunkCreateInfo createInfo; + createInfo.SetNormal(KMinBufferSize, KMinBufferSize); + createInfo.SetPaging(TChunkCreateInfo::EPaged); + createInfo.SetOwner(EOwnerProcess); + createInfo.SetGlobal(KChunkName); + test_KErrNone(DataPagedChunk.Create(createInfo)); + test(DataPagedChunk.IsPaged()); // this is only ever called if data paging is supported + DataPagedBuffer = (TUint8*)DataPagedChunk.Base(); + } + +void TestPagingErrors() + { + // test what happens when the paging system encounters errors such as failure when accessing + // media or decompressing paged data + + // page fault type: simulated error: exit type: exit category: exit reason: + TestPagingError(EPageFaultRomRead, EPagingErrorContextNone, EExitKill, KNullDesC, KErrNone); + TestPagingError(EPageFaultRomRead, EPagingErrorContextRomRead, EExitPanic, _L("PAGED-ROM-READ"), KErrAbort); + TestPagingError(EPageFaultRomRead, EPagingErrorContextRomDecompress, EExitPanic, _L("PAGED-ROM-COMP"), KErrAbort); + + TestPagingError(EPageFaultCodeRead, EPagingErrorContextNone, EExitKill, KNullDesC, KErrNone); + TestPagingError(EPageFaultCodeRead, EPagingErrorContextCodeRead, EExitPanic, _L("PAGED-CODE-READ"), KErrAbort); + TestPagingError(EPageFaultCodeRead, EPagingErrorContextCodeDecompress, EExitPanic, _L("PAGED-CODE-COMP"), KErrAbort); + + if (DataPagedBuffer) + { + // Note WDP write faults are only reported on the next read + WRITE(DataPagedBuffer); // ensure page is not blank and will be read from swap + + // page fault type: simulated error: exit type: exit category: exit reason: + TestPagingError(EPageFaultDataRead, EPagingErrorContextNone, EExitKill, KNullDesC, KErrNone); + TestPagingError(EPageFaultDataRead, EPagingErrorContextDataRead, EExitPanic, _L("PAGED-DATA-READ"), KErrAbort); + TestPagingError(EPageFaultDataWrite, EPagingErrorContextDataWrite, EExitKill, KNullDesC, KErrNone); + TestPagingError(EPageFaultDataRead, EPagingErrorContextNone, EExitPanic, _L("PAGED-DATA-WRITE"), KErrAbort); + + // this will now always panic when we try to access the first page so destroy and re-create it + DataPagedChunk.Close(); + CreateDataPagedChunk(); + } + + // test attribution of errors during IPC + TPagingErrorContext error; + if (RomPagedBuffer) + error = EPagingErrorContextRomRead; + else if (CodePagedBuffer) + error = EPagingErrorContextCodeRead; + else + error = EPagingErrorContextDataRead; + // ipc dir: client paged: server paged: client state: server state: client outcome: server outcome: + TestPagedIpc(EServerRead, EDesContentPaged, ENothingPaged, User::ERealtimeStateOff, User::ERealtimeStateOff, EAbortPanic, EBadDescriptor, error); + } + void TestLock() { // make sure live list is big enough @@ -1287,50 +1454,45 @@ test.Start(_L("Initialisation")); if (DPTest::Attributes() & DPTest::ERomPaging) + { test.Printf(_L("Rom paging supported\n")); + TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); + test(romHeader->iPageableRomStart); + // todo: for some reason the first part of page of paged rom doesn't seem to get paged out + // when we flush the paging cache, hence RomPagedBuffer starts some way into this + RomPagedBuffer = (TUint8*)romHeader + romHeader->iPageableRomStart + 64 * PageSize; + RomPagedBufferSize = romHeader->iPageableRomSize - 64 * PageSize; + test(RomPagedBufferSize > 0); + } + if (DPTest::Attributes() & DPTest::ECodePaging) + { test.Printf(_L("Code paging supported\n")); + test_KErrNone(PagedLibrary.Load(KTCodePagingDll4)); + TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)PagedLibrary.Lookup(KGetAddressOfDataFunctionOrdinal); + CodePagedBuffer = (TUint8*)func(CodePagedBufferSize); + test_NotNull(CodePagedBuffer); + test(CodePagedBufferSize > KMinBufferSize); + } + if (DPTest::Attributes() & DPTest::EDataPaging) { test.Printf(_L("Data paging supported\n")); DataPagingSupported = ETrue; - TChunkCreateInfo createInfo; - createInfo.SetNormal(KMinBufferSize, KMinBufferSize); - createInfo.SetPaging(TChunkCreateInfo::EPaged); - createInfo.SetOwner(EOwnerProcess); - createInfo.SetGlobal(KChunkName); - test_KErrNone(DataPagedChunk.Create(createInfo)); - test(DataPagedChunk.IsPaged()); // this is only ever called if data paging is supported - DataPagedBuffer = (TUint8*)DataPagedChunk.Base(); + CreateDataPagedChunk(); } if (DPTest::Attributes() & DPTest::ERomPaging) { // Use paged part of rom for testing - TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); - test(romHeader->iPageableRomStart); - // todo: for some reason the first part of page of paged rom doesn't seem to get paged out - // when we flush the paging cache, hence LargeBuffer starts some way into this - LargeBuffer = (TUint8*)romHeader + romHeader->iPageableRomStart + 64 * PageSize; - LargeBufferSize = romHeader->iPageableRomSize - 64 * PageSize; - test(LargeBufferSize > 0); - // Find a zero word in rom to set PagedHeaderDes to - TUint* ptr = (TUint*)LargeBuffer; - TUint* end = (TUint*)(LargeBuffer + LargeBufferSize); - while (*ptr && ptr < end) - ++ptr; - test(*ptr == 0); - test.Printf(_L("Found zero word at %08x\n"), ptr); - PagedHeaderDes = (TDesC8*)ptr; + LargeBuffer = RomPagedBuffer; + LargeBufferSize = RomPagedBufferSize; } else if (DPTest::Attributes() & DPTest::ECodePaging) { // Use code paged DLL for testing - test_KErrNone(PagedLibrary.Load(KTCodePagingDll4)); - TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)PagedLibrary.Lookup(KGetAddressOfDataFunctionOrdinal); - LargeBuffer = (TUint8*)func(LargeBufferSize); - test_NotNull(LargeBuffer); - PagedHeaderDes = (TDesC8*)LargeBuffer + 4; + LargeBuffer = CodePagedBuffer; + LargeBufferSize = CodePagedBufferSize; } else if (DPTest::Attributes() & DPTest::EDataPaging) { @@ -1344,7 +1506,16 @@ test.End(); return 0; } - + + // Find a paged zero word to set PagedHeaderDes to + TUint* ptr = (TUint*)LargeBuffer; + TUint* end = (TUint*)(LargeBuffer + LargeBufferSize); + while (*ptr && ptr < end) + ++ptr; + test(*ptr == 0); + test.Printf(_L("Found zero word at %08x\n"), ptr); + PagedHeaderDes = (TDesC8*)ptr; + test.Next(_L("Test HAL interface")); TestHAL(); @@ -1390,6 +1561,15 @@ test.Next(_L("Test no kernel faults when copying data from unpaged rom with mutex held")); TestReadHoldingMutex(); + +#ifdef _DEBUG + // test hook in kernel not present in release mode + if ((MemModelAttributes() & EMemModelTypeMask) == EMemModelTypeFlexible) + { + test.Next(_L("Test unrecoverable errors while paging")); + TestPagingErrors(); + } +#endif test.Next(_L("Close test driver")); Ldd.DestroyPlatHwChunk(); @@ -1398,11 +1578,14 @@ test.Next(_L("Test setting publish and subscribe properties from paged area")); TestPublishAndSubscribe(); +#ifndef _DEBUG + // no point benchmarking in debug mode if (DPTest::Attributes() & DPTest::ERomPaging) { test.Next(_L("Rom Paging Benchmark")); RomPagingBenchmark(); } +#endif PagedLibrary.Close(); gobbler.Close();