diff -r 000000000000 -r a41df078684a kernel/eka/memmodel/epoc/flexible/mmu/mpagearray.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpagearray.h Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,864 @@ +// 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: +// + +#ifndef MPAGEARRAY_H +#define MPAGEARRAY_H + +#include "mmu.h" + +const TUint KPageArraySegmentShift = 4; + +/** +Number of entries in each segment RPageArray::TSegment. +*/ +const TUint KPageArraySegmentSize = (1<=EMoving; + } + + /** + Return true if the array entry \a aPage is not present. + */ + static FORCE_INLINE TBool IsPresent(TPhysAddr aPage) + { + return State(aPage)!=ENotPresent; + } + + /** + Return the TState value in the array entry \a aPage. + */ + static FORCE_INLINE TState State(TPhysAddr aPage) + { + return (TState)(aPage&EStateMask); + } + + /** + Page moving has ended so set the page back to committed if no other + operation has occurred/is occurring. + + @param aEntry A reference to the entry to update. + */ + static FORCE_INLINE void MovePageEnd(TPhysAddr& aEntry) + { + if (State(aEntry) == EMoving) + aEntry = (aEntry & ~EStateMask) | ECommitted; + } + + /** + Update the physical address in the array entry \a aEntry. + @param aEntry A reference to the entry to update. + @param aPhysAddr The new physical address. + */ + static FORCE_INLINE void PageMoveNewAddr(TPhysAddr& aEntry, TPhysAddr aPhysAddr) + { + __NK_ASSERT_DEBUG(!(aPhysAddr & EStateMask)); + __NK_ASSERT_DEBUG(State(aEntry) == EMoving); + aEntry = (aEntry & EStateMask) | aPhysAddr; + } + + static void Init2A(); + static void Init2B(DMutex* aLock); + + RPageArray(); + ~RPageArray(); + + /** + Second stage constructor for the array. + + @param aMaxPages The maximum number of entries to be stored in the array. + @param aPreallocateMemory If true, then all the memory required to store the array + entries is allocated immediately - rather than on demand + as entries are added. + */ + TInt Construct(TUint aMaxPages, TBool aPreallocateMemory=EFalse); + + /** + Allocate all memory required to store array entries. + This is only for use during system boot. + */ + TInt PreallocateMemory(); + + /** + Ensures the memory to store a region of array entries is allocated and locked. + + @param aIndex Start index of region. + @param aCount Number of pages in region. + + @see RPageArray::Free() + */ + TInt Alloc(TUint aIndex, TUint aCount); + + /** + Revert the action of #Alloc by unlocking the memory used for a region of array entries. + Note, calling #Free for any entry more times than #Alloc was used will have + unpredictable results. + + @param aIndex Start index of region. + @param aCount Number of pages in region. + */ + void Free(TUint aIndex, TUint aCount); + + /** + Prepare to add (commit) pages to a region in this array. + This ensures the memory to store the entries is allocated and locked. It also, + optionally and by default, check that these entries are empty. + + @param aIndex Start index of region. + @param aCount Number of pages in region. + @param[out] aIter An iterator which covers the specified region. + @param aAllowExisting True if the region may contain non-empty entries. + False to assert entries are empty. + + @see RPageArray::AddEnd() + */ + TInt AddStart(TUint aIndex, TUint aCount, TIter& aIter, TBool aAllowExisting=EFalse); + + /** + End an 'add' operation started with #AddStart. + This must be called to unlock any page array memory which #AddStart locked. + + @param aIndex Start index of region. Must be same value as corresponding call to #AddStart. + @param aCount Number of pages in region. Must be same value as corresponding call to #AddStart. + */ + void AddEnd(TUint aIndex, TUint aCount); + + /** + Prepare to search a region in this array. + + @param aIndex Start index of region. + @param aCount Number of pages in region. + @param[out] aIter An iterator which covers the specified region. + + @see RPageArray::AddEnd() + */ + void FindStart(TUint aIndex, TUint aCount, TIter& aIter); + + /** + End a find operation started with #FindStart. + + @param aIndex Start index of region. Must be same value as corresponding call to #FindStart. + @param aCount Number of pages in region. Must be same value as corresponding call to #FindStart. + */ + void FindEnd(TUint aIndex, TUint aCount); + + /** + Prepare to add (commit) a single page to this array. + This ensures the memory to store the entry is allocated and locked. + + @param aIndex Index of entry. + @param[out] aPageList An iterator represents the single array entry. + + @return Pointer to the array entry, + or the null pointer if memory allocation failed. + + @see RPageArray::AddPage() + @see RPageArray::AddPageEnd() + */ + TPhysAddr* AddPageStart(TUint aIndex, TIter& aPageList); + + /** + Add (commit) a single page to the array. + + @param aPageEntry The address of the array entry as returned by AddPageStart. + @param aPage The physical address of the page being added. + */ + static void AddPage(TPhysAddr* aPageEntry, TPhysAddr aPage); + + /** + End an 'add' operation started with #AddPageStart. + This must be called to unlock any page array memory which #AddPageStart locked. + + @param aIndex Index of entry. Must be same value as corresponding call to #AddPageStart. + @param aDelta 1 (one), if the array entry was changed from ENotPresent state (e.g. AddPage called), + zero otherwise. + */ + void AddPageEnd(TUint aIndex, TInt aDelta); + + /** + Prepare to remove (decommit) a single page from this array. + + This function is similar to TIter::RemoveFind and updates the array entry and + memory locking in the same way. + + @param aIndex Index of entry. + @param[out] aPageList An iterator representing the single array entry. + Not set if this method returns the null pointer. + + @return Pointer to the array entry, + or the null pointer if entry does not need decommitting. + + @see RPageArray::RemovePage() + @see RPageArray::RemovePageEnd() + */ + TPhysAddr* RemovePageStart(TUint aIndex, TIter& aPageList); + + /** + Remove a single page from the array. + + This function is similar to TIter::Remove and updates the array entry in the same way. + + @param aPageEntry The address of the array entry as returned by RemovePageStart. + + @return The physical address of the page which was removed, + or KPhysAddrInvalid if no page was removed. + */ + static TPhysAddr RemovePage(TPhysAddr* aPageEntry); + + /** + End an 'remove' operation started with #RemovePageStart. + This must be called to unlock any page array memory which #RemovePageStart locked. + + @param aIndex Index of entry. Must be same value as corresponding call to #RemovePageStart. + @param aDelta 1 (one), if the array entry was set ENotPresent state (RemovePage succeeded), + zero otherwise. + */ + void RemovePageEnd(TUint aIndex, TInt aDelta); + + /** + Prepare to restrict access to a single page in this array. + + If the page entry state indicates that the page is already more restricted + than being requested, then the function returns the null pointer and does nothing. + + If the page does need its access restricting then its entry in the array is set to + ERestrictingNA and the memory for the entry is locked. + + @param aIndex Index of entry. + @param[out] aPageList An iterator representing the single array entry. + Not set if this method returns the null pointer. + + @return Pointer to the array entry, + or the null pointer if entry does not need it's access restricting further. + + @see RPageArray::RestrictPageNAEnd() + */ + TPhysAddr* RestrictPageNAStart(TUint aIndex, TIter& aPageList); + + /** + End an 'restrict' operation started with #RestrictPageStart. + This must be called to unlock any page array memory which #RestrictPageStart locked. + + @param aIndex Index of entry. Must be same value as corresponding call to #RestrictPageStart. + */ + void RestrictPageNAEnd(TUint aIndex); + + /** + Prepare to steal a single page from this array. + + The memory for the entry is locked and if the page entry is is in one of the committed + states then it is changed to state EStealing. + + @param aIndex Index of entry. + @param[out] aPageList An iterator representing the single array entry. + Not set if this method returns the null pointer. + + @return Pointer to the array entry. + + @see RPageArray::StealPageEnd() + */ + TPhysAddr* StealPageStart(TUint aIndex, TIter& aPageList); + + /** + End an 'steal' operation started with #StealPageStart. + This must be called to unlock any page array memory which #StealPageStart locked. + + @param aIndex Index of entry. Must be same value as corresponding call to #StealPageStart. + @param aDelta 1 (one), if the array entry was set ENotPresent state (the page was stolen), + zero otherwise. + */ + void StealPageEnd(TUint aIndex, TInt aDelta); + + /** + Prepare to move a page in this array by changing its state to EMoving. + + Note - the memory entry isn't locked as the RamAllocLock mutex must be held + through out the page moving process and therefore the page cannot be removed. + + @param aIndex The index of the entry to be moved. + @param[out] aPageList An iterator representing the single array entry. + Not set if this method returns the null pointer. + + @return Pointer to the array entry, NULL if the page cannot be moved. + + @see RPageArray::MovePageEnd() + */ + TPhysAddr* MovePageStart(TUint aIndex, TIter& aPageList); + + /** + Return the array entry for index \a aIndex. + */ + TPhysAddr Page(TUint aIndex); + + + /** + Return a pointer to the array entry for index \a aIndex. + + @return Pointer to the array entry, NULL if the page cannot found. + */ + TPhysAddr* PageEntry(TUint aIndex); + + /** + Return the physical address of the page at index \a aIndex, or KPhysAddrInvalid if none present. + */ + TPhysAddr PhysAddr(TUint aIndex); + + /** + Get the physical address for the pages stored in the specified region in the array. + + @param aIndex Start index of region. + @param aCount Number of pages in region. + @param[out] aPhysicalAddress If all pages are physically contiguous this is set to the start address, + otherwise this is set to KPhysAddrInvalid. + @param[out] aPhysicalPageList Pointer to array of \a aCount physical addresses which + will be filled with the physical addressed of each page in the region. + + @return 0 (zero) if all pages in region are physically contiguous; + 1 (one) if pages are not physically contiguous; + KErrNotFound, if any page in the region is not present. + */ + TInt PhysAddr(TUint aIndex, TUint aCount, TPhysAddr& aPhysicalAddress, TPhysAddr* aPhysicalPageList); + + enum + { + /** + Maximum number of bits which can be stored in an array entry by SetPagingManagerData. + */ + KPagingManagerDataBits = 32-(EFlagsShift+EStateShift), + }; + + enum + { + /** + Maximum value which can be stored in an array entry by SetPagingManagerData. + */ + KMaxPagingManagerData = (1u<=aIndex); + } + +FORCE_INLINE RPageArray::TIter RPageArray::TIter::Slice(TUint aIndex, TUint aEndIndex) + { + __NK_ASSERT_DEBUG(aEndIndex>=aIndex); + __NK_ASSERT_DEBUG(aIndex>=iIndex); + __NK_ASSERT_DEBUG(aEndIndex<=iEndIndex); + return TIter(iSegments,aIndex,aEndIndex); + } + +FORCE_INLINE RPageArray::TIter RPageArray::TIter::Left(TUint aCount) + { + __NK_ASSERT_DEBUG(aCount<=Count()); + return TIter(iSegments,iIndex,iIndex+aCount); + } + +FORCE_INLINE void RPageArray::TIter::Skip(TUint aCount) + { + __NK_ASSERT_DEBUG(iIndex+aCount>=iIndex); + __NK_ASSERT_DEBUG(iIndex+aCount<=iEndIndex); + iIndex += aCount; + } + + +// +// RPageArray +// + +FORCE_INLINE void RPageArray::FindEnd(TUint /*aIndex*/, TUint /*aCount*/) + { + // nothing to do + } + +FORCE_INLINE void RPageArray::AddPageEnd(TUint aIndex, TInt aDelta) + { + MmuLock::Lock(); + ReleasePage(aIndex,aDelta); + MmuLock::Unlock(); + } + +FORCE_INLINE void RPageArray::AddPage(TPhysAddr* aPageEntry, TPhysAddr aPage) + { + __NK_ASSERT_DEBUG(MmuLock::IsHeld()); + __NK_ASSERT_DEBUG((aPage&KPageMask)==0); + __NK_ASSERT_DEBUG(!RPageArray::IsPresent(*aPageEntry)); + *aPageEntry = aPage|RPageArray::ECommitted; + } + +FORCE_INLINE void RPageArray::RestrictPageNAEnd(TUint aIndex) + { + ReleasePage(aIndex,0); + } + +FORCE_INLINE void RPageArray::StealPageEnd(TUint aIndex, TInt aDelta) + { + ReleasePage(aIndex,-aDelta); + } + +FORCE_INLINE void RPageArray::RemovePageEnd(TUint aIndex, TInt aDelta) + { + MmuLock::Lock(); + ReleasePage(aIndex,-aDelta); + MmuLock::Unlock(); + } + +#endif