Convert Kernelhwsrv package from SFL to EPL
kernel\eka\compsupp is subject to the ARM EABI LICENSE
userlibandfileserver\fatfilenameconversionplugins\unicodeTables is subject to the Unicode license
kernel\eka\kernel\zlib is subject to the zlib license
// 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