kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp
branchRCL_3
changeset 43 c1f20ce4abcf
parent 41 0ffb4e86fcc9
child 44 3e88ff8f41d5
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp	Thu Aug 19 11:14:22 2010 +0300
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp	Tue Aug 31 16:34:26 2010 +0300
@@ -1393,6 +1393,10 @@
 	TInt r = Kern::AddHalEntry(EHalGroupVM, VMHalFunction, 0);
 	__NK_ASSERT_ALWAYS(r==KErrNone);
 	PageCleaningLock::Init();
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+	for (TInt i = 0 ; i < EMaxPagingBm ; ++i)
+		ResetBenchmarkData((TPagingBenchmark)i);
+#endif
 	}
 
 
@@ -2040,9 +2044,8 @@
 	}
 
 
-TInt DPager::CheckRealtimeThreadFault(DThread* aThread, TAny* aExceptionInfo)
+DThread* DPager::ResponsibleThread(DThread* aThread, TAny* aExceptionInfo)
 	{
-	// realtime threads shouldn't take paging faults...
 	DThread* client = aThread->iIpcClient;
 
 	// If iIpcClient is set then we are accessing the address space of a remote thread.  If we are
@@ -2051,29 +2054,81 @@
 	TIpcExcTrap* ipcTrap = (TIpcExcTrap*)aThread->iExcTrap;
 	if (ipcTrap && !ipcTrap->IsTIpcExcTrap())
 		ipcTrap = 0;
-	if (client && (!ipcTrap || ipcTrap->ExcLocation(aThread, aExceptionInfo) == TIpcExcTrap::EExcRemote))
+	if (client &&
+		(!ipcTrap || ipcTrap->ExcLocation(aThread, aExceptionInfo) == TIpcExcTrap::EExcRemote))
+		return client;
+	else
+		return NULL;
+	}
+
+
+TInt DPager::CheckRealtimeThreadFault(DThread* aThread, TAny* aExceptionInfo)
+	{
+	// realtime threads shouldn't take paging faults...
+	DThread* thread = ResponsibleThread(aThread, aExceptionInfo);
+
+	const char* message = thread ?
+		"Access to Paged Memory (by other thread)" : "Access to Paged Memory";
+
+	// kill respsonsible thread...
+	if(K::IllegalFunctionForRealtimeThread(thread, message))
 		{
-		// kill client thread...
-		if(K::IllegalFunctionForRealtimeThread(client,"Access to Paged Memory (by other thread)"))
-			{
-			// treat memory access as bad...
-			return KErrAbort;
-			}
-		// else thread is in 'warning only' state so allow paging...
+		// if we are killing the current thread and we are in a critical section, then the above
+		// kill will be deferred and we will continue executing. We will handle this by returning an
+		// error which means that the thread will take an exception (which hopefully is XTRAPed!)
+
+		// treat memory access as bad...
+		return KErrAbort;
 		}
 	else
 		{
-		// kill current thread...
-		if(K::IllegalFunctionForRealtimeThread(NULL,"Access to Paged Memory"))
-			{
-			// if current thread is in critical section, then the above kill will be deferred
-			// and we will continue executing. We will handle this by returning an error
-			// which means that the thread will take an exception (which hopefully is XTRAPed!)
-			return KErrAbort;
-			}
-		// else thread is in 'warning only' state so allow paging...
+		// thread is in 'warning only' state so allow paging...
+		return KErrNone;
 		}
-	return KErrNone;
+	}
+
+
+void DPager::KillResponsibleThread(TPagingErrorContext aContext, TInt aErrorCode,
+								   TAny* aExceptionInfo)
+	{
+	const char* message = NULL;
+	switch (aContext)
+		{
+		case EPagingErrorContextRomRead:
+			message = "PAGED-ROM-READ";
+			break;
+		case EPagingErrorContextRomDecompress:
+			message = "PAGED-ROM-COMP";
+			break;
+		case EPagingErrorContextCodeRead:
+			message = "PAGED-CODE-READ";
+			break;
+		case EPagingErrorContextCodeDecompress:
+			message = "PAGED-CODE-COMP";
+			break;
+		case EPagingErrorContextDataRead:
+			message = "PAGED-DATA-READ";
+			break;
+		case EPagingErrorContextDataWrite:
+			message = "PAGED-DATA-WRITE";
+			break;
+		default:
+			message = "PAGED-UNKNOWN";
+			break;
+		}
+
+	TPtrC8 category((const unsigned char*)message);
+	DThread* thread = ResponsibleThread(TheCurrentThread, aExceptionInfo);
+	if (thread)
+		{
+		NKern::LockSystem();
+		thread->Die(EExitPanic, aErrorCode,  category);
+		}
+	else
+		{
+		TheCurrentThread->SetExitInfo(EExitPanic, aErrorCode, category);
+		NKern::DeferredExit();
+		}
 	}
 
 
@@ -2099,6 +2154,16 @@
 		r = manager->HandleFault(aMemory, aFaultIndex, aMapping, aMapInstanceCount, aAccessPermissions);
 
 		TheThrashMonitor.NotifyEndPaging();
