kernel/eka/memmodel/epoc/flexible/mmu/mm.cpp
changeset 0 a41df078684a
child 62 4a8fed1c0ef6
child 90 947f0dc9f7a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mm.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1136 @@
+// 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 "memmodel.h"
+#include "mm.h"
+#include "mmu.h"
+#include "mobject.h"
+#include "mmapping.h"
+#include "mmanager.h"
+#include "mpdalloc.h"
+#include "mptalloc.h"
+#include "mpager.h"
+#include "maddressspace.h"
+
+
+
+
+//
+// DMutexPool
+//
+
+DMutexPool::~DMutexPool()
+	{
+	TUint i;
+	for(i=0; i<iCount; ++i)
+		{
+		DMutex* mutex = iMembers[i].iMutex;
+		if(mutex)
+			mutex->Close(0);
+		}
+	Kern::Free(iMembers);
+	}
+
+
+TInt DMutexPool::Create(TUint aCount, const TDesC* aName, TUint aOrder)
+	{
+	if(aCount>EMaxPoolSize)
+		return KErrTooBig;
+
+	iMembers = (SMember*)Kern::AllocZ(aCount*sizeof(SMember));
+	if(!iMembers)
+		return KErrNoMemory;
+
+	iCount = aCount;
+
+	TInt r = KErrNone;
+	TUint i;
+	for(i=0; i<aCount; ++i)
+		{
+		TKName name;
+		if(aName)
+			{
+			name = *aName;
+			name.AppendNum(i);
+			}
+		K::MutexCreate(iMembers[i].iMutex, name, NULL, EFalse, aOrder);
+		if(r!=KErrNone)
+			break;
+		}
+
+	return r;
+	}
+
+
+/**
+@class DMutexPool
+@details
+
+The cookie used for dynamically assigned mutexes is broken into three bit fields:
+- Bit 0, always set. (To distinguish the cookie from a proper DMutex*).
+- Bits 1 through #KMutexPoolIndexBits, these contain the index of the assigned
+  mutex within DMutexPool::iMembers.
+- Bits (#KMutexPoolIndexBits+1) through 31, the count of the number of threads waiting
+  for this particular mutex assignment. When this reaches zero, the mutex can
+  be unassigned.
+*/
+
+/**
+Number of bits used to contain the index value of a dynamically assigned pool mutex.
+*/
+const TUint KMutexPoolIndexBits = 7;
+
+const TUint KMutexPoolIndexMask = ((1<<KMutexPoolIndexBits)-1)<<1;
+const TUint KMutexPoolWaitCountIncrement = 1<<(KMutexPoolIndexBits+1);
+
+__ASSERT_COMPILE(DMutexPool::EMaxPoolSize<=TUint(KMutexPoolIndexMask/2+1)); // required for algorithm correctness
+
+__ASSERT_COMPILE(DMutexPool::EMaxPoolSize<=64); // required to avoid excessive system lock hold time
+
+
+void DMutexPool::Wait(DMutex*& aMutexRef)
+	{
+	NKern::LockSystem();
+
+	TUintPtr poolMutex = (TUintPtr)aMutexRef;
+	if(!poolMutex)
+		{
+		// try and find a free mutex, else use the next one...
+		TUint next = iNext;
+		do
+			{
+			if(iMembers[next].iUseCount==0)
+				break;
+			if(++next>=iCount)
+				next = 0;
+			}
+		while(next!=iNext);
+		// use found mutex...
+		++iMembers[next].iUseCount;
+		poolMutex = (next*2)+1; // mutex index*2 | 1
+		// update next...
+		if(++next>=iCount)
+			next = 0;
+		iNext = next;
+		}
+
+	DMutex* mutex = (DMutex*)poolMutex;
+	if(poolMutex&1)
+		{
+		// mutex is a pool mutex, get pointer, and update wait count...
+		SMember* member = &iMembers[(poolMutex&KMutexPoolIndexMask)>>1];
+		mutex = member->iMutex;
+		poolMutex += KMutexPoolWaitCountIncrement;
+		__NK_ASSERT_ALWAYS(poolMutex>=KMutexPoolWaitCountIncrement);
+		aMutexRef = (DMutex*)poolMutex;
+		}
+
+	mutex->Wait();
+
+	NKern::UnlockSystem();
+	}
+
+
+void DMutexPool::Signal(DMutex*& aMutexRef)
+	{
+	NKern::LockSystem();
+
+	TUintPtr poolMutex = (TUintPtr)aMutexRef;
+	__NK_ASSERT_ALWAYS(poolMutex);
+
+	DMutex* mutex = (DMutex*)poolMutex;
+
+	if(poolMutex&1)
+		{
+		// mutex is a pool mutex, get pointer, and update wait count...
+		SMember* member = &iMembers[(poolMutex&KMutexPoolIndexMask)>>1];
+		mutex = member->iMutex;
+		__NK_ASSERT_ALWAYS(poolMutex>=KMutexPoolWaitCountIncrement);
+		poolMutex -= KMutexPoolWaitCountIncrement;
+		if(poolMutex<KMutexPoolWaitCountIncrement)
+			{
+			--member->iUseCount;
+			poolMutex = 0;
+			}
+		aMutexRef = (DMutex*)poolMutex;
+		}
+
+	mutex->Signal();
+	}
+
+
+TBool DMutexPool::IsHeld(DMutex*& aMutexRef)
+	{
+	TBool held = false;
+	NKern::LockSystem();
+	TUintPtr poolMutex = (TUintPtr)aMutexRef;
+	if(poolMutex)
+		{
+		DMutex* mutex = (DMutex*)poolMutex;
+		if(poolMutex&1)
+			{
+			SMember* member = &iMembers[(poolMutex&KMutexPoolIndexMask)>>1];
+			mutex = member->iMutex;
+			}
+		held = mutex->iCleanup.iThread==&Kern::CurrentThread();
+		}
+	NKern::UnlockSystem();
+	return held;
+	}
+
+
+
+//
+// DReferenceCountedObject
+//
+
+DReferenceCountedObject::~DReferenceCountedObject()
+	{
+	__NK_ASSERT_DEBUG(iReferenceCount==0);
+	}
+
+
+void DReferenceCountedObject::Open()
+	{
+	__ASSERT_CRITICAL
+	TBool ok = __e32_atomic_tas_ord32(&iReferenceCount, 1, 1, 0);
+	__NK_ASSERT_ALWAYS(ok);
+	}
+
+
+TBool DReferenceCountedObject::TryOpen()
+	{
+	__ASSERT_CRITICAL
+	TBool ok = __e32_atomic_tas_ord32(&iReferenceCount, 1, 1, 0);
+	return ok;
+	}
+
+
+TBool DReferenceCountedObject::CheckCloseIsSafe()
+	{
+	__ASSERT_CRITICAL
+#ifdef _DEBUG
+	NFastMutex* fm = NKern::HeldFastMutex();
+	if(fm)
+		{
+		Kern::Printf("DReferenceCountedObject[0x%08x]::Close() fast mutex violation %M",this,fm);
+		return false;
+		}
+	SDblQue& ml = TheCurrentThread->iMutexList;
+	if(!ml.IsEmpty())
+		{
+		DMutex* m = _LOFF(ml.First(), DMutex, iOrderLink);
+		if(m->iOrder<KMutexOrdKernelHeap)
+			{
+			Kern::Printf("DReferenceCountedObject[0x%08x]::Close() mutex order violation holding mutex %O",this,m);
+			return false;
+			}
+		}
+#endif
+	return true;
+	}
+
+
+TBool DReferenceCountedObject::CheckAsyncCloseIsSafe()
+	{
+	__ASSERT_CRITICAL
+#ifdef _DEBUG
+	NFastMutex* fm = NKern::HeldFastMutex();
+	if(fm)
+		{
+		Kern::Printf("DReferenceCountedObject[0x%08x]::AsyncClose() fast mutex violation %M",this,fm);
+		return false;
+		}
+#endif
+	return true;
+	}
+
+
+void DReferenceCountedObject::Close()
+	{
+	__ASSERT_CRITICAL
+	__NK_ASSERT_DEBUG(CheckCloseIsSafe());
+	__NK_ASSERT_DEBUG(iReferenceCount>0);
+	if (__e32_atomic_tas_ord32(&iReferenceCount, 1, -1, 0) == 1)
+		delete this;
+	}
+
+
+void DReferenceCountedObject::AsyncClose()
+	{
+	__ASSERT_CRITICAL
+	__NK_ASSERT_DEBUG(CheckAsyncCloseIsSafe());
+	__NK_ASSERT_DEBUG(iReferenceCount>0);
+	if (__e32_atomic_tas_ord32(&iReferenceCount, 1, -1, 0) == 1)
+		AsyncDelete();
+	}
+
+
+//
+// Memory object functions
+//
+
+TInt MM::MemoryNew(DMemoryObject*& aMemory, TMemoryObjectType aType, TUint aPageCount, TMemoryCreateFlags aCreateFlags, TMemoryAttributes aAttributes)
+	{
+	TRACE(("MM::MemoryNew(?,0x%08x,0x%08x,0x%08x,0x%08x)",aType,aPageCount,aCreateFlags,*(TUint32*)&aAttributes));
+
+	DMemoryManager* manager;
+	if(aCreateFlags&EMemoryCreateCustomManager)
+		manager = (DMemoryManager*)aType;
+	else
+		{
+		switch(aType)
+			{
+		case EMemoryObjectUnpaged:
+			manager = TheUnpagedMemoryManager;
+			break;
+		case EMemoryObjectMovable:
+			manager = TheMovableMemoryManager;
+			break;
+		case EMemoryObjectPaged:
+			manager = TheDataPagedMemoryManager;
+			break;
+		case EMemoryObjectDiscardable:
+			manager = TheDiscardableMemoryManager;
+			break;
+		case EMemoryObjectHardware:
+			manager = TheHardwareMemoryManager;
+			break;
+		default:
+			manager = 0;
+			__NK_ASSERT_DEBUG(0);
+			break;
+			}
+		}
+	TMemoryCreateFlags flags = (TMemoryCreateFlags)(aCreateFlags&~(EMemoryCreateDemandPaged));
+	TInt r = manager->New(aMemory,aPageCount,aAttributes,flags);
+	TRACE(("MM::MemoryNew returns %d, aMemory=0x%08x",r,aMemory));
+#ifdef BTRACE_FLEXIBLE_MEM_MODEL
+	if (r == KErrNone)
+		aMemory->BTraceCreate();
+#endif
+	return r;
+	}
+
+
+TInt MM::MemoryClaimInitialPages(DMemoryObject* aMemory, TLinAddr aBase, TUint aSize, TMappingPermissions aPermissions, TBool aAllowGaps, TBool aAllowNonRamPages)
+	{
+	TRACE(("MM::MemoryClaimInitialPages(0x%08x,0x%08x,0x%08x,0x%08x,%d,%d)",aMemory,aBase,aPermissions,aSize,aAllowGaps!=0,aAllowNonRamPages!=0));
+	TInt r = aMemory->ClaimInitialPages(aBase,aSize,aPermissions,aAllowGaps,aAllowNonRamPages);
+	TRACE(("MM::MemoryClaimInitialPages returns %d",r));
+	__NK_ASSERT_DEBUG(r==KErrNone);
+	return r;
+	}
+
+
+void MM::MemorySetLock(DMemoryObject* aMemory, DMutex* aLock)
+	{
+	aMemory->SetLock(aLock);
+	}
+
+
+void MM::MemoryLock(DMemoryObject* aMemory)
+	{
+	MemoryObjectLock::Lock(aMemory);
+	}
+
+
+void MM::MemoryUnlock(DMemoryObject* aMemory)
+	{
+	MemoryObjectLock::Unlock(aMemory);
+	}
+
+
+void MM::MemoryDestroy(DMemoryObject*& aMemory)
+	{
+	DMemoryObject* memory = (DMemoryObject*)__e32_atomic_swp_ord_ptr(&aMemory, 0);
+	if (!memory)
+		return;
+	TRACE(("MM::MemoryDestroy(0x%08x)",memory));
+#ifdef BTRACE_FLEXIBLE_MEM_MODEL
+	BTraceContext4(BTrace::EFlexibleMemModel,BTrace::EMemoryObjectDestroy,memory);
+#endif
+	memory->iManager->Destruct(memory);
+	}
+
+
+TInt MM::MemoryAlloc(DMemoryObject* aMemory, TUint aIndex, TUint aCount)
+	{
+	TRACE(("MM::MemoryAlloc(0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount));
+	MemoryObjectLock::Lock(aMemory);
+	TInt r;
+	if(!aMemory->CheckRegion(aIndex,aCount))
+		r = KErrArgument;
+	else
+		r = aMemory->iManager->Alloc(aMemory,aIndex,aCount);
+	MemoryObjectLock::Unlock(aMemory);
+	TRACE(("MM::MemoryAlloc returns %d",r));
+	return r;
+	}
+
+
+TInt MM::MemoryAllocContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TUint aAlign, TPhysAddr& aPhysAddr)
+	{
+	TRACE(("MM::MemoryAllocContiguous(0x%08x,0x%08x,0x%08x,%d,?)",aMemory,aIndex,aCount,aAlign));
+	MemoryObjectLock::Lock(aMemory);
+	TInt r;
+	if(!aMemory->CheckRegion(aIndex,aCount))
+		r = KErrArgument;
+	else
+		r = aMemory->iManager->AllocContiguous(aMemory,aIndex,aCount,MM::RoundToPageShift(aAlign),aPhysAddr);
+	MemoryObjectLock::Unlock(aMemory);
+	TRACE(("MM::MemoryAlloc returns %d (aPhysAddr=0x%08x)",r,aPhysAddr));
+	return r;
+	}
+
+
+void MM::MemoryFree(DMemoryObject* aMemory, TUint aIndex, TUint aCount)
+	{
+	TRACE(("MM::MemoryFree(0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount));
+	MemoryObjectLock::Lock(aMemory);
+	aMemory->ClipRegion(aIndex,aCount);
+	aMemory->iManager->Free(aMemory,aIndex,aCount);
+	MemoryObjectLock::Unlock(aMemory);
+	}
+
+
+TInt MM::MemoryAddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages)
+	{
+	TRACE(("MM::MemoryAddPages(0x%08x,0x%08x,0x%08x,?)",aMemory,aIndex,aCount));
+	MemoryObjectLock::Lock(aMemory);
+	TInt r;
+	if(!aMemory->CheckRegion(aIndex,aCount))
+		r = KErrArgument;
+	else
+		r = aMemory->iManager->AddPages(aMemory,aIndex,aCount,aPages);
+	MemoryObjectLock::Unlock(aMemory);
+	TRACE(("MM::MemoryAddPages returns %d",r));
+	return r;
+	}
+
+
+TInt MM::MemoryAddContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr aPhysAddr)
+	{
+	TRACE(("MM::MemoryAddContiguous(0x%08x,0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount,aPhysAddr));
+	MemoryObjectLock::Lock(aMemory);
+	TInt r;
+	if(!aMemory->CheckRegion(aIndex,aCount))
+		r = KErrArgument;
+	else
+		r = aMemory->iManager->AddContiguous(aMemory,aIndex,aCount,aPhysAddr);
+	MemoryObjectLock::Unlock(aMemory);
+	TRACE(("MM::MemoryAddContiguous returns %d",r));
+	return r;
+	}
+
+
+TUint MM::MemoryRemovePages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages)
+	{
+	TRACE(("MM::MemoryRemovePages(0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount));
+	MemoryObjectLock::Lock(aMemory);
+	aMemory->ClipRegion(aIndex,aCount);
+	TInt r = aMemory->iManager->RemovePages(aMemory,aIndex,aCount,aPages);
+	if(r<0)
+		r = 0;
+	MemoryObjectLock::Unlock(aMemory);
+	TRACE(("MM::MemoryRemovePages returns %d",r));
+	return r;
+	}
+
+
+TInt MM::MemoryAllowDiscard(DMemoryObject* aMemory, TUint aIndex, TUint aCount)
+	{
+	TRACE(("MM::MemoryAllowDiscard(0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount));
+	MemoryObjectLock::Lock(aMemory);
+	TInt r;
+	if(!aMemory->CheckRegion(aIndex,aCount))
+		r = KErrArgument;
+	else
+		r = aMemory->iManager->AllowDiscard(aMemory,aIndex,aCount);
+	MemoryObjectLock::Unlock(aMemory);
+	TRACE(("MM::MemoryAllowDiscard returns %d",r));
+	return r;
+	}
+
+
+TInt MM::MemoryDisallowDiscard(DMemoryObject* aMemory, TUint aIndex, TUint aCount)
+	{
+	TRACE(("MM::MemoryDisallowDiscard(0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount));
+	MemoryObjectLock::Lock(aMemory);
+	TInt r;
+	if(!aMemory->CheckRegion(aIndex,aCount))
+		r = KErrArgument;
+	else
+		r = aMemory->iManager->DisallowDiscard(aMemory,aIndex,aCount);
+	MemoryObjectLock::Unlock(aMemory);
+	TRACE(("MM::MemoryDisallowDiscard returns %d",r));
+	return r;
+	}
+
+
+TInt MM::MemoryPhysAddr(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr& aPhysicalAddress, TPhysAddr* aPhysicalPageList)
+	{
+	TRACE(("MM::MemoryPhysAddr(0x%08x,0x%08x,0x%08x,?,?)",aMemory,aIndex,aCount));
+	TInt r = aMemory->PhysAddr(aIndex,aCount,aPhysicalAddress,aPhysicalPageList);
+	TRACE(("MM::MemoryPhysAddr returns %d aPhysicalAddress=0x%08x",r,aPhysicalAddress));
+	return r;
+	}
+
+
+void MM::MemoryBTracePrime(DMemoryObject* aMemory)
+	{
+	aMemory->BTraceCreate();
+	aMemory->iMappings.Lock();
+	TMappingListIter iter;
+	DMemoryMapping* mapping = (DMemoryMapping*)iter.Start(aMemory->iMappings);
+	while(mapping)
+		{
+		aMemory->iMappings.Unlock();	
+		mapping->BTraceCreate();
+		aMemory->iMappings.Lock();
+		mapping = (DMemoryMapping*)iter.Next();
+		}
+	iter.Finish();
+	aMemory->iMappings.Unlock();	
+	}
+
+
+void MM::MemoryClose(DMemoryObject* aMemory)
+	{
+	aMemory->Close();
+	}
+
+
+TBool MM::MemoryIsNotMapped(DMemoryObject* aMemory)
+	{
+	TBool r = aMemory->iMappings.IsEmpty();
+	TRACE2(("MM::MemoryIsNotMapped(0x%08x) returns %d",aMemory,r));
+	return r;
+	}
+
+//
+// Physical pinning
+//
+
+TInt MM::PinPhysicalMemory(DMemoryObject* aMemory, DPhysicalPinMapping* aPinObject, TUint aIndex, TUint aCount, TBool aReadOnly, TPhysAddr& aAddress, TPhysAddr* aPages, TUint32& aMapAttr, TUint& aColour)
+	{
+
+	if (!aMemory->CheckRegion(aIndex,aCount))
+	    return KErrArgument;
+
+	TMappingPermissions permissions = aReadOnly ? ESupervisorReadOnly : ESupervisorReadWrite;
+	TInt r = aPinObject->Pin(aMemory, aIndex, aCount, permissions);
+	if (r == KErrNone)
+		{
+		r = aPinObject->PhysAddr(aIndex, aCount, aAddress, aPages);
+		if (r>=KErrNone)
+			{
+			r = KErrNone; //Do not report discontigious memory in return value.
+			const TMappingAttributes2& mapAttr2 =
+				MM::LegacyMappingAttributes(aMemory->Attributes(), permissions);
+			*(TMappingAttributes2*)&aMapAttr = mapAttr2;
+			}
+		else
+			{
+			aPinObject->Unpin();
+			}
+		}
+
+	aColour = 0;
+	return r;
+	}
+
+
+TInt MM::MemoryWipe(DMemoryObject* aMemory)
+	{
+	__NK_ASSERT_ALWAYS(aMemory->iMappings.IsEmpty()); // can't be mapped otherwise confidentiality can't be guaranteed
+	TRACE2(("MM::MemoryWipe(0x%08x)",aMemory));
+	MemoryObjectLock::Lock(aMemory);
+	TInt r = aMemory->iManager->Wipe(aMemory);
+	MemoryObjectLock::Unlock(aMemory);
+	return r;
+	}
+
+
+TInt MM::MemorySetReadOnly(DMemoryObject* aMemory)
+	{
+	TRACE2(("MM::MemorySetReadOnly(0x%08x)",aMemory));
+	MemoryObjectLock::Lock(aMemory);
+	TInt r = aMemory->SetReadOnly();
+	MemoryObjectLock::Unlock(aMemory);
+	return r;
+	}
+
+//
+// Mapping functions
+//
+
+TInt MM::MappingNew(DMemoryMapping*& aMapping, DMemoryObject* aMemory, TMappingPermissions aPermissions, TInt aOsAsid, TMappingCreateFlags aFlags, TLinAddr aAddr, TUint aIndex, TUint aCount)
+	{
+	TRACE(("MM::MappingNew(?,0x%08x,0x%08x,%d,0x%08x,0x%08x,0x%08x,0x%08x)",aMemory, aPermissions, aOsAsid, aFlags, aAddr, aIndex, aCount));
+
+	/**
+	@todo Make mappings created with this function fail (panic?) if the are reused to map
+	another object.
+	*/
+	if(aCount==~0u)
+		aCount = aMemory->iSizeInPages-aIndex;
+
+	// if memory object reserves all resources, make mappings also do so...
+	if(aMemory->iFlags&DMemoryObject::EReserveResources)
+		FlagSet(aFlags,EMappingCreateReserveAllResources);
+
+	// check if mapping is for global user data...
+	if(aOsAsid==(TInt)KKernelOsAsid && aPermissions&EUser)
+		FlagSet(aFlags,EMappingCreateUserGlobalVirtual);
+	else
+		FlagClear(aFlags,EMappingCreateUserGlobalVirtual);
+
+	// set paged attribute for mapping...
+	if(aMemory->IsDemandPaged())
+		FlagSet(aFlags,EMappingCreateDemandPaged);
+	else
+		FlagClear(aFlags,EMappingCreateDemandPaged);
+
+	DMemoryMapping* mapping = 0;
+	TInt r = KErrNone;
+	if(!aMemory->CheckRegion(aIndex,aCount))
+		r = KErrArgument;
+	else
+		{
+		mapping = aMemory->CreateMapping(aIndex, aCount);
+		if(!mapping)
+			r = KErrNoMemory;
+		}
+
+	if(!mapping)
+		{
+		// free any virtual address the mapping should have adopted...
+		if(aFlags&EMappingCreateAdoptVirtual)
+			MM::VirtualFree(aOsAsid, aAddr, aCount<<KPageShift);
+		}
+	else
+		{
+		r = mapping->Construct(aMemory->Attributes(), aFlags, aOsAsid, aAddr, aCount<<KPageShift, aIndex<<KPageShift);
+		if(r==KErrNone)
+			r = mapping->Map(aMemory, aIndex, aCount, aPermissions);
+		if(r!=KErrNone)
+			{
+			mapping->Close();
+			mapping = 0;
+			}
+		}
+
+	aMapping = mapping;
+	TRACE(("MM::MappingNew returns %d (aMapping=0x%0x)",r,aMapping));
+#ifdef BTRACE_FLEXIBLE_MEM_MODEL
+	if (r == KErrNone)
+		aMapping->BTraceCreate();
+#endif
+	return r;
+	}
+
+
+TInt MM::MappingNew(DMemoryMapping*& aMapping, TUint aCount, TInt aOsAsid, TMappingCreateFlags aFlags, TLinAddr aAddr, TLinAddr aColourOffset)
+	{
+	TRACE2(("MM::MappingNew(?,0x%08x,%d,0x%08x,0x%08x,0x%08x)",aCount, aOsAsid, aFlags, aAddr, aColourOffset));
+
+	FlagClear(aFlags,EMappingCreateDemandPaged); // mapping can't use demand paged page tables
+
+	TInt r = KErrNone;
+	DMemoryMapping* mapping = new DFineMapping();
+	if(!mapping)
+		r = KErrNoMemory;
+
+	if(!mapping)
+		{
+		// free any virtual address the mapping should have adopted...
+		if(aFlags&EMappingCreateAdoptVirtual)
+			MM::VirtualFree(aOsAsid, aAddr, aCount<<KPageShift);
+		}
+	else
+		{
+		r = mapping->Construct(EMemoryAttributeStandard, aFlags, aOsAsid, aAddr, aCount<<KPageShift, aColourOffset);
+		if(r!=KErrNone)
+			{
+			mapping->Close();
+			mapping = 0;
+			}
+		}
+
+	aMapping = mapping;
+	TRACE2(("MM::MappingNew returns %d (aMapping=0x%0x)",r,aMapping));
+
+	return r;
+	}
+
+
+TInt MM::MappingMap(DMemoryMapping* aMapping, TMappingPermissions aPermissions, DMemoryObject* aMemory, TUint aIndex, TUint aCount)
+	{
+	TRACE2(("MM::MappingMap(0x%08x,0x%08x,0x%08x,0x%x,0x%x)",aMapping,aPermissions,aMemory,aIndex,aCount));
+	if(aCount==~0u)
+		aCount = aMemory->iSizeInPages-aIndex;
+	TInt r = aMapping->Map(aMemory, aIndex, aCount, aPermissions);
+	TRACE2(("MM::MappingMap returns %d",r));
+	return r;
+	}
+
+
+void MM::MappingUnmap(DMemoryMapping* aMapping)
+	{
+	if(aMapping->IsAttached())
+		{
+		TRACE2(("MM::MappingUnmap(0x%08x)",aMapping));
+		aMapping->Unmap();
+		}
+	}
+
+
+void MM::MappingDestroy(DMemoryMapping*& aMapping)
+	{
+	DMemoryMapping* mapping = (DMemoryMapping*)__e32_atomic_swp_ord_ptr(&aMapping, 0);
+	if (!mapping)
+		return;
+	TRACE(("MM::MappingDestroy(0x%08x)",mapping));
+#ifdef BTRACE_FLEXIBLE_MEM_MODEL
+	BTraceContext4(BTrace::EFlexibleMemModel,BTrace::EMemoryMappingDestroy,mapping);
+#endif
+	if(mapping->IsAttached())
+		mapping->Unmap();
+	mapping->Close();
+	}
+
+
+void MM::MappingDestroy(TLinAddr aAddr, TInt aOsAsid)
+	{
+	DMemoryMapping* mapping = AddressSpace[aOsAsid]->GetMapping(aAddr);
+	MM::MappingDestroy(mapping);
+	}
+
+
+void MM::MappingAndMemoryDestroy(DMemoryMapping*& aMapping)
+	{
+	DMemoryMapping* mapping = (DMemoryMapping*)__e32_atomic_swp_ord_ptr(&aMapping, 0);
+	TRACE(("MM::MappingAndMemoryDestroy(0x%08x)",mapping));
+	if (!mapping)
+		return;
+	DMemoryObject* memory = mapping->Memory(true); // safe because we assume owner hasn't unmapped mapping
+	MM::MappingDestroy(mapping);
+	MM::MemoryDestroy(memory);
+	}
+
+
+void MM::MappingAndMemoryDestroy(TLinAddr aAddr, TInt aOsAsid)
+	{
+	DMemoryMapping* mapping = AddressSpace[aOsAsid]->GetMapping(aAddr);
+	MM::MappingAndMemoryDestroy(mapping);
+	}
+
+
+TLinAddr MM::MappingBase(DMemoryMapping* aMapping)
+	{
+	TLinAddr base = aMapping->Base();
+	TRACE2(("MM::MappingBase(0x%08x) returns 0x%08x",aMapping,base));
+	return base;
+	}
+
+
+TInt MM::MappingOsAsid(DMemoryMapping* aMapping)
+	{
+	return aMapping->OsAsid();
+	}
+
+
+DMemoryObject* MM::MappingGetAndOpenMemory(DMemoryMapping* aMapping)
+	{
+	MmuLock::Lock();
+	DMemoryObject* memory = aMapping->Memory();
+	if (memory)
+		memory->Open();
+	MmuLock::Unlock();
+	TRACE2(("MM::MappingGetAndOpenMemory(0x%08x) returns 0x%08x",aMapping,memory));
+	return memory;
+	}
+
+
+void MM::MappingClose(DMemoryMapping* aMapping)
+	{
+	TRACE2(("MM::MappingClose(0x%08x)",aMapping));
+	aMapping->Close();
+	}
+
+
+DMemoryMapping* MM::FindMappingInThread(DMemModelThread* aThread, TLinAddr aAddr, TUint aSize, 
+										TUint& aOffsetInMapping, TUint& aInstanceCount)
+	{
+	if(aAddr>=KGlobalMemoryBase)
+		{
+		// Address in global region, so look it up in kernel's address space...
+		return FindMappingInAddressSpace(KKernelOsAsid, aAddr, aSize, aOffsetInMapping, aInstanceCount);
+		}
+
+	// Address in thread's process address space so open a reference to its os asid
+	// so that it remains valid for FindMappingInAddressSpace() call.
+	DMemModelProcess* process = (DMemModelProcess*)aThread->iOwningProcess;
+	TInt osAsid = process->TryOpenOsAsid();
+	if (osAsid < 0)
+		{// The process no longer owns an address space so can't have any mappings.
+		return NULL;
+		}
+
+	DMemoryMapping* r = FindMappingInAddressSpace(osAsid, aAddr, aSize, aOffsetInMapping, aInstanceCount);
+
+	process->CloseOsAsid();
+	return r;
+	}
+
+
+DMemoryMapping* MM::FindMappingInAddressSpace(	TUint aOsAsid, TLinAddr aAddr, TUint aSize, 
+												TUint& aOffsetInMapping, TUint& aInstanceCount)
+	{
+	return AddressSpace[aOsAsid]->FindMapping(aAddr, aSize, aOffsetInMapping, aInstanceCount);
+	}
+
+
+
+//
+// Address space
+//
+
+TInt MM::AddressSpaceAlloc(TPhysAddr& aPageDirectory)
+	{
+	return DAddressSpace::New(aPageDirectory);
+	}
+
+
+void MM::AddressSpaceFree(TUint aOsAsid)
+	{
+	AddressSpace[aOsAsid]->Close();
+	}
+
+
+void MM::AsyncAddressSpaceFree(TUint aOsAsid)
+	{
+	AddressSpace[aOsAsid]->AsyncClose();
+	}
+
+
+TInt MM::VirtualAllocCommon(TLinAddr& aLinAddr, TUint aSize, TBool aDemandPaged)
+	{
+	TRACE(("MM::VirtualAllocCommon(?,0x%08x,%d)",aSize,aDemandPaged));
+	TUint pdeType = aDemandPaged ? EVirtualSlabTypeDemandPaged : 0;
+	TInt r = DAddressSpace::AllocateUserCommonVirtualMemory(aLinAddr, aSize, 0, aSize, pdeType);
+	TRACE(("MM::VirtualAllocCommon returns %d region=0x%08x+0x%08x",r,aLinAddr,aSize));
+	return r;
+	}
+
+
+void MM::VirtualFreeCommon(TLinAddr aLinAddr, TUint aSize)
+	{
+	TRACE(("MM::VirtualFreeCommon(0x%08x,0x%08x)",aLinAddr,aSize));
+	DAddressSpace::FreeUserCommonVirtualMemory(aLinAddr, aSize);
+	}
+
+
+TInt MM::VirtualAlloc(TInt aOsAsid, TLinAddr& aLinAddr, TUint aSize, TBool aDemandPaged)
+	{
+	TRACE(("MM::VirtualAlloc(?,%d,0x%08x,%d)",aOsAsid,aSize,aDemandPaged));
+	TUint pdeType = aDemandPaged ? EVirtualSlabTypeDemandPaged : 0;
+	TInt r = AddressSpace[aOsAsid]->AllocateVirtualMemory(aLinAddr, aSize, 0, aSize, pdeType);
+	TRACE(("MM::VirtualAlloc returns %d region=0x%08x+0x%08x",r,aLinAddr,aSize));
+	return r;
+	}
+
+
+void MM::VirtualFree(TInt aOsAsid, TLinAddr aLinAddr, TUint aSize)
+	{
+	TRACE(("MM::VirtualFree(%d,0x%08x,0x%08x)",aOsAsid,aLinAddr,aSize));
+	AddressSpace[aOsAsid]->FreeVirtualMemory(aLinAddr, aSize);
+	}
+
+
+
+//
+// Init
+//
+
+void MM::Init1()
+	{
+	TheMmu.Init1();
+	}
+
+
+extern DMutexPool MemoryObjectMutexPool;
+extern DMutexPool AddressSpaceMutexPool;
+
+void MM::Init2()
+	{
+	TInt r;
+
+	TheMmu.Init2();
+
+	// create mutex pools before calling any functions which require them...
+	_LIT(KAddressSpaceMutexName,"AddressSpaceMutex");
+	r = AddressSpaceMutexPool.Create(4, &KAddressSpaceMutexName, KMutexOrdAddresSpace);
+	__NK_ASSERT_ALWAYS(r==KErrNone);
+	_LIT(KMemoryObjectMutexName,"MemoryObjectMutex");
+	r = MemoryObjectMutexPool.Create(8, &KMemoryObjectMutexName, KMutexOrdMemoryObject);
+	__NK_ASSERT_ALWAYS(r==KErrNone);
+
+	// use the Ram Allocator mutex for low-level memory functions...
+	DMutex* mmuAllocMutex = TheMmu.iRamAllocatorMutex;
+
+	// memory cleanup needs initialising before any memory is freed...
+	TMemoryCleanup::Init2();
+
+	// initialise allocators used for MMU operations...
+	RPageArray::Init2A();
+	PageTables.Init2(mmuAllocMutex); // must come before any other code which allocates memory objects
+	RPageArray::Init2B(mmuAllocMutex);
+	PageTables.Init2B();
+	PageDirectories.Init2();
+
+	// initialise address spaces...
+	DAddressSpace::Init2();
+
+	// init pager...
+	ThePager.Init2();
+
+	TheMmu.Init2Final();
+	}
+
+ 
+/** HAL Function wrapper for the RAM allocator.
+*/
+TInt RamHalFunction(TAny*, TInt aFunction, TAny* a1, TAny* a2)
+	{
+	return TheMmu.RamHalFunction(aFunction, a1, a2);
+	}
+
+
+void MM::Init3()
+	{
+	__KTRACE_OPT2(KBOOT,KMMU,Kern::Printf("MM::Init3"));
+	ThePager.Init3();
+
+	// Register a HAL Function for the Ram allocator.
+	TInt r = Kern::AddHalEntry(EHalGroupRam, RamHalFunction, 0);
+	__NK_ASSERT_ALWAYS(r==KErrNone);
+
+	TheMmu.Init3();
+	}
+
+
+TInt MM::InitFixedKernelMemory(DMemoryObject*& aMemory,
+							   TLinAddr aStart,
+							   TLinAddr aEnd,
+							   TUint aInitSize,
+							   TMemoryObjectType aType,
+							   TMemoryCreateFlags aMemoryCreateFlags,
+							   TMemoryAttributes aMemoryAttributes,
+							   TMappingCreateFlags aMappingCreateFlags
+							   )
+	{
+	TUint maxSize = aEnd-aStart;
+	TInt r = MM::MemoryNew(aMemory, aType, MM::BytesToPages(maxSize), aMemoryCreateFlags, aMemoryAttributes);
+	if(r==KErrNone)
+		{
+		TBool allowGaps = aInitSize&1; // lower bit of size is set if region to be claimed contains gaps
+		aInitSize &= ~1;
+		r = MM::MemoryClaimInitialPages(aMemory,aStart,aInitSize,ESupervisorReadWrite,allowGaps);
+		if(r==KErrNone)
+			{
+			DMemoryMapping* mapping;
+			r = MM::MappingNew(mapping,aMemory,ESupervisorReadWrite,KKernelOsAsid,aMappingCreateFlags,aStart);
+			// prevent any further mappings of this memory,
+			// this is needed for realtime and OOM guarantees...
+			aMemory->DenyMappings();
+			}
+		}
+	// Note, no cleanup is done if an error occurs because this function is only
+	// used at boot time and the system can't recover from an error
+	return r;
+	}
+
+
+void MM::Panic(MM::TMemModelPanic aPanic)
+	{
+	Kern::Fault("MemModel", aPanic);
+	}
+
+
+//
+//
+//
+
+TUint MM::BytesToPages(TUint aBytes)
+	{
+	if(aBytes&KPageMask)
+		Panic(EBadBytesToPages);
+	return aBytes>>KPageShift;
+	}
+
+
+TUint MM::RoundToPageSize(TUint aSize)
+	{
+	return (aSize+KPageMask)&~KPageMask;
+	}
+
+
+TUint MM::RoundToPageCount(TUint aSize)
+	{
+	return (aSize+KPageMask)>>KPageShift;
+	}
+
+
+TUint MM::RoundToPageShift(TUint aShift)
+	{
+	return aShift>(TUint)KPageShift ? aShift-KPageShift : 0;
+	}
+
+
+//
+//
+//
+
+void MM::ValidateLocalIpcAddress(TLinAddr aAddr, TUint aSize, TBool aWrite)
+	{
+	__NK_ASSERT_DEBUG(aSize);
+
+	TLinAddr end = aAddr+aSize-1;
+	if(end<aAddr)
+		end = ~(TLinAddr)0; // clip to end of memory
+
+	// if IPC region is in process local data area then it's OK...
+	if(end<KUserLocalDataEnd && aAddr>=KUserLocalDataBase)
+		return;
+
+	// if region overlaps alias region...
+	if(end>=KIPCAlias && aAddr<KIPCAlias+KIPCAliasAreaSize)
+		{
+		// remove alias...
+		((DMemModelThread*)TheCurrentThread)->RemoveAlias();
+		// make sure start address is in alias region...
+		if(aAddr<KIPCAlias)
+			aAddr = KIPCAlias;
+		// then cause fault now...
+		MM::UserPermissionFault(aAddr,aWrite);
+		}
+
+	if(end<(TLinAddr)KUserMemoryLimit)
+		return; // user memory is safe
+	
+	// Compare the current thread's process os asid to kernel asid, no need to 
+	// open a reference on the os asid as it is the current thread.
+	if(((DMemModelProcess*)TheCurrentThread->iOwningProcess)->OsAsid()==(TInt)KKernelOsAsid)
+		return; // kernel can access everything
+
+	// make sure address is in supervisor only region...
+	if(aAddr<KUserMemoryLimit)
+		aAddr = KUserMemoryLimit;
+	// then cause fault now...
+	MM::UserPermissionFault(aAddr,aWrite);
+	}
+
+
+void MM::UserPermissionFault(TLinAddr aAddr, TBool aWrite)
+	{
+	// Access aAddr with user permissions to generate an exception...
+	if(aWrite)
+		UserWriteFault(aAddr);
+	else
+		UserReadFault(aAddr);
+	__NK_ASSERT_ALWAYS(0); // shouldn't get here
+	}
+
+
+#ifndef __SMP__
+void MM::IpcAliasPde(TPde*& aPdePtr, TUint aOsAsid)
+	{
+	aPdePtr = &Mmu::PageDirectory(aOsAsid)[KIPCAlias>>KChunkShift];
+	}
+#endif
+
+
+TMappingPermissions MM::MappingPermissions(TBool aUser, TBool aWrite, TBool aExecute)
+	{
+	TUint perm	= 0;
+	if(aUser)
+		perm |= EUser;
+	if(aWrite)
+		perm |= EReadWrite;
+	if(aExecute)
+		perm |= EExecute;
+	return (TMappingPermissions)perm;
+	}
+
+
+TInt MM::MappingPermissions(TMappingPermissions& aPermissions, TMappingAttributes2 aLegacyAttributes)
+	{
+	TUint attr2 = *(TUint32*)&aLegacyAttributes;
+
+	TUint read = attr2&EMapAttrReadMask;
+	TUint write = (attr2&EMapAttrWriteMask)>>4;
+	TUint execute = (attr2&EMapAttrExecMask)>>8;
+
+	read |= execute; 	// execute access requires read access
+
+	if(write==0) 		// no write required
+		{
+		if((read&5)==0)
+			return KErrNotSupported; // neither supervisor nor user read specified
+		}
+	else if(write<4)	// supervisor write required
+		{
+		if(read>=4)
+			return KErrNotSupported; // user read requested (but no user write)
+		}
+
+	read |= write;		// write access implies read access
+
+	TUint user = read&4;
+	aPermissions = MappingPermissions(user,write,execute);
+
+	return KErrNone;
+	}
+
+
+TInt MM::MemoryAttributes(TMemoryAttributes& aAttributes, TMappingAttributes2 aLegacyAttributes)
+	{
+	TUint attr = aLegacyAttributes.Type();
+	if (aLegacyAttributes.Shared())
+		attr |= EMemoryAttributeShareable;
+	if (aLegacyAttributes.Parity())
+		attr |= EMemoryAttributeUseECC;
+	aAttributes = Mmu::CanonicalMemoryAttributes((TMemoryAttributes)attr);
+	return KErrNone;
+	}
+
+
+TMappingAttributes2 MM::LegacyMappingAttributes(TMemoryAttributes aAttributes, TMappingPermissions aPermissions)
+	{
+	TUint attr = Mmu::CanonicalMemoryAttributes(aAttributes);
+	return TMappingAttributes2
+		(
+		(TMemoryType)(attr&EMemoryAttributeTypeMask),
+		aPermissions&EUser,
+		aPermissions&EReadWrite,
+		aPermissions&EExecute,
+		attr&EMemoryAttributeShareable,
+		attr&EMemoryAttributeUseECC
+		);
+	}
+
+