author | mikek |
Sun, 27 Jun 2010 21:43:55 +0100 | |
branch | GCC_SURGE |
changeset 181 | bd8f1e65581b |
parent 0 | a41df078684a |
permissions | -rw-r--r-- |
// 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); }