sl@0: // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32\memmodel\epoc\moving\mprocess.cpp sl@0: // sl@0: // sl@0: sl@0: #include "memmodel.h" sl@0: #include "cache_maintenance.h" sl@0: #include "mmboot.h" sl@0: sl@0: #define iMState iWaitLink.iSpare1 sl@0: sl@0: _LIT(KDollarDat,"$DAT"); sl@0: _LIT(KLitDllDollarData,"DLL$DATA"); sl@0: sl@0: /******************************************** sl@0: * Process sl@0: ********************************************/ sl@0: void DMemModelProcess::Destruct() sl@0: { sl@0: NKern::LockSystem(); sl@0: if (this==TheCurrentAddressSpace) sl@0: TheCurrentAddressSpace=NULL; sl@0: if (this==TheCurrentVMProcess) sl@0: TheCurrentVMProcess=NULL; sl@0: if (this==TheCurrentDataSectionProcess) sl@0: TheCurrentDataSectionProcess=NULL; sl@0: if (this==TheCompleteDataSectionProcess) sl@0: TheCompleteDataSectionProcess=NULL; sl@0: NKern::UnlockSystem(); sl@0: DProcess::Destruct(); sl@0: } sl@0: sl@0: TInt DMemModelProcess::NewChunk(DChunk*& aChunk, SChunkCreateInfo& aInfo, TLinAddr& aRunAddr) sl@0: { sl@0: aChunk=NULL; sl@0: DMemModelChunk* pC=NULL; sl@0: TInt r=GetNewChunk(pC,aInfo); sl@0: if (r!=KErrNone) sl@0: { sl@0: if (pC) sl@0: pC->Close(NULL); sl@0: return r; sl@0: } sl@0: if (aInfo.iForceFixed || iAttributes & DMemModelProcess::EFixedAddress) sl@0: pC->iAttributes |= DMemModelChunk::EFixedAddress; sl@0: if (!aInfo.iGlobal && (iAttributes & DMemModelProcess::EPrivate)!=0) sl@0: pC->iAttributes |= DMemModelChunk::EPrivate; sl@0: if (pC->iChunkType==EDll || pC->iChunkType==EUserCode || pC->iChunkType==EUserSelfModCode || pC->iChunkType==EKernelCode) sl@0: pC->iAttributes |= (DMemModelChunk::EFixedAddress|DMemModelChunk::ECode); sl@0: pC->iOwningProcess=(aInfo.iGlobal)?NULL:this; sl@0: r=pC->Create(aInfo); sl@0: if (r==KErrNone && (aInfo.iOperations & SChunkCreateInfo::EAdjust)) sl@0: { sl@0: if (aInfo.iRunAddress!=0) sl@0: pC->SetFixedAddress(aInfo.iRunAddress,aInfo.iPreallocated); sl@0: if (aInfo.iPreallocated==0) sl@0: { sl@0: if (pC->iAttributes & DChunk::EDisconnected) sl@0: { sl@0: r=pC->Commit(aInfo.iInitialBottom,aInfo.iInitialTop-aInfo.iInitialBottom); sl@0: } sl@0: else if (pC->iAttributes & DChunk::EDoubleEnded) sl@0: { sl@0: r=pC->AdjustDoubleEnded(aInfo.iInitialBottom,aInfo.iInitialTop); sl@0: } sl@0: else sl@0: { sl@0: r=pC->Adjust(aInfo.iInitialTop); sl@0: } sl@0: } sl@0: if (r==KErrNone && pC->iHomeRegionBase==0 && (pC->iAttributes&DMemModelChunk::EFixedAddress)!=0) sl@0: { sl@0: r=pC->Reserve(0); sl@0: aRunAddr=(TLinAddr)pC->Base(); sl@0: } sl@0: } sl@0: if (r==KErrNone && (aInfo.iOperations & SChunkCreateInfo::EAdd)) sl@0: { sl@0: if (pC->iAttributes & DMemModelChunk::ECode) sl@0: Mmu::Get().SyncCodeMappings(); sl@0: if (pC->iChunkType!=EUserCode) sl@0: { sl@0: r=WaitProcessLock(); sl@0: if (r==KErrNone) sl@0: { sl@0: r=AddChunk(pC,aRunAddr,EFalse); sl@0: SignalProcessLock(); sl@0: } sl@0: } sl@0: else sl@0: aRunAddr=(TLinAddr)pC->Base(); // code chunks always fixed address sl@0: } sl@0: if (r==KErrNone) sl@0: { sl@0: pC->iDestroyedDfc = aInfo.iDestroyedDfc; sl@0: aChunk=(DChunk*)pC; sl@0: } sl@0: else sl@0: pC->Close(NULL); // NULL since chunk can't have been added to process sl@0: return r; sl@0: } sl@0: sl@0: TInt DMemModelProcess::DoCreate(TBool aKernelProcess, TProcessCreateInfo& aInfo) sl@0: { sl@0: __KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::DoCreate %O",this)); sl@0: sl@0: if (aKernelProcess) sl@0: iAttributes=ESupervisor|EFixedAddress|EPrivate; sl@0: else if (aInfo.iAttr & ECodeSegAttFixed) sl@0: iAttributes=EFixedAddress|EPrivate; sl@0: else sl@0: iAttributes=0; sl@0: if ((iAttributes & ESupervisor)==0 && (iAttributes & EFixedAddress)!=0) sl@0: { sl@0: CheckForFixedAccess(); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DMemModelProcess::CreateDataBssStackArea(TProcessCreateInfo& aInfo) sl@0: { sl@0: __KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::CreateDataBssStackArea %O",this)); sl@0: TInt dataBssSize=Mmu::RoundToPageSize(aInfo.iTotalDataSize); sl@0: TInt maxSize=dataBssSize+PP::MaxStackSpacePerProcess; sl@0: TBool fixed=(iAttributes & EFixedAddress); sl@0: sl@0: __KTRACE_OPT(KPROC,Kern::Printf("DataBssSize=%x, chunk max size %x",dataBssSize,maxSize)); sl@0: sl@0: SChunkCreateInfo cinfo; sl@0: cinfo.iGlobal=EFalse; sl@0: cinfo.iAtt=TChunkCreate::EDisconnected; sl@0: cinfo.iForceFixed=EFalse; sl@0: cinfo.iOperations=SChunkCreateInfo::EAdjust|SChunkCreateInfo::EAdd; sl@0: cinfo.iType=EUserData; sl@0: cinfo.iMaxSize=maxSize; sl@0: cinfo.iInitialBottom=0; sl@0: cinfo.iInitialTop=dataBssSize; sl@0: cinfo.iPreallocated=0; sl@0: cinfo.iName.Set(KDollarDat); sl@0: cinfo.iOwner=this; sl@0: if (fixed && dataBssSize!=0 && aInfo.iCodeLoadAddress) sl@0: { sl@0: const TRomImageHeader& rih=*(const TRomImageHeader*)aInfo.iCodeLoadAddress; sl@0: cinfo.iRunAddress=rih.iDataBssLinearBase; sl@0: } sl@0: else sl@0: cinfo.iRunAddress=0; sl@0: TInt r=NewChunk((DChunk*&)iDataBssStackChunk,cinfo,iDataBssRunAddress); sl@0: return r; sl@0: } sl@0: sl@0: TInt DMemModelProcess::AddChunk(DChunk* aChunk,TBool isReadOnly) sl@0: { sl@0: DMemModelChunk* pC=(DMemModelChunk*)aChunk; sl@0: TInt r=WaitProcessLock(); sl@0: if (r==KErrNone) sl@0: { sl@0: TInt pos=0; sl@0: r=ChunkIndex(pC,pos); sl@0: TLinAddr dataSectionBase=0; sl@0: if (r==0) // Found the chunk in this process, just up its count sl@0: { sl@0: iChunks[pos].iAccessCount++; sl@0: __KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::AddChunk %08x to %08x (Access count incremented to %d)",aChunk,this,iChunks[pos].iAccessCount)); sl@0: SignalProcessLock(); sl@0: return KErrNone; sl@0: } sl@0: r=AddChunk(pC,dataSectionBase,isReadOnly); sl@0: SignalProcessLock(); sl@0: } sl@0: __KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::AddChunk returns %d",r)); sl@0: return r; sl@0: } sl@0: sl@0: void FlushBeforeChunkMove(DMemModelChunk* aChunk) sl@0: { sl@0: Mmu& m = Mmu::Get(); sl@0: TUint32 ff=Mmu::EFlushDMove|Mmu::EFlushDPermChg; sl@0: if (aChunk->iAttributes & DMemModelChunk::ECode) // assumption here that code chunks don't move sl@0: ff |= Mmu::EFlushIPermChg; sl@0: m.GenericFlush(ff); sl@0: } sl@0: sl@0: TInt DMemModelProcess::AddChunk(DMemModelChunk* aChunk, TLinAddr& aDataSectionBase, TBool isReadOnly) sl@0: { sl@0: // sl@0: // Must hold the process $LOCK mutex before calling this sl@0: // sl@0: __KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::AddChunk %08x to %08x (for first time)",aChunk,this)); sl@0: TInt r=AllocateDataSectionBase(*((DMemModelChunk*)aChunk),(TUint&)aDataSectionBase); sl@0: if(r!=KErrNone) sl@0: return r; sl@0: sl@0: if (iNumChunks==KMaxChunksInProcess) sl@0: return KErrOverflow; // too many chunks in the process sl@0: sl@0: SChunkInfo *pC=iChunks; sl@0: SChunkInfo *pE=pC+iNumChunks-1; sl@0: NKern::LockSystem(); sl@0: while(pE>=pC && TUint(pE->iDataSectionBase)>TUint(aDataSectionBase)) sl@0: { sl@0: pE[1]=pE[0]; sl@0: pE--; sl@0: } sl@0: pC=pE+1; sl@0: pC->iDataSectionBase=aDataSectionBase; sl@0: pC->isReadOnly=isReadOnly; sl@0: pC->iAccessCount=1; sl@0: pC->iChunk=aChunk; sl@0: iNumChunks++; sl@0: sl@0: if(!(iAttributes&ESupervisor)) sl@0: { sl@0: TInt attribs=aChunk->iAttributes; sl@0: if (!(attribs&DMemModelChunk::EFixedAddress)) sl@0: { sl@0: iNumMovingChunks++; sl@0: iAttributes |= EMoving; sl@0: } sl@0: sl@0: if (attribs&DMemModelChunk::EFixedAccess) sl@0: { sl@0: NKern::UnlockSystem(); sl@0: AddFixedAccessChunk(aChunk); sl@0: goto done; // FINISHED sl@0: } sl@0: sl@0: iAttributes |= EVariableAccess; sl@0: if (attribs & DMemModelChunk::ECode) sl@0: { sl@0: iNumNonFixedAccessCodeChunks++; sl@0: iAttributes |= EVariableCode; sl@0: } sl@0: if (++iNumNonFixedAccessChunks==1) sl@0: { sl@0: NKern::UnlockSystem(); sl@0: DoAttributeChange(); // change process from fixed to variable access sl@0: NKern::LockSystem(); sl@0: } sl@0: sl@0: if (this!=TheCurrentThread->iOwningProcess) sl@0: { sl@0: // Adding chunk to another process sl@0: if (this==TheCurrentDataSectionProcess && !(attribs&DMemModelChunk::EFixedAddress)) sl@0: TheCompleteDataSectionProcess=NULL; // just set partial state change flag and leave chunk alone sl@0: if (this==TheCurrentAddressSpace) sl@0: TheCurrentAddressSpace=NULL; sl@0: NKern::UnlockSystem(); sl@0: goto done; // FINISHED sl@0: } sl@0: sl@0: // Adding chunk to currently active user process sl@0: { sl@0: TheCurrentAddressSpace=NULL; sl@0: Mmu& m = Mmu::Get(); sl@0: TUint32 ff=0; // flush flags sl@0: DMemModelChunk::TChunkState state=isReadOnly?DMemModelChunk::ERunningRO:DMemModelChunk::ERunningRW; sl@0: if (attribs&DMemModelChunk::EFixedAddress) sl@0: { sl@0: // Fixed address chunk, just change permissions sl@0: ff|=aChunk->ApplyTopLevelPermissions(state); sl@0: } sl@0: else if (this==TheCurrentDataSectionProcess) sl@0: { sl@0: // Moving chunk. sl@0: // This process is already in the data section, so just move the chunk down. sl@0: // Must do flushing first sl@0: TheCompleteDataSectionProcess=NULL; sl@0: FlushBeforeChunkMove(aChunk); sl@0: aChunk->MoveToRunAddress(aDataSectionBase,state); // idempotent sl@0: TheCompleteDataSectionProcess=this; sl@0: } sl@0: else if (iNumMovingChunks==1) sl@0: { sl@0: // The first moving chunk being added to a process with the data section occupied by another process. sl@0: // This is the problematic case - we must displace the other process from the data section. sl@0: // However we must allow preemption after each chunk is moved. Note that if a reschedule does sl@0: // occur the necessary chunk moves will have been done by the scheduler, so we can finish sl@0: // immediately. sl@0: // Must do cache flushing first sl@0: m.GenericFlush(Mmu::EFlushDMove); sl@0: if (TheCurrentDataSectionProcess) sl@0: { sl@0: if (TheCurrentDataSectionProcess->iAttributes & EVariableCode) sl@0: ff |= Mmu::EFlushIPermChg; sl@0: SChunkInfo* pOtherProcChunks=TheCurrentDataSectionProcess->iChunks; sl@0: SChunkInfo* pEndOtherProcChunks=pOtherProcChunks+TheCurrentDataSectionProcess->iNumChunks; sl@0: NKern::FlashSystem(); sl@0: // if a reschedule occurs, TheCompleteDataSectionProcess will become equal to this sl@0: while (TheCompleteDataSectionProcess!=this && pOtherProcChunksiChunk; sl@0: pChunk->MoveToHomeSection(); sl@0: ++pOtherProcChunks; sl@0: TheCompleteDataSectionProcess=NULL; sl@0: NKern::FlashSystem(); sl@0: } sl@0: } sl@0: if (TheCompleteDataSectionProcess!=this) sl@0: { sl@0: if (attribs & DMemModelChunk::ECode) sl@0: ff |= Mmu::EFlushIPermChg; sl@0: aChunk->MoveToRunAddress(aDataSectionBase,state); sl@0: TheCurrentDataSectionProcess=this; sl@0: TheCompleteDataSectionProcess=this; sl@0: } sl@0: } sl@0: TheCurrentAddressSpace=this; sl@0: TheCurrentVMProcess=this; sl@0: if (ff) sl@0: m.GenericFlush(ff); sl@0: } sl@0: } sl@0: NKern::UnlockSystem(); sl@0: done: sl@0: __KTRACE_OPT(KPROC,Kern::Printf("Added array entry for %x",aDataSectionBase)); sl@0: __KTRACE_OPT(KPROC,Kern::Printf("Chunks maxsize %x",pC->iChunk->MaxSize())); sl@0: __DEBUG_EVENT(EEventUpdateProcess, this); sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DMemModelProcess::AllocateDataSectionBase(DMemModelChunk& aChunk, TUint& aBase) sl@0: { sl@0: __KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::AllocateDataSectionBase")); sl@0: aBase=0; sl@0: if ((aChunk.iAttributes & DMemModelChunk::EPrivate) && this!=aChunk.iOwningProcess) sl@0: return KErrAccessDenied; sl@0: if (aChunk.iAttributes & DMemModelChunk::EFixedAddress) sl@0: { sl@0: aBase=aChunk.iHomeRegionBase; sl@0: return KErrNone; sl@0: } sl@0: Mmu& m = Mmu::Get(); sl@0: TLinAddr base=0; sl@0: TLinAddr maxBase=0; sl@0: switch (aChunk.iChunkType) sl@0: { sl@0: case EUserData: sl@0: base=m.iDataSectionBase; sl@0: maxBase=m.iDllDataBase; sl@0: break; sl@0: case EUserCode: sl@0: case EUserSelfModCode: sl@0: MM::Panic(MM::EUserCodeNotFixed); sl@0: break; sl@0: case EDllData: sl@0: aBase=m.iDllDataBase; sl@0: return KErrNone; sl@0: default: sl@0: __KTRACE_OPT(KPANIC,Kern::Printf("DMemModelProcess::AllocateDataSectionBase BadChunkType %d",aChunk.iChunkType)); sl@0: return KErrAccessDenied; sl@0: } sl@0: sl@0: TLinAddr lastBase=base; sl@0: SChunkInfo *pS=iChunks; sl@0: SChunkInfo *pE=pS+iNumChunks; sl@0: while (pSiDataSectionBase; sl@0: __KTRACE_OPT(KPROC,Kern::Printf("Chunk already at %x",thisBase)); sl@0: if (thisBase>=maxBase) sl@0: break; sl@0: if (thisBase>=base) // Within the range we are allocating sl@0: { sl@0: TInt gap=thisBase-lastBase; sl@0: if (gap>=aChunk.MaxSize()) sl@0: break; sl@0: lastBase=thisBase+pS->iChunk->MaxSize(); sl@0: } sl@0: pS++; sl@0: } sl@0: if (lastBase+aChunk.MaxSize()>maxBase) sl@0: { sl@0: __KTRACE_OPT(KPROC,Kern::Printf("ERROR - none allocated, out of memory")); sl@0: return KErrNoMemory; sl@0: } sl@0: aBase=lastBase; sl@0: __KTRACE_OPT(KPROC,Kern::Printf("User allocated %x",aBase)); sl@0: return KErrNone; sl@0: } sl@0: sl@0: TUint8* DMemModelProcess::DataSectionBase(DMemModelChunk* aChunk) sl@0: { sl@0: // this can't be called after $LOCK is deleted sl@0: Kern::MutexWait(*iProcessLock); sl@0: TInt pos=0; sl@0: TInt r=ChunkIndex(aChunk,pos); sl@0: if (r==0) // Found the chunk sl@0: { sl@0: TUint8* answer=((TUint8*)iChunks[pos].iDataSectionBase); sl@0: __KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::DataSectionBase %x",answer)); sl@0: Kern::MutexSignal(*iProcessLock); sl@0: return answer; sl@0: } sl@0: __KTRACE_OPT(KPROC,Kern::Printf("DMemModelProcess::DataSectionBase chunk %08x not present in %08x",aChunk,this)); sl@0: Kern::MutexSignal(*iProcessLock); sl@0: return(NULL); sl@0: } sl@0: sl@0: void DMemModelProcess::DoRemoveChunk(TInt aIndex) sl@0: { sl@0: // Must be called with process $LOCK mutex held sl@0: __DEBUG_EVENT(EEventUpdateProcess, this); sl@0: DMemModelChunk* chunk = iChunks[aIndex].iChunk; sl@0: Mmu& m = Mmu::Get(); sl@0: NKern::LockSystem(); sl@0: TInt attribs=chunk->iAttributes; sl@0: __KTRACE_OPT(KPROC,Kern::Printf("Removing Chunk attribs=%08x, Process attribs=%08x",attribs,iAttributes)); sl@0: if (!(attribs&DMemModelChunk::EFixedAccess)) sl@0: { sl@0: // Must leave chunk in process chunk list until we have flushed the cache if necessary sl@0: if (this==TheCurrentVMProcess && (attribs&DMemModelChunk::EFixedAddress)) sl@0: { sl@0: TUint32 ff=chunk->ApplyTopLevelPermissions(DMemModelChunk::ENotRunning); sl@0: m.GenericFlush(ff); sl@0: // the system must now remain locked until the chunk is removed from the process chunk list sl@0: } sl@0: if (this==TheCurrentDataSectionProcess && !(attribs&DMemModelChunk::EFixedAddress)) sl@0: { sl@0: // must do cache flush first sl@0: FlushBeforeChunkMove(chunk); // preemptible, but on return cache is free of chunk data sl@0: chunk->MoveToHomeSection(); sl@0: // the system must now remain locked until the chunk is removed from the process chunk list sl@0: } sl@0: } sl@0: sl@0: // Remove the chunk from the process chunk list sl@0: SChunkInfo *pD=iChunks+aIndex; sl@0: SChunkInfo *pS=iChunks+aIndex+1; sl@0: SChunkInfo *pE=iChunks+iNumChunks; sl@0: while(pSiChunk!=aChunk)) sl@0: { sl@0: pC++; sl@0: i++; sl@0: } sl@0: if (pC==pE) sl@0: return KErrNotFound; sl@0: aPos=i; sl@0: return KErrNone; sl@0: } sl@0: sl@0: void DMemModelProcess::RemoveDllData() sl@0: // sl@0: // Call with CodeSegLock held sl@0: // sl@0: { sl@0: Kern::SafeClose((DObject*&)iDllDataChunk, this); sl@0: } sl@0: sl@0: TInt DMemModelProcess::CreateDllDataChunk() sl@0: // sl@0: // Call with CodeSegLock held sl@0: // sl@0: { sl@0: __KTRACE_OPT(KDLL,Kern::Printf("DMemModelProcess %O CreateDllDataChunk",this)); sl@0: Mmu& m = Mmu::Get(); sl@0: SChunkCreateInfo c; sl@0: c.iGlobal=EFalse; sl@0: c.iAtt=TChunkCreate::EDisconnected; sl@0: c.iForceFixed=EFalse; sl@0: c.iOperations=SChunkCreateInfo::EAdjust|SChunkCreateInfo::EAdd; sl@0: c.iRunAddress=0; sl@0: c.iPreallocated=0; sl@0: c.iType=EDllData; sl@0: c.iMaxSize=(iAttributes&EFixedAddress) ? 1 : m.iMaxDllDataSize; // minimal size for fixed processes sl@0: c.iName.Set(KLitDllDollarData); sl@0: c.iOwner=this; sl@0: c.iInitialBottom=0; sl@0: c.iInitialTop=0; sl@0: TLinAddr runAddr; sl@0: return NewChunk((DChunk*&)iDllDataChunk,c,runAddr); sl@0: } sl@0: sl@0: void DMemModelProcess::FreeDllDataChunk() sl@0: { sl@0: iDllDataChunk->Close(this); sl@0: iDllDataChunk=NULL; sl@0: } sl@0: sl@0: TInt DMemModelProcess::CommitDllData(TLinAddr aBase, TInt aSize) sl@0: { sl@0: __KTRACE_OPT(KDLL,Kern::Printf("DMemModelProcess %O CommitDllData %08x+%x",this,aBase,aSize)); sl@0: TInt r=KErrNone; sl@0: if (!iDllDataChunk) sl@0: r=CreateDllDataChunk(); sl@0: if (r==KErrNone) sl@0: { sl@0: Mmu& m = Mmu::Get(); sl@0: TLinAddr dll_data_base=(iAttributes & EFixedAddress) ? (TLinAddr)iDllDataChunk->Base() sl@0: : TLinAddr(m.iDllDataBase); sl@0: TInt offset=aBase-dll_data_base; sl@0: __ASSERT_ALWAYS(TUint32(offset)iMaxSize),MM::Panic(MM::ECommitInvalidDllDataAddress)); sl@0: r=iDllDataChunk->Commit(offset, aSize); sl@0: if (r!=KErrNone && iDllDataChunk->iSize==0) sl@0: FreeDllDataChunk(); sl@0: } sl@0: __KTRACE_OPT(KDLL,Kern::Printf("CommitDllData returns %d",r)); sl@0: return r; sl@0: } sl@0: sl@0: void DMemModelProcess::DecommitDllData(TLinAddr aBase, TInt aSize) sl@0: { sl@0: __KTRACE_OPT(KDLL,Kern::Printf("DMemModelProcess %O DecommitDllData %08x+%x",this,aBase,aSize)); sl@0: Mmu& m = Mmu::Get(); sl@0: TLinAddr dll_data_base=(iAttributes & EFixedAddress) ? (TLinAddr)iDllDataChunk->Base() sl@0: : TLinAddr(m.iDllDataBase); sl@0: TInt offset=aBase-dll_data_base; sl@0: TInt r=iDllDataChunk->Decommit(offset, aSize); sl@0: __ASSERT_ALWAYS(r==KErrNone,MM::Panic(MM::EDecommitInvalidDllDataAddress)); sl@0: if (iDllDataChunk->iSize==0) sl@0: FreeDllDataChunk(); sl@0: } sl@0: sl@0: TInt DMemModelProcess::MapCodeSeg(DCodeSeg* aSeg) sl@0: { sl@0: DMemModelCodeSeg& seg=*(DMemModelCodeSeg*)aSeg; sl@0: __KTRACE_OPT(KDLL,Kern::Printf("Process %O MapCodeSeg %C", this, aSeg)); sl@0: TBool kernel_only=( (seg.iAttr&(ECodeSegAttKernel|ECodeSegAttGlobal)) == ECodeSegAttKernel ); sl@0: if (kernel_only && !(iAttributes&ESupervisor)) sl@0: return KErrNotSupported; sl@0: if (seg.iAttr&ECodeSegAttKernel || seg.iDataAllocBase==-1) sl@0: return KErrNone; // no extra mappings needed for kernel code or code with fixed data address sl@0: TInt r=KErrNone; sl@0: if (seg.IsDll()) sl@0: { sl@0: TInt total_data_size; sl@0: TLinAddr data_base; sl@0: seg.GetDataSizeAndBase(total_data_size, data_base); sl@0: if (r==KErrNone && total_data_size) sl@0: { sl@0: TInt size=Mmu::RoundToPageSize(total_data_size); sl@0: r=CommitDllData(data_base, size); sl@0: } sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: void DMemModelProcess::UnmapCodeSeg(DCodeSeg* aSeg) sl@0: { sl@0: DMemModelCodeSeg& seg=*(DMemModelCodeSeg*)aSeg; sl@0: __KTRACE_OPT(KDLL,Kern::Printf("Process %O UnmapCodeSeg %C", this, aSeg)); sl@0: if (seg.iAttr&ECodeSegAttKernel || seg.iDataAllocBase==-1) sl@0: return; // no extra mappings needed for kernel code or code with fixed data address sl@0: if (seg.IsDll()) sl@0: { sl@0: TInt total_data_size; sl@0: TLinAddr data_base; sl@0: seg.GetDataSizeAndBase(total_data_size, data_base); sl@0: if (total_data_size) sl@0: DecommitDllData(data_base, Mmu::RoundToPageSize(total_data_size)); sl@0: } sl@0: } sl@0: sl@0: TInt DMemModelProcess::NewShPool(DShPool*& /* aPool */, TShPoolCreateInfo& /* aInfo */) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TInt DThread::RawRead(const TAny* aSrc, TAny* aDest, TInt aLength, TInt aFlags, TIpcExcTrap* aExcTrap) sl@0: // sl@0: // Read from the thread's process. sl@0: // aSrc is run address of memory to read. The memory is in aThread's address space. sl@0: // aDest is the address of destination. The memory is in the current process's address space. sl@0: // aExcTrap, exception trap object to be updated if the actual memory access is performed on another memory area. It happens sl@0: // when reading is performed in chunks or if home adress is read instead of the provided run address. sl@0: // Enter and return with system locked. sl@0: { sl@0: const TUint8* pS=(const TUint8*)aSrc; sl@0: TUint8* pD=(TUint8*)aDest; sl@0: const TUint8* pC=NULL; sl@0: TBool check=ETrue; sl@0: TBool suspect=EFalse; sl@0: DThread* pT=TheCurrentThread; sl@0: while (aLength) sl@0: { sl@0: if (check) sl@0: { sl@0: suspect=((aFlags & KCheckLocalAddress) && !MM::CurrentAddress(pT,pD,aLength,ETrue)); sl@0: if (iMState==EDead) sl@0: return KErrDied; sl@0: pC=(const TUint8*)MM::CurrentAddress(this,pS,aLength,EFalse); sl@0: __KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawRead %08x<-[%08x::%08x]%08x+%x",pD,this,pS,pC,aLength)); sl@0: if (!pC) sl@0: return KErrBadDescriptor; sl@0: } sl@0: TInt len=Min(aLength,K::MaxMemCopyInOneGo); sl@0: if (aExcTrap) sl@0: { sl@0: aExcTrap->iSize = (len + 2*(sizeof(TInt32)-1));//+6 is for the worst case. We do not have to be precise here. sl@0: aExcTrap->iRemoteBase = (TLinAddr)pC & ~(sizeof(TInt32)-1); sl@0: if (aExcTrap->iLocalBase) sl@0: aExcTrap->iLocalBase = (TLinAddr)pD & ~(sizeof(TInt32)-1); sl@0: __KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawRead exc. update: %08x %08x %08x",aExcTrap->iLocalBase,aExcTrap->iRemoteBase,aExcTrap->iSize)); sl@0: } sl@0: sl@0: #ifdef __DEMAND_PAGING__ sl@0: XTRAP_PAGING_START(check); sl@0: CHECK_PAGING_SAFE; sl@0: #endif sl@0: sl@0: suspect?(void)umemput(pD,pC,len):(void)memcpy(pD,pC,len); sl@0: sl@0: #ifdef __DEMAND_PAGING__ sl@0: XTRAP_PAGING_END; sl@0: if(check<0) sl@0: return check; // paging error caused by bad client (I.e. 'this' thread was bad) sl@0: if(check) sl@0: { sl@0: __KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawRead paging trap, suspect %d, dest %08x, source %08x, length %d\n", suspect, pD, pC, len)); sl@0: continue; sl@0: } sl@0: #endif sl@0: sl@0: pD+=len; sl@0: pS+=len; sl@0: pC+=len; sl@0: aLength-=len; sl@0: if (aLength) sl@0: check=NKern::FlashSystem(); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DThread::RawWrite(const TAny* aDest, const TAny* aSrc, TInt aLength, TInt aFlags, DThread* aOriginatingThread, TIpcExcTrap* aExcTrap) sl@0: // sl@0: // Write to the thread's process. sl@0: // aDest is run address of memory to write. It resides in this thread's address space. sl@0: // aSrc is address of the source buffer. It resides in the current process's address space. sl@0: // aOriginatingThread is the thread on behalf of which this operation is performed (eg client of device driver). sl@0: // Enter and return with system locked sl@0: // aExcTrap, exception trap object to be updated if the actual memory access is performed on another memory area. It happens sl@0: // when reading is performed in chunks or if home adress is read instead of the provided run address. sl@0: // sl@0: { sl@0: TUint8* pD=(TUint8*)aDest; sl@0: const TUint8* pS=(const TUint8*)aSrc; sl@0: TUint8* pC=NULL; sl@0: TBool check=ETrue; sl@0: TBool suspect=EFalse; sl@0: DThread* pT=TheCurrentThread; sl@0: DThread* pO=aOriginatingThread; sl@0: if (!pO) sl@0: pO=pT; sl@0: DProcess* pF=K::TheFileServerProcess; sl@0: TBool special=(iOwningProcess==pF && pO->iOwningProcess==pF); sl@0: while (aLength) sl@0: { sl@0: if (check) sl@0: { sl@0: suspect=((aFlags & KCheckLocalAddress) && !MM::CurrentAddress(pT,pS,aLength,EFalse)); sl@0: if (iMState==EDead) sl@0: return KErrDied; sl@0: pC=(TUint8*)MM::CurrentAddress(this,pD,aLength,ETrue); sl@0: __KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawRead [%08x::%08x]%08x<-%08x+%x",this,pD,pC,pS,aLength)); sl@0: if (!pC) sl@0: { sl@0: if (special) sl@0: pC=pD; sl@0: else sl@0: return KErrBadDescriptor; sl@0: } sl@0: } sl@0: TInt len=Min(aLength,K::MaxMemCopyInOneGo); sl@0: if (aExcTrap) sl@0: { sl@0: aExcTrap->iSize = (len + 2*(sizeof(TInt32)-1));//+6 is for the worst case. We do not have to be precise here. sl@0: aExcTrap->iRemoteBase = (TLinAddr)pC & ~(sizeof(TInt32)-1); sl@0: if (aExcTrap->iLocalBase) sl@0: aExcTrap->iLocalBase = (TLinAddr)pS & ~(sizeof(TInt32)-1); sl@0: __KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawWrite exc. update %08x %08x %08x",aExcTrap->iLocalBase,aExcTrap->iRemoteBase,aExcTrap->iSize)); sl@0: } sl@0: sl@0: #ifdef __DEMAND_PAGING__ sl@0: XTRAP_PAGING_START(check); sl@0: // Must check that it is safe to page, unless we are reading from unpaged ROM in which case sl@0: // we allow it. umemget does this anyway, so we just need to check if suspect is not set. sl@0: if (!suspect) sl@0: { sl@0: CHECK_PAGING_SAFE_RANGE((TLinAddr)aSrc, aLength); sl@0: CHECK_DATA_PAGING_SAFE_RANGE((TLinAddr)aDest, aLength); sl@0: } sl@0: #endif sl@0: sl@0: suspect?(void)umemget(pC,pS,len):(void)memcpy(pC,pS,len); sl@0: sl@0: #ifdef __DEMAND_PAGING__ sl@0: XTRAP_PAGING_END sl@0: if(check<0) sl@0: return check; // paging error caused by bad client (I.e. 'this' thread was bad) sl@0: if(check) sl@0: { sl@0: __KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawWrite paging trap, suspect %d, dest %08x, src %08x, length %d\n", suspect, pC, pD, len)); sl@0: continue; sl@0: } sl@0: #endif sl@0: sl@0: pD+=len; sl@0: pS+=len; sl@0: pC+=len; sl@0: aLength-=len; sl@0: if (aLength) sl@0: check=NKern::FlashSystem(); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: #ifdef __DEBUGGER_SUPPORT__ sl@0: sl@0: TInt CodeModifier::SafeWriteCode(DProcess* aProcess, TLinAddr aAddress, TInt aSize, TUint aValue, void* aOldValue) sl@0: { sl@0: //Set exception handler. Make sure the boundaries cover the worst case (aSize = 4) sl@0: TIpcExcTrap xt; sl@0: xt.iLocalBase=0; sl@0: xt.iRemoteBase=(TLinAddr)aAddress&~3; //word aligned. sl@0: xt.iSize=sizeof(TInt); sl@0: xt.iDir=1; sl@0: NKern::LockSystem(); sl@0: TInt r=xt.Trap(NULL); sl@0: if (r==0) sl@0: { sl@0: r = WriteCode(aAddress, aSize, aValue, aOldValue); sl@0: xt.UnTrap(); sl@0: } sl@0: NKern::UnlockSystem(); sl@0: return r; sl@0: } sl@0: sl@0: TInt CodeModifier::WriteCode(TLinAddr aAddress, TInt aSize, TUint aValue, void* aOldValue) sl@0: { sl@0: TUint userChunkBase = (TUint)MM::UserCodeChunk->Base(); sl@0: TRomHeader romHeader = Epoc::RomHeader(); sl@0: sl@0: if (!((aAddress >= romHeader.iRomBase ) && (aAddress < (romHeader.iRomBase + romHeader.iUncompressedSize)))) //if not in ROM sl@0: if ( (aAddress (userChunkBase+MM::UserCodeChunk->MaxSize()) ) //and not in non-XIP code sl@0: return KErrBadDescriptor; sl@0: sl@0: // if page was moved by defrag there may be a cache line with the sl@0: // wrong, old physical address, so we must invalidate this first. sl@0: InternalCache::Invalidate(KCacheSelectD, (TLinAddr)aAddress, 4); sl@0: sl@0: //Copy data and clean/invalidate caches with interrupts disabled. sl@0: TInt irq=NKern::DisableAllInterrupts(); sl@0: switch(aSize) sl@0: { sl@0: case 1: sl@0: *(TUint8*) aOldValue = *(TUint8*)aAddress; sl@0: *(TUint8*) aAddress = (TUint8)aValue; sl@0: break; sl@0: case 2: sl@0: *(TUint16*) aOldValue = *(TUint16*)aAddress; sl@0: *(TUint16*) aAddress = (TUint16)aValue; sl@0: break; sl@0: default://It is 4 otherwise sl@0: *(TUint32*) aOldValue = *(TUint32*)aAddress; sl@0: *(TUint32*) aAddress = (TUint32)aValue; sl@0: break; sl@0: }; sl@0: CacheMaintenance::CodeChanged(aAddress, aSize, CacheMaintenance::ECodeModifier); sl@0: NKern::RestoreInterrupts(irq); sl@0: sl@0: return KErrNone; sl@0: } sl@0: #endif //__DEBUGGER_SUPPORT__ sl@0: sl@0: TInt DThread::ReadAndParseDesHeader(const TAny* aSrc, TDesHeader& aDest) sl@0: // sl@0: // Read the header of a remote descriptor. sl@0: // Enter and return with system locked sl@0: // sl@0: { sl@0: TInt r=KErrBadDescriptor; sl@0: DThread* thread = TheCurrentThread; sl@0: TRawDesHeader& header = (TRawDesHeader&)aDest; sl@0: sl@0: #ifdef __DEMAND_PAGING__ sl@0: retry: sl@0: TInt pagingFault; sl@0: XTRAP_PAGING_START(pagingFault); sl@0: CHECK_PAGING_SAFE; sl@0: thread->iIpcClient = this; sl@0: #endif sl@0: sl@0: const TUint32* pS=(const TUint32*)MM::CurrentAddress(this,aSrc,sizeof(TDesC8),EFalse); sl@0: if (pS && KErrNone==Kern::SafeRead(pS,&header[0],sizeof(TUint32))) sl@0: { sl@0: TInt type=header[0]>>KShiftDesType8; sl@0: static const TUint8 LengthLookup[16]={4,8,12,8,12,0,0,0,0,0,0,0,0,0,0,0}; sl@0: TInt len=LengthLookup[type]; sl@0: if(len>(TInt)sizeof(TUint32)) sl@0: { sl@0: if(KErrNone==Kern::SafeRead(pS+1,&header[1],len-sizeof(TUint32))) sl@0: r = type; sl@0: // else, bad descriptor sl@0: } sl@0: else if(len) sl@0: r = type; sl@0: // else, bad descriptor sl@0: } sl@0: sl@0: #ifdef __DEMAND_PAGING__ sl@0: thread->iIpcClient = NULL; sl@0: XTRAP_PAGING_END; sl@0: if(pagingFault<0) sl@0: return pagingFault; // paging error caused by bad client (I.e. 'this' thread was bad) sl@0: if(pagingFault) sl@0: goto retry; sl@0: #endif sl@0: sl@0: return K::ParseDesHeader(aSrc, header, aDest); sl@0: } sl@0: sl@0: DMemModelChunk* ChunkFromAddress(DThread* aThread, const TAny* aAddress) sl@0: { sl@0: DMemModelProcess* pP = (DMemModelProcess*)aThread->iOwningProcess; sl@0: DMemModelProcess::SChunkInfo* pS=pP->iChunks; sl@0: DMemModelProcess::SChunkInfo* pC=pS+pP->iNumChunks; sl@0: while(--pC>=pS && TUint(pC->iDataSectionBase)>TUint(aAddress)) {}; sl@0: if(pCiChunk; sl@0: } sl@0: sl@0: /** sl@0: Open a shared chunk in which a remote address range is located. sl@0: */ sl@0: DChunk* DThread::OpenSharedChunk(const TAny* aAddress, TBool aWrite, TInt& aOffset) sl@0: { sl@0: NKern::LockSystem(); sl@0: sl@0: DMemModelProcess* pP = (DMemModelProcess*)iOwningProcess; sl@0: DMemModelProcess::SChunkInfo* pS=pP->iChunks; sl@0: DMemModelProcess::SChunkInfo* pC=pS+pP->iNumChunks; sl@0: while(--pC>=pS && TUint(pC->iDataSectionBase)>TUint(aAddress)) {}; sl@0: if(pC>=pS) sl@0: { sl@0: DMemModelChunk* chunk = pC->iChunk; sl@0: if(chunk->iChunkType==ESharedKernelSingle || chunk->iChunkType==ESharedKernelMultiple) sl@0: { sl@0: TInt offset = (TInt)aAddress-(TInt)chunk->Base(); sl@0: if(TUint(offset)iMaxSize) && chunk->Open()==KErrNone) sl@0: { sl@0: aOffset = offset; sl@0: NKern::UnlockSystem(); sl@0: return chunk; sl@0: } sl@0: } sl@0: } sl@0: NKern::UnlockSystem(); sl@0: return 0; sl@0: } sl@0: sl@0: TInt DThread::PrepareMemoryForDMA(const TAny* aLinAddr, TInt aSize, TPhysAddr* aPhysicalPageList) sl@0: { sl@0: if ((iOwningProcess->iAttributes & DMemModelProcess::EFixedAddress )==0) sl@0: return KErrNotSupported; sl@0: Mmu& m=(Mmu&)*MmuBase::TheMmu; sl@0: return m.PreparePagesForDMA((TLinAddr)aLinAddr, aSize, aPhysicalPageList); sl@0: } sl@0: sl@0: TInt DThread::ReleaseMemoryFromDMA(const TAny* aLinAddr, TInt aSize, TPhysAddr* aPhysicalPageList) sl@0: { sl@0: if ((iOwningProcess->iAttributes & DMemModelProcess::EFixedAddress )==0) sl@0: return KErrNotSupported; sl@0: TInt pageCount = (((TInt)aLinAddr & KPageMask) + aSize + KPageMask) >> KPageShift; sl@0: Mmu& m=(Mmu&)*MmuBase::TheMmu; sl@0: return m.ReleasePagesFromDMA(aPhysicalPageList, pageCount); sl@0: }