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\arm\xkernel.cpp sl@0: // sl@0: // sl@0: sl@0: #include "arm_mem.h" sl@0: sl@0: sl@0: /******************************************** sl@0: * Thread sl@0: ********************************************/ sl@0: sl@0: TInt DArmPlatThread::SetupContext(SThreadCreateInfo& anInfo) sl@0: { sl@0: switch(iThreadType) sl@0: { sl@0: case EThreadSupervisor: sl@0: case EThreadMinimalSupervisor: sl@0: iNThread.SetDacr(Arm::DefaultDomainAccess); sl@0: case EThreadInitial: sl@0: break; sl@0: case EThreadUser: sl@0: { sl@0: DArmPlatProcess* pP=(DArmPlatProcess*)iOwningProcess; sl@0: iNThread.SetDacr(pP->iDacr); sl@0: if (pP->iAttributes & DMemModelProcess::EVariableAccess) sl@0: iNThread.SetAttributes(KThreadAttImplicitSystemLock|KThreadAttAddressSpace); sl@0: #ifndef __SMP__ sl@0: iNThread.iSpare3 /*iUserContextType*/ = NThread::EContextUndefined; sl@0: #endif sl@0: break; sl@0: } sl@0: } sl@0: iNThread.SetAddressSpace(iOwningProcess); sl@0: __KTRACE_OPT(KTHREAD,Kern::Printf("Thread %O DACR %08x Attrib %02x",this,iNThread.Dacr(),iNThread.Attributes())); sl@0: return KErrNone; sl@0: } sl@0: sl@0: DArmPlatProcess::DArmPlatProcess() sl@0: : iDomain(-1), iDacr(Arm::DefaultDomainAccess|0x3) // manager access to domain 0 sl@0: {} sl@0: sl@0: DArmPlatProcess::~DArmPlatProcess() sl@0: { sl@0: __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatProcess destruct, Domain=%d",iDomain)); sl@0: if (iDomain>=0) sl@0: ArmMmu::FreeDomain(iDomain); sl@0: DMemModelProcess::Destruct(); sl@0: } sl@0: sl@0: TInt DArmPlatProcess::GetNewChunk(DMemModelChunk*& aChunk, SChunkCreateInfo& aInfo) sl@0: { sl@0: aChunk=NULL; sl@0: DArmPlatChunk* pC=new DArmPlatChunk; sl@0: if (!pC) sl@0: return KErrNoMemory; sl@0: aChunk=pC; sl@0: pC->iChunkType=aInfo.iType; sl@0: switch(pC->iChunkType) sl@0: { sl@0: case EKernelData: sl@0: case EKernelStack: sl@0: case EKernelCode: sl@0: case EKernelMessage: sl@0: pC->iAttributes |= DMemModelChunk::EFixedAccess; sl@0: break; sl@0: case ERamDrive: sl@0: pC->iDomain=3; sl@0: pC->iAttributes |= DMemModelChunk::EFixedAccess; sl@0: break; sl@0: case EUserCode: sl@0: case EUserSelfModCode: sl@0: pC->iAttributes |= DMemModelChunk::EFixedAddress; sl@0: if (iDomain>=0) sl@0: { sl@0: __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatChunk create code chunk, owning process domain %d",iDomain)); sl@0: pC->iDomain=iDomain; sl@0: pC->iAttributes |= DMemModelChunk::EFixedAccess; sl@0: } sl@0: break; sl@0: case EDll: sl@0: break; sl@0: case EUserData: sl@0: case EDllData: sl@0: if (aInfo.iGlobal && (iAttributes & DMemModelProcess::EFixedAddress || aInfo.iForceFixed)) sl@0: { sl@0: TInt domain=ArmMmu::AllocDomain(); sl@0: if (domain>=0) sl@0: { sl@0: __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatChunk create global chunk, Domain %d allocated",domain)); sl@0: pC->iDomain=domain; sl@0: pC->iAttributes |= DMemModelChunk::EFixedAccess; sl@0: } sl@0: } sl@0: else if (!aInfo.iGlobal && iDomain>=0) sl@0: { sl@0: __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatChunk create local chunk, owning process domain %d",iDomain)); sl@0: pC->iDomain=iDomain; sl@0: pC->iAttributes |= DMemModelChunk::EFixedAccess; sl@0: } sl@0: break; sl@0: case ESharedKernelSingle: sl@0: case ESharedKernelMultiple: sl@0: case ESharedIo: sl@0: break; sl@0: default: sl@0: FAULT(); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: DArmPlatChunk::DArmPlatChunk() sl@0: : iDomain(-1) sl@0: {} sl@0: sl@0: DArmPlatChunk::~DArmPlatChunk() sl@0: { sl@0: if (!iOwningProcess && iDomain>=0) sl@0: { sl@0: __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatChunk destruct, Domain %d freed",iDomain)); sl@0: ArmMmu::FreeDomain(iDomain); sl@0: } sl@0: DMemModelChunk::Destruct(); sl@0: } sl@0: sl@0: TInt DArmPlatChunk::SetupPermissions() sl@0: { sl@0: Mmu& m = Mmu::Get(); sl@0: if(iChunkType==ESharedKernelSingle || iChunkType==ESharedKernelMultiple || iChunkType==ESharedIo) sl@0: { sl@0: // override map attributes for shared kernel chunks sl@0: TUint ma = (iMapAttr &~ EMapAttrAccessMask) | EMapAttrSupRw; sl@0: TPde pde; sl@0: TInt r = m.PdePtePermissions(ma, pde, iPtePermissions); sl@0: if (r != KErrNone) sl@0: return r; sl@0: iMapAttr = ma; sl@0: } sl@0: else sl@0: iPtePermissions=m.PtePermissions(iChunkType); sl@0: // PDE may need to set P bit for ECC in ARMv5 and later. sl@0: if (iDomain<0) sl@0: { sl@0: iPdePermissions[0]=m.PdePermissions(iChunkType,ENotRunning); sl@0: iPdePermissions[1]=m.PdePermissions(iChunkType,ERunningRO); sl@0: iPdePermissions[2]=m.PdePermissions(iChunkType,ERunningRW); sl@0: } sl@0: else sl@0: { sl@0: TPde pdePermissions = PT_PDE(iDomain); sl@0: iPdePermissions[0]=pdePermissions; sl@0: iPdePermissions[1]=pdePermissions; sl@0: iPdePermissions[2]=pdePermissions; sl@0: } sl@0: __KTRACE_OPT(KMMU,Kern::Printf("Chunk permissions PTE=%08x PDE0=%08x PDE1=%08x PDE2=%08x", sl@0: iPtePermissions,iPdePermissions[0],iPdePermissions[1],iPdePermissions[2])); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: // must hold process lock while iterating through thread list sl@0: void DArmPlatProcess::AdjustDomainAccess(TUint32 aClearMask, TUint32 aSetMask) sl@0: { sl@0: __KTRACE_OPT(KMMU,Kern::Printf("Process %O AdjustDomainAccess, clear %08x set %08x", sl@0: this,aClearMask,aSetMask)); sl@0: iDacr=(iDacr & ~aClearMask)|aSetMask; sl@0: __KTRACE_OPT(KMMU,Kern::Printf("DACR set to %08x",iDacr)); sl@0: SDblQueLink* pLink=iThreadQ.First(); sl@0: while (pLink!=&iThreadQ.iA) sl@0: { sl@0: DArmPlatThread* pT=_LOFF(pLink,DArmPlatThread,iProcessLink); sl@0: pLink=pLink->iNext; sl@0: pT->iNThread.ModifyDacr(aClearMask,aSetMask); sl@0: } sl@0: } sl@0: sl@0: // must hold process lock while iterating through thread list sl@0: void DArmPlatProcess::AdjustThreadAttributes(TUint8 aClearMask, TUint8 aSetMask) sl@0: { sl@0: __KTRACE_OPT(KMMU,Kern::Printf("Process %O AdjustThreadAttributes, clear %02x set %02x", sl@0: this,aClearMask,aSetMask)); sl@0: SDblQueLink* pLink=iThreadQ.First(); sl@0: NKern::LockSystem(); sl@0: while (pLink!=&iThreadQ.iA) sl@0: { sl@0: DArmPlatThread* pT=_LOFF(pLink,DArmPlatThread,iProcessLink); sl@0: pLink=pLink->iNext; sl@0: pT->iNThread.ModifyAttributes(aClearMask,aSetMask); sl@0: NKern::FlashSystem(); sl@0: } sl@0: NKern::UnlockSystem(); sl@0: } sl@0: sl@0: TInt DArmPlatProcess::AddFixedAccessChunk(DMemModelChunk *aChunk) sl@0: { sl@0: DArmPlatChunk* pC=(DArmPlatChunk*)aChunk; sl@0: if (pC->iChunkType==ESharedKernelSingle || pC->iChunkType==ESharedIo) sl@0: { sl@0: if (iDomain<0) sl@0: return KErrGeneral; sl@0: pC->iDomain = iDomain; sl@0: TInt r = pC->SetupPermissions(); sl@0: __ASSERT_ALWAYS(r==KErrNone, MM::Panic(MM::EAddFixedBadPerm)); sl@0: } sl@0: sl@0: __KTRACE_OPT(KMMU,Kern::Printf("Add fixed access chunk, domain=%d",pC->iDomain)); sl@0: sl@0: // if this is one of process's local chunks, nothing to do sl@0: if (pC->iDomain!=iDomain && !(iAttributes&ESupervisor)) sl@0: { sl@0: AdjustDomainAccess(0,2<<(pC->iDomain<<1)); // grant manager access to chunk's domain sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DArmPlatProcess::RemoveFixedAccessChunk(DMemModelChunk *aChunk) sl@0: { sl@0: DArmPlatChunk* pC=(DArmPlatChunk*)aChunk; sl@0: __KTRACE_OPT(KMMU,Kern::Printf("Remove fixed access chunk, domain=%d",pC->iDomain)); sl@0: if (pC->iChunkType==ESharedKernelSingle || pC->iChunkType==ESharedIo) sl@0: { sl@0: if (iDomain<0) sl@0: return KErrGeneral; sl@0: pC->iDomain = -1; sl@0: TInt r = pC->SetupPermissions(); sl@0: __ASSERT_ALWAYS(r==KErrNone, MM::Panic(MM::ERemoveFixedBadPerm)); sl@0: return KErrNone; sl@0: } sl@0: sl@0: // if this is one of process's local chunks, nothing to do sl@0: if (pC->iDomain!=iDomain && !(iAttributes&ESupervisor)) sl@0: { sl@0: AdjustDomainAccess(2<<(pC->iDomain<<1),0); // remove manager access to chunk's domain sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: void DArmPlatProcess::CheckForFixedAccess() sl@0: { sl@0: TInt domain=ArmMmu::AllocDomain(); sl@0: if (domain>=0) sl@0: { sl@0: __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatProcess create, Domain %d allocated",domain)); sl@0: iDomain=domain; sl@0: iDacr |= (2<<(domain<<1)); // grant manager access to allocated domain sl@0: iDacr &= ~2; // demote domain 0 to client access sl@0: } sl@0: } sl@0: sl@0: void DArmPlatProcess::DoAttributeChange() sl@0: { sl@0: // Called when a process changes from fixed to variable access or vice-versa. sl@0: TBool variable=iAttributes & EVariableAccess; sl@0: if (variable) sl@0: { sl@0: // process changing from fixed access to variable access sl@0: __KTRACE_OPT(KMMU,Kern::Printf("Process %O becomes variable access",this)); sl@0: AdjustThreadAttributes(0,KThreadAttImplicitSystemLock|KThreadAttAddressSpace); sl@0: AdjustDomainAccess(0,2); // promote domain 0 to manager access sl@0: } sl@0: else sl@0: { sl@0: // process changing from variable access to fixed access sl@0: __KTRACE_OPT(KMMU,Kern::Printf("Process %O becomes fixed access",this)); sl@0: AdjustDomainAccess(2,0); // demote domain 0 to client access sl@0: AdjustThreadAttributes(KThreadAttImplicitSystemLock|KThreadAttAddressSpace,0); sl@0: } sl@0: } sl@0: sl@0: TIpcExcTrap::TExcLocation TIpcExcTrap::ExcLocation(DThread* /*aThread*/, TAny* aContext) sl@0: { sl@0: TArmExcInfo& info=*(TArmExcInfo*)aContext; sl@0: sl@0: if (info.iExcCode==EArmExceptionDataAbort) sl@0: { sl@0: TLinAddr va=(TLinAddr)info.iFaultAddress; sl@0: if (va>=iRemoteBase && (va-iRemoteBase)=iLocalBase && (va-iLocalBase)