diff -r a179b74831c9 -r c1f20ce4abcf kernel/eka/memmodel/epoc/flexible/mmu/mpager.h --- a/kernel/eka/memmodel/epoc/flexible/mmu/mpager.h Thu Aug 19 11:14:22 2010 +0300 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpager.h Tue Aug 31 16:34:26 2010 +0300 @@ -152,6 +152,20 @@ void FlushAll(); /** + Flush demand paged pages in a specified region. + + The memory must reside in a single memory object. + + @param aProcess The process containing the pages to flush. + @param aStart The start address of the region. + @param aSize The size of the region in bytes. + + @return KErrBadDescriptor If the memory region is invalid or spans more than one memory object, + otherwise KErrNone. + */ + TInt FlushRegion(DMemModelProcess* aProcess, TLinAddr aStartAddress, TUint aSize); + + /** Give pages to paging system for managing. */ void DonatePages(TUint aCount, TPhysAddr* aPages); @@ -404,6 +418,23 @@ */ void SetCleanInSequence(TBool aCleanInSequence); + /** + Generate a new error code that includes both the original error code and some extra context + information. This is used to communicate context information from where it occurs to where it + is handled. + */ + TInt EmbedErrorContext(TPagingErrorContext aContext, TInt aError); + + /** + Extract the context information from a error code generated by #EmbedErrorContext. + */ + static TPagingErrorContext ExtractErrorContext(TInt aContextError); + + /** + Extract the original error code from a error code generated by #EmbedErrorContext. + */ + static TInt ExtractErrorCode(TInt aContextError); + private: /** Add a page to the head of the live page list. I.e. make it the 'youngest' page. @@ -626,6 +657,12 @@ TBool ReservePage(); /** + Determine the thread responsible for this page fault. This returns either NULL to indicate + the current thread, or a remote thread if the fault is caused by an IPC operation. + */ + DThread* ResponsibleThread(DThread* aThread, TAny* aExceptionInfo); + + /** Called when a realtime thread takes a paging fault. Checks whether it's OK for the thread to take to fault. @return KErrNone if the paging fault should be further processed @@ -633,6 +670,20 @@ TInt CheckRealtimeThreadFault(DThread* aThread, TAny* aExceptionInfo); /** + Kills the thread responsible for causing a page fault. + + This is called when a fatal error is encountered when handling a page fault, for example, if a + media access fails. + + Originally the paging system reacted by faulting the system in such cases. However the current + approach was thought to be preferable as this kind of error can happen in practice (even though + in theory it should not) and it means that the error code is reported and can be captured by + MobileCrash. + */ + void KillResponsibleThread(TPagingErrorContext aErrorCategory, TInt aErrorCode, + TAny* aExceptionInfo); + + /** Attempt to find the page table entry and page info for a page in the specified mapping. @param aOsAsid The OsAsid of the process that owns the mapping. @@ -694,11 +745,53 @@ TSpinLock iBenchmarkLock; SPagingBenchmarkInfo iBenchmarkInfo[EMaxPagingBm]; #endif //__DEMAND_PAGING_BENCHMARKS__ + +#ifdef _DEBUG + TPagingErrorContext iDebugFailContext; +#endif }; extern DPager ThePager; +// Functions to embed context information into error codes, using the following scheme: +// +// bits 0-16 taken from original error code +// bits 16-31 bitwise NOT of a TPagingErrorContext value +// +// Since the context informtion is a small positive integer, the resulting error code is still a +// negative integer. The value EPagingErrorContextNone is zero, yeilding the original error code +// unchanged if embedded. + +inline TInt DPager::EmbedErrorContext(TPagingErrorContext aContext, TInt aError) + { + __NK_ASSERT_DEBUG(aContext > 0 && aContext <= 0x7fff); +#ifdef _DEBUG + if (aError >= KErrNone) + { + TUint32 match = aContext; + if (__e32_atomic_cas_ord32(&iDebugFailContext, &match, 0)) + aError = KErrAbort; + } +#endif + if (aError >= KErrNone) + return aError; + if (aError < (TInt)0xffff0000) + aError = KErrGeneral; // lose error code, but doesn't happen in practice + return (aError & 0x0000ffff) | ((~aContext) << 16); + } + +inline TPagingErrorContext DPager::ExtractErrorContext(TInt aContextError) + { + return (TPagingErrorContext)((~aContextError) >> 16); + } + +inline TInt DPager::ExtractErrorCode(TInt aContextError) + { + return aContextError | 0x7fff000; + } + + #ifdef __DEMAND_PAGING_BENCHMARKS__ #define START_PAGING_BENCHMARK TUint32 _bmStart = NKern::FastCounter() @@ -999,5 +1092,4 @@ static void Init(); }; - #endif