kernel/eka/memmodel/epoc/moving/mprocess.cpp
changeset 0 a41df078684a
child 90 947f0dc9f7a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/memmodel/epoc/moving/mprocess.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,960 @@
+// 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\moving\mprocess.cpp
+// 
+//
+
+#include "memmodel.h"
+#include "cache_maintenance.h"
+#include "mmboot.h"
+
+#define iMState		iWaitLink.iSpare1
+
+_LIT(KDollarDat,"$DAT");
+_LIT(KLitDllDollarData,"DLL$DATA");
+
+/********************************************
+ * Process
+ ********************************************/
+void DMemModelProcess::Destruct()
+	{
+	NKern::LockSystem();
+	if (this==TheCurrentAddressSpace)
+		TheCurrentAddressSpace=NULL;
+	if (this==TheCurrentVMProcess)
+		TheCurrentVMProcess=NULL;
+	if (this==TheCurrentDataSectionProcess)
+		TheCurrentDataSectionProcess=NULL;
+	if (this==TheCompleteDataSectionProcess)
+		TheCompleteDataSectionProcess=NULL;
+	NKern::UnlockSystem();
+	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;
+		}
+	if (aInfo.iForceFixed || iAttributes & DMemModelProcess::EFixedAddress)
+		pC->iAttributes |= DMemModelChunk::EFixedAddress;
+	if (!aInfo.iGlobal && (iAttributes & DMemModelProcess::EPrivate)!=0)
+		pC->iAttributes |= DMemModelChunk::EPrivate;
+	if (pC->iChunkType==EDll || pC->iChunkType==EUserCode || pC->iChunkType==EUserSelfModCode || pC->iChunkType==EKernelCode)
+		pC->iAttributes |= (DMemModelChunk::EFixedAddress|DMemModelChunk::ECode);
+	pC->iOwningProcess=(aInfo.iGlobal)?NULL:this;
+	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)
+			{
+			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 && pC->iHomeRegionBase==0 && (pC->iAttributes&DMemModelChunk::EFixedAddress)!=0)
+			{
+			r=pC->Reserve(0);
+			aRunAddr=(TLinAddr)pC->Base();
+			}
+		}
+	if (r==KErrNone && (aInfo.iOperations & SChunkCreateInfo::EAdd))
+		{
+		if (pC->iAttributes & DMemModelChunk::ECode)
+			Mmu::Get().SyncCodeMappings();
+		if (pC->iChunkType!=EUserCode)
+			{
+			r=WaitProcessLock();
+			if (r==KErrNone)
+				{
+				r=AddChunk(pC,aRunAddr,EFalse);
+				SignalProcessLock();
+				}
+			}
+		else
+			aRunAddr=(TLinAddr)pC->Base();	// code chunks always fixed address
+		}
+	if (r==KErrNone)
+		{
+		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));
+
+	if (aKernelProcess)
+		iAttributes=ESupervisor|EFixedAddress|EPrivate;
+	else if (aInfo.iAttr & ECodeSegAttFixed)
+		iAttributes=EFixedAddress|EPrivate;
+	else
+		iAttributes=0;
+	if ((iAttributes & ESupervisor)==0 && (iAttributes & EFixedAddress)!=0)
+		{
+		CheckForFixedAccess();
+		}
+	return KErrNone;
+	}
+
+TInt DMemModelProcess::CreateDataBssStackArea(TProcessCreateInfo& aInfo)
+	{
+	__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::CreateDataBssStackArea %O",this));
+	TInt dataBssSize=Mmu::RoundToPageSize(aInfo.iTotalDataSize);
+	TInt maxSize=dataBssSize+PP::MaxStackSpacePerProcess;
+	TBool fixed=(iAttributes & EFixedAddress);
+
+	__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;
+	if (fixed && dataBssSize!=0 && aInfo.iCodeLoadAddress)
+		{
+		const TRomImageHeader& rih=*(const TRomImageHeader*)aInfo.iCodeLoadAddress;
+		cinfo.iRunAddress=rih.iDataBssLinearBase;
+		}
+	else
+		cinfo.iRunAddress=0;
+	TInt r=NewChunk((DChunk*&)iDataBssStackChunk,cinfo,iDataBssRunAddress);
+	return r;
+	}
+
+TInt DMemModelProcess::AddChunk(DChunk* aChunk,TBool isReadOnly)
+	{
+	DMemModelChunk* pC=(DMemModelChunk*)aChunk;
+	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 FlushBeforeChunkMove(DMemModelChunk* aChunk)
+	{
+	Mmu& m = Mmu::Get();
+	TUint32 ff=Mmu::EFlushDMove|Mmu::EFlushDPermChg;
+	if (aChunk->iAttributes & DMemModelChunk::ECode)		// assumption here that code chunks don't move
+		ff |= Mmu::EFlushIPermChg;
+	m.GenericFlush(ff);
+	}
+
+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 %08x to %08x (for first time)",aChunk,this));
+	TInt r=AllocateDataSectionBase(*((DMemModelChunk*)aChunk),(TUint&)aDataSectionBase);
+	if(r!=KErrNone)
+		return r;
+
+	if (iNumChunks==KMaxChunksInProcess)
+		return KErrOverflow;		// too many chunks in the process
+
+	SChunkInfo *pC=iChunks;
+	SChunkInfo *pE=pC+iNumChunks-1;
+	NKern::LockSystem();
+	while(pE>=pC && TUint(pE->iDataSectionBase)>TUint(aDataSectionBase))
+		{
+		pE[1]=pE[0];
+		pE--;
+		}
+	pC=pE+1;
+	pC->iDataSectionBase=aDataSectionBase;
+	pC->isReadOnly=isReadOnly;
+	pC->iAccessCount=1;
+	pC->iChunk=aChunk;
+	iNumChunks++;
+
+	if(!(iAttributes&ESupervisor))
+		{
+		TInt attribs=aChunk->iAttributes;
+		if (!(attribs&DMemModelChunk::EFixedAddress))
+			{
+			iNumMovingChunks++;
+			iAttributes |= EMoving;
+			}
+
+		if (attribs&DMemModelChunk::EFixedAccess)
+			{
+			NKern::UnlockSystem();
+			AddFixedAccessChunk(aChunk);
+			goto done;	// FINISHED
+			}
+
+		iAttributes |= EVariableAccess;
+		if (attribs & DMemModelChunk::ECode)
+			{
+			iNumNonFixedAccessCodeChunks++;
+			iAttributes |= EVariableCode;
+			}
+		if (++iNumNonFixedAccessChunks==1)
+			{
+			NKern::UnlockSystem();
+			DoAttributeChange();	// change process from fixed to variable access
+			NKern::LockSystem();
+			}
+
+		if (this!=TheCurrentThread->iOwningProcess)
+			{
+			// Adding chunk to another process
+			if (this==TheCurrentDataSectionProcess && !(attribs&DMemModelChunk::EFixedAddress))
+				TheCompleteDataSectionProcess=NULL;	// just set partial state change flag and leave chunk alone
+			if (this==TheCurrentAddressSpace)
+				TheCurrentAddressSpace=NULL;
+			NKern::UnlockSystem();
+			goto done;	// FINISHED
+			}
+
+		// Adding chunk to currently active user process
+		{
+		TheCurrentAddressSpace=NULL;
+		Mmu& m = Mmu::Get();
+		TUint32 ff=0;	// flush flags
+		DMemModelChunk::TChunkState state=isReadOnly?DMemModelChunk::ERunningRO:DMemModelChunk::ERunningRW;
+		if (attribs&DMemModelChunk::EFixedAddress)
+			{
+			// Fixed address chunk, just change permissions
+			ff|=aChunk->ApplyTopLevelPermissions(state);
+			}
+		else if (this==TheCurrentDataSectionProcess)
+			{
+			// Moving chunk.
+			// This process is already in the data section, so just move the chunk down.
+			// Must do flushing first
+			TheCompleteDataSectionProcess=NULL;
+			FlushBeforeChunkMove(aChunk);
+			aChunk->MoveToRunAddress(aDataSectionBase,state);	// idempotent
+			TheCompleteDataSectionProcess=this;
+			}
+		else if (iNumMovingChunks==1)
+			{
+			// The first moving chunk being added to a process with the data section occupied by another process.
+			// This is the problematic case - we must displace the other process from the data section.
+			// However we must allow preemption after each chunk is moved. Note that if a reschedule does
+			// occur the necessary chunk moves will have been done by the scheduler, so we can finish
+			// immediately.
+			// Must do cache flushing first
+			m.GenericFlush(Mmu::EFlushDMove);
+			if (TheCurrentDataSectionProcess)
+				{
+				if (TheCurrentDataSectionProcess->iAttributes & EVariableCode)
+					ff |= Mmu::EFlushIPermChg;
+				SChunkInfo* pOtherProcChunks=TheCurrentDataSectionProcess->iChunks;
+				SChunkInfo* pEndOtherProcChunks=pOtherProcChunks+TheCurrentDataSectionProcess->iNumChunks;
+				NKern::FlashSystem();
+				// if a reschedule occurs, TheCompleteDataSectionProcess will become equal to this
+				while (TheCompleteDataSectionProcess!=this && pOtherProcChunks<pEndOtherProcChunks)
+					{
+					DMemModelChunk *pChunk=pOtherProcChunks->iChunk;
+					pChunk->MoveToHomeSection();
+					++pOtherProcChunks;
+					TheCompleteDataSectionProcess=NULL;
+					NKern::FlashSystem();
+					}
+				}
+			if (TheCompleteDataSectionProcess!=this)
+				{
+				if (attribs & DMemModelChunk::ECode)
+					ff |= Mmu::EFlushIPermChg;
+				aChunk->MoveToRunAddress(aDataSectionBase,state);
+				TheCurrentDataSectionProcess=this;
+				TheCompleteDataSectionProcess=this;
+				}
+			}
+		TheCurrentAddressSpace=this;
+		TheCurrentVMProcess=this;
+		if (ff)
+			m.GenericFlush(ff);
+		}
+	}
+	NKern::UnlockSystem();
+done:
+	__KTRACE_OPT(KPROC,Kern::Printf("Added array entry for %x",aDataSectionBase));
+	__KTRACE_OPT(KPROC,Kern::Printf("Chunks maxsize %x",pC->iChunk->MaxSize()));
+	__DEBUG_EVENT(EEventUpdateProcess, this);
+	return KErrNone;
+	}
+
+TInt DMemModelProcess::AllocateDataSectionBase(DMemModelChunk& aChunk, TUint& aBase)
+	{
+	__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::AllocateDataSectionBase"));
+	aBase=0;
+	if ((aChunk.iAttributes & DMemModelChunk::EPrivate) && this!=aChunk.iOwningProcess)
+		return KErrAccessDenied;
+	if (aChunk.iAttributes & DMemModelChunk::EFixedAddress)
+		{
+		aBase=aChunk.iHomeRegionBase;
+		return KErrNone;
+		}
+	Mmu& m = Mmu::Get();
+	TLinAddr base=0;
+	TLinAddr maxBase=0;
+	switch (aChunk.iChunkType)
+		{
+	case EUserData:
+		base=m.iDataSectionBase;
+		maxBase=m.iDllDataBase;
+		break;
+	case EUserCode:
+	case EUserSelfModCode:
+		MM::Panic(MM::EUserCodeNotFixed);
+		break;
+	case EDllData:
+		aBase=m.iDllDataBase;
+		return KErrNone;
+	default:
+		__KTRACE_OPT(KPANIC,Kern::Printf("DMemModelProcess::AllocateDataSectionBase BadChunkType %d",aChunk.iChunkType));
+		return KErrAccessDenied;
+		}
+
+	TLinAddr lastBase=base;
+	SChunkInfo *pS=iChunks;
+	SChunkInfo *pE=pS+iNumChunks;
+	while (pS<pE)
+		{
+		TLinAddr thisBase=pS->iDataSectionBase;
+		__KTRACE_OPT(KPROC,Kern::Printf("Chunk already at %x",thisBase));
+		if (thisBase>=maxBase)
+			break;
+		if (thisBase>=base) // Within the range we are allocating
+			{
+			TInt gap=thisBase-lastBase;
+			if (gap>=aChunk.MaxSize())
+				break;
+			lastBase=thisBase+pS->iChunk->MaxSize();
+			}
+		pS++;
+		}
+	if (lastBase+aChunk.MaxSize()>maxBase)
+		{
+		__KTRACE_OPT(KPROC,Kern::Printf("ERROR - none allocated, out of memory"));
+		return KErrNoMemory;
+		}
+	aBase=lastBase;
+	__KTRACE_OPT(KPROC,Kern::Printf("User allocated %x",aBase));
+	return KErrNone;
+	}
+
+TUint8* DMemModelProcess::DataSectionBase(DMemModelChunk* aChunk)
+	{
+	// this can't be called after $LOCK is deleted
+	Kern::MutexWait(*iProcessLock);
+	TInt pos=0;
+	TInt r=ChunkIndex(aChunk,pos);
+	if (r==0) // Found the chunk
+		{
+		TUint8* answer=((TUint8*)iChunks[pos].iDataSectionBase);
+		__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::DataSectionBase %x",answer));
+		Kern::MutexSignal(*iProcessLock);
+		return answer;
+		}
+	__KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::DataSectionBase chunk %08x not present in %08x",aChunk,this));
+	Kern::MutexSignal(*iProcessLock);
+	return(NULL);
+	}
+
+void DMemModelProcess::DoRemoveChunk(TInt aIndex)
+	{
+	// Must be called with process $LOCK mutex held
+	__DEBUG_EVENT(EEventUpdateProcess, this);
+	DMemModelChunk* chunk = iChunks[aIndex].iChunk;
+	Mmu& m = Mmu::Get();
+	NKern::LockSystem();
+	TInt attribs=chunk->iAttributes;
+	__KTRACE_OPT(KPROC,Kern::Printf("Removing Chunk attribs=%08x, Process attribs=%08x",attribs,iAttributes));
+	if (!(attribs&DMemModelChunk::EFixedAccess))
+		{
+		// Must leave chunk in process chunk list until we have flushed the cache if necessary
+		if (this==TheCurrentVMProcess && (attribs&DMemModelChunk::EFixedAddress))
+			{
+			TUint32 ff=chunk->ApplyTopLevelPermissions(DMemModelChunk::ENotRunning);
+			m.GenericFlush(ff);
+			// the system must now remain locked until the chunk is removed from the process chunk list
+			}
+		if (this==TheCurrentDataSectionProcess && !(attribs&DMemModelChunk::EFixedAddress))
+			{
+			// must do cache flush first
+			FlushBeforeChunkMove(chunk);	// preemptible, but on return cache is free of chunk data
+			chunk->MoveToHomeSection();
+			// the system must now remain locked until the chunk is removed from the process chunk list
+			}
+		}
+
+	// Remove the chunk from the process chunk list
+	SChunkInfo *pD=iChunks+aIndex;
+	SChunkInfo *pS=iChunks+aIndex+1;
+	SChunkInfo *pE=iChunks+iNumChunks;
+	while(pS<pE)
+		*pD++=*pS++;
+	iNumChunks--;
+
+	// Update the process attribute flags
+	if (!(attribs&DMemModelChunk::EFixedAddress))
+		{
+		if (--iNumMovingChunks==0)
+			iAttributes &= ~EMoving;
+		}
+	if (!(attribs&DMemModelChunk::EFixedAccess))
+		{
+		if ((attribs&DMemModelChunk::ECode) && --iNumNonFixedAccessCodeChunks==0)
+				iAttributes &= ~EVariableCode;
+		if (this==TheCurrentDataSectionProcess && !(iAttributes&EMoving))
+			{
+			TheCurrentDataSectionProcess=NULL;
+			TheCompleteDataSectionProcess=NULL;
+			}
+		if (--iNumNonFixedAccessChunks==0)
+			{
+			iAttributes &= ~EVariableAccess;
+			if (this==TheCurrentVMProcess)
+				{
+				TheCurrentVMProcess=NULL;
+				TheCurrentAddressSpace=NULL;
+				}
+			NKern::UnlockSystem();
+			DoAttributeChange();	// change process from variable to fixed access
+			}
+		else
+			NKern::UnlockSystem();
+		}
+	else
+		{
+		NKern::UnlockSystem();
+		RemoveFixedAccessChunk(chunk);
+		}
+	}
+
+/**
+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)
+	while(iNumChunks)
+		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::RemoveChunk %08x from %08x",aChunk,this));
+	Kern::MutexWait(*iProcessLock);
+	TInt pos=0;
+	TInt r=ChunkIndex(aChunk,pos);
+	__KTRACE_OPT(KPROC,if(r) Kern::Printf("Chunk lookup failed with %d",r));
+	if (r==0) // Found the chunk
+		{
+		__KTRACE_OPT(KPROC,Kern::Printf("Chunk access count %d",iChunks[pos].iAccessCount));
+		if (--iChunks[pos].iAccessCount==0)
+			DoRemoveChunk(pos);
+		}
+	Kern::MutexSignal(*iProcessLock);
+	}
+
+TInt DMemModelProcess::ChunkIndex(DMemModelChunk* aChunk,TInt& aPos)
+	{
+	if (aChunk==NULL)
+		return(KErrNotFound);
+	TInt i=0;
+	SChunkInfo *pC=iChunks;
+	SChunkInfo *pE=pC+iNumChunks;
+	while(pC<pE && (pC->iChunk!=aChunk))
+		{
+		pC++;
+		i++;
+		}
+	if (pC==pE)
+		return KErrNotFound;
+	aPos=i;
+	return KErrNone;
+	}
+
+void DMemModelProcess::RemoveDllData()
+//
+// Call with CodeSegLock held
+//
+	{
+	Kern::SafeClose((DObject*&)iDllDataChunk, this);
+	}
+
+TInt DMemModelProcess::CreateDllDataChunk()
+//
+// Call with CodeSegLock held
+//
+	{
+	__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=0;
+	c.iPreallocated=0;
+	c.iType=EDllData;
+	c.iMaxSize=(iAttributes&EFixedAddress) ? 1 : m.iMaxDllDataSize;	// minimal size for fixed processes
+	c.iName.Set(KLitDllDollarData);
+	c.iOwner=this;
+	c.iInitialBottom=0;
+	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)
+		{
+		Mmu& m = Mmu::Get();
+		TLinAddr dll_data_base=(iAttributes & EFixedAddress) ? (TLinAddr)iDllDataChunk->Base()
+														: TLinAddr(m.iDllDataBase);
+		TInt offset=aBase-dll_data_base;
+		__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));
+	Mmu& m = Mmu::Get();
+	TLinAddr dll_data_base=(iAttributes & EFixedAddress) ? (TLinAddr)iDllDataChunk->Base()
+													: TLinAddr(m.iDllDataBase);
+	TInt offset=aBase-dll_data_base;
+	TInt r=iDllDataChunk->Decommit(offset, aSize);
+	__ASSERT_ALWAYS(r==KErrNone,MM::Panic(MM::EDecommitInvalidDllDataAddress));
+	if (iDllDataChunk->iSize==0)
+		FreeDllDataChunk();
+	}
+
+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 || seg.iDataAllocBase==-1)
+		return KErrNone;	// no extra mappings needed for kernel code or code with fixed data address
+	TInt r=KErrNone;
+	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);
+			}
+		}
+	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 || seg.iDataAllocBase==-1)
+		return;	// no extra mappings needed for kernel code or code with fixed data address
+	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));
+		}
+	}
+
+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.
+// aSrc is run address of memory to read. The memory is in aThread's address space.
+// aDest is the address of destination. The memory is in the current process's address space.
+// aExcTrap, exception trap object to be updated if the actual memory access is performed on another memory area. It happens 
+//           when  reading is performed in chunks or if home adress is read instead of the provided run address.
+// Enter and return with system locked.
+	{
+	const TUint8* pS=(const TUint8*)aSrc;
+	TUint8* pD=(TUint8*)aDest;
+	const TUint8* pC=NULL;
+	TBool check=ETrue;
+	TBool suspect=EFalse;
+	DThread* pT=TheCurrentThread;
+	while (aLength)
+		{
+		if (check)
+			{
+			suspect=((aFlags & KCheckLocalAddress) && !MM::CurrentAddress(pT,pD,aLength,ETrue));
+			if (iMState==EDead)
+				return KErrDied;
+			pC=(const TUint8*)MM::CurrentAddress(this,pS,aLength,EFalse);
+			__KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawRead %08x<-[%08x::%08x]%08x+%x",pD,this,pS,pC,aLength));
+			if (!pC)
+				return KErrBadDescriptor;
+			}
+		TInt len=Min(aLength,K::MaxMemCopyInOneGo);
+		if (aExcTrap)
+			{
+			aExcTrap->iSize = (len + 2*(sizeof(TInt32)-1));//+6 is for the worst case. We do not have to be precise here.
+			aExcTrap->iRemoteBase = (TLinAddr)pC & ~(sizeof(TInt32)-1);		
+			if (aExcTrap->iLocalBase)
+				aExcTrap->iLocalBase = (TLinAddr)pD & ~(sizeof(TInt32)-1);
+			__KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawRead exc. update: %08x %08x %08x",aExcTrap->iLocalBase,aExcTrap->iRemoteBase,aExcTrap->iSize));
+			}
+
+#ifdef __DEMAND_PAGING__
+		XTRAP_PAGING_START(check);
+		CHECK_PAGING_SAFE;
+#endif
+
+		suspect?(void)umemput(pD,pC,len):(void)memcpy(pD,pC,len);
+
+#ifdef __DEMAND_PAGING__
+		XTRAP_PAGING_END;
+		if(check<0)
+			return check; // paging error caused by bad client (I.e. 'this' thread was bad)
+		if(check)
+			{
+			__KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawRead paging trap, suspect %d, dest %08x, source %08x, length %d\n", suspect, pD, pC, len));
+			continue;
+			}
+#endif
+
+		pD+=len;
+		pS+=len;
+		pC+=len;
+		aLength-=len;
+		if (aLength)
+			check=NKern::FlashSystem();
+		}
+	return KErrNone;
+	}
+
+TInt DThread::RawWrite(const TAny* aDest, const TAny* aSrc, TInt aLength, TInt aFlags, DThread* aOriginatingThread, TIpcExcTrap* aExcTrap)
+//
+// Write to the thread's process.
+// aDest is run address of memory to write. It resides in this thread's address space.
+// aSrc is address of the source buffer. It resides in the current process's address space.
+// aOriginatingThread is the thread on behalf of which this operation is performed (eg client of device driver).
+// Enter and return with system locked
+// aExcTrap, exception trap object to be updated if the actual memory access is performed on another memory area. It happens 
+//           when  reading is performed in chunks or if home adress is read instead of the provided run address.
+//
+	{
+	TUint8* pD=(TUint8*)aDest;
+	const TUint8* pS=(const TUint8*)aSrc;
+	TUint8* pC=NULL;
+	TBool check=ETrue;
+	TBool suspect=EFalse;
+	DThread* pT=TheCurrentThread;
+	DThread* pO=aOriginatingThread;
+	if (!pO)
+		pO=pT;
+	DProcess* pF=K::TheFileServerProcess;
+	TBool special=(iOwningProcess==pF && pO->iOwningProcess==pF);
+	while (aLength)
+		{
+		if (check)
+			{
+			suspect=((aFlags & KCheckLocalAddress) && !MM::CurrentAddress(pT,pS,aLength,EFalse));
+			if (iMState==EDead)
+				return KErrDied;
+			pC=(TUint8*)MM::CurrentAddress(this,pD,aLength,ETrue);
+			__KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawRead [%08x::%08x]%08x<-%08x+%x",this,pD,pC,pS,aLength));
+			if (!pC)
+				{
+				if (special)
+					pC=pD;
+				else
+					return KErrBadDescriptor;
+				}
+			}
+		TInt len=Min(aLength,K::MaxMemCopyInOneGo);
+		if (aExcTrap)
+			{
+			aExcTrap->iSize = (len + 2*(sizeof(TInt32)-1));//+6 is for the worst case. We do not have to be precise here.
+			aExcTrap->iRemoteBase = (TLinAddr)pC & ~(sizeof(TInt32)-1);	
+			if (aExcTrap->iLocalBase)
+				aExcTrap->iLocalBase = (TLinAddr)pS & ~(sizeof(TInt32)-1);
+			__KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawWrite exc. update %08x %08x %08x",aExcTrap->iLocalBase,aExcTrap->iRemoteBase,aExcTrap->iSize));
+			}
+
+#ifdef __DEMAND_PAGING__
+		XTRAP_PAGING_START(check);
+		// Must check that it is safe to page, unless we are reading from unpaged ROM in which case
+		// we allow it.  umemget does this anyway, so we just need to check if suspect is not set.
+		if (!suspect)
+			{
+			CHECK_PAGING_SAFE_RANGE((TLinAddr)aSrc, aLength);
+			CHECK_DATA_PAGING_SAFE_RANGE((TLinAddr)aDest, aLength);
+			}
+#endif
+
+		suspect?(void)umemget(pC,pS,len):(void)memcpy(pC,pS,len);
+
+#ifdef __DEMAND_PAGING__
+		XTRAP_PAGING_END
+		if(check<0)
+			return check; // paging error caused by bad client (I.e. 'this' thread was bad)
+		if(check)
+			{
+			__KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawWrite paging trap, suspect %d, dest %08x, src %08x, length %d\n", suspect, pC, pD, len));
+			continue;
+			}
+#endif
+
+		pD+=len;
+		pS+=len;
+		pC+=len;
+		aLength-=len;
+		if (aLength)
+			check=NKern::FlashSystem();
+		}
+	return KErrNone;
+	}
+
+#ifdef __DEBUGGER_SUPPORT__
+
+TInt CodeModifier::SafeWriteCode(DProcess* aProcess, TLinAddr aAddress, TInt aSize, TUint aValue, void* aOldValue)
+	{
+	//Set exception handler. Make sure the boundaries cover the worst case (aSize = 4)
+	TIpcExcTrap xt;
+	xt.iLocalBase=0;
+	xt.iRemoteBase=(TLinAddr)aAddress&~3; //word aligned.
+	xt.iSize=sizeof(TInt);
+	xt.iDir=1;
+	NKern::LockSystem();
+	TInt r=xt.Trap(NULL);
+	if (r==0)
+		{
+		r = WriteCode(aAddress, aSize, aValue, aOldValue);
+		xt.UnTrap();
+		}
+	NKern::UnlockSystem();
+	return r;	
+	}
+
+TInt CodeModifier::WriteCode(TLinAddr aAddress, TInt aSize, TUint aValue, void* aOldValue)
+	{
+	TUint userChunkBase = (TUint)MM::UserCodeChunk->Base();
+	TRomHeader romHeader = Epoc::RomHeader();
+
+	if (!((aAddress >= romHeader.iRomBase ) && (aAddress < (romHeader.iRomBase + romHeader.iUncompressedSize))))  //if not in ROM
+		if ( (aAddress<userChunkBase) || (aAddress) > (userChunkBase+MM::UserCodeChunk->MaxSize()) ) //and not in non-XIP code
+			return KErrBadDescriptor;
+
+	// if page was moved by defrag there may be a cache line with the
+	// wrong, old physical address, so we must invalidate this first.
+	InternalCache::Invalidate(KCacheSelectD, (TLinAddr)aAddress, 4);
+
+	//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__
+
+TInt DThread::ReadAndParseDesHeader(const TAny* aSrc, TDesHeader& aDest)
+//
+// Read the header of a remote descriptor.
+// Enter and return with system locked
+//
+	{
+	TInt r=KErrBadDescriptor;
+	DThread* thread = TheCurrentThread;
+	TRawDesHeader& header = (TRawDesHeader&)aDest;
+
+#ifdef __DEMAND_PAGING__
+retry:
+	TInt pagingFault;
+	XTRAP_PAGING_START(pagingFault);
+	CHECK_PAGING_SAFE;
+	thread->iIpcClient = this;
+#endif
+
+	const TUint32* pS=(const TUint32*)MM::CurrentAddress(this,aSrc,sizeof(TDesC8),EFalse);
+	if (pS && KErrNone==Kern::SafeRead(pS,&header[0],sizeof(TUint32)))
+		{
+		TInt type=header[0]>>KShiftDesType8;
+		static const TUint8 LengthLookup[16]={4,8,12,8,12,0,0,0,0,0,0,0,0,0,0,0};
+		TInt len=LengthLookup[type];
+		if(len>(TInt)sizeof(TUint32))
+			{
+			if(KErrNone==Kern::SafeRead(pS+1,&header[1],len-sizeof(TUint32)))
+				r = type;
+			// else, bad descriptor
+			}
+		else if(len)
+			r = type;
+		// else, bad descriptor
+		}
+
+#ifdef __DEMAND_PAGING__
+	thread->iIpcClient = NULL;
+	XTRAP_PAGING_END;
+	if(pagingFault<0)
+		return pagingFault; // paging error caused by bad client (I.e. 'this' thread was bad)
+	if(pagingFault)
+		goto retry;
+#endif
+	
+	return K::ParseDesHeader(aSrc, header, aDest);
+	}
+
+DMemModelChunk* ChunkFromAddress(DThread* aThread, const TAny* aAddress)
+	{
+	DMemModelProcess* pP = (DMemModelProcess*)aThread->iOwningProcess;
+	DMemModelProcess::SChunkInfo* pS=pP->iChunks;
+	DMemModelProcess::SChunkInfo* pC=pS+pP->iNumChunks;
+	while(--pC>=pS && TUint(pC->iDataSectionBase)>TUint(aAddress)) {};
+	if(pC<pS)
+		return 0;
+	return pC->iChunk;
+	}
+
+/**
+	Open a shared chunk in which a remote address range is located.
+*/
+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->iNumChunks;
+	while(--pC>=pS && TUint(pC->iDataSectionBase)>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)
+	{
+	if ((iOwningProcess->iAttributes & DMemModelProcess::EFixedAddress )==0)
+		return KErrNotSupported;
+	Mmu& m=(Mmu&)*MmuBase::TheMmu;
+	return m.PreparePagesForDMA((TLinAddr)aLinAddr, aSize, aPhysicalPageList);
+	}
+
+TInt DThread::ReleaseMemoryFromDMA(const TAny* aLinAddr, TInt aSize, TPhysAddr* aPhysicalPageList)
+	{
+	if ((iOwningProcess->iAttributes & DMemModelProcess::EFixedAddress )==0)
+		return KErrNotSupported;
+	TInt pageCount = (((TInt)aLinAddr & KPageMask) + aSize + KPageMask) >> KPageShift;
+	Mmu& m=(Mmu&)*MmuBase::TheMmu;
+	return m.ReleasePagesFromDMA(aPhysicalPageList, pageCount);
+	}