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\mmu\t_pin.cpp sl@0: // Tests kernel APIs for logical pinning by pinning memory and using a realtime thread to check that sl@0: // no page faults are taken while accessing it. 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 "d_memorytest.h" sl@0: #include "t_codepaging_dll.h" sl@0: #include "mmudetect.h" sl@0: #include "freeram.h" sl@0: sl@0: RTest test(_L("T_PIN")); sl@0: sl@0: _LIT(KTCodePagingDll4, "t_codepaging_dll4.dll"); sl@0: const TInt KMinBufferSize = 16384; sl@0: sl@0: RMemoryTestLdd Ldd; sl@0: RMemoryTestLdd Ldd2; sl@0: RLibrary PagedLibrary; sl@0: const TUint8* PagedBuffer = NULL; sl@0: const TUint8* UnpagedBuffer = NULL; sl@0: TInt PageSize; sl@0: sl@0: TInt FreeRamNoWait() sl@0: { sl@0: TMemoryInfoV1Buf meminfo; sl@0: UserHal::MemoryInfo(meminfo); sl@0: return meminfo().iFreeRamInBytes; sl@0: } sl@0: sl@0: void CheckMemoryPresent(const TUint8* aBuffer, TInt aSize, TBool aExpected) sl@0: { sl@0: if (aExpected) sl@0: test.Printf(_L(" Checking memory at %08x is present\n"), aBuffer); sl@0: else sl@0: test.Printf(_L(" Checking memory at %08x is not present\n"), aBuffer); sl@0: for (TInt i = 0 ; i < aSize ; i += PageSize) sl@0: test_Equal(aExpected, Ldd.IsMemoryPresent(aBuffer + i)); sl@0: } sl@0: sl@0: void FlushPagingCache() sl@0: { sl@0: test_KErrNone(DPTest::FlushCache()); sl@0: } sl@0: sl@0: void TestPinVirtualMemoryUnpaged() sl@0: { sl@0: test.Printf(_L("Create logical pin object\n")); sl@0: test_KErrNone(Ldd.CreateVirtualPinObject()); sl@0: #ifdef __EPOC32__ sl@0: CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue); sl@0: test.Printf(_L("Perform logical pin operation on zero-length buffer\n")); sl@0: test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, 0)); sl@0: CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue); sl@0: test.Printf(_L("Perform logical unpin operation\n")); sl@0: test_KErrNone(Ldd.UnpinVirtualMemory()); sl@0: CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue); sl@0: test.Printf(_L("Perform logical pin operation on whole buffer\n")); sl@0: test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, KMinBufferSize)); sl@0: CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue); sl@0: test.Printf(_L("Perform logical unpin operation\n")); sl@0: test_KErrNone(Ldd.UnpinVirtualMemory()); sl@0: CheckMemoryPresent(UnpagedBuffer, KMinBufferSize, ETrue); sl@0: #else sl@0: // Don't check for memory presence on emulator as paging not supported. sl@0: test.Printf(_L("Perform logical pin operation on zero-length buffer\n")); sl@0: test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, 0)); sl@0: test.Printf(_L("Perform logical unpin operation\n")); sl@0: test_KErrNone(Ldd.UnpinVirtualMemory()); sl@0: test.Printf(_L("Perform logical pin operation on whole buffer\n")); sl@0: test_KErrNone(Ldd.PinVirtualMemory((TLinAddr)UnpagedBuffer, KMinBufferSize)); sl@0: test.Printf(_L("Perform logical unpin operation\n")); sl@0: test_KErrNone(Ldd.UnpinVirtualMemory()); sl@0: #endif sl@0: test.Printf(_L("Perform logical unpin operation (again)\n")); sl@0: test_KErrNone(Ldd.UnpinVirtualMemory()); // test double unpin ok sl@0: test.Printf(_L("Destroy logical pin object\n")); sl@0: test_KErrNone(Ldd.DestroyVirtualPinObject()); sl@0: test.Printf(_L("Destroy logical pin object (again)\n")); sl@0: test_KErrNone(Ldd.DestroyVirtualPinObject()); // test double destroy ok sl@0: } sl@0: sl@0: void TestPinPhysicalMemory() sl@0: { sl@0: sl@0: TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask; sl@0: if (mm < EMemModelTypeFlexible) sl@0: { sl@0: test.Printf(_L("Memory model (%d) doesn't support physical pining\n"),mm); sl@0: return; sl@0: } sl@0: TInt i; sl@0: TInt8* UCBase; sl@0: RChunk chunk; sl@0: sl@0: test.Printf(_L("Allocate user chunk\n")); sl@0: TChunkCreateInfo createInfo; sl@0: createInfo.SetDisconnected(0,KUCPageCount*PageSize,KUCPageCount*PageSize); sl@0: createInfo.SetPaging(TChunkCreateInfo::EPaged); sl@0: test_KErrNone(chunk.Create(createInfo)); sl@0: UCBase = (TInt8*)chunk.Base(); sl@0: sl@0: test.Printf(_L("Create physical pin object\n")); sl@0: test_KErrNone(Ldd.CreatePhysicalPinObject()); sl@0: sl@0: test.Printf(_L("Perform physical pin operation on zero-length buffer\n")); sl@0: test_KErrNone(Ldd.PinPhysicalMemory((TLinAddr)UCBase, 0)); sl@0: sl@0: test.Printf(_L("Perform physical unpin operation\n")); sl@0: test_KErrNone(Ldd.UnpinPhysicalMemory()); sl@0: sl@0: test.Printf(_L("Perform Physical pin operation on the chunk\n")); sl@0: test_KErrNone(Ldd.PinPhysicalMemory((TLinAddr)UCBase, KUCPageCount*PageSize)); sl@0: sl@0: test.Printf(_L("Test that pinned physical memory preserves its mapping when recommited\n")); sl@0: test_KErrNone(chunk.Decommit(0,KUCPageCount*PageSize)); //Decommit all sl@0: for (i=KUCPageCount-1;i>=0;i--) test_KErrNone(chunk.Commit(i*PageSize,PageSize)); //Commit in reverse order sl@0: for (i=0;i>32); } sl@0: private: sl@0: TUint iSeed; sl@0: }; sl@0: sl@0: #define SOAK_CHECK(r) \ sl@0: if(r!=KErrNone) \ sl@0: { \ sl@0: RDebug::Printf("SOAK_CHECK fail at line %d",__LINE__); \ sl@0: return r; \ sl@0: } \ sl@0: sl@0: TInt SoakThread(TAny*) sl@0: { sl@0: RMemoryTestLdd ldd; sl@0: TInt r = ldd.Open(); sl@0: SOAK_CHECK(r) sl@0: sl@0: r = ldd.CreateVirtualPinObject(); sl@0: SOAK_CHECK(r) sl@0: sl@0: TRandom random((TUint32)&ldd); sl@0: sl@0: while(!SoakEnd) sl@0: { sl@0: TUint start = random(KMinBufferSize); sl@0: TUint end = random(KMinBufferSize); sl@0: if(start>end) sl@0: { sl@0: TUint temp = start; sl@0: start = end; sl@0: end = temp; sl@0: } sl@0: const TUint32 KPageMask = 0xfff; sl@0: start &= ~KPageMask; sl@0: end = (end+KPageMask)&~KPageMask; sl@0: sl@0: r = ldd.PinVirtualMemory((TLinAddr)(PagedBuffer+start),end-start); sl@0: SOAK_CHECK(r) sl@0: sl@0: r = ldd.UnpinVirtualMemory(); sl@0: SOAK_CHECK(r) sl@0: } sl@0: sl@0: r = ldd.DestroyVirtualPinObject(); sl@0: SOAK_CHECK(r) sl@0: sl@0: CLOSE_AND_WAIT(ldd); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: void TestPinVirtualMemoryPagedSoak() sl@0: { sl@0: test.Start(_L("Create timer")); sl@0: RTimer timer; sl@0: test_KErrNone(timer.CreateLocal()); sl@0: sl@0: test.Next(_L("Create threads")); sl@0: const TUint KNumThreads = 4; sl@0: TRequestStatus status[KNumThreads]; sl@0: RThread thread[KNumThreads]; sl@0: TUint i; sl@0: for(i=0; i=0;i--) test_KErrNone(chunk.Commit(i*PageSize,PageSize)); //Commit in reverse order sl@0: for (i=0;i>1; sl@0: // This test step relies on mapping objet being smaller than the user chunk sl@0: // and as mapping object will always be >=2 pages, user chunk must be at least 4. sl@0: __ASSERT_COMPILE(KUCPageCount >= 4); sl@0: test_KErrNone(Ldd.CreateKernelMapObject(mappingSize)); sl@0: TChunkCreateInfo chunkInfo; sl@0: chunkInfo.SetNormal(KUCBytes, KUCBytes); sl@0: chunkInfo.SetPaging(TChunkCreateInfo::EUnpaged); sl@0: test_KErrNone(chunk.Create(chunkInfo)); sl@0: sl@0: test.Printf(_L("Map and pin an unpaged chunk with pre-reserved resources\n")); sl@0: __KHEAP_FAILNEXT(1); // Ensure any attempted kernel heap allocations fail. sl@0: test_KErrNone(Ldd.KernelMapMemory((TLinAddr)chunk.Base(), mappingSize)); sl@0: test_KErrNone(Ldd.KernelUnmapMemory()); sl@0: sl@0: test.Printf(_L("Map more memory than we have pre-reserved resources for\n")); sl@0: test_Equal(KErrArgument, Ldd.KernelMapMemory((TLinAddr)chunk.Base(), mappingSize*2)); sl@0: sl@0: test.Printf(_L("Destroy the kernel map object with pre-reserved resources\n")); sl@0: test_KErrNone(Ldd.DestroyKernelMapObject()); // This will also unpin the memory. sl@0: // Clear the kernel heap fail next. sl@0: __KHEAP_RESET; sl@0: chunk.Close(); sl@0: } sl@0: sl@0: TInt E32Main() sl@0: { sl@0: test.Title(); sl@0: test.Start(_L("Test kernel pinning APIs")); sl@0: sl@0: if (DPTest::Attributes() & DPTest::ERomPaging) sl@0: test.Printf(_L("Rom paging supported\n")); sl@0: if (DPTest::Attributes() & DPTest::ECodePaging) sl@0: test.Printf(_L("Code paging supported\n")); sl@0: if (DPTest::Attributes() & DPTest::EDataPaging) sl@0: test.Printf(_L("Data paging supported\n")); sl@0: sl@0: test.Next(_L("Loading test drivers")); sl@0: test_KErrNone(Ldd.Open()); sl@0: test_KErrNone(Ldd2.Open()); sl@0: sl@0: test.Next(_L("Getting page size")); sl@0: test_KErrNone(UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&PageSize,0)); sl@0: sl@0: test.Next(_L("Setting up paged and unpaged buffers")); sl@0: sl@0: #ifdef __EPOC32__ sl@0: // Use unpaged rom for our unpaged buffer sl@0: TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); sl@0: UnpagedBuffer = (TUint8*)romHeader; sl@0: TInt size = romHeader->iPageableRomStart ? romHeader->iPageableRomStart : romHeader->iUncompressedSize; sl@0: test(size >= KMinBufferSize); sl@0: sl@0: if (DPTest::Attributes() & DPTest::ERomPaging) sl@0: { sl@0: // Use end of paged ROM for our paged buffer sl@0: test(romHeader->iPageableRomStart); sl@0: TInt offset = romHeader->iPageableRomStart + romHeader->iPageableRomSize - KMinBufferSize; sl@0: offset &= ~0xfff; sl@0: test(offset>=romHeader->iPageableRomStart); sl@0: PagedBuffer = (TUint8*)romHeader + offset; sl@0: } sl@0: else if (DPTest::Attributes() & DPTest::ECodePaging) sl@0: { sl@0: // Use code paged DLL for our paged buffer sl@0: test_KErrNone(PagedLibrary.Load(KTCodePagingDll4)); sl@0: TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)PagedLibrary.Lookup(KGetAddressOfDataFunctionOrdinal); sl@0: TInt size; sl@0: PagedBuffer = (TUint8*)func(size); sl@0: test_NotNull(PagedBuffer); sl@0: test(size >= KMinBufferSize); sl@0: } sl@0: #else sl@0: UnpagedBuffer = (TUint8*)User::Alloc(KMinBufferSize); sl@0: test_NotNull(UnpagedBuffer); sl@0: #endif sl@0: sl@0: RDebug::Printf("UnpagedBuffer=%x\n",UnpagedBuffer); sl@0: RDebug::Printf("PagedBuffer=%x\n",PagedBuffer); sl@0: sl@0: __KHEAP_MARK; sl@0: sl@0: test.Next(_L("Logical pin unpaged memory")); sl@0: TestPinVirtualMemoryUnpaged(); sl@0: sl@0: test.Next(_L("Logical pin invalid memory")); sl@0: TestPinVirtualMemoryInvalid(); sl@0: sl@0: test.Next(_L("Physical pinning")); sl@0: TestPinPhysicalMemory(); sl@0: sl@0: test.Next(_L("Physical pinning OOM")); sl@0: TestPhysicalPinOutOfMemory(); sl@0: sl@0: test.Next(_L("Kernel pin mapping")); sl@0: TestMapAndPinMemory(); sl@0: sl@0: test.Next(_L("Pin OOM Tests")); sl@0: TestPinOutOfMemory(); sl@0: sl@0: if (PagedBuffer) sl@0: { sl@0: test.Next(_L("Logical pin paged memory")); sl@0: TestPinVirtualMemoryPaged(); sl@0: sl@0: test.Next(_L("Logical pin paged memory soak test")); sl@0: TestPinVirtualMemoryPagedSoak(); sl@0: } sl@0: sl@0: if (DPTest::Attributes() & DPTest::EDataPaging) sl@0: { sl@0: test.Next(_L("Logical pin then decommit memory")); sl@0: TestPinVirtualMemoryDecommit(); sl@0: } sl@0: sl@0: // wait for any async cleanup in the supervisor to finish first... sl@0: UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0); sl@0: __KHEAP_MARKEND; sl@0: sl@0: #ifndef __EPOC32__ sl@0: User::Free((TAny*)UnpagedBuffer); sl@0: #endif sl@0: sl@0: PagedLibrary.Close(); sl@0: Ldd.Close(); sl@0: Ldd2.Close(); sl@0: test.End(); sl@0: sl@0: return KErrNone; sl@0: }