+
+		// If the paging system encountered an error paging in the memory (as opposed to a thread
+		// accessing non-existent memory), then panic the appropriate thread.  Unfortunately this
+		// situation does occur as media such as eMMC wears out towards the end of its life. 
+		if (r != KErrNone)
+			{
+			TPagingErrorContext context = ExtractErrorContext(r);
+			if (context != EPagingErrorContextNone)
+				KillResponsibleThread(context, ExtractErrorCode(r), aExceptionInfo);
+			}
 		}
 	return r;
 	}
@@ -2325,6 +2390,100 @@
 	}
 
 
+TInt DPager::FlushRegion(DMemModelProcess* aProcess, TLinAddr aStartAddress, TUint aSize)
+	{
+	if (aSize == 0)
+		return KErrNone;
+
+	// find mapping
+	NKern::ThreadEnterCS();
+	TUint offsetInMapping;
+	TUint mapInstanceCount;
+	DMemoryMapping* mapping = MM::FindMappingInProcess(aProcess, aStartAddress, aSize,
+													   offsetInMapping, mapInstanceCount);
+	if (!mapping)
+		{
+		NKern::ThreadLeaveCS();
+		return KErrBadDescriptor;
+		}
+
+	// check whether memory is demand paged
+	MmuLock::Lock();
+	DMemoryObject* memory = mapping->Memory();
+	if(mapInstanceCount != mapping->MapInstanceCount() || memory == NULL || !memory->IsDemandPaged())
+		{
+		MmuLock::Unlock();
+		mapping->Close();
+		NKern::ThreadLeaveCS();
+		return KErrNone;
+		}
+
+	TRACE(("DPager::FlushRegion: %O %08x +%d", aProcess, aStartAddress, aSize));
+	if (!K::Initialising)
+		TRACE2(("  context %T %d", NCurrentThread(), NKern::CurrentContext()));
+
+	// why did we not get assertion failures before I added this?
+	__NK_ASSERT_DEBUG(!Kern::CurrentThread().IsRealtime());
+
+	// acquire necessary locks
+	MmuLock::Unlock();
+	RamAllocLock::Lock();
+	PageCleaningLock::Lock();
+	MmuLock::Lock();
+
+	// find region in memory object
+	TUint startPage = (offsetInMapping >> KPageShift) + mapping->iStartIndex;
+	TUint sizeInPages = ((aStartAddress & KPageMask) + aSize - 1) >> KPageShift;
+	TUint endPage = startPage + sizeInPages;
+	TRACE2(("DPager::FlushRegion: page range is %d to %d", startPage, endPage));
+	
+	// attempt to flush each page
+	TUint index = startPage;
+	while (mapping->MapInstanceCount() == mapInstanceCount &&
+		   mapping->Memory() && index <= endPage)
+		{
+		TRACE2(("DPager::FlushRegion: flushing page %d", index));
+		TPhysAddr physAddr = memory->iPages.PhysAddr(index);
+		
+		if (physAddr != KPhysAddrInvalid)
+			{
+			TRACE2(("DPager::FlushRegion: phys addr is %08x", physAddr));
+			SPageInfo* pi = SPageInfo::SafeFromPhysAddr(physAddr);
+			if (pi)
+				{
+				__NK_ASSERT_DEBUG(pi->Type() == SPageInfo::EManaged);
+				SPageInfo::TPagedState state = pi->PagedState();
+				if (state==SPageInfo::EPagedYoung || state==SPageInfo::EPagedOld ||
+					state==SPageInfo::EPagedOldestClean || state==SPageInfo::EPagedOldestDirty)
+					{
+					TRACE2(("DPager::FlushRegion: attempt to steal page"));
+					TInt r = StealPage(pi);
+					if(r==KErrNone)
+						{
+						TRACE2(("DPager::FlushRegion: attempt to page out %08x", physAddr));
+						AddAsFreePage(pi);
+						TRACE2(("DPager::FlushRegion: paged out %08x", physAddr));
+						}
+					else
+						TRACE2(("DPager::FlushRegion: page out %08x failed with %d", physAddr, r));
+					}
+				}
+			}
+		
+		MmuLock::Flash();
+		++index;
+		}
+	
+	MmuLock::Unlock();
+	PageCleaningLock::Unlock();
+	RamAllocLock::Unlock();
+	mapping->Close();
+	NKern::ThreadLeaveCS();
+	TRACE2(("DPager::FlushRegion: done"));
+	return KErrNone;
+	}
+
+
 void DPager::GetLiveListInfo(SVMCacheInfo& aInfo)
 	{
 	MmuLock::Lock(); // ensure consistent set of values are read...
@@ -2546,7 +2705,18 @@
 		if ((K::MemModelAttributes & EMemModelAttrDataPaging) == 0)
 			return KErrNotSupported;
 		return SetDataWriteSize((TUint)a1);
-	
+
+#ifdef _DEBUG
+	case EVMHalDebugSetFail:
+		{
+		TUint context = (TUint)a1;
+		if (context >= EMaxPagingErrorContext)
+			return KErrArgument;
+		__e32_atomic_store_ord32(&(ThePager.iDebugFailContext), context);
+		return KErrNone;
+		}
+#endif
+
 	default:
 		return KErrNotSupported;
 		}