diff -r 000000000000 -r 96e5fb8b040d kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.h Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,397 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +/** + @file + @internalComponent +*/ + +#ifndef MPTALLOC_H +#define MPTALLOC_H + +#include "mcleanup.h" + +/** +Number of #SPageTableInfo structures which will fit into a page of RAM. +*/ +const TUint KPageTableInfosPerPage = KPageSize/sizeof(SPageTableInfo); + +/** +Number of pages of page tables which correspond to a page of page infos. +*/ +const TUint KPageTableGroupSize = KPageTableInfosPerPage/KPtClusterSize; + +/** +Max number of RAM pages which can be used for page tables. +*/ +const TUint KMaxPageTablePages = (KPageTableEnd-KPageTableBase)/KPageSize; + + +/** +The maximum number of pages required to pin a single page table. +*/ +const TUint KNumPagesToPinOnePageTable = 2; // 1 page table page + 1 page table info page + + +/** +Class for allocating MMU page tables. +*/ +class PageTableAllocator + { +public: + void Init2(DMutex* aLock); + void Init2B(); + + /** + Allocate a page table. + + @param aDemandPaged True if the page table will be used to map demand paged memory; + false, otherwise. + + @return Virtual address of the allocated page table, + or the null-pointer if there was insufficient memory. + + @pre #PageTablesLockIsHeld, i.e. current thread has called #Lock() + */ + TPte* Alloc(TBool aDemandPaged); + + /** + Free a page table previously aquired with #Alloc. + + @param aPageTable Virtual address of the page table, + + @pre #PageTablesLockIsHeld, i.e. current thread has called #Lock() + */ + void Free(TPte* aPageTable); + + /** + Acquire the mutex used to protect page table allocation. + */ + void Lock(); + + /** + Release the mutex used to protect page table allocation. + */ + void Unlock(); + + /** + Return true if the current thread has acquired the mutex used to protect page table allocation. + I.e. has called #Lock(). + */ + TBool LockIsHeld(); + + /** + Steal a RAM page which is currently being used to store demand paged page tables + or page table infos. + + This removes the page tables contained in the RAM from any objects which own + them and then returns the RAM to the demand paging system as a free page. This + will not ever return KErrNone indicating that the page has been successfully + stolen. + + This is only intended for use by DPageTableMemoryManager::StealPage. + + @param aPageInfo The page information structure of the page to be stolen. + + @return KErrCompletion to indicate that the page was stolen but has been + returned to the demand paging live list as a free page. + Otherwise, KErrInUse if the page was not able to be freed. + + @pre #PageTablesLockIsHeld, i.e. current thread has called #Lock() + @pre MmuLock held. + */ + TInt StealPage(SPageInfo* aPageInfo); + + /** + Discards a page of page tables or page table infos but only if it is demand paged. + + This will only be invoked on page table info pages or pinned paged tables + as they aren't on the live list and so M::MovePage() will not know the pager + can discard them. + + @param aMemory This should always be the page table info memory object. + @param aOldPageInfo The page info of the page to discard. + @param aBlockZoneId The ID of any RAM zone not to be allocated into. + @param aBlockRest ETrue when any allocations should stop if blocked zone hit. + + @return KErrNone if the page could be successfully discarded and its RAM page freed. + */ + TInt MovePage( DMemoryObject* aMemory, SPageInfo* aOldPageInfo, + TUint aBlockZoneId, TBool aBlockRest); + +#ifdef _DEBUG + /** + Debug function for use by DPager::RemovePage() to allow it to remove + pages with paged state == EUnpaged. + + A page table page may be stolen when it is unpaged as it has been + allocated via DMemoryMapping::AllocatePageTable() but not yet rejuvenated + by Mmu::PageInPages() as the MmuLock is released between these stages. + + A page table info page is never added to the live list so it will always + be unpaged but it can be stolen so allow it to be removed. + + @param aPageInfo The page info of the page. + + @return ETrue if the page is a page table info page, EFalse otherwise. + */ + TBool IsPageTableUnpagedRemoveAllowed(SPageInfo* aPageInfo); +#endif + + /** + Pin the RAM page containing a page table, as well as the RAM page + containing its #SPageTableInfo structure. + + @param aPageTable Virtual address of the page table, + @param aPinArgs The resources to use for pinning. This must have + at least #KNumPagesToPinOnePageTable replacement + pages available. + */ + static void PinPageTable(TPte* aPageTable, TPinArgs& aPinArgs); + + /** + Unpin the RAM page containing a page table, as well as the RAM page + containing its #SPageTableInfo structure. + This reverses the action of #PinPageTable. + + @param aPageTable Virtual address of the page table, + @param aPinArgs The resources to use for pinning. The replacement + pages count in this will be incremented for each + completely unpinned, e.g. those which can be reused + as new replacement pages or freed. + */ + static void UnpinPageTable(TPte* aPageTable, TPinArgs& aPinArgs); + +private: + /** + Sub-allocator used for managing page tables of a given 'pagedness' (paged/not-paged). + Each allocator maintains a list free page tables (#iFreeList) from which it can allocate. + As well as a separate list of RAM pages which have no allocated page tables, #iCleanupList. + Page tables in the RAM on #iCleanupList do not appear in #iFreeList. + */ + class TSubAllocator + { + public: + void Init2(PageTableAllocator* iAllocator, TUint aReserveCount, TBool aDemandPaged); + + /** + Allocate a page table from this sub-allocator. + + @return The #SPageTableInfo structure of the page table, + or the null-pointer if none could be allocated. + */ + SPageTableInfo* Alloc(); + + /** + Free a page table back to this sub-allocator. + + @param aPageTableInfo The #SPageTableInfo structure of the page table. + */ + void Free(SPageTableInfo* aPageTableInfo); + + /** + Add a single page of page tables to this allocator for management. + + @param aPageTableInfo The #SPageTableInfo structure of the first page table + contained in the page. + */ + void AllocPage(SPageTableInfo* aPageTableInfo); + + /** + Attempt to remove a single unused page of page tables from this allocator. + + @return The #SPageTableInfo structure of the first page table contained + in the removed page. Or the null-pointer if there were no unused + memory to be freed. + */ + SPageTableInfo* FreePage(); + + /** + Move a page of RAM containing page tables to #iCleanupList. + All page tables in the page must be currently unused. + + @param aPageTableInfo The #SPageTableInfo structure of the first page table + contained in the page. + */ + void MoveToCleanup(SPageTableInfo* aPageTableInfo); + + /** + Return true if there are whole RAM pages which can be freed from this + sub-allocator without reducing #iFreeCount below #iReserveCount. + */ + TBool IsCleanupRequired(); + + /** + Debug check returning true if this objects lists are in a valid state. + */ + TBool CheckFreeList(); + public: + SDblQue iFreeList; ///< List of unused page tables, linked by their SPageTableInfo::FreeLink. + SDblQue iCleanupList; ///< List of unused pages, linked by the SPageTableInfo::FreeLink of the first page table in the page. + TUint iFreeCount; ///< Total free page tables in pages on #iFreeList and #iCleanupList. + TUint iReserveCount; ///< Minimum number of page tables to keep in reserve. + TBool iDemandPaged; ///< True if this allocator id used for demand paged page tables. + }; + + /** + Implementation of #Alloc. + */ + TPte* DoAlloc(TBool aDemandPaged); + + /** + Implementation of #Free. + */ + void DoFree(TPte* aPageTable); + + /** + Allocate resources for a pages worth of page tables owned by \a aSubAllocator. + + @return True if the resources were successfully allocated. + + @pre #PageTablesLockIsHeld, i.e. current thread has called #Lock() + */ + TBool AllocReserve(TSubAllocator& aSubAllocator); + + /** + Free the resources taken up by a pages worth of unused page tables + owned by \a aSubAllocator. + + @return True, if any resources were freed. + False, if there are no more unused resources. + + @pre #PageTablesLockIsHeld, i.e. current thread has called #Lock() + */ + TBool FreeReserve(TSubAllocator& aSubAllocator); + + /** + Steal a RAM page which is currently being used to store demand paged page + table infos. + + This removes all the page tables references by the page table infos contained in + the RAM from any objects which own them and then returns the RAM to the demand + paging system as a free page. This will not ever return KErrNone indicating that + the page has been successfully stolen. + + This is only intended for use by PageTableAllocator::StealPage. + + @param aPageInfo The page information structure of the page to be stolen. + + @return KErrCompletion to indicate that the page was stolen but has been + returned to the demand paging live list as a free page. + Otherwise, KErrInUse if the page was not able to be freed. + + @pre #PageTablesLockIsHeld, i.e. current thread has called #Lock() + @pre MmuLock held. + */ + TInt StealPageTableInfo(SPageInfo* aPageInfo); + + /** + Free all unused resources taken up for page table management. + */ + void Cleanup(); + + /** + Trampoline function for use with iCleanup which redirects to #Cleanup(). + */ + static void CleanupTrampoline(TAny* aSelf); + +private: + /** + Sub-allocator for allocating unpaged page tables. + */ + TSubAllocator iUnpagedAllocator; + + /** + Sub-allocator for allocating demand paged page tables. + */ + TSubAllocator iPagedAllocator; + + /** + Object used for queueing cleanup callbacks to #CleanupTrampoline. + */ + TMemoryCleanup iCleanup; + + /** + Recursion count for #Alloc. + */ + TUint iAllocating; + + /** + The mutex used to protect page table allocation. + */ + DMutex* iLock; + + /** + The memory object used to store the memory containing page tables. + */ + DMemoryObject* iPageTableMemory; + + /** + The memory object used to store #SPageTableInfo structures. + */ + DMemoryObject* iPageTableInfoMemory; + + /** + Helper class for allocating page index values within #iPageTableMemory. + This wraps up to two bitmap allocators, one each used for paged and unpaged + page tables. + + Page indexes are allocated in a way which ensures that there will not be + any SPageTableInfo structures for unpaged page tables in the same RAM page + as the structures for paged page tables. + */ + class TPtPageAllocator + { + public: + void Init2(TUint aNumInitPages); + TInt Alloc(TBool aDemandPaged); + void Free(TUint aPageIndex, TBool aDemandPaged); + TBool IsDemandPaged(SPageInfo* aPageInfo) + {// Is the highest page table index this page table info page can reference + // allocated within the demand paged region of the page table address space. + TUint groupIndex = aPageInfo->Index(); + return ((groupIndex+1) * KPageTableGroupSize)-1 >= iUpperWaterMark; + } + private: + TBitMapAllocator* iLowerAllocator; ///< Allocator for unpaged page tables + TUint iLowerWaterMark; ///< Highest page index allocated by iLowerAllocator + TBitMapAllocator* iUpperAllocator; ///< Allocator for demand paged page tables + TUint iUpperWaterMark; ///< Lowest page index allocated by iUpperAllocator + }; + + /** + Allocator for page indexes within #iPageTableMemory. + */ + TPtPageAllocator iPtPageAllocator; + + /** + Array which contains usage for pages of #SPageTableInfo structures. + When the count is zero, there are no structure in use in the corresponding + page of memory in #iPageTableInfoMemory. Indicating that the memory may be + freed. + */ + TUint16 iPageTableGroupCounts[KMaxPageTablePages/KPageTableGroupSize]; + + friend class TSubAllocator; + }; + + +/** +The single instance of the #PageTableAllocator. +*/ +extern PageTableAllocator PageTables; + + +#endif