sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalComponent sl@0: */ sl@0: sl@0: #ifndef MPAGER_H sl@0: #define MPAGER_H sl@0: sl@0: struct SVMCacheInfo; sl@0: class DMemModelThread; sl@0: class DMemoryMappingBase; sl@0: sl@0: class DPager sl@0: { sl@0: public: sl@0: DPager(); sl@0: void Init2(); sl@0: void Init3(); sl@0: sl@0: FORCE_INLINE TUint NumberOfFreePages() sl@0: { sl@0: return iNumberOfFreePages; sl@0: } sl@0: sl@0: FORCE_INLINE TUint NumberOfDirtyPages() sl@0: { sl@0: TUint ret; sl@0: MmuLock::Lock(); sl@0: ret = iNumberOfDirtyPages; sl@0: MmuLock::Unlock(); sl@0: return ret; sl@0: } sl@0: sl@0: FORCE_INLINE void SetWritable(SPageInfo& aPageInfo) sl@0: { sl@0: if (!aPageInfo.IsDirty()) sl@0: {// This is the first mapping to write to the page so increase the sl@0: // dirty page count. sl@0: aPageInfo.SetWritable(); sl@0: iNumberOfDirtyPages++; sl@0: } sl@0: } sl@0: sl@0: FORCE_INLINE void SetClean(SPageInfo& aPageInfo) sl@0: { sl@0: __NK_ASSERT_DEBUG(iNumberOfDirtyPages); sl@0: __NK_ASSERT_DEBUG(aPageInfo.IsDirty()); sl@0: aPageInfo.SetClean(); sl@0: iNumberOfDirtyPages--; sl@0: } sl@0: sl@0: /** sl@0: Remove RAM pages from the cache and return them to the system's free pool. sl@0: (Free them.) sl@0: sl@0: This is called by class Mmu when it requires more free RAM to meet an sl@0: allocation request. sl@0: sl@0: @param aNumPages The number of pages to free up. sl@0: @return True if all pages could be freed, false otherwise sl@0: @pre RamAlloc mutex held. sl@0: */ sl@0: TBool GetFreePages(TInt aNumPages); sl@0: sl@0: sl@0: /** sl@0: Attempts to rejuvenate or page in the page to the mapping that took the page fault. sl@0: sl@0: @param aPc Address of instruction causing the fault. sl@0: @param aFaultAddress Address of memory access which faulted. sl@0: @param aFaultAsid The asid of the faulting thread's process. sl@0: @param aAccessPermissions Bitmask of values from enum TAccessPermissions, which sl@0: indicates the permissions required by faulting memory access. sl@0: @param aMapInstanceCount The instance count of the mapping when it took the page fault. sl@0: @param aThread The thread that took the page fault. sl@0: @param aExceptionInfo The processor specific exception info. sl@0: sl@0: @return KErrNone if the page is now accessable, otherwise one of the system wide error codes. sl@0: */ sl@0: TInt HandlePageFault( TLinAddr aPc, TLinAddr aFaultAddress, TUint aFaultAsid, TUint aFaultIndex, sl@0: TUint aAccessPermissions, DMemoryObject* aMemory, DMemoryMapping* aMapping, sl@0: TUint aMapInstanceCount, DThread* aThread, TAny* aExceptionInfo); sl@0: sl@0: sl@0: /** sl@0: Fault enumeration sl@0: */ sl@0: enum TFault sl@0: { sl@0: }; sl@0: sl@0: /** sl@0: Fault the system. sl@0: */ sl@0: static void Fault(TFault aFault); sl@0: sl@0: /** sl@0: Get state of live page list. sl@0: */ sl@0: void GetLiveListInfo(SVMCacheInfo& aInfo); sl@0: sl@0: /** sl@0: Resize the live page list. sl@0: */ sl@0: TInt ResizeLiveList(TUint aMinimumPageCount, TUint aMaximumPageCount); sl@0: sl@0: /** sl@0: Recalculate live list size. sl@0: */ sl@0: TInt ResizeLiveList(); sl@0: sl@0: /** sl@0: Flush (unmap) all memory which is demand paged. sl@0: This reduces the live page list to a minimum. sl@0: */ sl@0: void FlushAll(); sl@0: sl@0: /** sl@0: Give pages to paging system for managing. sl@0: */ sl@0: void DonatePages(TUint aCount, TPhysAddr* aPages); sl@0: sl@0: /** sl@0: Reclaim pages from paging system which were previously donated with DonatePages. sl@0: sl@0: @param aCount Number of pages. sl@0: @param aPages Array of pages (as stored in an RPageArray). sl@0: sl@0: @return KErrNone if successful. sl@0: KErrNoMemory if paging system doesn't have enough spare pages. This will leave some or all of the pages still managed by the pager. sl@0: KErrNotFound if some of the pages were not actually being managed by the pager. sl@0: */ sl@0: TInt ReclaimPages(TUint aCount, TPhysAddr* aPages); sl@0: sl@0: /** sl@0: Called by class Mmu whenever a page of RAM is freed. The page state will be EUnused. sl@0: If the page was being used by the pager then this gives it the opportunity to update sl@0: any internal state. If the pager wishes to retain ownership of the page the it must sl@0: return the result KErrNone, any other value will cause the page to be returned to the sl@0: systems free pool. sl@0: */ sl@0: TInt PageFreed(SPageInfo* aPageInfo); sl@0: sl@0: // sl@0: // following public members for use by memory managers... sl@0: // sl@0: sl@0: /** sl@0: Allocate a number of RAM pages to store demand paged content. sl@0: These pages are obtained from... sl@0: sl@0: 1. An unused page in the live page list. sl@0: 2. The systems free pool. sl@0: 3. The oldest page from the live page list. sl@0: */ sl@0: TInt PageInAllocPages(TPhysAddr* aPages, TUint aCount, Mmu::TRamAllocFlags aAllocFlags); sl@0: sl@0: /** sl@0: Free a number of RAM pages allocated by PageInAllocPages. sl@0: */ sl@0: void PageInFreePages(TPhysAddr* aPages, TUint aCount); sl@0: sl@0: /** sl@0: Called to add a new page to the live list after a fault has occurred. sl@0: sl@0: @param aPageInfo The page. sl@0: sl@0: @pre MmuLock held sl@0: @post MmuLock held (but may have been released by this function) sl@0: */ sl@0: void PagedIn(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: @param aPageInfo The page. sl@0: @param aPinArgs Owner of a replacement page which will be used to substitute for the pinned page. sl@0: sl@0: @pre MmuLock held sl@0: @post MmuLock held (but may have been released by this function) sl@0: */ sl@0: void PagedInPinned(SPageInfo* aPageInfo, TPinArgs& aPinArgs); sl@0: sl@0: /** sl@0: @pre MmuLock held sl@0: @post MmuLock left unchanged. sl@0: */ sl@0: void PagedInUnneeded(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: @param aPageInfo The page to unpin. sl@0: @param aPinArgs The resources used for pinning. The replacement pages allocated sl@0: to this will be increased for each page which was became completely sl@0: unpinned. sl@0: sl@0: @pre MmuLock held sl@0: @post MmuLock held (but may have been released by this function) sl@0: */ sl@0: void Unpin(SPageInfo* aPageInfo, TPinArgs& aPinArgs); sl@0: sl@0: /** sl@0: @param aPageInfo The page to pin. Must be page being demand paged. sl@0: @param aPinArgs Owner of a replacement page which will be used to substitute for the pinned page. sl@0: sl@0: @pre MmuLock held sl@0: @post MmuLock held (but may have been released by this function) sl@0: */ sl@0: void Pin(SPageInfo* aPageInfo, TPinArgs& aPinArgs); sl@0: sl@0: sl@0: /** sl@0: @pre MmuLock held sl@0: @post MmuLock held (but may have been released by this function) sl@0: */ sl@0: void RejuvenatePageTable(TPte* aPt); sl@0: sl@0: /** sl@0: */ sl@0: TBool ReservePages(TUint aRequiredCount, TUint& aCount); sl@0: sl@0: /** sl@0: */ sl@0: void UnreservePages(TUint& aCount); sl@0: sl@0: /** sl@0: Enumeration of instrumented paging events which only require the sl@0: SPageInfo object as an argument. sl@0: */ sl@0: enum TEventSimple sl@0: { sl@0: EEventPageInNew, sl@0: EEventPageInAgain, sl@0: EEventPageInUnneeded, sl@0: EEventPageInFree, sl@0: EEventPageOut, sl@0: EEventPageAged, sl@0: EEventPagePin, sl@0: EEventPageUnpin, sl@0: EEventPageDonate, sl@0: EEventPageReclaim, sl@0: EEventPageAgedClean, sl@0: EEventPageAgedDirty, sl@0: EEventPagePageTableAlloc sl@0: }; sl@0: sl@0: /** sl@0: Signal the occurrence of an event of type TEventSimple. sl@0: */ sl@0: void Event(TEventSimple aEvent, SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: Enumeration of instrumented paging events which require the faulting address sl@0: and program counter as arguments. sl@0: */ sl@0: enum TEventWithAddresses sl@0: { sl@0: EEventPageInStart, sl@0: EEventPageRejuvenate sl@0: }; sl@0: sl@0: /** sl@0: Signal the occurrence of an event of type TEventWithAddresses. sl@0: */ sl@0: void Event(TEventWithAddresses aEvent, SPageInfo* aPageInfo, TLinAddr aPc, TLinAddr aFaultAddress, TUint aAccessPermissions); sl@0: sl@0: /** sl@0: Get the pager's event info data. sl@0: */ sl@0: void GetEventInfo(SVMEventInfo& aInfoOut); sl@0: sl@0: /** sl@0: Reset the pager's event info data. sl@0: */ sl@0: void ResetEventInfo(); sl@0: sl@0: /** sl@0: Attempt to discard the specified page. sl@0: sl@0: @param aOldPageInfo The page info of the page to discard. sl@0: @param aBlockZoneId The ID of the RAM zone not to allocate any required new page into. sl@0: @param aBlockRest Set to ETrue when we don't want the allocator to search for new pages if the RAM sl@0: zone with ID==aBlockZoneId is encountered, i.e. a general RAM defrag operation. sl@0: */ sl@0: TInt DiscardPage(SPageInfo* aOldPageInfo, TUint aBlockZoneId, TBool aBlockRest); sl@0: sl@0: sl@0: /** sl@0: Update any live list links to replace the old page with the new page. sl@0: This is to be used when a page has been moved. sl@0: sl@0: @param aOldPageInfo The page info of the page to replace. sl@0: @param aNewPageInfo The page info of the page to be used instead of the old page. sl@0: */ sl@0: void ReplacePage(SPageInfo& aOldPageInfo, SPageInfo& aNewPageInfo); sl@0: sl@0: sl@0: // sl@0: // following public members for use by TPinArgs... sl@0: // sl@0: sl@0: /** sl@0: */ sl@0: TBool AllocPinReplacementPages(TUint aNumPages); sl@0: sl@0: /** sl@0: */ sl@0: void FreePinReplacementPages(TUint aNumPages); sl@0: sl@0: private: sl@0: /** sl@0: Add a page to the head of the live page list. I.e. make it the 'youngest' page. sl@0: sl@0: @pre MmuLock held sl@0: @post MmuLock left unchanged. sl@0: */ sl@0: void AddAsYoungestPage(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: Mark a page as type EUnused and add it to the end of the live page list. sl@0: I.e. make it the 'oldest' page, so that it is the first page to be reused. sl@0: sl@0: @pre MmuLock held sl@0: @post MmuLock left unchanged. sl@0: */ sl@0: void AddAsFreePage(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: Remove a page from live page list. sl@0: It paged state is set to EUnpaged. sl@0: sl@0: @pre MmuLock held sl@0: @post MmuLock left unchanged. sl@0: */ sl@0: void RemovePage(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: Remove the oldest page from the live page list and perform #StealPage. sl@0: sl@0: @pre MmuLock held sl@0: @post MmuLock left unchanged. sl@0: */ sl@0: SPageInfo* StealOldestPage(); sl@0: sl@0: /** sl@0: Steal a page from the memory object (if any) which is using the page. sl@0: If successful the returned page will be in the EUnknown state and the sl@0: cache state for the page is indeterminate. This is the same state as sl@0: if the page had been allocated by Mmu::AllocRam. sl@0: sl@0: @pre RamAlloc mutex held sl@0: @pre MmuLock held sl@0: @post MmuLock held (but may have been released by this function) sl@0: */ sl@0: TInt StealPage(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: Restrict the access permissions for a page. sl@0: sl@0: @param aPageInfo The page. sl@0: @param aRestriction The restriction type to apply. sl@0: */ sl@0: TInt RestrictPage(SPageInfo* aPageInfo, TRestrictPagesType aRestriction); sl@0: sl@0: /** sl@0: Get a RAM page from the system's free pool and add it to the live list as a free page. sl@0: sl@0: @return False if out of memory; sl@0: true otherwise, though new free page may still have already been used. sl@0: sl@0: @pre MmuLock held sl@0: @post MmuLock held (but may have been released by this function) sl@0: */ sl@0: TBool TryGrowLiveList(); sl@0: sl@0: /** sl@0: Get a RAM page from the system's free pool. sl@0: sl@0: @pre RamAllocLock held. sl@0: sl@0: @return The page or NULL if no page is available. sl@0: */ sl@0: SPageInfo* GetPageFromSystem(Mmu::TRamAllocFlags aAllocFlags, TUint aBlockZoneId=KRamZoneInvalidId, TBool aBlockRest=EFalse); sl@0: sl@0: /** sl@0: Put a page back on the system's free pool. sl@0: sl@0: @pre RamAllocLock held. sl@0: */ sl@0: void ReturnPageToSystem(); sl@0: sl@0: /** sl@0: Put a specific page back on the system's free pool. sl@0: sl@0: @pre RamAllocLock held. sl@0: */ sl@0: void ReturnPageToSystem(SPageInfo& aPageInfo); sl@0: sl@0: /** sl@0: Allocate a RAM page to store demand paged content. sl@0: This tries to obtain a RAM from the following places: sl@0: 1. An unused page in the live page list. sl@0: 2. The systems free pool. sl@0: 3. The oldest page from the live page list. sl@0: */ sl@0: SPageInfo* PageInAllocPage(Mmu::TRamAllocFlags aAllocFlags); sl@0: sl@0: /** sl@0: If the number of young pages exceeds that specified by iYoungOldRatio then a sl@0: single page is made 'old'. Call this after adding a new 'young' page. sl@0: sl@0: @pre MmuLock held sl@0: @post MmuLock held (but may have been released by this function) sl@0: */ sl@0: void BalanceAges(); sl@0: sl@0: /** sl@0: If HaveTooManyPages() then return them to the system. sl@0: */ sl@0: void RemoveExcessPages(); sl@0: sl@0: /** sl@0: @return True if pager has too many pages, false otherwise. sl@0: */ sl@0: TBool HaveTooManyPages(); sl@0: sl@0: /** sl@0: @return True if pager has its maximum number of pages, false otherwise. sl@0: */ sl@0: TBool HaveMaximumPages(); sl@0: sl@0: /** sl@0: Attempt to rejuvenate a page in which a page fault occurred. sl@0: sl@0: @param aOsAsid Address space ID in which fault occurred. sl@0: @param aAddress Address of memory access which faulted. sl@0: @param aAccessPermissions Bitmask of values from enum TAccessPermissions, which sl@0: indicates the permissions required by faulting memory access. sl@0: @param aPc Address of instruction causing the fault. (Used for tracing.) sl@0: @param aMapping The mapping that maps the page that took the fault. sl@0: @param aMapInstanceCount The instance count of the mappig when the page fault occurred. sl@0: @param aThread The thread that took the page fault. sl@0: @param aExceptionInfo The processor specific exception info. sl@0: sl@0: @return KErrNone if the page was remapped, KErrAbort if the mapping has be reused or detached, sl@0: KErrNotFound if it may be possible to page in the page. sl@0: */ sl@0: TInt TryRejuvenate( TInt aOsAsid, TLinAddr aAddress, TUint aAccessPermissions, TLinAddr aPc, sl@0: DMemoryMappingBase* aMapping, TUint aMapInstanceCount, DThread* aThread, sl@0: TAny* aExceptionInfo); sl@0: sl@0: /** sl@0: Reserve one page for guaranteed locking use. sl@0: Increments iReservePageCount if successful. sl@0: sl@0: @return True if operation was successful. sl@0: */ sl@0: TBool ReservePage(); sl@0: sl@0: /** sl@0: Called when a realtime thread takes a paging fault. sl@0: Checks whether it's OK for the thread to take to fault. sl@0: @return KErrNone if the paging fault should be further processed sl@0: */ sl@0: TInt CheckRealtimeThreadFault(DThread* aThread, TAny* aExceptionInfo); sl@0: sl@0: /** sl@0: Attempt to find the page table entry and page info for a page in the specified mapping. sl@0: sl@0: @param aOsAsid The OsAsid of the process that owns the mapping. sl@0: @param aAddress The linear address of the page. sl@0: @param aMapping The mapping that maps the linear address. sl@0: @param aMapInstanceCount The instance count of the mapping. sl@0: @param[out] aPte Will return a pointer to the page table entry for the page. sl@0: @param[out] aPageInfo Will return a pointer to the page info for the page. sl@0: sl@0: @return KErrNone on success, KErrAbort when the mapping is now invalid, KErrNotFound when sl@0: the page table or page info can't be found. sl@0: */ sl@0: TInt PteAndInfoFromLinAddr( TInt aOsAsid, TLinAddr aAddress, DMemoryMappingBase* aMapping, sl@0: TUint aMapInstanceCount, TPte*& aPte, SPageInfo*& aPageInfo); sl@0: #ifdef _DEBUG sl@0: /** sl@0: Check consistency of live list. sl@0: */ sl@0: TBool CheckLists(); sl@0: sl@0: void TraceCounts(); sl@0: #endif sl@0: sl@0: private: sl@0: TUint iMinYoungPages; ///< Minimum number of young pages in live list required for correct functioning. sl@0: TUint iAbsoluteMinPageCount;///< Absolute minimum number of pages in live to meet algorithm constraints sl@0: private: sl@0: TUint iMinimumPageCount; /**< Minimum size for the live page list, including locked pages */ sl@0: TUint iMaximumPageCount; /**< Maximum size for the live page list, including locked pages */ sl@0: TUint16 iYoungOldRatio; /**< Ratio of young to old pages in the live page list */ sl@0: SDblQue iYoungList; /**< Head of 'young' page list. */ sl@0: TUint iYoungCount; /**< Number of young pages */ sl@0: SDblQue iOldList; /**< Head of 'old' page list. */ sl@0: TUint iOldCount; /**< Number of old pages */ sl@0: #ifdef _USE_OLDEST_LISTS sl@0: SDblQue iOldestCleanList; /**< Head of 'oldestClean' page list. */ sl@0: TUint iOldestCleanCount; /**< Number of 'oldestClean' pages */ sl@0: SDblQue iOldestDirtyList; /**< Head of 'oldestDirty' page list. */ sl@0: TUint iOldestDirtyCount; /**< Number of 'oldestDirty' pages */ sl@0: TUint16 iOldOldestRatio; /**< Ratio of old pages to oldest to clean and dirty in the live page list*/ sl@0: #endif sl@0: TUint iNumberOfFreePages; sl@0: TUint iNumberOfDirtyPages; /**< The total number of dirty pages in the paging cache. Protected by MmuLock */ sl@0: TUint iInitMinimumPageCount;/**< Initial value for iMinimumPageCount */ sl@0: TUint iInitMaximumPageCount;/**< Initial value for iMaximumPageCount */ sl@0: TUint iReservePageCount; /**< Number of pages reserved for locking */ sl@0: TUint iMinimumPageLimit; /**< Minimum size for iMinimumPageCount, not including locked pages. sl@0: iMinimumPageCount >= iMinimumPageLimit + iReservePageCount */ sl@0: SVMEventInfo iEventInfo; sl@0: sl@0: #ifdef __DEMAND_PAGING_BENCHMARKS__ sl@0: public: sl@0: void RecordBenchmarkData(TPagingBenchmark aBm, TUint32 aStartTime, TUint32 aEndTime); sl@0: void ResetBenchmarkData(TPagingBenchmark aBm); sl@0: SPagingBenchmarkInfo iBenchmarkInfo[EMaxPagingBm]; sl@0: #endif //__DEMAND_PAGING_BENCHMARKS__ sl@0: }; sl@0: sl@0: extern DPager ThePager; sl@0: sl@0: sl@0: #ifdef __DEMAND_PAGING_BENCHMARKS__ sl@0: sl@0: #define START_PAGING_BENCHMARK TUint32 _bmStart = NKern::FastCounter() sl@0: #define END_PAGING_BENCHMARK(bm) ThePager.RecordBenchmarkData(bm, _bmStart, NKern::FastCounter()) sl@0: sl@0: #else sl@0: sl@0: #define START_PAGING_BENCHMARK sl@0: #define END_PAGING_BENCHMARK(bm) sl@0: #endif // __DEMAND_PAGING_BENCHMARKS__ sl@0: sl@0: sl@0: FORCE_INLINE void DPager::Event(TEventSimple aEvent, SPageInfo* aPageInfo) sl@0: { sl@0: switch(aEvent) sl@0: { sl@0: case EEventPageInNew: sl@0: TRACEP(("DP: %O PageIn 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext12(BTrace::EPaging,BTrace::EPagingPageIn,aPageInfo->PhysAddr(),aPageInfo->Owner(),aPageInfo->Index()); sl@0: #endif sl@0: ++iEventInfo.iPageInReadCount; sl@0: break; sl@0: sl@0: case EEventPageInAgain: sl@0: TRACEP(("DP: %O PageIn (again) 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext4(BTrace::EPaging,BTrace::EPagingMapPage,aPageInfo->PhysAddr()); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPageInUnneeded: sl@0: TRACEP(("DP: %O PageIn (unneeded) 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext0(BTrace::EPaging,BTrace::EPagingPageInUnneeded); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPageInFree: sl@0: TRACEP(("DP: %O PageInFree 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext4(BTrace::EPaging,BTrace::EPagingPageInFree,aPageInfo->PhysAddr()); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPageOut: sl@0: TRACEP(("DP: %O PageOut 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext4(BTrace::EPaging,BTrace::EPagingPageOut,aPageInfo->PhysAddr()); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPageAged: sl@0: TRACEP(("DP: %O Aged 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING_VERBOSE sl@0: BTraceContext4(BTrace::EPaging,BTrace::EPagingAged,aPageInfo->PhysAddr()); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPagePin: sl@0: TRACEP(("DP: %O Pin 0x%08x count=%d",TheCurrentThread,aPageInfo->PhysAddr(),aPageInfo->PinCount())); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext8(BTrace::EPaging,BTrace::EPagingPageLock,aPageInfo->PhysAddr(),aPageInfo->PinCount()); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPageUnpin: sl@0: TRACEP(("DP: %O Unpin 0x%08x count=%d",TheCurrentThread,aPageInfo->PhysAddr(),aPageInfo->PinCount())); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext8(BTrace::EPaging,BTrace::EPagingPageUnlock,aPageInfo->PhysAddr(),aPageInfo->PinCount()); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPageDonate: sl@0: TRACEP(("DP: %O Donate 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext12(BTrace::EPaging,BTrace::EPagingDonatePage,aPageInfo->PhysAddr(),aPageInfo->Owner(),aPageInfo->Index()); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPageReclaim: sl@0: TRACEP(("DP: %O Reclaim 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext4(BTrace::EPaging,BTrace::EPagingReclaimPage,aPageInfo->PhysAddr()); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPageAgedClean: sl@0: TRACEP(("DP: %O AgedClean 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING_VERBOSE sl@0: BTraceContext4(BTrace::EPaging,BTrace::EPagingAgedClean,aPageInfo->PhysAddr()); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPageAgedDirty: sl@0: TRACEP(("DP: %O AgedDirty 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING_VERBOSE sl@0: BTraceContext4(BTrace::EPaging,BTrace::EPagingAgedDirty,aPageInfo->PhysAddr()); sl@0: #endif sl@0: break; sl@0: sl@0: case EEventPagePageTableAlloc: sl@0: TRACEP(("DP: %O PageTableAlloc 0x%08x",TheCurrentThread,aPageInfo->PhysAddr())); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext4(BTrace::EPaging,BTrace::EPagingPageTableAlloc,aPageInfo->PhysAddr()); sl@0: #endif sl@0: break; sl@0: sl@0: default: sl@0: __NK_ASSERT_DEBUG(0); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: FORCE_INLINE void DPager::Event(TEventWithAddresses aEvent, SPageInfo* aPageInfo, TLinAddr aPc, TLinAddr aFaultAddress, TUint aAccessPermissions) sl@0: { sl@0: switch(aEvent) sl@0: { sl@0: case EEventPageInStart: sl@0: TRACEP(("DP: %O HandlePageFault 0x%08x 0x%08x %d",TheCurrentThread,aFaultAddress,aPc,aAccessPermissions)); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext12(BTrace::EPaging,BTrace::EPagingPageInBegin,aFaultAddress,aPc,aAccessPermissions); sl@0: #endif sl@0: ++iEventInfo.iPageFaultCount; sl@0: break; sl@0: sl@0: case EEventPageRejuvenate: sl@0: TRACEP(("DP: %O Rejuvenate 0x%08x 0x%08x 0x%08x %d",TheCurrentThread,aPageInfo->PhysAddr(),aFaultAddress,aPc,aAccessPermissions)); sl@0: #ifdef BTRACE_PAGING sl@0: BTraceContext12(BTrace::EPaging,BTrace::EPagingRejuvenate,aPageInfo->PhysAddr(),aFaultAddress,aPc); sl@0: #endif sl@0: ++iEventInfo.iPageFaultCount; sl@0: break; sl@0: sl@0: default: sl@0: __NK_ASSERT_DEBUG(0); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: /** sl@0: Multiplier for number of request objects in pool per drive that supports paging. sl@0: */ sl@0: const TInt KPagingRequestsPerDevice = 2; sl@0: sl@0: sl@0: class DPagingRequest; sl@0: class DPageReadRequest; sl@0: class DPageWriteRequest; sl@0: sl@0: /** sl@0: A pool of paging requests for use by a single paging device. sl@0: */ sl@0: class DPagingRequestPool : public DBase sl@0: { sl@0: public: sl@0: DPagingRequestPool(TUint aNumPageReadRequest,TUint aNumPageWriteRequest); sl@0: DPageReadRequest* AcquirePageReadRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount); sl@0: DPageWriteRequest* AcquirePageWriteRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount); sl@0: private: sl@0: ~DPagingRequestPool(); sl@0: private: sl@0: class TGroup sl@0: { sl@0: public: sl@0: TGroup(TUint aNumRequests); sl@0: DPagingRequest* FindCollision(DMemoryObject* aMemory, TUint aIndex, TUint aCount); sl@0: DPagingRequest* GetRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount); sl@0: void Signal(DPagingRequest* aRequest); sl@0: public: sl@0: TUint iNumRequests; sl@0: DPagingRequest** iRequests; sl@0: SDblQue iFreeList; sl@0: }; sl@0: TGroup iPageReadRequests; sl@0: TGroup iPageWriteRequests; sl@0: sl@0: friend class DPagingRequest; sl@0: friend class DPageReadRequest; sl@0: friend class DPageWriteRequest; sl@0: }; sl@0: sl@0: sl@0: /** sl@0: Resources needed to service a paging request. sl@0: */ sl@0: class DPagingRequest : public SDblQueLink sl@0: { sl@0: public: sl@0: DPagingRequest(DPagingRequestPool::TGroup& aPoolGroup); sl@0: void Release(); sl@0: void Wait(); sl@0: void Signal(); sl@0: void SetUse(DMemoryObject* aMemory, TUint aIndex, TUint aCount); sl@0: TBool CheckUse(DMemoryObject* aMemory, TUint aIndex, TUint aCount); sl@0: TBool IsCollision(DMemoryObject* aMemory, TUint aIndex, TUint aCount); sl@0: TLinAddr MapPages(TUint aColour, TUint aCount, TPhysAddr* aPages); sl@0: void UnmapPages(TBool aIMBRequired); sl@0: public: sl@0: TThreadMessage iMessage; /**< Used by the media driver to queue requests */ sl@0: DMutex* iMutex; /**< A mutex for synchronisation and priority inheritance. */ sl@0: TInt iUsageCount;/**< How many threads are using or waiting for this object. */ sl@0: TLinAddr iBuffer; /**< A buffer to read compressed data into. Size is EMaxPages+1 pages.*/ sl@0: protected: sl@0: Mmu::TTempMapping iTempMapping; sl@0: private: sl@0: DPagingRequestPool::TGroup& iPoolGroup; sl@0: // used to identify memory request is used for... sl@0: DMemoryObject* iUseRegionMemory; sl@0: TUint iUseRegionIndex; sl@0: TUint iUseRegionCount; sl@0: }; sl@0: sl@0: sl@0: /** sl@0: Resources needed to service a page in request. sl@0: */ sl@0: class DPageReadRequest : public DPagingRequest sl@0: { sl@0: public: sl@0: inline DPageReadRequest(DPagingRequestPool::TGroup& aPoolGroup) sl@0: : DPagingRequest(aPoolGroup) sl@0: {} sl@0: TInt Construct(); sl@0: enum sl@0: { sl@0: EMaxPages = 4 sl@0: }; sl@0: static TUint ReservedPagesRequired(); sl@0: private: sl@0: ~DPageReadRequest(); // can't delete sl@0: public: sl@0: TLinAddr iBuffer; /**< A buffer to read compressed data into. Size is EMaxPages+1 pages.*/ sl@0: private: sl@0: DMemoryObject* iMemory; sl@0: private: sl@0: static TInt iAllocNext; sl@0: }; sl@0: sl@0: sl@0: FORCE_INLINE TUint DPageReadRequest::ReservedPagesRequired() sl@0: { sl@0: return iAllocNext*EMaxPages; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Resources needed to service a page out request. sl@0: */ sl@0: class DPageWriteRequest : public DPagingRequest sl@0: { sl@0: public: sl@0: inline DPageWriteRequest(DPagingRequestPool::TGroup& aPoolGroup) sl@0: : DPagingRequest(aPoolGroup) sl@0: {} sl@0: TInt Construct(); sl@0: enum sl@0: { sl@0: EMaxPages = 1 sl@0: }; sl@0: private: sl@0: ~DPageWriteRequest(); // can't delete sl@0: private: sl@0: static TInt iAllocNext; sl@0: }; sl@0: sl@0: sl@0: #endif