kernel/eka/memmodel/epoc/multiple/mprocess.cpp
changeset 9 96e5fb8b040d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/memmodel/epoc/multiple/mprocess.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,1029 @@
+// Copyright (c) 1994-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:
+// e32\memmodel\epoc\multiple\mprocess.cpp
+// 
+//
+
+#include "memmodel.h"
+#include "mmboot.h"
+#include "cache_maintenance.h"
+#include <demand_paging.h>
+
+#define iMState		iWaitLink.iSpare1
+
+// just for convenience...
+#define KAmSelfMod	(DMemModelChunk::ECode | DMemModelChunk::EAddressLocal)
+
+_LIT(KDollarDat,"$DAT");
+_LIT(KLitDollarCode,"$CODE");
+_LIT(KLitDllDollarData,"DLL$DATA");
+
+#ifdef __CPU_HAS_BTB
+extern void __FlushBtb();
+#endif
+
+const TInt KChunkGranularity=4;
+
+/********************************************
+ * Process
+ ********************************************/
+void DMemModelProcess::Destruct()
+	{
+	__ASSERT_ALWAYS(!iChunkCount && !iCodeChunk && !iDllDataChunk, MM::Panic(MM::EProcessDestructChunksRemaining));
+	Kern::Free(iChunks);
+	Kern::Free(iLocalSection);
+	if (iOsAsid)
+		{
+		Mmu& m=Mmu::Get();
+		MmuBase::Wait();
+		m.FreeOsAsid(iOsAsid);
+		iOsAsid=0;
+		MmuBase::Signal();
+#ifndef __SMP__
+		LastUserSelfMod=0;  // must force a BTB flush when next selfmod chunk switched in
+#endif
+		}
+#ifdef __CPU_HAS_BTB
+	__FlushBtb();
+#endif
+	DProcess::Destruct();
+	}
+
+TInt DMemModelProcess::NewChunk(DChunk*& aChunk, SChunkCreateInfo& aInfo, TLinAddr& aRunAddr)
+	{
+	aChunk=NULL;
+	DMemModelChunk* pC=NULL;
+	TInt r=GetNewChunk(pC,aInfo);
+	if (r!=KErrNone)
+		{
+		if (pC)
+			pC->Close(NULL);
+		return r;
+		}
+	TInt mapType=pC->iAttributes & DMemModelChunk::EMapTypeMask;
+	pC->iOwningProcess=(mapType==DMemModelChunk::EMapTypeLocal)?this:NULL;
+#ifdef __CPU_HAS_BTB
+	if ((pC->iAttributes & KAmSelfMod) == KAmSelfMod)  // it's a potentially overlapping self-mod
+		{
+		iSelfModChunks++;
+#ifndef __SMP__
+		LastUserSelfMod = this;  // we become the last selfmodding process
+#endif
+		__FlushBtb();		// we need to do this, as there may be bad branches already in the btb
+		}
+#endif
+	r=pC->Create(aInfo);
+	if (r==KErrNone && (aInfo.iOperations & SChunkCreateInfo::EAdjust))
+		{
+		if (aInfo.iRunAddress!=0)
+			pC->SetFixedAddress(aInfo.iRunAddress,aInfo.iPreallocated);
+		if (aInfo.iPreallocated==0 && aInfo.iInitialTop!=0)
+			{
+			if (pC->iAttributes & DChunk::EDisconnected)
+				{
+				r=pC->Commit(aInfo.iInitialBottom,aInfo.iInitialTop-aInfo.iInitialBottom);
+				}
+			else if (pC->iAttributes & DChunk::EDoubleEnded)
+				{
+				r=pC->AdjustDoubleEnded(aInfo.iInitialBottom,aInfo.iInitialTop);
+				}
+			else
+				{
+				r=pC->Adjust(aInfo.iInitialTop);
+				}
+			}
+		}
+	if (r==KErrNone && (aInfo.iOperations & SChunkCreateInfo::EAdd))
+		{
+//			if (pC->iAttributes & DMemModelChunk::ECode)
+//				MM::TheMmu->SyncCodeMappings();
+		if (mapType!=DMemModelChunk::EMapTypeGlobal)
+			{
+			r=WaitProcessLock();
+			if (r==KErrNone)
+				{
+				r=AddChunk(pC,aRunAddr,EFalse);
+				SignalProcessLock();
+				}
+			}
+		else
+			aRunAddr=(TLinAddr)pC->Base();
+		}
+	if (r==KErrNone)
+		{
+		if(r==KErrNone)
+			if(pC->iKernelMirror)
+				aRunAddr = (TLinAddr)pC->iKernelMirror->Base();
+		pC->iDestroyedDfc = aInfo.iDestroyedDfc;
+		aChunk=(DChunk*)pC;
+		}
+	else
+		pC->Close(NULL);	// NULL since chunk can't have been added to process
+	return r;
+	}
+
+TInt DMemModelProcess::DoCreate(TBool aKernelProcess, TProcessCreateInfo& aInfo)
+	{
+	__KTRACE_OPT(KPROC,Kern::Printf(">DMemModelProcess::DoCreate %O",this));
+
+	Mmu& m=Mmu::Get();
+	TInt r=KErrNone;
+
+	iSelfModChunks=0;  // we don't have any yet.
+
+	if (aKernelProcess)
+		{
+		iAttributes |= ESupervisor;
+		//iOsAsid=0;
+//		Leave these till Mmu::Init2
+//		if (m.iLocalPdSize)
+//			iLocalPageDir=m.LinearToPhysical(TLinAddr(m.LocalPageDir(0)));
+//		iGlobalPageDir=m.LinearToPhysical(TLinAddr(m.GlobalPageDir(0)));
+		m.iAsidInfo[0]=((TUint32)this)|1;
+		iAddressCheckMaskR=0xffffffff;
+		iAddressCheckMaskW=0xffffffff;
+		}
+	else
+		{
+		MmuBase::Wait();
+		r=m.NewOsAsid(EFalse);
+		if (r>=0)
+			{
+			iOsAsid=r;
+			if (m.iLocalPdSize)
+				iLocalPageDir=m.LinearToPhysical(TLinAddr(m.LocalPageDir(r)));
+			else
+				iGlobalPageDir=m.LinearToPhysical(TLinAddr(m.GlobalPageDir(r)));
+			m.iAsidInfo[r] |= (TUint32)this;
+			r=KErrNone;
+			}
+		MmuBase::Signal();
+		if (r==KErrNone && 0==(iLocalSection=TLinearSection::New(m.iUserLocalBase, m.iUserLocalEnd)) )
+			r=KErrNoMemory;
+		}
+
+	__KTRACE_OPT(KPROC,Kern::Printf("OS ASID=%d, LPD=%08x, GPD=%08x, ASID info=%08x",iOsAsid,iLocalPageDir,
+											iGlobalPageDir,m.iAsidInfo[iOsAsid]));
+	__KTRACE_OPT(KPROC,Kern::Printf("<DMemModelProcess::DoCreate %d",r));
+	return r;
+	}
+
+TInt DMemModelProcess::CreateDataBssStackArea(TProcessCreateInfo& aInfo)
+	{
+	__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::CreateDataBssStackArea %O",this));
+	Mmu& m=Mmu::Get();
+	TInt dataBssSize=Mmu::RoundToPageSize(aInfo.iTotalDataSize);
+	TInt maxSize=dataBssSize+PP::MaxStackSpacePerProcess;
+	TLinAddr dataRunAddress=m.iUserLocalBase;
+	iDataBssRunAddress=dataRunAddress;
+
+	__KTRACE_OPT(KPROC,Kern::Printf("DataBssSize=%x, chunk max size %x",dataBssSize,maxSize));
+
+	SChunkCreateInfo cinfo;
+	cinfo.iGlobal=EFalse;
+	cinfo.iAtt=TChunkCreate::EDisconnected;
+	cinfo.iForceFixed=EFalse;
+	cinfo.iOperations=SChunkCreateInfo::EAdjust|SChunkCreateInfo::EAdd;
+	cinfo.iType=EUserData;
+	cinfo.iMaxSize=maxSize;
+	cinfo.iInitialBottom=0;
+	cinfo.iInitialTop=dataBssSize;
+	cinfo.iPreallocated=0;
+	cinfo.iName.Set(KDollarDat);
+	cinfo.iOwner=this;
+	cinfo.iRunAddress=0;
+	TLinAddr cb;
+	TInt r=NewChunk((DChunk*&)iDataBssStackChunk,cinfo,cb);
+	return r;
+	}
+
+TInt DMemModelProcess::AddChunk(DChunk* aChunk, TBool isReadOnly)
+	{
+	DMemModelChunk* pC=(DMemModelChunk*)aChunk;
+	if ((pC->iAttributes & DMemModelChunk::EPrivate) && this!=pC->iOwningProcess)
+		return KErrAccessDenied;
+	TInt r=WaitProcessLock();
+	if (r==KErrNone)
+		{
+		TInt pos=0;
+		r=ChunkIndex(pC,pos);
+		TLinAddr dataSectionBase=0;
+		if (r==0) // Found the chunk in this process, just up its count
+			{
+			iChunks[pos].iAccessCount++;
+			__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::AddChunk %08x to %08x (Access count incremented to %d)",aChunk,this,iChunks[pos].iAccessCount));
+			SignalProcessLock();
+			return KErrNone;
+			}
+		r=AddChunk(pC,dataSectionBase,isReadOnly);
+		SignalProcessLock();
+		}
+	__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::AddChunk returns %d",r));
+	return r;
+	}
+
+void M::FsRegisterThread()
+	{
+	DMemModelChunk* pC=(DMemModelChunk*)PP::TheRamDriveChunk;
+	TInt mapType=pC->iAttributes & DMemModelChunk::EMapTypeMask;
+	if (mapType!=DMemModelChunk::EMapTypeLocal)
+		{
+		DMemModelProcess* pP=(DMemModelProcess*)TheCurrentThread->iOwningProcess;
+		TLinAddr dataSectionBase;
+		TInt r=pP->WaitProcessLock();
+		if (r==KErrNone)
+			r=pP->AddChunk(pC,dataSectionBase,EFalse);
+		__ASSERT_ALWAYS(r==KErrNone, MM::Panic(MM::EFsRegisterThread));
+		pP->SignalProcessLock();
+		}
+	}
+
+TInt DMemModelProcess::AddChunk(DMemModelChunk* aChunk, TLinAddr& aDataSectionBase, TBool isReadOnly)
+	{
+	//
+	// Must hold the process $LOCK mutex before calling this
+	//
+	__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::AddChunk %O to %O",aChunk,this));
+	SChunkInfo *pC=iChunks;
+	SChunkInfo *pE=pC+iChunkCount-1;
+	TLinAddr base=TLinAddr(aChunk->iBase);
+	TInt i=0;
+
+#ifdef __CPU_HAS_BTB
+	if ((aChunk->iAttributes & KAmSelfMod)==KAmSelfMod)  // it's a potentially overlapping self-mod
+		{
+		iSelfModChunks++;
+#ifndef __SMP__
+		LastUserSelfMod = this;  // we become the last selfmodding process
+#endif
+		__FlushBtb();		// we need to do this, as there may be bad branches already in the btb
+		}
+#endif
+	if (iChunkCount)
+		{
+		for (; pE>=pC && TLinAddr(pE->iChunk->iBase)>base; --pE);
+		if (pE>=pC && TLinAddr(pE->iChunk->iBase)+pE->iChunk->iMaxSize>base)
+			return KErrInUse;
+		pC=pE+1;
+		if (pC<iChunks+iChunkCount && base+aChunk->iMaxSize>TLinAddr(pC->iChunk->iBase))
+			return KErrInUse;
+		i=pC-iChunks;
+		}
+	if (iChunkCount==iChunkAlloc)
+		{
+		TInt newAlloc=iChunkAlloc+KChunkGranularity;
+		TInt r=Kern::SafeReAlloc((TAny*&)iChunks,iChunkAlloc*sizeof(SChunkInfo),newAlloc*sizeof(SChunkInfo));
+		if (r!=KErrNone)
+			return r;
+		pC=iChunks+i;
+		iChunkAlloc=newAlloc;
+		}
+	memmove(pC+1,pC,(iChunkCount-i)*sizeof(SChunkInfo));
+	++iChunkCount;
+	pC->isReadOnly=isReadOnly;
+	pC->iAccessCount=1;
+	pC->iChunk=aChunk;
+	aDataSectionBase=base;
+	Mmu& m=Mmu::Get();
+	if (aChunk->iOsAsids)
+		{
+		// only need to do address space manipulation for shared chunks
+		MmuBase::Wait();
+		aChunk->iOsAsids->Alloc(iOsAsid,1);
+		TLinAddr a;
+		TInt i=0;
+		for (a=TLinAddr(aChunk->iBase); a<TLinAddr(aChunk->iBase)+aChunk->iMaxSize; a+=m.iChunkSize, ++i)
+			{
+			TInt ptid=aChunk->iPageTables[i];
+			if (ptid!=0xffff)
+				m.DoAssignPageTable(ptid,a,aChunk->iPdePermissions,(const TAny*)iOsAsid);
+			}
+		MmuBase::Signal();
+		}
+	if (aChunk->iChunkType==ERamDrive)
+		{
+		NKern::LockSystem();
+		iAddressCheckMaskR |= m.iRamDriveMask;
+		iAddressCheckMaskW |= m.iRamDriveMask;
+		NKern::UnlockSystem();
+		}
+	__DEBUG_EVENT(EEventUpdateProcess, this);
+	return KErrNone;
+	}
+
+void DMemModelProcess::DoRemoveChunk(TInt aIndex)
+	{
+	__DEBUG_EVENT(EEventUpdateProcess, this);
+	DMemModelChunk* chunk = iChunks[aIndex].iChunk;
+	memmove(iChunks+aIndex, iChunks+aIndex+1, (iChunkCount-aIndex-1)*sizeof(SChunkInfo));
+	--iChunkCount;
+	Mmu& m=Mmu::Get();
+	if (chunk->iOsAsids)
+		{
+		// only need to do address space manipulation for shared chunks
+		MmuBase::Wait();
+		chunk->iOsAsids->Free(iOsAsid);
+		TLinAddr a;
+		for (a=TLinAddr(chunk->iBase); a<TLinAddr(chunk->iBase)+chunk->iMaxSize; a+=m.iChunkSize)
+			m.DoUnassignPageTable(a,(const TAny*)iOsAsid);
+		TUint32 mask=(chunk->iAttributes&DMemModelChunk::ECode)?Mmu::EFlushITLB:0;
+		m.GenericFlush(mask|Mmu::EFlushDTLB);
+
+		MmuBase::Signal();
+		}
+	if (chunk->iChunkType==ERamDrive)
+		{
+		NKern::LockSystem();
+		iAddressCheckMaskR &= ~m.iRamDriveMask;
+		iAddressCheckMaskW &= ~m.iRamDriveMask;
+		NKern::UnlockSystem();
+		}
+	}
+
+/**
+Final chance for process to release resources during its death.
+
+Called with process $LOCK mutex held (if it exists).
+This mutex will not be released before it is deleted.
+I.e. no other thread will ever hold the mutex again.
+*/
+void DMemModelProcess::FinalRelease()
+	{
+	// Clean up any left over chunks (such as SharedIo buffers)
+	if(iProcessLock)
+		while(iChunkCount)
+			DoRemoveChunk(0);
+	}
+
+void DMemModelProcess::RemoveChunk(DMemModelChunk *aChunk)
+	{
+	// note that this can't be called after the process $LOCK mutex has been deleted
+	// since it can only be called by a thread in this process doing a handle close or
+	// dying, or by the process handles array being deleted due to the process dying,
+	// all of which happen before $LOCK is deleted.
+	__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess %O RemoveChunk %O",this,aChunk));
+	Kern::MutexWait(*iProcessLock);
+	TInt pos=0;
+	TInt r=ChunkIndex(aChunk,pos);
+
+	if (r==KErrNone) // Found the chunk
+		{
+		__KTRACE_OPT(KPROC,Kern::Printf("Chunk access count %d",iChunks[pos].iAccessCount));
+		if (--iChunks[pos].iAccessCount==0)
+			{
+			DoRemoveChunk(pos);
+#ifdef __CPU_HAS_BTB
+			if ((aChunk->iAttributes & KAmSelfMod)==KAmSelfMod)  // was a self-mod code chunk
+				if (iSelfModChunks)
+					iSelfModChunks--;
+#endif
+			}
+		}
+	Kern::MutexSignal(*iProcessLock);
+	}
+
+TInt DMemModelProcess::ChunkIndex(DMemModelChunk* aChunk,TInt& aPos)
+	{
+	if (!aChunk)
+		return KErrNotFound;
+	SChunkInfo *pC=iChunks;
+	SChunkInfo *pE=pC+iChunkCount;
+	for (; pC<pE && pC->iChunk!=aChunk; ++pC);
+	if (pC==pE)
+		return KErrNotFound;
+	aPos=pC-iChunks;
+	return KErrNone;
+	}
+
+TInt DMemModelProcess::MapCodeSeg(DCodeSeg* aSeg)
+	{
+	DMemModelCodeSeg& seg=*(DMemModelCodeSeg*)aSeg;
+	__KTRACE_OPT(KDLL,Kern::Printf("Process %O MapCodeSeg %C", this, aSeg));
+	TBool kernel_only=( (seg.iAttr&(ECodeSegAttKernel|ECodeSegAttGlobal)) == ECodeSegAttKernel );
+	if (kernel_only && !(iAttributes&ESupervisor))
+		return KErrNotSupported;
+	if (seg.iAttr&ECodeSegAttKernel)
+		return KErrNone;	// no extra mappings needed for kernel code
+	TInt r=KErrNone;
+	if (seg.Pages())
+		r=MapUserRamCode(seg.Memory(),EFalse);
+	if (seg.IsDll())
+		{
+		TInt total_data_size;
+		TLinAddr data_base;
+		seg.GetDataSizeAndBase(total_data_size, data_base);
+		if (r==KErrNone && total_data_size)
+			{
+			TInt size=Mmu::RoundToPageSize(total_data_size);
+			r=CommitDllData(data_base, size);
+			if (r!=KErrNone && seg.Pages())
+				UnmapUserRamCode(seg.Memory(), EFalse);
+			}
+		}
+	return r;
+	}
+
+void DMemModelProcess::UnmapCodeSeg(DCodeSeg* aSeg)
+	{
+	DMemModelCodeSeg& seg=*(DMemModelCodeSeg*)aSeg;
+	__KTRACE_OPT(KDLL,Kern::Printf("Process %O UnmapCodeSeg %C", this, aSeg));
+	if (seg.iAttr&ECodeSegAttKernel)
+		return;	// no extra mappings needed for kernel code
+	if (seg.IsDll())
+		{
+		TInt total_data_size;
+		TLinAddr data_base;
+		seg.GetDataSizeAndBase(total_data_size, data_base);
+		if (total_data_size)
+			DecommitDllData(data_base, Mmu::RoundToPageSize(total_data_size));
+		}
+	if (seg.Pages())
+		UnmapUserRamCode(seg.Memory(), EFalse);
+	}
+
+void DMemModelProcess::RemoveDllData()
+//
+// Call with CodeSegLock held
+//
+	{
+	}
+
+TInt DMemModelProcess::CreateCodeChunk()
+	{
+	__KTRACE_OPT(KDLL,Kern::Printf("DMemModelProcess %O CreateCodeChunk",this));
+	TBool kernel=iAttributes&ESupervisor;
+	Mmu& m=Mmu::Get();
+	SChunkCreateInfo c;
+	c.iGlobal=kernel;
+	c.iAtt = TChunkCreate::EDisconnected | (kernel? 0 : TChunkCreate::EMemoryNotOwned);
+	c.iForceFixed=EFalse;
+	c.iOperations=SChunkCreateInfo::EAdjust|SChunkCreateInfo::EAdd;
+	c.iRunAddress=kernel ? 0 : m.iUserCodeBase;
+	c.iPreallocated=0;
+	c.iType=kernel ? EKernelCode : EUserCode;
+	c.iMaxSize=m.iMaxUserCodeSize;
+	c.iName.Set(KLitDollarCode);
+	c.iOwner=this;
+	c.iInitialTop=0;
+	TLinAddr runAddr;
+	TInt r = NewChunk((DChunk*&)iCodeChunk,c,runAddr);
+	return r;
+	}
+
+void DMemModelProcess::FreeCodeChunk()
+	{
+	iCodeChunk->Close(this);
+	iCodeChunk=NULL;
+	}
+
+TInt DMemModelProcess::MapUserRamCode(DMemModelCodeSegMemory* aMemory, TBool aLoading)
+	{
+	__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess %O MapUserRamCode %C %d %d %d",
+									this, aMemory->iCodeSeg, aLoading, iOsAsid, aMemory->iIsDemandPaged));
+	__ASSERT_MUTEX(DCodeSeg::CodeSegLock);
+
+	TInt r;
+
+	if (!iCodeChunk)
+		{
+		r=CreateCodeChunk();
+		__KTRACE_OPT(KPROC,Kern::Printf("CreateCodeChunk returns %d", r));
+		if (r!=KErrNone)
+			return r;
+		}
+
+	MmuBase::Wait();
+
+	Mmu& m=Mmu::Get();
+	TInt offset=aMemory->iRamInfo.iCodeRunAddr-TLinAddr(iCodeChunk->iBase);
+	TInt codeSize = aMemory->iPageCount<<m.iPageShift;
+	TBool paged = aMemory->iIsDemandPaged;
+	DChunk::TCommitType commitType = paged ? DChunk::ECommitVirtual : DChunk::ECommitDiscontiguousPhysical;
+	r=iCodeChunk->Commit(offset, codeSize, commitType, aMemory->iPages);
+	__KTRACE_OPT(KPROC,Kern::Printf("Commit Pages returns %d", r));
+	if(r==KErrNone)
+		{
+		if (aLoading && !paged)
+			{
+			iCodeChunk->ApplyPermissions(offset, codeSize, m.iUserCodeLoadPtePerm);
+			UNLOCK_USER_MEMORY();
+			memset((TAny*)(aMemory->iRamInfo.iCodeLoadAddr+aMemory->iRamInfo.iCodeSize+aMemory->iRamInfo.iDataSize), 0x03, codeSize-(aMemory->iRamInfo.iCodeSize+aMemory->iRamInfo.iDataSize));
+			LOCK_USER_MEMORY();
+			}
+		if(aLoading && aMemory->iDataPageCount)
+			{
+			TInt dataSize = aMemory->iDataPageCount<<m.iPageShift;
+			r=iCodeChunk->Commit(offset+codeSize, dataSize, DChunk::ECommitDiscontiguousPhysical, aMemory->iPages+aMemory->iPageCount);
+			if(r==KErrNone)
+				{
+				iCodeChunk->ApplyPermissions(offset+codeSize, dataSize, m.iUserCodeLoadPtePerm);
+				UNLOCK_USER_MEMORY();
+				memset((TAny*)(aMemory->iRamInfo.iDataLoadAddr+aMemory->iRamInfo.iDataSize), 0x03, dataSize-aMemory->iRamInfo.iDataSize);
+				LOCK_USER_MEMORY();
+				}
+			}
+		if(r!=KErrNone)
+			{
+			// error, so decommit up code pages we had already committed...
+			DChunk::TDecommitType decommitType = paged ? DChunk::EDecommitVirtual : DChunk::EDecommitNormal;
+			iCodeChunk->Decommit(offset, codeSize, decommitType);
+			}
+		else
+			{
+			// indicate codeseg is now successfully mapped into the process...
+			NKern::LockSystem();
+			aMemory->iOsAsids->Free(iOsAsid);
+			NKern::UnlockSystem();
+			}
+		}
+
+	MmuBase::Signal();
+
+	if(r!=KErrNone && iCodeChunk->iSize==0)
+		FreeCodeChunk(); // cleanup any unused code chunk we would otherwise leave lying around
+
+	return r;
+	}
+
+void DMemModelProcess::UnmapUserRamCode(DMemModelCodeSegMemory* aMemory, TBool aLoading)
+	{
+	__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess %O UnmapUserRamCode %C %d %d",
+									this, aMemory->iCodeSeg, iOsAsid, aMemory->iIsDemandPaged != 0));
+
+	__ASSERT_MUTEX(DCodeSeg::CodeSegLock);
+
+	MmuBase::Wait();
+
+	NKern::LockSystem();
+	aMemory->iOsAsids->Alloc(iOsAsid, 1);
+	NKern::UnlockSystem();
+
+	Mmu& m=Mmu::Get();
+	__NK_ASSERT_DEBUG(iCodeChunk);
+	TInt offset=aMemory->iRamInfo.iCodeRunAddr-TLinAddr(iCodeChunk->iBase);
+	TInt codeSize = aMemory->iPageCount<<m.iPageShift;
+	TBool paged = aMemory->iIsDemandPaged;
+	DChunk::TDecommitType decommitType = paged ? DChunk::EDecommitVirtual : DChunk::EDecommitNormal;
+	TInt r=iCodeChunk->Decommit(offset, codeSize, decommitType);
+	__ASSERT_DEBUG(r==KErrNone, MM::Panic(MM::EDecommitFailed));
+	(void)r; //Supress the warning in urel build
+
+	if(aLoading && aMemory->iDataPageCount)
+		{
+		// decommit pages used to store data section...
+		TInt dataSize = aMemory->iDataPageCount<<m.iPageShift;
+		r=iCodeChunk->Decommit(offset+codeSize, dataSize);
+		__ASSERT_DEBUG(r==KErrNone, MM::Panic(MM::EDecommitFailed));
+		(void)r; //Supress the warning in urel build
+		}
+	__NK_ASSERT_DEBUG(iCodeChunk->iSize >= 0);
+
+	MmuBase::Signal();
+
+	if (iCodeChunk->iSize==0)
+		FreeCodeChunk();
+	}
+
+TInt DMemModelProcess::CreateDllDataChunk()
+	{
+	__KTRACE_OPT(KDLL,Kern::Printf("DMemModelProcess %O CreateDllDataChunk",this));
+	Mmu& m=Mmu::Get();
+	SChunkCreateInfo c;
+	c.iGlobal=EFalse;
+	c.iAtt=TChunkCreate::EDisconnected;
+	c.iForceFixed=EFalse;
+	c.iOperations=SChunkCreateInfo::EAdjust|SChunkCreateInfo::EAdd;
+	c.iRunAddress=m.iDllDataBase;
+	c.iPreallocated=0;
+	c.iType=EDllData;
+	c.iMaxSize=m.iMaxDllDataSize;
+	c.iName.Set(KLitDllDollarData);
+	c.iOwner=this;
+	c.iInitialTop=0;
+	TLinAddr runAddr;
+	return NewChunk((DChunk*&)iDllDataChunk,c,runAddr);
+	}
+
+void DMemModelProcess::FreeDllDataChunk()
+	{
+	iDllDataChunk->Close(this);
+	iDllDataChunk=NULL;
+	}
+
+TInt DMemModelProcess::CommitDllData(TLinAddr aBase, TInt aSize)
+	{
+	__KTRACE_OPT(KDLL,Kern::Printf("DMemModelProcess %O CommitDllData %08x+%x",this,aBase,aSize));
+	TInt r=KErrNone;
+	if (!iDllDataChunk)
+		r=CreateDllDataChunk();
+	if (r==KErrNone)
+		{
+		TInt offset=aBase-(TLinAddr)iDllDataChunk->iBase;
+		__ASSERT_ALWAYS(TUint32(offset)<TUint32(iDllDataChunk->iMaxSize),MM::Panic(MM::ECommitInvalidDllDataAddress));
+		r=iDllDataChunk->Commit(offset, aSize);
+		if (r!=KErrNone && iDllDataChunk->iSize==0)
+			FreeDllDataChunk();
+		}
+	__KTRACE_OPT(KDLL,Kern::Printf("CommitDllData returns %d",r));
+	return r;
+	}
+
+void DMemModelProcess::DecommitDllData(TLinAddr aBase, TInt aSize)
+	{
+	__KTRACE_OPT(KDLL,Kern::Printf("DMemModelProcess %O DecommitDllData %08x+%x",this,aBase,aSize));
+	TInt offset=aBase-(TLinAddr)iDllDataChunk->iBase;
+	TInt r=iDllDataChunk->Decommit(offset, aSize);
+	__ASSERT_ALWAYS(r==KErrNone,MM::Panic(MM::EDecommitInvalidDllDataAddress));
+	if (iDllDataChunk->iSize==0)
+		FreeDllDataChunk();
+	}
+
+TInt DMemModelProcess::NewShPool(DShPool*& /* aPool */, TShPoolCreateInfo& /* aInfo */)
+	{
+	return KErrNotSupported;
+	}
+
+
+TInt DThread::RawRead(const TAny* aSrc, TAny* aDest, TInt aLength, TInt aFlags, TIpcExcTrap* /*aExcTrap*/)
+//
+// Read from the thread's process.
+// Enter and return with system locked
+// aSrc      Run address of memory to read
+// aDest     Current address of destination
+// aExcTrap  Exception trap object to be updated if the actual memory access is performed on other memory area then specified.
+//           It happens when  reading is performed on un-aligned memory area.
+//
+	{
+	Mmu& m=Mmu::Get();
+	DMemModelThread& t=*(DMemModelThread*)TheCurrentThread;
+	DMemModelProcess* pP=(DMemModelProcess*)iOwningProcess;
+	TLinAddr src=(TLinAddr)aSrc;
+	TLinAddr dest=(TLinAddr)aDest;
+	TBool localIsSafe=ETrue;
+	TInt result = KErrNone;
+
+	while (aLength)
+		{
+		if (iMState==EDead)
+			{
+			result = KErrDied;
+			break;
+			}
+		TLinAddr alias_src;
+		TInt alias_size;
+		TInt alias_result=t.Alias(src, pP, aLength, EMapAttrReadUser, alias_src, alias_size);
+		if (alias_result<0)
+			{
+			result = KErrBadDescriptor;	// bad permissions
+			break;
+			}
+		NKern::UnlockSystem();
+
+		__KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawRead %08x<-%08x+%x",dest,alias_src,alias_size));
+		if(aFlags&KCheckLocalAddress)
+			localIsSafe = m.ValidateLocalIpcAddress(dest,alias_size,ETrue);
+
+		CHECK_PAGING_SAFE;
+
+		COND_UNLOCK_USER_MEMORY(localIsSafe);
+
+		if(alias_result)
+			{
+			// remote address is safe for direct access...
+			if (localIsSafe)
+				memcpy( (TAny*)dest, (const TAny*)alias_src, alias_size);
+			else
+				umemput( (TAny*)dest, (const TAny*)alias_src, alias_size);
+			}
+		else
+			{
+			// remote address is NOT safe for direct access, so use user permision checks when reading...
+			if (localIsSafe)
+				umemget( (TAny*)dest, (const TAny*)alias_src, alias_size);
+			else
+				uumemcpy( (TAny*)dest, (const TAny*)alias_src, alias_size);
+			}
+
+		LOCK_USER_MEMORY();
+
+		src+=alias_size;
+		dest+=alias_size;
+		aLength-=alias_size;
+		NKern::LockSystem();
+		}
+	t.RemoveAlias();
+	return result;
+	}
+
+TInt DThread::RawWrite(const TAny* aDest, const TAny* aSrc, TInt aLength, TInt aFlags, DThread* anOriginatingThread, TIpcExcTrap* /*aExcTrap*/)
+//
+// Write to the thread's process.
+// Enter and return with system locked
+// aDest               Run address of memory to write
+// aSrc                Current address of destination
+// anOriginatingThread The thread on behalf of which this operation is performed (eg client of device driver).
+// aExcTrap            Exception trap object to be updated if the actual memory access is performed on other memory area then specified.
+//                     It happens when reading is performed on un-aligned memory area.
+//
+	{
+	Mmu& m=Mmu::Get();
+	DMemModelThread& t=*(DMemModelThread*)TheCurrentThread;
+	DMemModelProcess* pP=(DMemModelProcess*)iOwningProcess;
+	TLinAddr src=(TLinAddr)aSrc;
+	TLinAddr dest=(TLinAddr)aDest;
+	TBool localIsSafe=ETrue;
+	DThread* pO=anOriginatingThread?anOriginatingThread:&t;
+	DProcess* pF=K::TheFileServerProcess;
+	TBool special=(iOwningProcess==pF && pO->iOwningProcess==pF);
+	TUint32 perm=special ? EMapAttrWriteSup : EMapAttrWriteUser;
+	TInt result = KErrNone;
+
+	while (aLength)
+		{
+		if (iMState==EDead)
+			{
+			result = KErrDied;
+			break;
+			}
+		TLinAddr alias_dest;
+		TInt alias_size;
+		TInt alias_result=t.Alias(dest, pP, aLength, perm, alias_dest, alias_size);
+		if (alias_result<0)
+			{
+			result = KErrBadDescriptor;	// bad permissions
+			break;
+			}
+		NKern::UnlockSystem();
+
+		__KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawWrite %08x+%x->%08x",src,alias_size,alias_dest));
+		if(aFlags&KCheckLocalAddress)
+			localIsSafe = m.ValidateLocalIpcAddress(src,alias_size,EFalse);
+
+		// Must check that it is safe to page, unless we are reading from unpaged ROM in which case
+		// we allow it.  umemget and uumemcpy do this anyway, so we just need to check if
+		// localIsSafe is set.
+		if (localIsSafe)
+			{
+			CHECK_PAGING_SAFE_RANGE(src, aLength);
+			CHECK_DATA_PAGING_SAFE_RANGE(dest, aLength);
+			}
+
+		COND_UNLOCK_USER_MEMORY(localIsSafe);
+
+		if(alias_result)
+			{
+			// remote address is safe for direct access...
+			if (localIsSafe)
+				memcpy( (TAny*)alias_dest, (const TAny*)src, alias_size);
+			else
+				umemget( (TAny*)alias_dest, (const TAny*)src, alias_size);
+			}
+		else
+			{
+			// remote address is NOT safe for direct access, so use user permision checks when writing...
+			if (localIsSafe)
+				umemput( (TAny*)alias_dest, (const TAny*)src, alias_size);
+			else
+				uumemcpy( (TAny*)alias_dest, (const TAny*)src, alias_size);
+			}
+
+		LOCK_USER_MEMORY();
+
+		src+=alias_size;
+		dest+=alias_size;
+		aLength-=alias_size;
+		NKern::LockSystem();
+		}
+	t.RemoveAlias();
+	return result;
+	}
+
+#ifdef __DEBUGGER_SUPPORT__
+
+/**
+@pre Calling thread must be in critical section
+@pre CodeSeg mutex held
+*/
+TInt CodeModifier::SafeWriteCode(DProcess* aProcess, TLinAddr aAddress, TInt aSize, TUint aValue, void* aOldValue)
+	{
+	Mmu& m=Mmu::Get();
+	MmuBase::Wait();
+
+	NKern::LockSystem();
+
+	// Find physical address of the page, the breakpoint belongs to
+	TPhysAddr physAddr = m.LinearToPhysical(aAddress,((DMemModelProcess*)aProcess)->iOsAsid);
+	__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::SafeWriteCode - PA:%x", physAddr));
+	if (physAddr==KPhysAddrInvalid)
+		{
+		__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::SafeWriteCode - invalid VA"));
+		NKern::UnlockSystem();
+		MmuBase::Signal();
+		return KErrBadDescriptor;
+		}
+
+	// Temporarily map physical page
+	TLinAddr tempAddr = m.MapTemp (physAddr&~m.iPageMask, aAddress);
+	tempAddr |=  aAddress & m.iPageMask;
+	__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::SafeWriteCode - tempAddr:%x",tempAddr));
+
+	//Set exception handler. Make sure the boundaries cover the worst case (aSize = 4)
+	TIpcExcTrap xt;
+	xt.iLocalBase=0;
+	xt.iRemoteBase=(TLinAddr)tempAddr&~3; //word aligned.
+	xt.iSize=sizeof(TInt);
+	xt.iDir=1;
+
+	TInt r=xt.Trap(NULL);
+	if (r==0)
+		{
+		r = WriteCode(tempAddr, aSize, aValue, aOldValue);
+		xt.UnTrap();
+		}
+
+	m.UnmapTemp();
+	NKern::UnlockSystem();
+	MmuBase::Signal();
+	return r;	
+	}
+
+/**
+@pre Calling thread must be in critical section
+@pre CodeSeg mutex held
+*/
+TInt CodeModifier::WriteCode(TLinAddr aAddress, TInt aSize, TUint aValue, void* aOldValue)
+	{
+	// We do not want to be interrupted by e.g. ISR that will run altered code before IMB-Range.
+	// Therefore, copy data and clean/invalidate caches with interrupts disabled.
+	TInt irq=NKern::DisableAllInterrupts();
+	switch(aSize)
+		{
+		case 1:
+			*(TUint8*) aOldValue = *(TUint8*)aAddress;
+			*(TUint8*) aAddress  = (TUint8)aValue;
+			 break;
+		case 2:
+			*(TUint16*) aOldValue = *(TUint16*)aAddress;
+			*(TUint16*) aAddress  = (TUint16)aValue;
+			 break;
+		default://It is 4 otherwise
+			*(TUint32*) aOldValue = *(TUint32*)aAddress;
+			*(TUint32*) aAddress  = (TUint32)aValue;
+			 break;
+		};
+	CacheMaintenance::CodeChanged(aAddress, aSize, CacheMaintenance::ECodeModifier);
+	NKern::RestoreInterrupts(irq);
+	return KErrNone;
+	}
+#endif //__DEBUGGER_SUPPORT__
+
+
+#ifdef __MARM__
+
+// the body of ReadDesHeader is machine coded on ARM...
+extern TInt ThreadDoReadAndParseDesHeader(DThread* aThread, const TAny* aSrc, TUint32* aDest);
+
+TInt DThread::ReadAndParseDesHeader(const TAny* aSrc, TDesHeader& aDest)
+//
+// Read and parse the header of a remote descriptor.
+// Enter and return with system locked
+//
+	{
+	// todo: remove use of system lock from callers, when they have been un-exported from the kernel
+	NKern::UnlockSystem();	
+	TInt r = ThreadDoReadAndParseDesHeader(this,aSrc,(TUint32*)&aDest);
+	NKern::LockSystem();
+	return r;
+	}
+
+
+#else // !__MARM__
+
+
+TInt DThread::ReadAndParseDesHeader(const TAny* aSrc, TDesHeader& aDest)
+//
+// Read and parse the header of a remote descriptor.
+// Enter and return with system locked
+//
+	{
+	static const TUint8 LengthLookup[16] = {4,8,12,8,12,0,0,0,0,0,0,0,0,0,0,0};
+
+	DMemModelThread& t = *(DMemModelThread*)TheCurrentThread;
+	TInt r = KErrBadDescriptor;
+
+	CHECK_PAGING_SAFE;
+
+	DMemModelProcess* pP = (DMemModelProcess*)iOwningProcess;
+	TLinAddr src = (TLinAddr)aSrc;
+	const TUint32* pAlias;
+	TInt alias_size;
+	TInt alias_result = t.Alias(src, pP, 12, EMapAttrReadUser, (TLinAddr&)pAlias, alias_size);
+	if (alias_result<0)
+		return KErrBadDescriptor;	// bad permissions
+	NKern::UnlockSystem();
+	t.iIpcClient = this;
+	TUint32* dest = (TUint32*)&aDest;
+	if (Kern::SafeRead(pAlias, dest, sizeof(TUint32)))
+		goto fail;
+
+	{
+	TInt type=*dest>>KShiftDesType8;
+
+	src += sizeof(TUint32);
+	alias_size -=  sizeof(TUint32);
+	++pAlias;
+	++dest;
+
+	TInt l=LengthLookup[type];
+	if (l==0)
+		goto fail;
+
+	l -= sizeof(TUint32); // we've already read one word
+	if (l>0 && alias_size)
+		{
+get_more:
+		// more to go - get rest or as much as is currently aliased
+		TInt ll = alias_size>=l ? l : alias_size;
+		if(Kern::SafeRead(pAlias, dest, l))
+			goto fail;
+		l -= ll;
+		src += TLinAddr(ll);
+		dest = (TUint32*)(TLinAddr(dest) + TLinAddr(ll));
+		}
+	if (l>0)
+		{
+		// more to go - need to step alias on
+		NKern::LockSystem();
+		alias_result = t.Alias(src, pP, l, EMapAttrReadUser, (TLinAddr&)pAlias, alias_size);
+		if (alias_result<0)
+			goto fail_locked;
+		NKern::UnlockSystem();
+		goto get_more;
+		}
+
+	r = K::ParseDesHeader(aSrc, *(TRawDesHeader*)&aDest, aDest);
+	}
+
+fail:
+	NKern::LockSystem();
+fail_locked:
+	t.RemoveAlias();
+	t.iIpcClient = NULL;
+	return r;
+	}
+
+
+#endif
+
+
+DChunk* DThread::OpenSharedChunk(const TAny* aAddress, TBool aWrite, TInt& aOffset)
+	{
+	NKern::LockSystem();
+	
+	DMemModelProcess* pP = (DMemModelProcess*)iOwningProcess;
+	DMemModelProcess::SChunkInfo* pS=pP->iChunks;
+	DMemModelProcess::SChunkInfo* pC=pS+pP->iChunkCount;
+	while(--pC>=pS && TUint(pC->iChunk->Base())>TUint(aAddress)) {};
+	if(pC>=pS)
+		{
+		DMemModelChunk* chunk = pC->iChunk;
+		if(chunk->iChunkType==ESharedKernelSingle || chunk->iChunkType==ESharedKernelMultiple)
+			{
+			TInt offset = (TInt)aAddress-(TInt)chunk->Base();
+			if(TUint(offset)<TUint(chunk->iMaxSize) && chunk->Open()==KErrNone)
+				{
+				aOffset = offset;
+				NKern::UnlockSystem();
+				return chunk;
+				}
+			}
+		}
+	NKern::UnlockSystem();
+	return 0;
+	}
+
+TInt DThread::PrepareMemoryForDMA(const TAny* aLinAddr, TInt aSize, TPhysAddr* aPhysicalPageList)
+	{
+	TInt asid = ((DMemModelProcess*)iOwningProcess)->iOsAsid;
+	Mmu& m=(Mmu&)*MmuBase::TheMmu;
+	return m.PreparePagesForDMA((TLinAddr)aLinAddr, aSize, asid, aPhysicalPageList);
+	}
+
+TInt DThread::ReleaseMemoryFromDMA(const TAny* aLinAddr, TInt aSize, TPhysAddr* aPhysicalPageList)
+	{
+	TInt pageCount = (((TInt)aLinAddr & KPageMask) + aSize + KPageMask) >> KPageShift;
+	Mmu& m=(Mmu&)*MmuBase::TheMmu;
+	return m.ReleasePagesFromDMA(aPhysicalPageList, pageCount);
+	}
+