kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp
branchRCL_3
changeset 43 c1f20ce4abcf
parent 41 0ffb4e86fcc9
child 44 3e88ff8f41d5
equal deleted inserted replaced
42:a179b74831c9 43:c1f20ce4abcf
  1391 	TheDataPagedMemoryManager->Init3();
  1391 	TheDataPagedMemoryManager->Init3();
  1392 	TheCodePagedMemoryManager->Init3();
  1392 	TheCodePagedMemoryManager->Init3();
  1393 	TInt r = Kern::AddHalEntry(EHalGroupVM, VMHalFunction, 0);
  1393 	TInt r = Kern::AddHalEntry(EHalGroupVM, VMHalFunction, 0);
  1394 	__NK_ASSERT_ALWAYS(r==KErrNone);
  1394 	__NK_ASSERT_ALWAYS(r==KErrNone);
  1395 	PageCleaningLock::Init();
  1395 	PageCleaningLock::Init();
       
  1396 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  1397 	for (TInt i = 0 ; i < EMaxPagingBm ; ++i)
       
  1398 		ResetBenchmarkData((TPagingBenchmark)i);
       
  1399 #endif
  1396 	}
  1400 	}
  1397 
  1401 
  1398 
  1402 
  1399 void DPager::Fault(TFault aFault)
  1403 void DPager::Fault(TFault aFault)
  1400 	{
  1404 	{
  2038 	aCount = 0;
  2042 	aCount = 0;
  2039 	MmuLock::Unlock();
  2043 	MmuLock::Unlock();
  2040 	}
  2044 	}
  2041 
  2045 
  2042 
  2046 
  2043 TInt DPager::CheckRealtimeThreadFault(DThread* aThread, TAny* aExceptionInfo)
  2047 DThread* DPager::ResponsibleThread(DThread* aThread, TAny* aExceptionInfo)
  2044 	{
  2048 	{
  2045 	// realtime threads shouldn't take paging faults...
       
  2046 	DThread* client = aThread->iIpcClient;
  2049 	DThread* client = aThread->iIpcClient;
  2047 
  2050 
  2048 	// If iIpcClient is set then we are accessing the address space of a remote thread.  If we are
  2051 	// If iIpcClient is set then we are accessing the address space of a remote thread.  If we are
  2049 	// in an IPC trap, this will contain information the local and remote addresses being accessed.
  2052 	// in an IPC trap, this will contain information the local and remote addresses being accessed.
  2050 	// If this is not set then we assume than any fault must be the fault of a bad remote address.
  2053 	// If this is not set then we assume than any fault must be the fault of a bad remote address.
  2051 	TIpcExcTrap* ipcTrap = (TIpcExcTrap*)aThread->iExcTrap;
  2054 	TIpcExcTrap* ipcTrap = (TIpcExcTrap*)aThread->iExcTrap;
  2052 	if (ipcTrap && !ipcTrap->IsTIpcExcTrap())
  2055 	if (ipcTrap && !ipcTrap->IsTIpcExcTrap())
  2053 		ipcTrap = 0;
  2056 		ipcTrap = 0;
  2054 	if (client && (!ipcTrap || ipcTrap->ExcLocation(aThread, aExceptionInfo) == TIpcExcTrap::EExcRemote))
  2057 	if (client &&
  2055 		{
  2058 		(!ipcTrap || ipcTrap->ExcLocation(aThread, aExceptionInfo) == TIpcExcTrap::EExcRemote))
  2056 		// kill client thread...
  2059 		return client;
  2057 		if(K::IllegalFunctionForRealtimeThread(client,"Access to Paged Memory (by other thread)"))
       
  2058 			{
       
  2059 			// treat memory access as bad...
       
  2060 			return KErrAbort;
       
  2061 			}
       
  2062 		// else thread is in 'warning only' state so allow paging...
       
  2063 		}
       
  2064 	else
  2060 	else
  2065 		{
  2061 		return NULL;
  2066 		// kill current thread...
  2062 	}
  2067 		if(K::IllegalFunctionForRealtimeThread(NULL,"Access to Paged Memory"))
  2063 
  2068 			{
  2064 
  2069 			// if current thread is in critical section, then the above kill will be deferred
  2065 TInt DPager::CheckRealtimeThreadFault(DThread* aThread, TAny* aExceptionInfo)
  2070 			// and we will continue executing. We will handle this by returning an error
  2066 	{
  2071 			// which means that the thread will take an exception (which hopefully is XTRAPed!)
  2067 	// realtime threads shouldn't take paging faults...
  2072 			return KErrAbort;
  2068 	DThread* thread = ResponsibleThread(aThread, aExceptionInfo);
  2073 			}
  2069 
  2074 		// else thread is in 'warning only' state so allow paging...
  2070 	const char* message = thread ?
  2075 		}
  2071 		"Access to Paged Memory (by other thread)" : "Access to Paged Memory";
  2076 	return KErrNone;
  2072 
       
  2073 	// kill respsonsible thread...
       
  2074 	if(K::IllegalFunctionForRealtimeThread(thread, message))
       
  2075 		{
       
  2076 		// if we are killing the current thread and we are in a critical section, then the above
       
  2077 		// kill will be deferred and we will continue executing. We will handle this by returning an
       
  2078 		// error which means that the thread will take an exception (which hopefully is XTRAPed!)
       
  2079 
       
  2080 		// treat memory access as bad...
       
  2081 		return KErrAbort;
       
  2082 		}
       
  2083 	else
       
  2084 		{
       
  2085 		// thread is in 'warning only' state so allow paging...
       
  2086 		return KErrNone;
       
  2087 		}
       
  2088 	}
       
  2089 
       
  2090 
       
  2091 void DPager::KillResponsibleThread(TPagingErrorContext aContext, TInt aErrorCode,
       
  2092 								   TAny* aExceptionInfo)
       
  2093 	{
       
  2094 	const char* message = NULL;
       
  2095 	switch (aContext)
       
  2096 		{
       
  2097 		case EPagingErrorContextRomRead:
       
  2098 			message = "PAGED-ROM-READ";
       
  2099 			break;
       
  2100 		case EPagingErrorContextRomDecompress:
       
  2101 			message = "PAGED-ROM-COMP";
       
  2102 			break;
       
  2103 		case EPagingErrorContextCodeRead:
       
  2104 			message = "PAGED-CODE-READ";
       
  2105 			break;
       
  2106 		case EPagingErrorContextCodeDecompress:
       
  2107 			message = "PAGED-CODE-COMP";
       
  2108 			break;
       
  2109 		case EPagingErrorContextDataRead:
       
  2110 			message = "PAGED-DATA-READ";
       
  2111 			break;
       
  2112 		case EPagingErrorContextDataWrite:
       
  2113 			message = "PAGED-DATA-WRITE";
       
  2114 			break;
       
  2115 		default:
       
  2116 			message = "PAGED-UNKNOWN";
       
  2117 			break;
       
  2118 		}
       
  2119 
       
  2120 	TPtrC8 category((const unsigned char*)message);
       
  2121 	DThread* thread = ResponsibleThread(TheCurrentThread, aExceptionInfo);
       
  2122 	if (thread)
       
  2123 		{
       
  2124 		NKern::LockSystem();
       
  2125 		thread->Die(EExitPanic, aErrorCode,  category);
       
  2126 		}
       
  2127 	else
       
  2128 		{
       
  2129 		TheCurrentThread->SetExitInfo(EExitPanic, aErrorCode, category);
       
  2130 		NKern::DeferredExit();
       
  2131 		}
  2077 	}
  2132 	}
  2078 
  2133 
  2079 
  2134 
  2080 TInt DPager::HandlePageFault(	TLinAddr aPc, TLinAddr aFaultAddress, TUint aFaultAsid, TUint aFaultIndex,
  2135 TInt DPager::HandlePageFault(	TLinAddr aPc, TLinAddr aFaultAddress, TUint aFaultAsid, TUint aFaultIndex,
  2081 								TUint aAccessPermissions, DMemoryObject* aMemory, DMemoryMapping* aMapping,
  2136 								TUint aAccessPermissions, DMemoryObject* aMemory, DMemoryMapping* aMapping,
  2097 
  2152 
  2098 		DMemoryManager* manager = aMemory->iManager;
  2153 		DMemoryManager* manager = aMemory->iManager;
  2099 		r = manager->HandleFault(aMemory, aFaultIndex, aMapping, aMapInstanceCount, aAccessPermissions);
  2154 		r = manager->HandleFault(aMemory, aFaultIndex, aMapping, aMapInstanceCount, aAccessPermissions);
  2100 
  2155 
  2101 		TheThrashMonitor.NotifyEndPaging();
  2156 		TheThrashMonitor.NotifyEndPaging();
       
  2157 
       
  2158 		// If the paging system encountered an error paging in the memory (as opposed to a thread
       
  2159 		// accessing non-existent memory), then panic the appropriate thread.  Unfortunately this
       
  2160 		// situation does occur as media such as eMMC wears out towards the end of its life. 
       
  2161 		if (r != KErrNone)
       
  2162 			{
       
  2163 			TPagingErrorContext context = ExtractErrorContext(r);
       
  2164 			if (context != EPagingErrorContextNone)
       
  2165 				KillResponsibleThread(context, ExtractErrorCode(r), aExceptionInfo);
       
  2166 			}
  2102 		}
  2167 		}
  2103 	return r;
  2168 	return r;
  2104 	}
  2169 	}
  2105 
  2170 
  2106 
  2171 
  2323 	RamAllocLock::Unlock();
  2388 	RamAllocLock::Unlock();
  2324 	NKern::ThreadLeaveCS();
  2389 	NKern::ThreadLeaveCS();
  2325 	}
  2390 	}
  2326 
  2391 
  2327 
  2392 
       
  2393 TInt DPager::FlushRegion(DMemModelProcess* aProcess, TLinAddr aStartAddress, TUint aSize)
       
  2394 	{
       
  2395 	if (aSize == 0)
       
  2396 		return KErrNone;
       
  2397 
       
  2398 	// find mapping
       
  2399 	NKern::ThreadEnterCS();
       
  2400 	TUint offsetInMapping;
       
  2401 	TUint mapInstanceCount;
       
  2402 	DMemoryMapping* mapping = MM::FindMappingInProcess(aProcess, aStartAddress, aSize,
       
  2403 													   offsetInMapping, mapInstanceCount);
       
  2404 	if (!mapping)
       
  2405 		{
       
  2406 		NKern::ThreadLeaveCS();
       
  2407 		return KErrBadDescriptor;
       
  2408 		}
       
  2409 
       
  2410 	// check whether memory is demand paged
       
  2411 	MmuLock::Lock();
       
  2412 	DMemoryObject* memory = mapping->Memory();
       
  2413 	if(mapInstanceCount != mapping->MapInstanceCount() || memory == NULL || !memory->IsDemandPaged())
       
  2414 		{
       
  2415 		MmuLock::Unlock();
       
  2416 		mapping->Close();
       
  2417 		NKern::ThreadLeaveCS();
       
  2418 		return KErrNone;
       
  2419 		}
       
  2420 
       
  2421 	TRACE(("DPager::FlushRegion: %O %08x +%d", aProcess, aStartAddress, aSize));
       
  2422 	if (!K::Initialising)
       
  2423 		TRACE2(("  context %T %d", NCurrentThread(), NKern::CurrentContext()));
       
  2424 
       
  2425 	// why did we not get assertion failures before I added this?
       
  2426 	__NK_ASSERT_DEBUG(!Kern::CurrentThread().IsRealtime());
       
  2427 
       
  2428 	// acquire necessary locks
       
  2429 	MmuLock::Unlock();
       
  2430 	RamAllocLock::Lock();
       
  2431 	PageCleaningLock::Lock();
       
  2432 	MmuLock::Lock();
       
  2433 
       
  2434 	// find region in memory object
       
  2435 	TUint startPage = (offsetInMapping >> KPageShift) + mapping->iStartIndex;
       
  2436 	TUint sizeInPages = ((aStartAddress & KPageMask) + aSize - 1) >> KPageShift;
       
  2437 	TUint endPage = startPage + sizeInPages;
       
  2438 	TRACE2(("DPager::FlushRegion: page range is %d to %d", startPage, endPage));
       
  2439 	
       
  2440 	// attempt to flush each page
       
  2441 	TUint index = startPage;
       
  2442 	while (mapping->MapInstanceCount() == mapInstanceCount &&
       
  2443 		   mapping->Memory() && index <= endPage)
       
  2444 		{
       
  2445 		TRACE2(("DPager::FlushRegion: flushing page %d", index));
       
  2446 		TPhysAddr physAddr = memory->iPages.PhysAddr(index);
       
  2447 		
       
  2448 		if (physAddr != KPhysAddrInvalid)
       
  2449 			{
       
  2450 			TRACE2(("DPager::FlushRegion: phys addr is %08x", physAddr));
       
  2451 			SPageInfo* pi = SPageInfo::SafeFromPhysAddr(physAddr);
       
  2452 			if (pi)
       
  2453 				{
       
  2454 				__NK_ASSERT_DEBUG(pi->Type() == SPageInfo::EManaged);
       
  2455 				SPageInfo::TPagedState state = pi->PagedState();
       
  2456 				if (state==SPageInfo::EPagedYoung || state==SPageInfo::EPagedOld ||
       
  2457 					state==SPageInfo::EPagedOldestClean || state==SPageInfo::EPagedOldestDirty)
       
  2458 					{
       
  2459 					TRACE2(("DPager::FlushRegion: attempt to steal page"));
       
  2460 					TInt r = StealPage(pi);
       
  2461 					if(r==KErrNone)
       
  2462 						{
       
  2463 						TRACE2(("DPager::FlushRegion: attempt to page out %08x", physAddr));
       
  2464 						AddAsFreePage(pi);
       
  2465 						TRACE2(("DPager::FlushRegion: paged out %08x", physAddr));
       
  2466 						}
       
  2467 					else
       
  2468 						TRACE2(("DPager::FlushRegion: page out %08x failed with %d", physAddr, r));
       
  2469 					}
       
  2470 				}
       
  2471 			}
       
  2472 		
       
  2473 		MmuLock::Flash();
       
  2474 		++index;
       
  2475 		}
       
  2476 	
       
  2477 	MmuLock::Unlock();
       
  2478 	PageCleaningLock::Unlock();
       
  2479 	RamAllocLock::Unlock();
       
  2480 	mapping->Close();
       
  2481 	NKern::ThreadLeaveCS();
       
  2482 	TRACE2(("DPager::FlushRegion: done"));
       
  2483 	return KErrNone;
       
  2484 	}
       
  2485 
       
  2486 
  2328 void DPager::GetLiveListInfo(SVMCacheInfo& aInfo)
  2487 void DPager::GetLiveListInfo(SVMCacheInfo& aInfo)
  2329 	{
  2488 	{
  2330 	MmuLock::Lock(); // ensure consistent set of values are read...
  2489 	MmuLock::Lock(); // ensure consistent set of values are read...
  2331 	aInfo.iMinSize = iMinimumPageCount<<KPageShift;
  2490 	aInfo.iMinSize = iMinimumPageCount<<KPageShift;
  2332 	aInfo.iMaxSize = iMaximumPageCount<<KPageShift;
  2491 	aInfo.iMaxSize = iMaximumPageCount<<KPageShift;
  2544 		if(!TheCurrentThread->HasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by VMHalFunction(EVMHalSetDataWriteSize)")))
  2703 		if(!TheCurrentThread->HasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by VMHalFunction(EVMHalSetDataWriteSize)")))
  2545 			K::UnlockedPlatformSecurityPanic();
  2704 			K::UnlockedPlatformSecurityPanic();
  2546 		if ((K::MemModelAttributes & EMemModelAttrDataPaging) == 0)
  2705 		if ((K::MemModelAttributes & EMemModelAttrDataPaging) == 0)
  2547 			return KErrNotSupported;
  2706 			return KErrNotSupported;
  2548 		return SetDataWriteSize((TUint)a1);
  2707 		return SetDataWriteSize((TUint)a1);
  2549 	
  2708 
       
  2709 #ifdef _DEBUG
       
  2710 	case EVMHalDebugSetFail:
       
  2711 		{
       
  2712 		TUint context = (TUint)a1;
       
  2713 		if (context >= EMaxPagingErrorContext)
       
  2714 			return KErrArgument;
       
  2715 		__e32_atomic_store_ord32(&(ThePager.iDebugFailContext), context);
       
  2716 		return KErrNone;
       
  2717 		}
       
  2718 #endif
       
  2719 
  2550 	default:
  2720 	default:
  2551 		return KErrNotSupported;
  2721 		return KErrNotSupported;
  2552 		}
  2722 		}
  2553 	}
  2723 	}
  2554 
  2724