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 |