--- 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;
}