sl@0: // Copyright (c) 2007-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: #include sl@0: #include "mm.h" sl@0: #include "mmu.h" sl@0: sl@0: #include "mpagearray.h" sl@0: #include "mslaballoc.h" sl@0: sl@0: sl@0: static RStaticSlabAllocator PageSegmentAllocator; sl@0: sl@0: sl@0: // sl@0: // RPageArray::TSegment sl@0: // sl@0: sl@0: RPageArray::TSegment* RPageArray::TSegment::New() sl@0: { sl@0: __NK_ASSERT_DEBUG(!MmuLock::IsHeld()); sl@0: sl@0: // allocate segment... sl@0: TSegment* s = PageSegmentAllocator.Alloc(); sl@0: if(!s) sl@0: return s; sl@0: sl@0: // initialise segment... sl@0: s->iCounts = 1; // lock count = 1, alloc count = 0 sl@0: TPhysAddr* p = s->iPages; sl@0: TPhysAddr* pEnd = p+KPageArraySegmentSize; sl@0: TPhysAddr nullPage = EEmptyEntry; sl@0: do *p++ = nullPage; sl@0: while(piCounts==0); sl@0: #ifdef _DEBUG sl@0: TPhysAddr* p = aSegment->iPages; sl@0: TPhysAddr* pEnd = p+KPageArraySegmentSize; sl@0: do sl@0: { sl@0: TPhysAddr a = *p++; sl@0: if(IsPresent(a)) sl@0: { sl@0: Kern::Printf("TSegment Delete with allocated pages! [%d]=0x%08x",p-aSegment->iPages-1,a); sl@0: __NK_ASSERT_DEBUG(0); sl@0: } sl@0: } sl@0: while(piCounts, (TUint32)-(TInt)aCount); sl@0: __NK_ASSERT_DEBUG(oldCounts&KPageArraySegmentLockCountMask); // alloc count must have been non-zero before decrementing sl@0: sl@0: #ifdef _DEBUG sl@0: if((oldCounts&KPageArraySegmentLockCountMask)==aCount) sl@0: { sl@0: // check alloc count is consistent... sl@0: TUint allocCount = s->iCounts>>KPageArraySegmentAllocCountShift; sl@0: __NK_ASSERT_DEBUG(allocCount<=KPageArraySegmentSize); sl@0: TUint realAllocCount = 0; sl@0: TPhysAddr* p = s->iPages; sl@0: TPhysAddr* pEnd = p+KPageArraySegmentSize; sl@0: do sl@0: { sl@0: if(IsPresent(*p++)) sl@0: ++realAllocCount; sl@0: } sl@0: while(p1) sl@0: return oldCounts; // return 'true' to indicate segment still exists sl@0: sl@0: // delete segment... sl@0: aSegment = 0; sl@0: return (TBool)Delete(s); // returns 'false' sl@0: } sl@0: sl@0: sl@0: FORCE_INLINE void RPageArray::TSegment::AdjustAllocCount(TInt aDelta) sl@0: { sl@0: __NK_ASSERT_DEBUG((iCounts&KPageArraySegmentLockCountMask)); sl@0: __e32_atomic_add_ord32(&iCounts, TUint32(aDelta)<>KPageArraySegmentAllocCountShift; sl@0: TUint lockCount = iCounts&KPageArraySegmentLockCountMask; sl@0: Kern::Printf("RPageArray::TSegment[0x%08x]::Dump() allocCount=%d lockCount=%d",this,allocCount,lockCount); sl@0: for(TUint i=0; i>KPageArraySegmentShift]->iPages+offset; sl@0: sl@0: TUint n = KPageArraySegmentSize-offset; sl@0: if(n>aMaxCount) sl@0: n = aMaxCount; sl@0: if(n>size) sl@0: n = size; sl@0: return n; sl@0: } sl@0: sl@0: sl@0: TUint RPageArray::TIter::AddFind(TIter& aPageList) sl@0: { sl@0: TRACE2(("RPageArray::TIter::AddFind range 0x%x..0x%x",iIndex,iEndIndex)); sl@0: sl@0: TUint index = iIndex; sl@0: TUint endIndex = iEndIndex; sl@0: if(index==endIndex) sl@0: { sl@0: nothing_found: sl@0: aPageList.iIndex = endIndex; sl@0: aPageList.iEndIndex = endIndex; sl@0: TRACE2(("RPageArray::TIter::AddFind returns 0x%x+0x%x",iEndIndex,0)); sl@0: return 0; sl@0: } sl@0: sl@0: TSegment** pS = iSegments+(index>>KPageArraySegmentShift); sl@0: TPhysAddr* p; sl@0: TUint limit; sl@0: sl@0: MmuLock::Lock(); sl@0: sl@0: // scan for empty entries... sl@0: do sl@0: { sl@0: // get segment... sl@0: p = (*pS++)->iPages+(index&KPageArraySegmentMask); sl@0: TUint nextIndex = (index+KPageArraySegmentSize)&~KPageArraySegmentMask; sl@0: limit = (nextIndex=endIndex) sl@0: break; sl@0: MmuLock::Flash(); sl@0: // get next segment... sl@0: p = (*pS++)->iPages; sl@0: TUint nextIndex = index+KPageArraySegmentSize; sl@0: limit = (nextIndex>KPageArraySegmentShift); sl@0: do sl@0: { sl@0: // get segment... sl@0: TSegment* s = *pS++; sl@0: TPhysAddr* p = s->iPages+(index&KPageArraySegmentMask); sl@0: TUint nextIndex = (index+KPageArraySegmentSize)&~KPageArraySegmentMask; sl@0: TUint limit = (nextIndexAdjustAllocCount(limit-index); sl@0: do sl@0: { sl@0: __NK_ASSERT_DEBUG((*aPages&KPageMask)==0); sl@0: __NK_ASSERT_DEBUG(!IsPresent(*p)); // AddFind only found not-present entries sl@0: *p++ = *aPages++|ECommitted; sl@0: } sl@0: while(++index>KPageArraySegmentShift); sl@0: sl@0: do sl@0: { sl@0: // get segment... sl@0: TSegment* s = *pS++; sl@0: TPhysAddr* p = s->iPages+(index&KPageArraySegmentMask); sl@0: TUint nextIndex = (index+KPageArraySegmentSize)&~KPageArraySegmentMask; sl@0: TUint limit = (nextIndexAdjustAllocCount(limit-index); sl@0: do sl@0: { sl@0: __NK_ASSERT_DEBUG(!IsPresent(*p)); // AddFind only found not-present entries sl@0: *p++ = aPhysAddr|ECommitted; sl@0: aPhysAddr += KPageSize; sl@0: } sl@0: while(++index>KPageArraySegmentShift)==((index+aCount-1)>>KPageArraySegmentShift)); sl@0: TSegment* s = iSegments[index>>KPageArraySegmentShift]; sl@0: __NK_ASSERT_DEBUG(s); sl@0: __NK_ASSERT_DEBUG(s->iCounts&KPageArraySegmentLockCountMask); sl@0: s->AdjustAllocCount(aChanged); sl@0: Skip(aCount); sl@0: } sl@0: sl@0: sl@0: TUint RPageArray::TIter::Find(TIter& aPageList) sl@0: { sl@0: TRACE2(("RPageArray::TIter::Find range 0x%x..0x%x",iIndex,iEndIndex)); sl@0: sl@0: MmuLock::Lock(); sl@0: TUint index = iIndex; sl@0: TUint endIndex = iEndIndex; sl@0: TSegment** pS = iSegments+(index>>KPageArraySegmentShift); sl@0: TUint nextIndex = (index+KPageArraySegmentSize)&~KPageArraySegmentMask; sl@0: sl@0: // search for first page... sl@0: while(indexiPages+(index&KPageArraySegmentMask); sl@0: TUint limit = (nextIndexiPages+(index&KPageArraySegmentMask); sl@0: if(!RPageArray::IsPresent(*p++)) sl@0: break; sl@0: sl@0: // segment has pages, lock it... sl@0: s->Lock(); sl@0: sl@0: // scan rest of entries... sl@0: TUint nextIndex = (index+KPageArraySegmentSize)&~KPageArraySegmentMask; sl@0: TUint limit = (nextIndex>KPageArraySegmentShift); sl@0: TUint nextIndex = (index+KPageArraySegmentSize)&~KPageArraySegmentMask; sl@0: sl@0: // search for first page... sl@0: while(indexiPages+(index&KPageArraySegmentMask); sl@0: TUint limit = (nextIndex=EDecommitting) sl@0: goto start_done; sl@0: } sl@0: while(++indexiPages+(index&KPageArraySegmentMask); sl@0: TPhysAddr page = *p++; sl@0: if(State(page)Lock(); sl@0: sl@0: // scan rest of entries... sl@0: TUint nextIndex = (index+KPageArraySegmentSize)&~KPageArraySegmentMask; sl@0: TUint limit = (nextIndex>KPageArraySegmentShift); sl@0: sl@0: MmuLock::Lock(); sl@0: sl@0: do sl@0: { sl@0: // get segment... sl@0: TSegment* s = *pS++; sl@0: TPhysAddr* p = s->iPages+(index&KPageArraySegmentMask); sl@0: TUint nextIndex = (index+KPageArraySegmentSize)&~KPageArraySegmentMask; sl@0: TUint limit = (nextIndexAdjustAllocCount(-1); sl@0: TPhysAddr pagePhys = page&~KPageMask; sl@0: aPages[count++] = pagePhys; sl@0: TRACE2(("RPageArray::TIter::Remove index=0x%x returns 0x%08x",index,pagePhys)); sl@0: if(count>=aMaxCount) sl@0: { sl@0: ++index; sl@0: goto done; sl@0: } sl@0: } sl@0: // check not removing managed pages without the RamAllocLock... sl@0: __NK_ASSERT_DEBUG(RamAllocLock::IsHeld() sl@0: || SPageInfo::FromPhysAddr(page)->Type()!=SPageInfo::EManaged); sl@0: } sl@0: } sl@0: while(++index>KPageArraySegmentShift); sl@0: sl@0: MmuLock::Lock(); sl@0: sl@0: do sl@0: { sl@0: // get segment... sl@0: TSegment* s = *pS++; sl@0: TPhysAddr* p = s->iPages+(index&KPageArraySegmentMask); sl@0: TUint nextIndex = (index+KPageArraySegmentSize)&~KPageArraySegmentMask; sl@0: TUint limit = (nextIndex>KPageArraySegmentShift); sl@0: sl@0: MmuLock::Lock(); sl@0: sl@0: do sl@0: { sl@0: // get segment... sl@0: TSegment* s = *pS++; sl@0: TPhysAddr* p = s->iPages+(index&KPageArraySegmentMask); sl@0: TUint nextIndex = (index+KPageArraySegmentSize)&~KPageArraySegmentMask; sl@0: TUint limit = (nextIndex>KPageArraySegmentShift; sl@0: iSegments = (TSegment**)Kern::AllocZ(iNumSegments*sizeof(TSegment*)); sl@0: if(!iSegments) sl@0: return KErrNoMemory; sl@0: sl@0: if(!aPreallocateMemory) sl@0: return KErrNone; sl@0: sl@0: return PreallocateMemory(); sl@0: } sl@0: sl@0: sl@0: TInt RPageArray::PreallocateMemory() sl@0: { sl@0: MmuLock::Lock(); sl@0: sl@0: __NK_ASSERT_DEBUG(!iPreallocatedMemory); sl@0: iPreallocatedMemory = true; sl@0: sl@0: TSegment** pS = iSegments; sl@0: TSegment** pGEnd = pS+iNumSegments; sl@0: do sl@0: { sl@0: if(!GetOrAllocateSegment(pS,1)) sl@0: { sl@0: iNumSegments = pS-iSegments; // truncate to amount successfully allocated sl@0: MmuLock::Unlock(); sl@0: return KErrNoMemory; sl@0: } sl@0: } sl@0: while(++pSDump(); sl@0: #endif sl@0: __NK_ASSERT_DEBUG(!*pS); sl@0: ++pS; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: MmuLock::Lock(); sl@0: while(pSDump(); sl@0: #endif sl@0: __NK_ASSERT_DEBUG(!*pS); sl@0: TRACE2(("RPageArray::~RPageArray delete segment=%d",pS-iSegments)); sl@0: ++pS; sl@0: if(pSLock(aLockCount); sl@0: return s; sl@0: } sl@0: sl@0: // no segment, so allocate one... sl@0: MmuLock::Unlock(); sl@0: s = TSegment::New(); sl@0: MmuLock::Lock(); sl@0: if(!s) sl@0: return s; sl@0: sl@0: // if someone else allocated one... sl@0: if(*aSegmentEntry) sl@0: { sl@0: // free the one we created... sl@0: TSegment::Unlock(s); sl@0: //and retry... sl@0: continue; sl@0: } sl@0: sl@0: // use new segment... sl@0: TRACE2(("RPageArray::GetOrAllocateSegment new segment=%d",aSegmentEntry-iSegments)); sl@0: *aSegmentEntry = s; sl@0: if(--aLockCount) sl@0: s->Lock(aLockCount); sl@0: return s; sl@0: } sl@0: } sl@0: sl@0: sl@0: TInt RPageArray::Alloc(TUint aIndex, TUint aCount) sl@0: { sl@0: TRACE2(("RPageArray::Alloc(0x%x,0x%x)",aIndex,aCount)); sl@0: __NK_ASSERT_DEBUG(aIndex+aCount<=iNumSegments*KPageArraySegmentSize); sl@0: __NK_ASSERT_DEBUG(aIndex+aCount>=aIndex); sl@0: sl@0: MmuLock::Lock(); sl@0: sl@0: TUint index = aIndex; sl@0: TUint endIndex = aIndex+aCount; sl@0: TSegment** pS = iSegments+(index>>KPageArraySegmentShift); sl@0: while(indexaIndex); sl@0: sl@0: MmuLock::Lock(); sl@0: sl@0: TUint index = aIndex; sl@0: TUint endIndex = aIndex+aCount; sl@0: TSegment** pS = iSegments+(index>>KPageArraySegmentShift); sl@0: while(indexaIndex); sl@0: sl@0: aIter.Set(iSegments,aIndex,aIndex+aCount); sl@0: sl@0: MmuLock::Lock(); sl@0: sl@0: TInt r; sl@0: TUint index = aIndex; sl@0: TUint endIndex = aIndex+aCount; sl@0: TSegment** pS = iSegments+(index>>KPageArraySegmentShift); sl@0: while(indexiPages+(index&KPageArraySegmentMask); sl@0: TUint limit = (nextIndexLock(); sl@0: sl@0: if(indexaIndex) sl@0: Release(iSegments,aIndex,endIndex-aIndex); sl@0: sl@0: // return error... sl@0: return r; sl@0: } sl@0: sl@0: sl@0: void RPageArray::AddEnd(TUint aIndex, TUint aCount) sl@0: { sl@0: Release(iSegments,aIndex,aCount); sl@0: } sl@0: sl@0: sl@0: void RPageArray::FindStart(TUint aIndex, TUint aCount, TIter& aIter) sl@0: { sl@0: TRACE2(("RPageArray::FindStart(0x%x,0x%x,?)",aIndex,aCount)); sl@0: __NK_ASSERT_DEBUG(aIndex+aCount<=iNumSegments*KPageArraySegmentSize); sl@0: __NK_ASSERT_DEBUG(aIndex+aCount>aIndex); sl@0: sl@0: aIter.Set(iSegments,aIndex,aIndex+aCount); sl@0: } sl@0: sl@0: sl@0: void RPageArray::Release(TSegment** aSegments, TUint aIndex, TUint aCount) sl@0: { sl@0: __NK_ASSERT_DEBUG(aIndex+aCount>aIndex); sl@0: sl@0: MmuLock::Lock(); sl@0: sl@0: TSegment** pS = aSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment** pGLast = aSegments+((aIndex+aCount-1)>>KPageArraySegmentShift); sl@0: __NK_ASSERT_DEBUG(pS<=pGLast); sl@0: TUint flash = 0; sl@0: do sl@0: { sl@0: MmuLock::Flash(flash,KMaxPagesInOneGo); sl@0: if(TSegment::Unlock(*pS)==0) sl@0: { sl@0: TRACE2(("RPageArray::Release delete segment=%d",pS-aSegments)); sl@0: } sl@0: ++pS; sl@0: } sl@0: while(pS<=pGLast); sl@0: sl@0: MmuLock::Unlock(); sl@0: } sl@0: sl@0: sl@0: TPhysAddr* RPageArray::AddPageStart(TUint aIndex, TIter& aPageList) sl@0: { sl@0: __NK_ASSERT_DEBUG(aIndex<=iNumSegments*KPageArraySegmentSize); sl@0: sl@0: MmuLock::Lock(); sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = GetOrAllocateSegment(pS,1); sl@0: MmuLock::Unlock(); sl@0: sl@0: if(!s) sl@0: return 0; sl@0: sl@0: aPageList.Set(iSegments,aIndex,aIndex+1); sl@0: sl@0: return s->iPages+(aIndex&KPageArraySegmentMask); sl@0: } sl@0: sl@0: sl@0: TPhysAddr* RPageArray::RemovePageStart(TUint aIndex, TIter& aPageList) sl@0: { sl@0: __NK_ASSERT_DEBUG(aIndex<=iNumSegments*KPageArraySegmentSize); sl@0: sl@0: MmuLock::Lock(); sl@0: sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = *pS; sl@0: if(!s) sl@0: { sl@0: MmuLock::Unlock(); sl@0: return 0; sl@0: } sl@0: sl@0: TPhysAddr* p = s->iPages+(aIndex&KPageArraySegmentMask); sl@0: TPhysAddr page = *p; sl@0: if(State(page)Lock(); sl@0: sl@0: MmuLock::Unlock(); sl@0: sl@0: aPageList.Set(iSegments,aIndex,aIndex+1); sl@0: sl@0: return p; sl@0: } sl@0: sl@0: sl@0: TPhysAddr RPageArray::RemovePage(TPhysAddr* aPageEntry) sl@0: { sl@0: __NK_ASSERT_DEBUG(MmuLock::IsHeld()); sl@0: TPhysAddr page = *aPageEntry; sl@0: __NK_ASSERT_DEBUG(State(page)!=EStealing); // can't be stealing as that only happens with the RamAllocLock held, which we should already hold if freeing demand paged pages sl@0: if(State(page)==EDecommitting || State(page)==EDecommitted) sl@0: { sl@0: // remove a page... sl@0: if(page&EUnmapVetoed) sl@0: { sl@0: *aPageEntry = (page&~(EUnmapVetoed|EStateMask))|EDecommitted; // change to EDecommitted state sl@0: } sl@0: else sl@0: { sl@0: *aPageEntry = EEmptyEntry; sl@0: return page&~KPageMask; sl@0: } sl@0: // check not removing managed pages without the RamAllocLock... sl@0: __NK_ASSERT_DEBUG(RamAllocLock::IsHeld() sl@0: || SPageInfo::FromPhysAddr(page)->Type()!=SPageInfo::EManaged); sl@0: } sl@0: return KPhysAddrInvalid; sl@0: } sl@0: sl@0: sl@0: TPhysAddr* RPageArray::RestrictPageNAStart(TUint aIndex, TIter& aPageList) sl@0: { sl@0: __NK_ASSERT_DEBUG(MmuLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(aIndex<=iNumSegments*KPageArraySegmentSize); sl@0: sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = *pS; sl@0: if(!s) sl@0: return 0; sl@0: sl@0: TPhysAddr* p = s->iPages+(aIndex&KPageArraySegmentMask); sl@0: TPhysAddr page = *p; sl@0: if(State(page) < RPageArray::ERestrictingNA) sl@0: return 0; sl@0: sl@0: *p = (page&~EStateMask) | RPageArray::ERestrictingNA; sl@0: sl@0: s->Lock(); sl@0: sl@0: aPageList.Set(iSegments,aIndex,aIndex+1); sl@0: sl@0: return p; sl@0: } sl@0: sl@0: sl@0: TPhysAddr* RPageArray::StealPageStart(TUint aIndex, TIter& aPageList) sl@0: { sl@0: __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(MmuLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(aIndex<=iNumSegments*KPageArraySegmentSize); sl@0: sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = *pS; sl@0: __NK_ASSERT_DEBUG(s); // we only steal pages in the live list and these can not go away yet because we hold the RamAllocLock sl@0: sl@0: TPhysAddr* p = s->iPages+(aIndex&KPageArraySegmentMask); sl@0: TPhysAddr page = *p; sl@0: sl@0: if(State(page)>EStealing) sl@0: *p = (page&~EStateMask)|EStealing; sl@0: sl@0: s->Lock(); sl@0: sl@0: aPageList.Set(iSegments,aIndex,aIndex+1); sl@0: sl@0: return p; sl@0: } sl@0: sl@0: sl@0: TPhysAddr* RPageArray::MovePageStart(TUint aIndex, TIter& aPageList) sl@0: { sl@0: __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(MmuLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(aIndex <= iNumSegments*KPageArraySegmentSize); sl@0: sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = *pS; sl@0: // The segment should always exist for a page that is being moved. sl@0: __NK_ASSERT_DEBUG(s); sl@0: sl@0: TPhysAddr* p = s->iPages+(aIndex&KPageArraySegmentMask); sl@0: TPhysAddr page = *p; sl@0: if(State(page) <= RPageArray::EMoving) sl@0: return NULL; sl@0: sl@0: *p = (page & ~EStateMask) | EMoving; sl@0: sl@0: aPageList.Set(iSegments, aIndex, aIndex+1); sl@0: sl@0: return p; sl@0: } sl@0: sl@0: sl@0: void RPageArray::ReleasePage(TUint aIndex, TInt aDelta) sl@0: { sl@0: __NK_ASSERT_DEBUG(MmuLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(aIndex<=iNumSegments*KPageArraySegmentSize); sl@0: sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = *pS; sl@0: __NK_ASSERT_DEBUG(s); // must exist because FindPageStart/AddPageStart locked it sl@0: sl@0: __NK_ASSERT_DEBUG(aDelta>=-1 && aDelta<=1); sl@0: if(aDelta) sl@0: s->AdjustAllocCount(aDelta); sl@0: sl@0: if(TSegment::Unlock(*pS)==0) sl@0: { sl@0: TRACE2(("RPageArray::ReleasePage delete segment=%d",pS-iSegments)); sl@0: } sl@0: } sl@0: sl@0: sl@0: TPhysAddr RPageArray::Page(TUint aIndex) sl@0: { sl@0: __NK_ASSERT_DEBUG(MmuLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(aIndex<=iNumSegments*KPageArraySegmentSize); sl@0: sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = *pS; sl@0: if(!s) sl@0: return ENotPresent; sl@0: return s->iPages[aIndex&KPageArraySegmentMask]; sl@0: } sl@0: sl@0: sl@0: TPhysAddr* RPageArray::PageEntry(TUint aIndex) sl@0: { sl@0: __NK_ASSERT_DEBUG(MmuLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(aIndex<=iNumSegments*KPageArraySegmentSize); sl@0: sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = *pS; sl@0: if(!s) sl@0: return NULL; sl@0: return s->iPages + (aIndex & KPageArraySegmentMask); sl@0: } sl@0: sl@0: sl@0: TUint RPageArray::PagingManagerData(TUint aIndex) sl@0: { sl@0: __NK_ASSERT_DEBUG(MmuLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(aIndex<=iNumSegments*KPageArraySegmentSize); sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = *pS; sl@0: __NK_ASSERT_DEBUG(s); sl@0: TPhysAddr* p = &s->iPages[aIndex&KPageArraySegmentMask]; sl@0: sl@0: TPhysAddr entry = *p; sl@0: if(IsPresent(entry)) sl@0: { sl@0: #ifdef _DEBUG sl@0: SPageInfo* pi = SPageInfo::SafeFromPhysAddr(entry&~KPageMask); sl@0: if(!pi) sl@0: Kern::Printf("RPageArray::PagingManagerData bad entry 0x%08x",entry); sl@0: __NK_ASSERT_DEBUG(pi); sl@0: #else sl@0: SPageInfo* pi = SPageInfo::FromPhysAddr(entry); sl@0: #endif sl@0: entry = pi->PagingManagerData(); sl@0: } sl@0: __NK_ASSERT_DEBUG((entry&(EFlagsMask|EStateMask))==ENotPresent); sl@0: sl@0: return entry>>(EFlagsShift+EStateShift); sl@0: } sl@0: sl@0: sl@0: void RPageArray::SetPagingManagerData(TUint aIndex, TUint aValue) sl@0: { sl@0: aValue = (aValue<<(EFlagsShift+EStateShift))|ENotPresent; sl@0: sl@0: __NK_ASSERT_DEBUG(MmuLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(aIndex<=iNumSegments*KPageArraySegmentSize); sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = *pS; sl@0: __NK_ASSERT_DEBUG(s); sl@0: TPhysAddr* p = &s->iPages[aIndex&KPageArraySegmentMask]; sl@0: sl@0: TPhysAddr entry = *p; sl@0: if(!IsPresent(entry)) sl@0: *p = aValue; sl@0: else sl@0: { sl@0: #ifdef _DEBUG sl@0: SPageInfo* pi = SPageInfo::SafeFromPhysAddr(entry&~KPageMask); sl@0: if(!pi) sl@0: Kern::Printf("RPageArray::SetPagingManagerData bad entry 0x%08x",entry); sl@0: __NK_ASSERT_DEBUG(pi); sl@0: #else sl@0: SPageInfo* pi = SPageInfo::FromPhysAddr(entry); sl@0: #endif sl@0: pi->SetPagingManagerData(aValue); sl@0: } sl@0: } sl@0: sl@0: sl@0: TPhysAddr RPageArray::PhysAddr(TUint aIndex) sl@0: { sl@0: __NK_ASSERT_DEBUG(MmuLock::IsHeld()); sl@0: __NK_ASSERT_DEBUG(aIndex<=iNumSegments*KPageArraySegmentSize); sl@0: sl@0: TSegment** pS = iSegments+(aIndex>>KPageArraySegmentShift); sl@0: TSegment* s = *pS; sl@0: if(s) sl@0: { sl@0: TPhysAddr page = s->iPages[aIndex&KPageArraySegmentMask]; sl@0: if(IsPresent(page)) sl@0: { sl@0: return page&~KPageMask; sl@0: } sl@0: } sl@0: return KPhysAddrInvalid; sl@0: } sl@0: sl@0: sl@0: TInt RPageArray::PhysAddr(TUint aIndex, TUint aCount, TPhysAddr& aPhysicalAddress, TPhysAddr* aPhysicalPageList) sl@0: { sl@0: __NK_ASSERT_DEBUG(aCount); sl@0: MmuLock::Lock(); sl@0: sl@0: TUint32* pageList = aPhysicalPageList; sl@0: sl@0: // get first page... sl@0: TPhysAddr physStart = PhysAddr(aIndex++); sl@0: if(physStart==KPhysAddrInvalid) sl@0: { sl@0: MmuLock::Unlock(); sl@0: return KErrNotFound; sl@0: } sl@0: if(pageList) sl@0: *pageList++ = physStart; sl@0: sl@0: TUint32 nextPhys = physStart+KPageSize; sl@0: sl@0: TUint flash = 0; sl@0: while(--aCount) sl@0: { sl@0: MmuLock::Flash(flash,KMaxPagesInOneGo); sl@0: sl@0: // get next page... sl@0: TPhysAddr phys = PhysAddr(aIndex++); sl@0: if(phys==KPhysAddrInvalid) sl@0: { sl@0: MmuLock::Unlock(); sl@0: return KErrNotFound; sl@0: } sl@0: if(pageList) sl@0: *pageList++ = phys; sl@0: sl@0: // check for contiguity... sl@0: if(phys!=nextPhys) sl@0: nextPhys = KPhysAddrInvalid; sl@0: else sl@0: nextPhys += KPageSize; sl@0: } sl@0: sl@0: MmuLock::Unlock(); sl@0: sl@0: if(nextPhys==KPhysAddrInvalid) sl@0: { sl@0: // memory is discontiguous... sl@0: if(!aPhysicalPageList) sl@0: return KErrNotFound; sl@0: aPhysicalAddress = KPhysAddrInvalid; sl@0: return 1; sl@0: } sl@0: else sl@0: { sl@0: // memory is contiguous... sl@0: aPhysicalAddress = physStart; sl@0: return KErrNone; sl@0: } sl@0: } sl@0: sl@0: