kernel/eka/memmodel/epoc/flexible/mmu/mmappinglist.cpp
changeset 0 a41df078684a
child 22 2f92ad2dc5db
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmappinglist.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,209 @@
+// 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:
+//
+
+#include <plat_priv.h>
+#include "mm.h"
+#include "mmu.h"
+
+#include "mmappinglist.h"
+#include "mmapping.h"
+
+
+TSpinLock TMappingListBase::iSpinLock(TSpinLock::EOrderGenericIrqHigh3);
+
+
+//
+// TMappingList
+//
+
+void TMappingList::Add(DMemoryMappingBase* aMapping)
+	{
+	__NK_ASSERT_DEBUG(LockIsHeld());
+	aMapping->iLink.InsertBefore(this);
+	}
+
+
+void TMappingList::Remove(DMemoryMappingBase* aMapping)
+	{
+	__NK_ASSERT_DEBUG(LockIsHeld());
+	aMapping->iLink.Remove();
+	}
+
+
+// Utility methods
+
+void TMappingList::RemapPage(TPhysAddr& aPageArray, TUint aIndex, TBool aInvalidateTLB)
+	{
+	Lock();
+	TMappingListIter iter;
+	DMemoryMappingBase* mapping = iter.Start(*this);
+	while(mapping)
+		{		
+		TUint start = aIndex-mapping->iStartIndex;
+		if(start < mapping->iSizeInPages && !mapping->IsPinned())
+			{
+			// remap the page in the mapping...
+			mapping->Open();
+			TUint mapInstanceCount = mapping->MapInstanceCount();
+			Unlock();
+			mapping->RemapPage(aPageArray, aIndex, mapInstanceCount, aInvalidateTLB);
+			mapping->AsyncClose();
+			}
+		else
+			{
+			// the mapping doesn't contain the page or is a pinned mapping and therefore doesn't own
+			// any page tables...
+			Unlock();
+			}
+		Lock();
+		mapping = iter.Next();
+		}
+	iter.Finish();
+	Unlock();
+	}
+
+
+//
+// TMappingListIter
+//
+
+DMemoryMappingBase* TMappingListIter::Start(TMappingList& aList)
+	{
+	TRACE2(("TMappingListIter::Start"));
+	__NK_ASSERT_DEBUG(LockIsHeld());
+	return Next(&aList);
+	}
+
+
+void TMappingListIter::Finish()
+	{
+	TRACE2(("TMappingListIter::Finish"));
+	__NK_ASSERT_DEBUG(LockIsHeld());
+	Remove();
+	}
+
+
+DMemoryMappingBase* TMappingListIter::Next(TMappingListBase* aPrev)
+	{
+	// avoid live-lock by only flashing iSpinLock after a number of attempts greater
+	// than the number of CPU cores, that way each core is guaranteed to make some headway...
+	const TUint KFlashPeriod = KMaxCpus+1;
+	__ASSERT_COMPILE(KFlashPeriod<10); // make sure limit is sensible, if not, will need more complex live-lock avoidance
+	TUint flash = 0;
+
+	TMappingListBase* prev = aPrev;
+	TMappingListBase* next = prev->iNext;
+	for(;;)
+		{
+		TUint type = next->iType;
+
+		// at end of list?
+		if(type==EHead)
+			{
+			// yes, so put iterator back at end...
+			prev->iNext = this;
+			next->iPrev = this;
+			iNext = next;
+			iPrev = prev;
+			// return NULL...
+			TRACE2(("TMappingListIter::Next returns 0"));
+			return 0;
+			}
+
+		// move past next...
+		prev = next;
+		next = next->iNext;
+
+		// have we found a mapping?
+		if(type==ELink)
+			{
+			// yes, so insert iterator after it...
+			prev->iNext = this;
+			next->iPrev = this;
+			iNext = next;
+			iPrev = prev;
+			// return mapping...
+			DMemoryMappingBase* mapping = (DMemoryMappingBase*)((TLinAddr)prev-_FOFF(DMemoryMappingBase,iLink));
+			TRACE2(("TMappingListIter::Next returns 0x%08x",mapping));
+			return mapping;
+			}
+
+		// move on to next...
+		TRACE2(("TMappingListIter::Next skip %d",next->iType));
+
+		// but first see if we need to flash lock...
+		if(++flash>=KFlashPeriod)
+			{
+			// we need to flash the lock, but first put iterator back in list so we don't loose our place...
+			prev->iNext = this;
+			next->iPrev = this;
+			iNext = next;
+			iPrev = prev;
+			// flash lock...
+			__SPIN_FLASH_IRQ(iSpinLock);
+			// remove iterator again...
+			next = iNext;
+			prev = iPrev;
+			prev->iNext = next;
+			next->iPrev = prev;
+			}
+
+		// loop back and try next
+		}
+	}
+
+
+DMemoryMappingBase* TMappingListIter::Next()
+	{
+	__NK_ASSERT_DEBUG(LockIsHeld());
+
+	TMappingListBase* next = iNext;
+	TMappingListBase* prev = iPrev;
+	TUint type = next->iType;
+
+	// at end of list?
+	if(type==EHead)
+		{
+		// yes, return NULL...
+		TRACE2(("TMappingListIter::Next returns 0"));
+		return 0;
+		}
+
+	// unlink iterator...
+	prev->iNext = next;
+	next->iPrev = prev;
+
+	// have we found a mapping?
+	if(type==ELink)
+		{
+		// yes, so insert iterator after it...
+		prev = next;
+		next = next->iNext;
+		prev->iNext = this;
+		next->iPrev = this;
+		iNext = next;
+		iPrev = prev;
+		// return mapping...
+		DMemoryMappingBase* mapping = (DMemoryMappingBase*)((TLinAddr)prev-_FOFF(DMemoryMappingBase,iLink));
+		TRACE2(("TMappingListIter::Next returns 0x%08x",mapping));
+		return mapping;
+		}
+
+	// handle more complicated situations...
+	return Next(next);
+	}
+
+
+