--- /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