diff -r 000000000000 -r 96e5fb8b040d kernel/eka/kernel/sexec.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/kernel/sexec.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,2785 @@ +// 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\kernel\sexec.cpp +// +// + +#include +#include +#include +//#include +#include "execs.h" + +TInt ExecHandler::ObjectNext(TObjectType aType, TBuf8& aName, TFindHandle& aFindHandle) +// +// Do the next find. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ObjectNext type %d",aType)); + if (aType<0 || aType>=ENumObjectTypes) + K::PanicKernExec(EBadObjectType); + DObjectCon* pC=K::Containers[aType]; + TFullName fn; + TFullName match; + TFindHandle h; + Kern::KUDesGet(match,aName); + kumemget32(&h,&aFindHandle,sizeof(h)); + __KTRACE_OPT(KEXEC,Kern::Printf("ObjN: %lS %08x", &match, h.Handle())); + NKern::ThreadEnterCS(); + TInt r=pC->FindByFullName(h, match, fn); + NKern::ThreadLeaveCS(); + Kern::KUDesPut(aName,fn); + kumemput32(&aFindHandle,&h,sizeof(h)); + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ObjectNext ret %d",r)); + return r; + } + +TUint8 *ExecHandler::ChunkBase(DChunk* aChunk) +// +// Return the address of the base of the Chunk. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ChunkBase")); + return (TUint8*)aChunk->Base(&Kern::CurrentProcess()); + } + +TInt ExecHandler::ChunkSize(DChunk* aChunk) +// +// Return the current size of the Chunk. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ChunkSize")); + return aChunk->Size(); + } + +TInt ExecHandler::ChunkMaxSize(DChunk* aChunk) +// +// Return the maximum size of the Chunk. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ChunkMaxSize")); + return aChunk->MaxSize(); + } + +TInt ExecHandler::ChunkBottom(DChunk* aChunk) +// +// Return the position of the bottom of the chunk +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ChunkBottom")); + return aChunk->Bottom(); + } + +TInt ExecHandler::ChunkTop(DChunk* aChunk) +// +// Return the position of the top of the chunk +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ChunkTop")); + return aChunk->Top(); + } + +void ExecHandler::MutexWait(DMutex* aMutex) +// +// Wait for the mutex. +// + { + +// __KTRACE_OPT(KEXEC,Kern::Printf("Exec::MutexWait")); + aMutex->Wait(); + } + +void ExecHandler::MutexSignal(DMutex* aMutex) +// +// Signal the mutex. +// + { + +// __KTRACE_OPT(KEXEC,Kern::Printf("Exec::MutexSignal")); + if (TheCurrentThread==aMutex->iCleanup.iThread) + { + aMutex->Signal(); + return; + } + K::PanicCurrentThread(EAccessDenied); + } + +/** +Test if mutex is held by the current thread. +@return True if the current thread has waited on the mutex, false otherwise. +*/ +TBool ExecHandler::MutexIsHeld(DMutex* aMutex) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::MutexIsHeld")); + return TheCurrentThread==aMutex->iCleanup.iThread; + } + +void ExecHandler::ProcessType(DProcess* aProcess, TUidType& aUids) +// +// Get process' UIDs. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessType")); + TUidType uids(aProcess->iUids); + NKern::UnlockSystem(); + kumemput32(&aUids,&uids,sizeof(TUidType)); + } + +TInt ExecHandler::ProcessId(DProcess* aProcess) +// +// Get process ID. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessId")); + return (TInt)aProcess->iId; + } + +void ExecHandler::ProcessSecurityInfo(DProcess* aProcess,SSecurityInfo& aInfo) +// +// Get process security info. +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessSecurityInfo")); + SSecurityInfo info(aProcess->iS); + NKern::UnlockSystem(); + kumemput32(&aInfo,&info,sizeof(info)); + } + +void ExecHandler::ThreadSecurityInfo(DThread* aThread,SSecurityInfo& aInfo) +// +// Get threads security info. +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadSecurityInfo")); + SSecurityInfo info(aThread->iOwningProcess->iS); + NKern::UnlockSystem(); + kumemput32(&aInfo,&info,sizeof(info)); + } + +void ExecHandler::MessageSecurityInfo(DThread* aClient,SSecurityInfo& aInfo) +// +// Get clients security info. +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::MessageSecurityInfo")); + SSecurityInfo info(aClient->iOwningProcess->iS); + NKern::UnlockSystem(); + kumemput32(&aInfo,&info,sizeof(info)); + } + +TInt ExecHandler::SessionSecurityInfo(TInt aSession,SSecurityInfo& aInfo) +// +// Get session security info. +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::SessionSecurityInfo")); + TInt r = KErrBadHandle; + SSecurityInfo info; + NKern::LockSystem(); + DSession* s = (DSession*)TheCurrentThread->ObjectFromHandle(aSession,ESession); + if (s) + { + if (s->iServer && s->iServer->iOwningThread) + { + // session is connected, and server is alive + info = s->iServer->iOwningThread->iOwningProcess->iS; + r = KErrNone; + } + else + { + r = KErrServerTerminated; + } + } + NKern::UnlockSystem(); + if (r==KErrNone) + kumemput32(&aInfo,&info,sizeof(info)); + return r; + } + +void ExecHandler::CreatorSecurityInfo(SSecurityInfo& aInfo) +// +// Get creator's security info. +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::CreatorSecurityInfo")); + kumemput32(&aInfo,&TheCurrentThread->iOwningProcess->iCreatorInfo,sizeof(aInfo)); + } + +void ExecHandler::DisabledCapabilities(SCapabilitySet& aCaps) +// +// Get the set of capabilities which are not to be checked (implemented by effectively +// setting them for all executables). +// + { + __KTRACE_OPT(KEXEC, Kern::Printf("Exec::DisabledCapabilities")); +#ifdef __PLATSEC_UNLOCKED__ + kumemput32(&aCaps, &TheSuperPage().iDisabledCapabilities, sizeof(aCaps)); +#else + kumemset(&aCaps, 0, sizeof(aCaps)); +#endif // __PLATSEC_UNLOCKED__ + } + +void ExecHandler::ProcessResume(DProcess* aProcess) +// +// Resume the first thread in the process. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessResume")); + if (aProcess->iCreatorId!=TheCurrentThread->iOwningProcess->iId) // Not creator... + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RProcess::Resume")); + aProcess->Resume(); + } + +void ExecHandler::ProcessFileName(DProcess* aProcess, TDes8& aName) +// +// Return the process file name. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessFileName")); + TFileName fn; + DCodeSeg* pS=aProcess->iCodeSeg; + if (pS) + pS->AppendFullFileName(fn); + NKern::UnlockSystem(); + if (pS) + P::NormalizeExecutableFileName(fn); + Kern::KUDesPut(aName, fn); + } + +TInt ExecHandler::ProcessCommandLineLength(DProcess* aProcess) +// +// Return the process command line length. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessCommandLineLength")); + + if (aProcess->iSecurityZone!=TheCurrentThread->iOwningProcess->iSecurityZone) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RProcess::CommandLineLength")); + const TDesC* pC=aProcess->iCommandLine; +#ifdef _UNICODE + return pC?(pC->Length()>>1):0; +#else + return pC?(pC->Length()):0; +#endif + } + +void ExecHandler::ProcessCommandLine(DProcess* aProcess, TDes8& aCommandLine) +// +// Return the process command line. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessCommandLine")); + if (aProcess->iSecurityZone!=TheCurrentThread->iOwningProcess->iSecurityZone) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RProcess::CommandLine")); + aProcess->CheckedOpen(); + DThread& t=*TheCurrentThread; + t.iTempObj=aProcess; + NKern::UnlockSystem(); + const TDesC* pC=aProcess->iCommandLine; + if (!pC) + pC=&KNullDesC; + Kern::KUDesPut(aCommandLine,*pC); + NKern::ThreadEnterCS(); + t.iTempObj=NULL; + aProcess->Close(NULL); + NKern::ThreadLeaveCS(); + } + +TExitType ExecHandler::ProcessExitType(DProcess* aProcess) +// +// Return the exit type. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessExitType")); + return (TExitType)aProcess->iExitType; + } + +TInt ExecHandler::ProcessExitReason(DProcess* aProcess) +// +// Return the exit reason. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessExitReason")); + return aProcess->iExitReason; + } + +void ExecHandler::ProcessExitCategory(DProcess* aProcess, TDes8& aName) +// +// Return the category of the exit type. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessExitCategory")); + TBufC exitCat(aProcess->iExitCategory); + NKern::UnlockSystem(); + Kern::KUDesPut(aName,exitCat); + } + +LOCAL_D const TProcessPriority procPriorityConvertTable[8]= + { + EPriorityLow, EPriorityBackground, EPriorityForeground, EPriorityHigh, + EPriorityWindowServer, EPriorityFileServer, EPrioritySupervisor, EPriorityRealTimeServer + }; + +LOCAL_D const TThreadPriority thrdPriorityConvertTable[8]= + { + EPriorityMuchLess, EPriorityMuchLess, EPriorityLess, EPriorityNormal, + EPriorityMore, EPriorityMuchMore, EPriorityRealTime, EPriorityRealTime + }; + +LOCAL_C TThreadPriority ConvertThreadPriority(TInt p) + { + switch(p) + { + case EThrdPriorityAbsoluteVeryLow: + return EPriorityAbsoluteVeryLow; + case EThrdPriorityAbsoluteLowNormal: + return EPriorityAbsoluteLowNormal; + case EThrdPriorityAbsoluteLow: + return EPriorityAbsoluteLow; + case EThrdPriorityAbsoluteBackgroundNormal: + return EPriorityAbsoluteBackgroundNormal; + case EThrdPriorityAbsoluteBackground: + return EPriorityAbsoluteBackground; + case EThrdPriorityAbsoluteForegroundNormal: + return EPriorityAbsoluteForegroundNormal; + case EThrdPriorityAbsoluteForeground: + return EPriorityAbsoluteForeground; + case EThrdPriorityAbsoluteHighNormal: + return EPriorityAbsoluteHighNormal; + case EThrdPriorityAbsoluteHigh: + return EPriorityAbsoluteHigh; + case EThrdPriorityAbsoluteRealTime1: + return EPriorityAbsoluteRealTime1; + case EThrdPriorityAbsoluteRealTime2: + return EPriorityAbsoluteRealTime2; + case EThrdPriorityAbsoluteRealTime3: + return EPriorityAbsoluteRealTime3; + case EThrdPriorityAbsoluteRealTime4: + return EPriorityAbsoluteRealTime4; + case EThrdPriorityAbsoluteRealTime5: + return EPriorityAbsoluteRealTime5; + case EThrdPriorityAbsoluteRealTime6: + return EPriorityAbsoluteRealTime6; + case EThrdPriorityAbsoluteRealTime7: + return EPriorityAbsoluteRealTime7; + case EThrdPriorityAbsoluteRealTime8: + return EPriorityAbsoluteRealTime8; + default: + if (p>=-8 && p<0) + return thrdPriorityConvertTable[p+8]; + } + return EPriorityNormal; + } + +LOCAL_C TBool ProcessPriorityValid(TProcessPriority p) + { + switch(p) + { + case EPriorityLow: + case EPriorityBackground: + case EPriorityForeground: + case EPriorityHigh: + return ETrue; + default: + return EFalse; + } + } + +TProcessPriority ExecHandler::ProcessPriority(DProcess* aProcess) +// +// Get the process base priority. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessPriority")); + return procPriorityConvertTable[aProcess->iPriority]; + } + +TInt ExecHandler::ProcessSetPriority(DProcess* aProcess, TProcessPriority aPriority) +// +// Set the process base priority. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessSetPriority")); + aProcess->CheckedOpen(); + DThread& t=*TheCurrentThread; + t.iTempObj=aProcess; + NKern::UnlockSystem(); + if (!ProcessPriorityValid(aPriority)) + K::PanicKernExec(EBadPriority); + + TBool allowed=ETrue; + DProcess* currentProcess=TheCurrentThread->iOwningProcess; + if (aProcess->iSecurityZone!=currentProcess->iSecurityZone) // Not self... + if (aProcess->iCreatorId!=currentProcess->iId) // Not creator + { + TInt processPriority=aProcess->iPriority; + if (!(aProcess->iFlags&KProcessFlagPriorityControl) // No remote control... + || (processPriority!=EProcPriorityBackground && processPriority!=EProcPriorityForeground && processPriority!=EProcPriorityHigh) + || (aPriority!=EPriorityBackground && aPriority!=EPriorityForeground && aPriority!=EPriorityHigh) ) // Or not foreground/background/high + allowed=!(TheSuperPage().KernelConfigFlags() & EKernelConfigPlatSecProcessIsolation); + } + + NKern::ThreadEnterCS(); + t.iTempObj=NULL; + if(allowed) + aProcess->SetPriority(aPriority); + aProcess->Close(NULL); + NKern::ThreadLeaveCS(); + if (allowed) + { + return KErrNone; + } + else + { + return KErrPermissionDenied; + } + + } + + + +const TUint32 KDefinedProcessFlags= + KProcessFlagSystemCritical| + KProcessFlagSystemPermanent| + KProcessFlagJustInTime| + KProcessFlagPriorityControl| + KThreadFlagProcessCritical; + +const TUint32 KRestrictedProcessFlags = + ~(KProcessFlagJustInTime|KProcessFlagPriorityControl|KThreadFlagProcessCritical); // All but these are restricted + +const TUint32 KSelfOnlyProcessFlags = + ~0u; // (KProcessFlagJustInTime|KProcessFlagPriorityControl); // Only self can change these + +const TUint32 KDefinedThreadFlags= + KThreadFlagProcessCritical| + KThreadFlagProcessPermanent| + KThreadFlagSystemCritical| + KThreadFlagSystemPermanent| + KThreadFlagLastChance| + KThreadFlagRealtime| + KThreadFlagRealtimeTest; + +const TUint32 KRestrictedThreadFlags = + ~(KThreadFlagProcessCritical|KThreadFlagProcessPermanent|KThreadFlagLastChance| + KThreadFlagRealtime|KThreadFlagRealtimeTest); // All but these are restricted + +const TUint32 KSelfOnlyThreadFlags = + ~0u; // (KThreadFlagProcessCritical|KThreadFlagProcessPermanent|KThreadFlagLastChance); // Only owning process can change these + + +TUint ExecHandler::ProcessFlags(DProcess* aProcess) +// +// Get the process flags +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessFlags")); + return aProcess->iFlags; + } + +TUint ExecHandler::ThreadProcessFlags(DThread* aThread) +// +// Get the process flags +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadProcessFlags")); + return aThread->iOwningProcess->iFlags; + } + +void ExecHandler::ProcessSetFlags(DProcess* aProcess, TUint aClearMask, TUint aSetMask) +// +// Set the process flags +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessSetFlags")); + + TUint flags = aProcess->iFlags; + TUint modified = ((flags&~aClearMask)|aSetMask); + modified = (modified^flags)&KDefinedProcessFlags; + + DProcess* currentProcess=TheCurrentThread->iOwningProcess; + + if (modified&KSelfOnlyProcessFlags) + if(aProcess->iSecurityZone!=currentProcess->iSecurityZone) + if(aProcess->iCreatorId!=currentProcess->iId) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Attempt to modify the attributes of another Process. Possibly RProcess::SetSystem.")); + + if (modified&KRestrictedProcessFlags) + if(!currentProcess->HasCapability(ECapabilityProtServ,__PLATSEC_DIAGNOSTIC_STRING("Checked by User::SetProcessCritical (or RProcess::SetSystem)"))) + K::LockedPlatformSecurityPanic(); + + aProcess->iFlags=flags^modified; + + // if flags altered before resume, original thread inherits system critical and + // process critical from process. + if (!(aProcess->iAttributes & DProcess::EResumed)) + { + TUint32& tf = aProcess->FirstThread()->iFlags; + tf = (tf &~ (KThreadFlagSystemCritical|KThreadFlagProcessCritical)) | + (aProcess->iFlags & (KThreadFlagSystemCritical|KThreadFlagProcessCritical)); + } + } + +TInt ExecHandler::SemaphoreWait(DSemaphore* aSemaphore, TInt aTimeout) +// +// Wait for a signal. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::SemaphoreWait")); + if (aTimeout) + { + if (aTimeout<0) + { + NKern::UnlockSystem(); + return KErrArgument; + } + + // Convert microseconds to NTimer ticks, rounding up + TInt ntp = NKern::TickPeriod(); + aTimeout += ntp-1; + aTimeout /= ntp; + } + return aSemaphore->Wait(aTimeout); + } + +void ExecHandler::SemaphoreSignal1(DSemaphore* aSemaphore) +// +// Signal the semaphore once. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::SemaphoreSignal1")); + aSemaphore->Signal(); + } + +void ExecHandler::SemaphoreSignalN(DSemaphore* aSem, TInt aCount) +// +// Signal the semaphore aCount times. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::SemaphoreSignalN")); + aSem->CheckedOpen(); + NKern::ThreadEnterCS(); + aSem->SignalN(aCount); + NKern::UnlockSystem(); + aSem->Close(NULL); + NKern::ThreadLeaveCS(); + } + +TInt ExecHandler::ThreadId(DThread* aThread) +// +// Get thread ID. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadId")); + return (TInt)aThread->iId; + } + +LOCAL_C TBool IsThreadPriorityAbsoluteRealTime(TThreadPriority p) +// +// Returns true if priority is an absolute "real time" thread priority. +// + { + switch(p) + { + case EPriorityAbsoluteRealTime1: + case EPriorityAbsoluteRealTime2: + case EPriorityAbsoluteRealTime3: + case EPriorityAbsoluteRealTime4: + case EPriorityAbsoluteRealTime5: + case EPriorityAbsoluteRealTime6: + case EPriorityAbsoluteRealTime7: + case EPriorityAbsoluteRealTime8: + return ETrue; + default: + return EFalse; + } + } + +void ExecHandler::ThreadResume(DThread* aThread) +// +// Resume a thread. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadResume")); + if (aThread->iOwningProcess->iSecurityZone!=TheCurrentThread->iOwningProcess->iSecurityZone) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Use of RThread::Resume on a thread in another process")); + aThread->Resume(); + } + +TThreadPriority ExecHandler::ThreadPriority(DThread* aThread) +// +// Get the threads priority. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadPriority")); + return ConvertThreadPriority(aThread->iThreadPriority); + } + +void ExecHandler::ThreadSetPriority(DThread* aThread,TThreadPriority aPriority) +// +// Set the threads priority. +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadSetPriority")); + if (aThread->iOwningProcess->iSecurityZone!=TheCurrentThread->iOwningProcess->iSecurityZone) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Use of RThread::SetPriority on a thread in a different process")); + if(IsThreadPriorityAbsoluteRealTime(aPriority) && + !(TheCurrentThread->HasCapability(ECapabilityProtServ,__PLATSEC_DIAGNOSTIC_STRING("Checked by RThread::SetPriority")))) + K::LockedPlatformSecurityPanic(); + else + aThread->SetPriority(aPriority); + } + +TProcessPriority ExecHandler::ThreadProcessPriority(DThread* aThread) +// +// Get the owning process's priority. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadProcessPriority")); + return procPriorityConvertTable[aThread->iOwningProcess->iPriority]; + } + +void ExecHandler::ThreadSetProcessPriority(DThread* aThread, TProcessPriority aPriority) +// +// Set the owning process's priority. +// + { + ExecHandler::ProcessSetPriority(aThread->iOwningProcess,aPriority); + } + +TUint ExecHandler::ThreadFlags(DThread* aThread) +// +// Get the threads flag state. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadFlags")); + return(aThread->iFlags); + } + +void ExecHandler::ThreadSetFlags(DThread* aThread,TUint aClearMask,TUint aSetMask) +// +// Set the thread flags +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadSetFlags")); + TUint flags = aThread->iFlags; + TUint modified = ((flags&~aClearMask)|aSetMask); + modified = (modified^flags)&KDefinedThreadFlags; + + DProcess* currentProcess=TheCurrentThread->iOwningProcess; + + if (modified&KSelfOnlyThreadFlags) + if(aThread->iOwningProcess->iSecurityZone!=currentProcess->iSecurityZone) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Attempt to modify attributes of a thread in another process. Possibly RThread::SetSystem")); + + if (modified&KRestrictedThreadFlags) + if(!currentProcess->HasCapability(ECapabilityProtServ,__PLATSEC_DIAGNOSTIC_STRING("Checked by User::SetCritical (or RThread::SetSystem)"))) + K::LockedPlatformSecurityPanic(); + + aThread->iFlags=flags^modified; + } + +TExitType ExecHandler::ThreadExitType(DThread* aThread) +// +// Return the exit type. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadExitType")); + return (TExitType)aThread->iExitType; + } + +TInt ExecHandler::ThreadExitReason(DThread* aThread) +// +// Return the exit reason. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadExitReason")); + return aThread->iExitReason; + } + +void ExecHandler::ThreadExitCategory(DThread* aThread, TDes8& aName) +// +// Return the category of the exit type. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadExitCategory")); + TBufC exitCat(aThread->iExitCategory); + NKern::UnlockSystem(); + Kern::KUDesPut(aName,exitCat); + } + +void ExecHandler::ThreadRequestSignal(DThread* aThread) +// +// Signal a request completion. +// Enter with system locked, return with system unlocked. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadRequestSignal")); + if(aThread->iOwningProcess!=TheCurrentThread->iOwningProcess) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Attempt to use RThread::RequestComplete on a thread in another process")); + NKern::ThreadRequestSignal(&aThread->iNThread, SYSTEM_LOCK); + } + +TInt ExecHandler::FindHandleOpen(TOwnerType aType, const TFindHandle& aFindHandle) + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::FindHandleOpen")); + TFindHandle fh; + kumemget32(&fh,&aFindHandle,sizeof(fh)); + NKern::ThreadEnterCS(); + TInt h; + TInt r=TheCurrentThread->OpenFindHandle(aType,fh,h); + if(r==KErrNone) + r = h; + NKern::ThreadLeaveCS(); + if (r==KErrBadHandle) + K::PanicKernExec(EBadHandle); + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::FindHandleOpen returns %d",r)); + return r; + } + +TInt ExecHandler::HandleClose(TInt aHandle) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::HandleClose %08x",aHandle)); + NKern::ThreadEnterCS(); + TInt r=K::HandleClose(aHandle); + NKern::ThreadLeaveCS(); + if (r==KErrBadHandle) + K::PanicKernExec(EBadHandle); + else if (r==DObject::EObjectUnmapped) + TheCurrentThread->iOwningProcess->WaitDllLock(); + return r; + } + +TInt ExecHandler::LastThreadHandle() + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::LastThreadHandle")); + DThread& t=*TheCurrentThread; + NKern::ThreadEnterCS(); + RObjectIx::Wait(); + TInt r=t.iHandles.LastHandle(); + RObjectIx::Signal(); + NKern::ThreadLeaveCS(); + if (r) + r|=KHandleFlagLocal; + return r; + } + +TInt ExecHandler::ChunkCreate(TOwnerType aType, const TDesC8* aName, TChunkCreate& anInfo) + { + TKName n; + if (aName) + Kern::KUDesGet(n,*aName); + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ChunkCreate %lS",&n)); + TChunkCreate uinfo; + SChunkCreateInfo info; + kumemget32(&uinfo,&anInfo,sizeof(uinfo)); + info.iGlobal=uinfo.iAtt & TChunkCreate::EGlobal; + info.iAtt = uinfo.iAtt&TChunkCreate::EChunkCreateAttMask; + info.iForceFixed=uinfo.iForceFixed; + info.iOperations=SChunkCreateInfo::EAdjust; // adjust but don't add to process + info.iRunAddress=0; + info.iType=(uinfo.iAtt & TChunkCreate::ECode) ? EUserSelfModCode : EUserData; + info.iMaxSize=uinfo.iMaxSize; + info.iInitialBottom=uinfo.iInitialBottom; + info.iInitialTop=uinfo.iInitialTop; + info.iPreallocated=0; + info.iClearByte = uinfo.iClearByte; + DThread* pT=TheCurrentThread; + DProcess* pP=pT->iOwningProcess; + if (aName) + info.iName.Set(n); + else + info.iName.Set(NULL,0); + if (!info.iGlobal) + info.iOwner=(aType==EOwnerThread)?(DObject*)pT:(DObject*)pP; + else + info.iOwner=NULL; + NKern::ThreadEnterCS(); + DChunk* pC=NULL; + TLinAddr addr; + TInt r=pP->NewChunk(pC,info,addr); + if (r==KErrNone) + r=K::MakeHandle(aType,pC); // this will add the chunk to the process + if (rClose(NULL); // can't have been added so NULL + NKern::ThreadLeaveCS(); + __KTRACE_OPT(KTHREAD,Kern::Printf("Exec::ChunkCreate returns %d",r)); + return r; + } + +TInt ExecHandler::ChunkSetRestrictions(DChunk* aChunk, TUint aRestrictions) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ChunkSetRestrictions %O flags=%x",aChunk,aRestrictions)); + if(aChunk->iControllingOwner!=TheCurrentThread->iOwningProcess->iId) + return KErrAccessDenied; + aChunk->iRestrictions = aRestrictions; + return KErrNone; + } + +TInt ExecHandler::ChunkAdjust(DChunk* aChunk, TInt aType, TInt a1, TInt a2) + { + __KTRACE_OPT(KPROC,Kern::Printf("Exec::ChunkAdjust %O type %d a1=%x a2=%x",aChunk,aType,a1,a2)); + aChunk->CheckedOpen(); + NKern::ThreadEnterCS(); + NKern::UnlockSystem(); + TInt r=KErrNone; + TInt s=aChunk->CheckAccess(); + if (s!=KErrNone) + goto done; + if((aChunk->iRestrictions&EChunkPreventAdjust) && (aChunk->iControllingOwner!=TheCurrentThread->iOwningProcess->iId)) + { + r=KErrAccessDenied; + goto done; + } + switch (aType) + { + case EChunkAdjust: + r=aChunk->Adjust(a1); + break; + case EChunkAdjustDoubleEnded: + r=aChunk->AdjustDoubleEnded(a1,a2); + break; + case EChunkCommit: + r=aChunk->Commit(a1,a2); + break; + case EChunkDecommit: + r=aChunk->Decommit(a1,a2); + break; + case EChunkAllocate: + r=aChunk->Allocate(a1); + break; + case EChunkLock: + if(&Kern::CurrentProcess()!=aChunk->iOwningProcess) + r = KErrAccessDenied; + else + r=aChunk->Lock(a1,a2); + break; + case EChunkUnlock: + if(&Kern::CurrentProcess()!=aChunk->iOwningProcess) + r = KErrAccessDenied; + else + r=aChunk->Unlock(a1,a2); + break; + default: + r=KErrArgument; + break; + } +done: + aChunk->Close(NULL); // NULL because we didn't up the process access count + NKern::ThreadLeaveCS(); + if (s!=KErrNone) + K::PanicKernExec(EAccessDenied); + __KTRACE_OPT(KPROC,Kern::Printf("Exec::ChunkAdjust returns %d",r)); + return r; + } + + +/** +@return ETrue if the chunk is data paged, EFalse otherwise. +*/ +TBool ExecHandler::ChunkIsPaged(DChunk* aChunk) + { + return (aChunk->iAttributes & DChunk::EDataPaged) != 0; + } + + +/** +@return ETrue if the process is data paged, EFalse otherwise. +*/ +TBool ExecHandler::ProcessDefaultDataPaged(DProcess* aProcess) + { + return (aProcess->iAttributes & DProcess::EDataPaged) != 0; + } + + + +TInt ExecHandler::OpenObject(TObjectType aObjType, const TDesC8& aName, TOwnerType aType) + { + __KTRACE_OPT(KTHREAD,Kern::Printf("Exec::OpenObject %lS",&aName)); + TFullName n; + Kern::KUDesGet(n,aName); + if (Kern::ValidateFullName(n)!=KErrNone) + K::PanicKernExec(EBadName); + if ((TUint)aObjType>=(TUint)ENumObjectTypes) + K::PanicKernExec(EBadObjectType); + TInt h=0; + DObject* pO=NULL; + NKern::ThreadEnterCS(); + TInt r=TheCurrentThread->OpenObject(aType,n,h,pO,aObjType); + NKern::ThreadLeaveCS(); + if(r==KErrNone) + r = h; + __KTRACE_OPT(KTHREAD,Kern::Printf("Exec::OpenObject returns %d",r)); + return r; + } + + +TInt ExecHandler::HandleDuplicate(TInt aThreadHandle, TOwnerType aType, TInt& aHandle) + { + TInt h; + kumemget32(&h, &aHandle, sizeof(h)); + __KTRACE_OPT(KTHREAD,Kern::Printf("Exec::HandleDuplicate %08x", h)); + DThread* pC=TheCurrentThread; + NKern::LockSystem(); + DThread* pT=(DThread*)K::ThreadEnterCS(aThreadHandle,EThread); + __KTRACE_OPT(KTHREAD,Kern::Printf("Exec::HandleDuplicate source thread %O",pT)); + TInt r=KErrBadHandle; + NKern::LockSystem(); + DObject* pO=pT->ObjectFromHandle(h); + h = 0; // now holds value to be returned + if (pO) + r=pO->Open(); + NKern::UnlockSystem(); + if (r==KErrNone) + { + if (pO->Protection()!=DObject::EGlobal + && pT->iOwningProcess->iSecurityZone!=pC->iOwningProcess->iSecurityZone) + { +#ifndef __REMOVE_PLATSEC_DIAGNOSTICS__ + r = PlatSec::ProcessIsolationFail(__PLATSEC_DIAGNOSTIC_STRING("Checked by RHandleBase::Duplicate")); +#else //__REMOVE_PLATSEC_DIAGNOSTICS__ + r = PlatSec::EmitDiagnostic(); +#endif // !__REMOVE_PLATSEC_DIAGNOSTICS__ + } + if (r==KErrNone) + r = pC->MakeHandle(aType, pO, h); // this will add to process if necessary + if (rClose(NULL); // can't have been added to process so NULL + } + pT->Close(NULL); + TInt s = KErrNone; + XTRAP(s, XT_DEFAULT, kumemput32(&aHandle, &h, sizeof(h))); + if (s!=KErrNone && r==KErrNone) + pC->HandleClose(h); + NKern::ThreadLeaveCS(); + if (r == KErrBadHandle) + K::PanicKernExec(EBadHandle); + if (s != KErrNone) + K::PanicKernExec(ECausedException); + __KTRACE_OPT(KTHREAD,Kern::Printf("Exec::HandleDuplicate returns %d",r)); + return r; + } + +TInt ExecHandler::MutexCreate(const TDesC8* aName, TOwnerType aType) + { + TKName n; + DObject* pO=NULL; + const TDesC* pN=NULL; + if (aName) + { + Kern::KUDesGet(n,*aName); + pN=&n; + } + else if (aType==EOwnerThread) + pO=TheCurrentThread; + else + pO=TheCurrentThread->iOwningProcess; + __KTRACE_OPT(KSEMAPHORE,Kern::Printf("Exec::MutexCreate %lS",aName)); + NKern::ThreadEnterCS(); + DMutex* pM; + TInt r=K::MutexCreate(pM, *pN, pO, ETrue, KMutexOrdUser); + if (r==KErrNone) + { + if(aName) + pM->SetProtection(n.Length()? DObject::EGlobal : DObject::EProtected); + r=K::MakeHandle(aType,pM); + if (rClose(NULL); + } + NKern::ThreadLeaveCS(); + __KTRACE_OPT(KSEMAPHORE,Kern::Printf("Exec::MutexCreate returns %d",r)); + return r; + } + +TInt ExecHandler::SemaphoreCreate(const TDesC8* aName, TInt aCount, TOwnerType aType) + { + __KTRACE_OPT(KSEMAPHORE,Kern::Printf("Exec::SemaphoreCreate %lS",aName)); + TKName n; + DObject* pO=NULL; + const TDesC* pN=NULL; + if (aName) + { + Kern::KUDesGet(n,*aName); + pN=&n; + } + else if (aType==EOwnerThread) + pO=TheCurrentThread; + else + pO=TheCurrentThread->iOwningProcess; + NKern::ThreadEnterCS(); + TInt r=KErrNoMemory; + DSemaphore* pS=new DSemaphore; + if (pS) + r=pS->Create(pO,pN,aCount); + if (r==KErrNone) + { + if(aName) + pS->SetProtection(n.Length()? DObject::EGlobal : DObject::EProtected); + r=K::MakeHandle(aType,pS); + } + if (rClose(NULL); + NKern::ThreadLeaveCS(); + __KTRACE_OPT(KSEMAPHORE,Kern::Printf("Exec::SemaphoreCreate returns %d",r)); + return r; + } + +LOCAL_C TInt OpenById(TUint anId, TOwnerType aType, TBool aProcess) + { + NKern::ThreadEnterCS(); + TInt type=aProcess?EProcess:EThread; + DObjectCon* pC=K::Containers[type]; + pC->Wait(); + DObject* pO=aProcess?(DObject*)Kern::ProcessFromId(anId):(DObject*)Kern::ThreadFromId(anId); + TInt r=KErrNotFound; + if (pO && (r=pO->Open())==KErrNone) + { + pC->Signal(); // must release this before opening handle + DProcess* pP; + if(aProcess) + pP=(DProcess*)pO; + else + pP=((DThread*)pO)->iOwningProcess; + + if( pO->Protection()!=DObject::EGlobal + && pP->iSecurityZone!=TheCurrentThread->iOwningProcess->iSecurityZone) + { +#ifndef __REMOVE_PLATSEC_DIAGNOSTICS__ + r = PlatSec::ProcessIsolationFail(__PLATSEC_DIAGNOSTIC_STRING("Checked by RThread::Open(TThreadId)")); +#else //__REMOVE_PLATSEC_DIAGNOSTICS__ + r = PlatSec::EmitDiagnostic(); +#endif // !__REMOVE_PLATSEC_DIAGNOSTICS__ + } + if (r==KErrNone) + r=K::MakeHandle(aType,pO); + if (rClose(NULL); + } + else + pC->Signal(); + NKern::ThreadLeaveCS(); + return r; + } + +TInt ExecHandler::ThreadOpenById(TUint anId, TOwnerType aType) + { + __KTRACE_OPT(KTHREAD,Kern::Printf("Exec::ThreadOpenById %d",anId)); + TInt r=OpenById(anId,aType,EFalse); + __KTRACE_OPT(KTHREAD,Kern::Printf("Exec::ThreadOpenById returns %d",r)); + return r; + } + +TInt ExecHandler::ProcessOpenById(TUint anId, TOwnerType aType) + { + __KTRACE_OPT(KPROC,Kern::Printf("Exec::ProcessOpenById %d",anId)); + TInt r=OpenById(anId,aType,ETrue); + __KTRACE_OPT(KPROC,Kern::Printf("Exec::ProcessOpenById returns %d",r)); + return r; + } + +// Enter with system locked, return with system unlocked +void ExecHandler::ThreadLogon(DThread* aThread, TRequestStatus* aStatus, TBool aRendezvous) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadLogon")); + aThread->CheckedOpen(); + NKern::ThreadEnterCS(); + NKern::UnlockSystem(); + TInt r=aThread->Logon(aStatus,aRendezvous); + if (r!=KErrNone) + { + if (r==KErrDied) + r=aThread->iExitReason; + Kern::RequestComplete(aStatus,r); + } + aThread->Close(NULL); + NKern::ThreadLeaveCS(); + } + +// Enter with system locked, return with system unlocked +TInt ExecHandler::ThreadLogonCancel(DThread* aThread, TRequestStatus* aStatus, TBool aRendezvous) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadLogonCancel")); + aThread->CheckedOpen(); + NKern::ThreadEnterCS(); + NKern::UnlockSystem(); + DThread& t = *TheCurrentThread; + TUint32 type = TLogon::ETargetThread; + if (aRendezvous) + type |= TLogon::ERendezvous; + TInt r = TLogon::Cancel(t.iOwnedLogons, aThread, aStatus, type); + aThread->Close(NULL); + NKern::ThreadLeaveCS(); + return r; + } + +// Enter with system locked, return with system unlocked +void ExecHandler::ProcessLogon(DProcess* aProcess, TRequestStatus* aStatus, TBool aRendezvous) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessLogon")); + aProcess->CheckedOpen(); + NKern::ThreadEnterCS(); + NKern::UnlockSystem(); + TInt r=aProcess->Logon(aStatus,aRendezvous); + if (r!=KErrNone) + { + if (r==KErrDied) + r=aProcess->iExitReason; + Kern::RequestComplete(aStatus,r); + } + aProcess->Close(NULL); + NKern::ThreadLeaveCS(); + } + +// Enter with system locked, return with system unlocked +TInt ExecHandler::ProcessLogonCancel(DProcess* aProcess, TRequestStatus* aStatus, TBool aRendezvous) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessLogonCancel")); + aProcess->CheckedOpen(); + NKern::ThreadEnterCS(); + NKern::UnlockSystem(); + DThread& t = *TheCurrentThread; + TUint32 type = TLogon::ETargetProcess; + if (aRendezvous) + type |= TLogon::ERendezvous; + TInt r = TLogon::Cancel(t.iOwnedLogons, aProcess, aStatus, type); + aProcess->Close(NULL); + NKern::ThreadLeaveCS(); + return r; + } + +TAny* ExecHandler::DllTls(TInt aHandle, TInt aDllUid) + { + // no protection needed since only this thread can access the TLS array + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::DllTls")); +#ifndef __EPOC32__ + extern TInt LookupDllUid(TInt); + + if (aDllUid == KDllUid_Special) + aDllUid = LookupDllUid(aHandle); +#endif + return TheCurrentThread->Tls(aHandle,aDllUid); + } + +TInt ExecHandler::DllSetTls(TInt aHandle, TInt aDllUid, TAny* aPtr) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::DllSetTls %08x->%08x", aHandle, aPtr)); +#ifndef __EPOC32__ + extern TInt LookupDllUid(TInt); + + if (aDllUid == KDllUid_Special) + aDllUid = LookupDllUid(aHandle); +#endif + NKern::ThreadEnterCS(); + TInt r=TheCurrentThread->SetTls(aHandle,aDllUid,aPtr); + NKern::ThreadLeaveCS(); + return r; + } + +void ExecHandler::DllFreeTls(TInt aHandle) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::DllFreeTls")); + NKern::ThreadEnterCS(); + TheCurrentThread->FreeTls(aHandle); + NKern::ThreadLeaveCS(); + } + +TInt ExecHandler::ThreadRename(TInt aHandle, const TDesC8& aName) + { + TKName n; + Kern::KUDesGet(n,aName); + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadRename %lS",&n)); + NKern::LockSystem(); + DThread* pT=(DThread*)K::ThreadEnterCS(aHandle,EThread); + if (pT!=TheCurrentThread && + pT->iOwningProcess->iSecurityZone!=TheCurrentThread->iOwningProcess->iSecurityZone) + { + if(TheSuperPage().KernelConfigFlags() & EKernelConfigPlatSecEnforcement) + { + pT->Close(NULL); + K::ThreadLeaveCS(); + } + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RThread::Rename")); + if(TheSuperPage().KernelConfigFlags() & EKernelConfigPlatSecEnforcement) + Kern::Fault("ThreadRename",0); + } + TInt r=pT->Rename(n); + pT->Close(NULL); + NKern::ThreadLeaveCS(); + return r; + } + +TInt ExecHandler::ProcessRename(TInt aHandle, const TDesC8& aName) + { + TKName n; + Kern::KUDesGet(n,aName); + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessRename %lS",&n)); + NKern::LockSystem(); + DProcess* pP=(DProcess*)K::ThreadEnterCS(aHandle,EProcess); + if (pP->iSecurityZone!=TheCurrentThread->iOwningProcess->iSecurityZone) + { + if(TheSuperPage().KernelConfigFlags() & EKernelConfigPlatSecEnforcement) + { + pP->Close(NULL); + K::ThreadLeaveCS(); + } + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RProcess::Rename")); + if(TheSuperPage().KernelConfigFlags() & EKernelConfigPlatSecEnforcement) + Kern::Fault("ProcessRename",0); + } + TInt r=pP->Rename(n); + pP->Close(NULL); + NKern::ThreadLeaveCS(); + return r; + } + +TInt ExecHandler::ThreadProcess(DThread* aThread) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadProcess")); + DProcess* pP=aThread->iOwningProcess; + pP->Open(); // can't get an error here + NKern::ThreadEnterCS(); + NKern::UnlockSystem(); + TInt r=K::MakeHandle(EOwnerThread,pP); + if (rClose(NULL); + NKern::ThreadLeaveCS(); + return r; + } + +RAllocator* ExecHandler::ThreadGetHeap(DThread* aThread) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadGetHeap %O",aThread)); + if (aThread->iOwningProcess->iSecurityZone!=TheCurrentThread->iOwningProcess->iSecurityZone) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RThread::Heap")); + return aThread->iAllocator; + } + +void ExecHandler::HandleName(TInt aHandle, TDes8& aName) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::HandleName")); + DObject* pO=NULL; + TInt r=K::OpenObjectFromHandle(aHandle,pO); + if (r!=KErrNone) + K::PanicKernExec(EBadHandle); + TKName n; + pO->Name(n); + pO->Close(NULL); + NKern::ThreadLeaveCS(); + Kern::KUDesPut(aName,n); + } + +void ExecHandler::HandleFullName(TInt aHandle, TDes8& aFullName) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::HandleFullName")); + DObject* pO=NULL; + TInt r=K::OpenObjectFromHandle(aHandle,pO); + if (r!=KErrNone) + K::PanicKernExec(EBadHandle); + TFullName n; + pO->FullName(n); + pO->Close(NULL); + NKern::ThreadLeaveCS(); + Kern::KUDesPut(aFullName,n); + } + +void ExecHandler::HandleCount(DThread* aThread, TInt& aProcessHandleCount, TInt& aThreadHandleCount) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::HandleCount")); + TInt tCount=aThread->iHandles.ActiveCount(); + TInt pCount=aThread->iOwningProcess->iHandles.ActiveCount(); + NKern::UnlockSystem(); + kumemput32(&aProcessHandleCount,&pCount,sizeof(pCount)); + kumemput32(&aThreadHandleCount,&tCount,sizeof(tCount)); + } + +TInt ExecHandler::GetBTraceId(DObject* aObj) +// +// Get the BTraceID of any given RHandleBase-derived object. In practice +// this ID is simply a pointer to the associated DObject. +// + { + return (TInt)aObj; + } + +void ExecHandler::HandleInfo(TInt aHandle, THandleInfo* anInfo) +// +// Find out how many threads and processes have an open handle on the object given by +// a handle, and whether it's open in this process and thread. +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::HandleInfo")); + THandleInfo hinfo; + memclr(&hinfo, sizeof(hinfo)); + DObject* pO=NULL; + TInt r=K::OpenObjectFromHandle(aHandle,pO); + if (r==KErrNone) + { + RObjectIx::Wait(); + DProcess* pCurrentProcess=TheCurrentThread->iOwningProcess; + hinfo.iNumOpenInThread=TheCurrentThread->iHandles.Count(pO); + hinfo.iNumOpenInProcess=pCurrentProcess->iHandles.Count(pO); + + DObjectCon& threads=*K::Containers[EThread]; + threads.Wait(); + TInt c=threads.Count(); + TInt i=0; + for (;iiHandles.At(pO); + if (r!=KErrNotFound) + { + ++hinfo.iNumThreads; + if (pT->iOwningProcess==pCurrentProcess) + ++hinfo.iNumOpenInProcess; + } + } + threads.Signal(); + DObjectCon& processes=*K::Containers[EProcess]; + processes.Wait(); + c=processes.Count(); + for (i=0;iiHandles.At(pO); + if (r!=KErrNotFound) + ++hinfo.iNumProcesses; + } + processes.Signal(); + RObjectIx::Signal(); + pO->Close(NULL); + NKern::ThreadLeaveCS(); + } + kumemput32(anInfo,&hinfo,sizeof(hinfo)); + } + +TUint ExecHandler::HandleAttributes(TInt aHandle) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::HandleAttributes")); + TUint attributes = RHandleBase::EReadAccess | RHandleBase::EDirectReadAccess; + NKern::LockSystem(); + DObject* pO = K::ObjectFromHandle(aHandle); + if (pO->UniqueID() - 1 == EChunk) + { + DChunk* pChunk = (DChunk*) pO; + if (!(pChunk->iAttributes & DChunk::EReadOnly) || + (TheCurrentThread->iOwningProcess->iId == pChunk->iControllingOwner)) + { + attributes |= (RHandleBase::EWriteAccess | RHandleBase::EDirectWriteAccess); + } + } + else + { + attributes |= (RHandleBase::EWriteAccess | RHandleBase::EDirectWriteAccess); + } + NKern::UnlockSystem(); + return attributes; + } + +TLibraryFunction ExecHandler::LibraryLookup(TInt aLibraryHandle, TInt aOrdinal) + { + TLibraryFunction f = NULL; + NKern::LockSystem(); + +XTRAP_PAGING_RETRY( + DLibrary* library = (DLibrary*)K::ObjectFromHandle(aLibraryHandle,ELibrary); + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::LibraryLookup %O %d",library,aOrdinal)); + DCodeSeg* pS = library->iCodeSeg; + if(pS) + f = pS->Lookup(aOrdinal); +) + NKern::UnlockSystem(); + return f; + } + +/** +Retrieves pointer to the named symbol export data, if present. + +@param aProcessHandle Handle to the process whose code seg to search +@return Pointer to named symbol export data if its present, NULL otherwise +@internalComponent +*/ +TAny* ExecHandler::ProcessExeExportData(void) + { + DProcess* pP = &Kern::CurrentProcess(); + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessExeExportData %O",pP)); + DCodeSeg* pS = pP->CodeSeg(); // can't be null if process is running + + // Lookup() returns NULL if this is not a stdexe/stddll + return (TAny*)pS->Lookup(0); + } + +void ExecHandler::LibraryType(DLibrary* aLibrary, TUidType& aUids) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::LibraryType")); + TUidType uids; + memclr(&uids, sizeof(uids)); + DCodeSeg* pS=aLibrary->iCodeSeg; + if (pS) + uids=pS->iUids; + __KTRACE_OPT(KEXEC,Kern::Printf("UIDS: %08x,%08x,%08x",uids.iUid[0],uids.iUid[1],uids.iUid[2])); + NKern::UnlockSystem(); + kumemput32(&aUids,&uids,sizeof(TUidType)); + } + +void ExecHandler::LibraryFileName(DLibrary* aLibrary, TDes8& aFileName) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::LibraryFileName")); + TFileName fn; + DCodeSeg* pS=aLibrary->iCodeSeg; + if (pS) + pS->AppendFullFileName(fn); + NKern::UnlockSystem(); + P::NormalizeExecutableFileName(fn); + Kern::KUDesPut(aFileName, fn); + } + +TInt ExecHandler::HalFunction(TInt aGroup, TInt aFunction, TAny* a1, TAny* a2) + { + TInt aDeviceNumber = TUint(aGroup)>>16; + aGroup=aGroup&0xffff; + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::HalFunction(%d,%d,%08x,%08x,%d)",aGroup,aFunction,a1,a2,aDeviceNumber)); + TInt r=KErrNotSupported; + if(TUint(aDeviceNumber)>=TUint(KMaxHalEntries)) + return r; + if (aGroup>=0 && aGroup0) + { + if(!pE->iExtendedEntries) + return r; + pBase=pE->iExtendedEntries + (aDeviceNumber-1); + } + NKern::LockSystem(); + f=pBase->iFunction; + p=pBase->iPtr; + NKern::UnlockSystem(); + if (f) + r=(*f)(p,aFunction,a1,a2); + } + return r; + } + +TUint32 ExecHandler::DebugMask() + { + return TheSuperPage().iDebugMask[0]; + } + +TUint32 ExecHandler::DebugMaskIndex(TUint aIndex) + { + if (aIndex >= (TUint)KNumTraceMaskWords) + return 0; + else + return TheSuperPage().iDebugMask[aIndex]; + } + +void ExecHandler::SetDebugMask(TUint32 aVal) + { + TheSuperPage().iDebugMask[0]=(TInt)aVal; + } + +void ExecHandler::SetDebugMaskIndex(TUint32 aVal, TUint aIndex) + { + if (aIndex >= (TUint)KNumTraceMaskWords) return; + + // check that we have permission to set KALLTHREADSSYSTEM bit + if (aIndex == DEBUGMASKWORD2 && (aVal & (1 << (KALLTHREADSSYSTEM%32)))) + { + DProcess* currentProcess=TheCurrentThread->iOwningProcess; + if(!currentProcess->HasCapability(ECapabilityProtServ,__PLATSEC_DIAGNOSTIC_STRING("Checked by User::SetDebugMask(TUint32, TUint)"))) + K::UnlockedPlatformSecurityPanic(); + } + + TheSuperPage().iDebugMask[aIndex]=(TInt)aVal; + } + +RAllocator* ExecHandler::HeapSwitch(RAllocator* aA) + { + DThread* pT = TheCurrentThread; + RAllocator* pA = pT->iAllocator; + pT->iAllocator = aA; + if (!pT->iCreatedAllocator) + pT->iCreatedAllocator = aA; + return pA; + } + +void ExecHandler::KernelHeapDebug(TInt aFunction, TInt a1, TAny* a2) + { + (void)aFunction; + (void)a1; + (void)a2; + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::KernelHeapDebug %d,%08x,%08x",aFunction,a1,a2)); +#ifdef _DEBUG + TInt panic=KMinTInt; + switch (aFunction) + { + case EDbgMarkStart: + NKern::ThreadEnterCS(); + K::Allocator->__DbgMarkStart(); + NKern::ThreadLeaveCS(); + break; + + case EDbgMarkCheck: + { + TBuf8 name; + TKernelHeapMarkCheckInfo info; + kumemget32(&info,a2,sizeof(info)); + Kern::KUDesGet(name,*info.iFileName); + NKern::ThreadEnterCS(); + TInt r = K::Allocator->__DbgMarkCheck(info.iCountAll, a1, name, info.iLineNum); + if (r!=KErrNone) + panic=EFailedKernelHeapCheck; + NKern::ThreadLeaveCS(); + break; + } + + case EDbgMarkEnd: + { + NKern::ThreadEnterCS(); + TInt r = K::Allocator->__DbgMarkEnd(a1); + if (r!=KErrNone) + panic=EFailedKernelHeapCheck; + NKern::ThreadLeaveCS(); + break; + } + + case EDbgSetAllocFail: + NKern::ThreadEnterCS(); + K::Allocator->__DbgSetAllocFail((RAllocator::TAllocFail)a1,(TInt)a2); + NKern::ThreadLeaveCS(); + break; + + case EDbgSetBurstAllocFail: + { + SRAllocatorBurstFail burstFail; + kumemget32(&burstFail, a2, sizeof(SRAllocatorBurstFail)); + NKern::ThreadEnterCS(); + K::Allocator->__DbgSetBurstAllocFail((RAllocator::TAllocFail)a1, burstFail.iRate, burstFail.iBurst); + NKern::ThreadLeaveCS(); + break; + } + + case EDbgCheckFailure: + { + NKern::ThreadEnterCS(); + TUint failures = K::Allocator->__DbgCheckFailure(); + NKern::ThreadLeaveCS(); + kumemput32(a2, (TAny*)&failures, sizeof(TUint)); + break; + } + + default: + panic=EBadKernelHeapDebugFunction; + break; + } + if (panic>KMinTInt) + K::PanicKernExec(panic); +#endif + } + +TExceptionHandler ExecHandler::ExceptionHandler(DThread* aThread) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ExceptionHandler")); + if(aThread!=TheCurrentThread) + if(TheCurrentThread->iOwningProcess->iSecurityZone!=KSecurityZoneLegacyCode + || aThread->iOwningProcess->iSecurityZone!=KSecurityZoneLegacyCode + ) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RThread::ExceptionHandler")); + return aThread->iExceptionHandler; + } + +TInt ExecHandler::SetExceptionHandler(DThread* aThread, TExceptionHandler aHandler, TUint32 aMask) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::SetExceptionHandler")); + if(aThread!=TheCurrentThread) + if(TheCurrentThread->iOwningProcess->iSecurityZone!=KSecurityZoneLegacyCode + || aThread->iOwningProcess->iSecurityZone!=KSecurityZoneLegacyCode + ) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RThread::SetExceptionHandler")); + aThread->iExceptionHandler=aHandler; + aThread->iExceptionMask=aMask; + return KErrNone; + } + +void ExecHandler::ModifyExceptionMask(DThread* aThread, TUint32 aClearMask, TUint32 aSetMask) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ModifyExceptionMask")); + if(aThread!=TheCurrentThread) + if(TheCurrentThread->iOwningProcess->iSecurityZone!=KSecurityZoneLegacyCode + || aThread->iOwningProcess->iSecurityZone!=KSecurityZoneLegacyCode + ) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RThread::ModifyExceptionMask")); + TUint& m=aThread->iExceptionMask; + m=(m&~aClearMask)|aSetMask; + } + +TInt ExecHandler::RaiseException(DThread* aThread, TExcType aType) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::RaiseException %d on %O",aType,aThread)); + if(aThread!=TheCurrentThread) + if(TheCurrentThread->iOwningProcess->iSecurityZone!=KSecurityZoneLegacyCode + || aThread->iOwningProcess->iSecurityZone!=KSecurityZoneLegacyCode + ) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RThread::RaiseException")); + return aThread->RaiseException(aType); + } + +TBool ExecHandler::IsExceptionHandled(DThread* aThread,TExcType aType, TBool aSwExcInProgress) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::IsExceptionHandled %d %d",aType,aSwExcInProgress)); + if(aThread!=TheCurrentThread) + if(TheCurrentThread->iOwningProcess->iSecurityZone!=KSecurityZoneLegacyCode + || aThread->iOwningProcess->iSecurityZone!=KSecurityZoneLegacyCode + ) + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Checked by RThread::IsExceptionHandled")); + TBool isHandled=aThread->IsExceptionHandled(aType); + NKern::UnlockSystem(); + if (aSwExcInProgress) + DKernelEventHandler::Dispatch(EEventSwExc, (TAny*)aType, NULL); + return isHandled; + } + +void ExecHandler::ThreadContext(DThread* aThread, TDes8& aDes) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadContext %O",aThread)); + TBuf8 c; + aThread->Context(c); + NKern::UnlockSystem(); + Kern::InfoCopy(aDes,c); + } + +TInt ExecHandler::ThreadStackInfo(DThread* aThread, TThreadStackInfo& aInfo) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadStackInfo %O",aThread)); + TThreadStackInfo info; + memclr(&info, sizeof(info)); + TInt r=KErrGeneral; + if(aThread->iUserStackRunAddress) + { + info.iBase = aThread->iUserStackRunAddress+aThread->iUserStackSize; + info.iLimit = aThread->iUserStackRunAddress; + info.iExpandLimit = aThread->iUserStackRunAddress; + r = KErrNone; + } + NKern::UnlockSystem(); + kumemput32(&aInfo,&info,sizeof(info)); + return r; + } + +TInt ExecHandler::ProcessGetMemoryInfo(TInt aProcessHandle, TModuleMemoryInfo& aInfo) + { + TModuleMemoryInfo info; + memclr(&info, sizeof(info)); + TInt r = KErrGeneral; + NKern::LockSystem(); + +XTRAP_PAGING_RETRY( + DProcess* process = (DProcess*)K::ObjectFromHandle(aProcessHandle,EProcess); + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessGetMemoryInfo %O",process)); + DCodeSeg* seg=process->iCodeSeg; + if(seg) + r = seg->GetMemoryInfo(info,TheCurrentThread->iOwningProcess); +) + NKern::UnlockSystem(); + kumemput32(&aInfo, &info, sizeof(info)); + return r; + } + +TInt ExecHandler::LibraryGetMemoryInfo(TInt aLibraryHandle, TModuleMemoryInfo& aInfo) + { + TModuleMemoryInfo info; + memclr(&info, sizeof(info)); + TInt r = KErrGeneral; + NKern::LockSystem(); + +XTRAP_PAGING_RETRY( + DLibrary* library = (DLibrary*)K::ObjectFromHandle(aLibraryHandle,ELibrary); + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::LibraryGetMemoryInfo %O",library)); + DCodeSeg* seg=library->iCodeSeg; + if(seg) + r = seg->GetMemoryInfo(info,TheCurrentThread->iOwningProcess); +) + NKern::UnlockSystem(); + kumemput32(&aInfo, &info, sizeof(info)); + return r; + } + +void AccessMachineConfig() + { + NKern::ThreadEnterCS(); + Kern::MutexWait(*K::MachineConfigMutex); + } + +void EndAccessMachineConfig() + { + Kern::MutexSignal(*K::MachineConfigMutex); + NKern::ThreadLeaveCS(); + } + +TInt ExecHandler::MachineConfiguration(TDes8& aConfig, TInt& aSize) +// +// Get the machine configuration +// Enter and leave with system unlocked +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::MachineConfiguration")); + if(!Kern::CurrentThreadHasCapability(ECapabilityReadDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by User::MachineConfiguration"))) + K::UnlockedPlatformSecurityPanic(); + const TPtrC8 platConfig(A::MachineConfiguration()); + TInt platSize=platConfig.Length(); + TInt usize=sizeof(TUid)+sizeof(TVersion)+sizeof(platSize)+platSize; + + TInt ulen, umax; + Kern::KUDesInfo(aConfig,ulen,umax); + TInt r = KErrArgument; + if(umax uid; + TPckgBuf version; + TPckgBuf platSizeBuf; + TInt platSize; + TInt i=0; + TPtrC8 platConfig; + DThread& t=*TheCurrentThread; + + // first allocate a kernel-side buffer big enough to hold the new configuration + NKern::ThreadEnterCS(); + pB=(TUint8*)Kern::Alloc(len); + if (!pB) + goto endSetMachineConfig2; + t.iTempAlloc=pB; // if we are killed, pB will be deleted + NKern::ThreadLeaveCS(); + + // copy the configuration + kumemget(pB,pC,len); + r=KErrArgument; + if (len<(TInt)(sizeof(TUid)+sizeof(TVersion)+sizeof(TInt))) + goto endSetMachineConfig; + + // extract and check the UID + uid.Copy(pB+i,(TInt)sizeof(TUid)); + if (uid().iUid!=KMachineConfigurationUidValue) + goto endSetMachineConfig; + i+=(TInt)sizeof(TUid); + + // extract and check the version + version.Copy(pB+i,(TInt)sizeof(TVersion)); + r=KErrNotSupported; + if(!Kern::QueryVersionSupported(TVersion(KMachineConfigurationMajorVersionNumber,KMachineConfigurationMinorVersionNumber,KMachineConfigurationBuildVersionNumber),version())) + goto endSetMachineConfig; + i+=(TInt)sizeof(TVersion); + + // extract and check the super page size + platSizeBuf.Copy(pB+i,(TInt)sizeof(TInt)); + i+=(TInt)sizeof(TInt); + platSize=platSizeBuf(); + r=KErrArgument; + if (platSize>(len-i)) + goto endSetMachineConfig; + + platConfig.Set(pB+i,platSize); + + // restore the super page config + AccessMachineConfig(); + K::SetMachineConfiguration(platConfig); + r=KErrNone; + EndAccessMachineConfig(); + +endSetMachineConfig: + NKern::ThreadEnterCS(); + t.iTempAlloc=NULL; + delete pB; +endSetMachineConfig2: + NKern::ThreadLeaveCS(); + return r; + } + +TInt ExecHandler::ThreadCreate(const TDesC8& aName, TOwnerType aType, SThreadCreateInfo& aInfo) + { + TKName n; + Kern::KUDesGet(n,aName); + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadCreate %lS",&n)); + TUint32 infoBuf[KMaxThreadCreateInfo/sizeof(TUint32)]; + SThreadCreateInfo& info = *(SThreadCreateInfo*)infoBuf; + kumemget32(&info, &aInfo, sizeof(SThreadCreateInfo)); + TInt r = ( (info.iTotalSize < (TInt)sizeof(SThreadCreateInfo)) || (info.iTotalSize > KMaxThreadCreateInfo) || (info.iTotalSize & 7) ) + ? KErrArgument : KErrNone; + if (info.iUserStackSize < KMaxThreadCreateInfo*2) + r=KErrArgument; + if (r==KErrNone) + { + if (info.iTotalSize > (TInt)sizeof(SThreadCreateInfo)) + kumemget32( (&info)+1, (&aInfo)+1, info.iTotalSize-(TInt)sizeof(SThreadCreateInfo) ); + info.iType=EThreadUser; + info.iSupervisorStackSize=0; // zero means use default value + info.iSupervisorStack=NULL; + info.iInitialThreadPriority=EThrdPriorityNormal; + info.iName.Set(n); + NKern::ThreadEnterCS(); + DThread* pT=NULL; + TInt h; + r=TheCurrentThread->iOwningProcess->NewThread(pT, info, &h, aType); + if(r==KErrNone) + r = h; + NKern::ThreadLeaveCS(); + } + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadCreate returns %d",r)); + return r; + } + +/******************************************** + * Kernel-side executive calls + ********************************************/ + +TInt K::MutexCreate(DMutex*& aMutex, const TDesC& aName, DObject* anOwner, TBool aVisible, TUint aOrder) + { + __KTRACE_OPT(KSEMAPHORE,Kern::Printf("K::MutexCreate %lS owner %O visible=%d order=%02x",&aName,anOwner,aVisible,aOrder)); + DMutex* pM=new DMutex; + TInt r=KErrNoMemory; + if (pM) + { + r=pM->Create(anOwner, &aName, aVisible, aOrder); + if (r==KErrNone) + aMutex=pM; + else + pM->Close(NULL); + } + __KTRACE_OPT(KSEMAPHORE,Kern::Printf("K::MutexCreate returns %d %08x",r,pM)); + return r; + } + +/** Creates a new thread. + + It receives a parameter of type SThreadCreateInfo. The members of this structure have the following meaning for this function: + + iHandle [out] Heap allocated DThread pointer to the new created thread. + This member is valid only if the return code is KErrNone. + Do not assume it's NULL if the operation failed. + iType [in] Specifies if the thread will run in User mode or in Kernel mode. + It can be one of: + EThreadInitial - this is the initial thread + EThreadSupervisor - this runs in supervisor mode + EThreadMinimalSupervisor - this runs in supervisor mode and has no handles array + EThreadUser - this runs in User Mode + EThreadAPInitial - this is the initial thread on a non-boot processor (SMP only) + iFunction [in] This is the function that will be run in the new thread. + iPtr [in] Extra custom parameters passed to iFunction when it starts running. + iSupervisorStack Ignored. + iSupervisorStackSize [in] If the thread is a Kernel thread, this parameter will specify the desired supervisor stack size. + If the size is 0, the size will be specified by K::SupervisorThreadStackSize, which is 4K. + The size will be rounded up to Page or Block size. + iUserStack Ignored. + iUserStackSize [in] If the thread is a User Mode thread, this parameter will specify the desired user stack size. + The size will be rounded up to Page or Block size. + It will fail with KErrTooBig if the size is greater than PP::MaxUserThreadStack which is usually set to 0x14000 (80K). + iInitialThreadPriority [in] Initial priority for this thread. Must be in [0,63] interval. + iName [in] Name of the thread. In case you do not specify a name for this thread, it will be created EProtected + and any attempts to open it will fail with KErrPermissionDenied. Otherwise, the object will be EGlobal. + iTotalSize [in] Total size in bytes of the SThreadCreateInfo, including the extras. Fails with KErrArgument if it's less than sizeof(SThreadCreateInfo) or greater than KMaxThreadCreateInfo. + + It can fail with KErrArgument if aInfo.iTotalSize is not set correctly or aInfo.iPriority is not in [0,63] interval + In x86 port it can fail with KErrArgument if anInfo.iStackBase is NULL or anInfo.iStackSize is less than 0x100 + It can fail with KErrTooBig if aInfo.iUserStackSize is bigger than maximum user stack size + It can fail in Emulator with a Win32 error code returned by GetLastError if the Win32 thread or the scheduler Win32 event cannot be created + It can fail with KErrDied if the thread dies during the creation process + It can fail with KErrNoMemory in OOM scenarios. + It can fail with KErrGeneral indicating a general malfunction or data corruption. + + If it succeeds it will return the heap allocated DThread pointer to the new created thread in iHandle member of aInfo + + @param aInfo Information passed by the caller to specify how to create the thread. + + @pre Calling thread must be in a critical section. + @pre Call in a thread context. + @pre Kernel must be unlocked. + @pre interrupts enabled + @pre No fast mutex can be held + + @post Calling thread is in a critical section. +*/ +EXPORT_C TInt Kern::ThreadCreate(SThreadCreateInfo& aInfo) + { + CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Kern::ThreadCreate"); + __KTRACE_OPT(KEXEC,Kern::Printf("Kern::ThreadCreate %lS",&aInfo.iName)); + aInfo.iHandle=NULL; + DThread* pT=NULL; + TBool svc = aInfo.iType!=EThreadUser; + DProcess* pP = svc ? K::TheKernelProcess : TheCurrentThread->iOwningProcess; + aInfo.iSupervisorStack = NULL; + aInfo.iUserStack = NULL; + TInt r = pP->NewThread(pT, aInfo, NULL, EOwnerProcess); + if (r==KErrNone) + aInfo.iHandle = pT; + __KTRACE_OPT(KEXEC,Kern::Printf("Kern::ThreadCreate returns %d",r)); + return r; + } + +#ifdef _UNICODE +void ccopy (TUint16* aDest, const TAny* aSrc) +{ + TUint16* pSrc = (TUint16*)aSrc; + if(aSrc) { + TUint16* p = aDest + 1; + for (;*pSrc;) + *p++ = *pSrc++; + *aDest = (TUint16)(p-aDest-1); + } + else + *aDest = 0; +} +#else +void ccopy (TUint8* aDest, const TAny* aSrc) +{ + TUint8* pSrc = (TUint8*)aSrc; + if(aSrc) { + TUint8* p = aDest + 1; + for (;*pSrc;) + *p++ = *pSrc++; + *aDest = (TUint8)(p-aDest-1); + } + else + *aDest = 0; +} +#endif + +TInt ExecHandler::GetModuleNameFromAddress(TAny* aPtr, TDes8& aModuleName) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::GetModuleNameFromAddress 0x%X", aPtr)); + TFileName fn; + Kern::AccessCode(); + DCodeSeg* pSeg = Kern::CodeSegFromAddress( (TLinAddr)aPtr, TheCurrentThread->iOwningProcess ); + if (pSeg) + pSeg->AppendFullFileName(fn); + Kern::EndAccessCode(); + if (!pSeg) + { + return KErrNotFound; + } + Kern::KUDesPut(aModuleName, fn); + return KErrNone; + } + +TInt ExecHandler::LocaleExports(TAny* aHandle, TLibraryFunction* aExportList) +// +// Change Locale setups +// +// NOTES +// +// 1. A mutex is NOT used to protect this, so if it is called by more than one thread +// simultaneousely, the locale info may be garbled. +// 2. Locale libraries are never closed once they have been used. This prevents them from +// being unloaded whilst other threads are referencing the data contained in them. +// 3. This function doesn't duplicate the EKA1 behaviour of saving the default data for +// restoring later. +// +// The current use case for this function is that it is called once by WSERV after boot, +// so the above points should never be a problem. ( A generic 'change locale' will cause +// all sorts of problems throught the OS, so current practice won't change before a +// comprehensive rearchitecture occurs anyway.) +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::LocaleExports")); + + DCodeSeg& cs=*DCodeSeg::VerifyCallerAndHandle(aHandle); + + if(cs.iUids.iUid[1].iUid != KLocaleDllUid.iUid) + return KErrNotSupported; + + // Increment the code segment's access count + // This will increment every time the same locale is reloaded, but + // this doesn't matter since we don't unload locale DLLs. + NKern::ThreadEnterCS(); + DCodeSeg::Wait(); + cs.CheckedOpen(); + DCodeSeg::Signal(); + NKern::ThreadLeaveCS(); + + TLibraryFunction data[KNumLocaleExports]; + TInt n; + for(n=0; niOwningProcess == K::TheFileServerProcess) + { + UNLOCK_USER_MEMORY(); + TInt r = A::CallSupervisorFunction(aFunction,aParameter); + LOCK_USER_MEMORY(); + return r; + } +#endif + K::PanicKernExec(EAccessDenied); + return 0; + } + +_LIT(KDriveZed, "Z:"); +void ExecHandler::DllFileName(TInt aHandle, TDes8& aFileName) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::DllFileName %08x",aHandle)); + TFileName n; + Kern::AccessCode(); + DCodeSeg* pS=DCodeSeg::CodeSegFromEntryPoint(aHandle); + if (pS) + pS->AppendFullFileName(n); + else + n=KDriveZed; + Kern::EndAccessCode(); + if (pS) + P::NormalizeExecutableFileName(n); + Kern::KUDesPut(aFileName,n); + } + +#ifdef MONITOR_THREAD_CPU_TIME +TInt ExecHandler::ThreadGetCpuTime(DThread* aThread, Int64& aTime) + { +#ifndef __SMP__ + TInt64 time = (1000000 * aThread->iNThread.iTotalCpuTime) / NKern::FastCounterFrequency(); + NKern::UnlockSystem(); + kumemput32(&aTime, &time, sizeof(TInt64)); +#else + TUint64 t = NKern::ThreadCpuTime(&aThread->iNThread); + NKern::UnlockSystem(); + TUint32 f = NKern::CpuTimeMeasFreq(); + TUint64 t2 = t>>32; + t = ((t<<32)>>32)*1000000; + t2 *= 1000000; + t2 += (t>>32); + t &= TUint64(KMaxTUint32); + TUint64 q2 = t2/f; + t2 -= q2*f; + t += (t2<<32); + TUint64 q = t/f; + q += (q2<<32); + kumemput32(&aTime, &q, sizeof(TInt64)); +#endif + return KErrNone; + } +#else +TInt ExecHandler::ThreadGetCpuTime(DThread* /*aThread*/, Int64& /*aTime*/) + { + NKern::UnlockSystem(); + return KErrNotSupported; + } +#endif + +TInt ExecHandler::SetMemoryThresholds(TInt aLowThreshold, TInt aGoodThreshold) + { + if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by UserSvr::SetMemoryThresholds"))) + K::LockedPlatformSecurityPanic(); + if (aLowThreshold<0 || aGoodThresholdiOwningProcess; + pP->iFlags |= (KThreadFlagProcessCritical | KProcessFlagSystemPermanent); + pT->iFlags |= KThreadFlagSystemPermanent; + if (K::TheFileServerProcess && K::TheFileServerProcess!=pP) + K::PanicCurrentThread(EAccessDenied); + K::TheFileServerProcess=pP; + K::ThreadEnterCS(); + pP->SetPriority(EPriorityFileServer); + M::FsRegisterThread(); + K::ThreadLeaveCS(); + } + + +void ExecHandler::RegisterTrustedChunk(DChunk* aChunk) +// +// Register file server's chunk intended for DMA transfer +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::RegisterTrustedChunk %x",aChunk)); + + DProcess* pP=TheCurrentThread->iOwningProcess; + if (K::TheFileServerProcess && K::TheFileServerProcess!=pP) + { + K::PanicCurrentThread(EAccessDenied); + } + aChunk->iAttributes |= DChunk::ETrustedChunk; + } + +void ExecHandler::WsRegisterThread() +// +// Register the window server thread +// + { + + __KTRACE_OPT(KBOOT,Kern::Printf("Window server thread registered")); + DProcess* pP=TheCurrentThread->iOwningProcess; + if (K::TheWindowServerProcess && K::TheWindowServerProcess!=pP) + K::PanicCurrentThread(EAccessDenied); + K::TheWindowServerProcess=pP; + K::ThreadEnterCS(); + pP->SetPriority(EPriorityWindowServer); + K::ThreadLeaveCS(); + } + +void ExecHandler::RequestSignal(TInt aCount) +// +// Signal the request semaphore. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::RequestSignal %d",aCount)); + NKern::ThreadRequestSignal(NULL,aCount); + } + +TInt ExecHandler::ThreadRequestCount(DThread* aThread) +// +// Get the request semaphores count. +// + { + + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadRequestCount")); + return aThread->iNThread.iRequestSemaphore.iCount; + } + +void CompleteUserAfter(TAny* aPtr) + { + DThread* pT=DThread::FromTimer(aPtr); + if (pT->iTimer.iState==TTimer::EWaiting) + { + Kern::QueueRequestComplete(pT,pT->iTimer.iRequest,KErrNone); + pT->iTimer.iState=TTimer::EIdle; + } + } + +void CompleteUserAt(TAny* aPtr) + { + DThread* pT=DThread::FromTimer(aPtr); + if (pT->iTimer.iState==TTimer::EWaiting) + { + Kern::QueueRequestComplete(pT,pT->iTimer.iRequest,KErrNone); + pT->iTimer.iState=TTimer::EIdle; + } + } + +void CompleteUserAfterHighRes(TAny* aPtr) + { + DThread* pT=DThread::FromTimer(aPtr); + NKern::LockSystem(); + pT->iTimer.iState=TTimer::EIdle; + Kern::QueueRequestComplete(pT,pT->iTimer.iRequest,KErrNone); + NKern::UnlockSystem(); + } + +void ExecHandler::After(TInt anInterval, TRequestStatus& aStatus) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::After %d",anInterval)); + TInt iv=anInterval; + if (iv<=0) + { + // just rotate the ready queue for this thread + NKern::RotateReadyList(-1); + TRequestStatus* s=&aStatus; + Kern::RequestComplete(s,KErrNone); + return; + } + NKern::ThreadEnterCS(); + TInt r=TheCurrentThread->iTimer.After(iv,CompleteUserAfter,aStatus); + NKern::ThreadLeaveCS(); + if (r==KErrInUse) + K::PanicKernExec(ETimerAlreadyPending); + else if (r!=KErrNone) + { + TRequestStatus* s=&aStatus; + Kern::RequestComplete(s,r); + } + } + +void ExecHandler::AfterHighRes(TInt anInterval, TRequestStatus& aStatus) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::AfterHighRes %d",anInterval)); + TInt r=TheCurrentThread->iTimer.AfterHighRes(anInterval,CompleteUserAfterHighRes,aStatus); + if (r==KErrInUse) + K::PanicCurrentThread(ETimerAlreadyPending); + } + +void ExecHandler::At(const TTimeK& aTime, TRequestStatus& aStatus) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::At")); + TTimeK time; + kumemget32(&time,&aTime,sizeof(time)); + NKern::ThreadEnterCS(); + TInt r=TheCurrentThread->iTimer.At(time,CompleteUserAt,aStatus); + NKern::ThreadLeaveCS(); + if (r==KErrInUse) + K::PanicKernExec(ETimerAlreadyPending); + else if (r!=KErrNone) + { + TRequestStatus* s=&aStatus; + Kern::RequestComplete(s,r); + } + } + +#ifndef __FASTEXEC_MACHINE_CODED__ +RAllocator* ExecHandler::Heap() + { + return TheCurrentThread->iAllocator; + } + +extern void InvalidFastExec(); + +TTrapHandler* ExecHandler::PushTrapFrame(TTrap* aFrame) +// +// Push a new trap frame. +// + { +#ifdef __LEAVE_EQUALS_THROW__ +#ifdef __WINS__ + // On WINS overload this function to remember when a TWin32SEHTrap is installed + // over another one + DThread& t=*TheCurrentThread; + t.iFrame=aFrame; + return 0; +#else + InvalidFastExec(); + return (TTrapHandler*)aFrame; // Prevents compiler warnings +#endif +#else + DThread& t=*TheCurrentThread; + aFrame->iHandler=t.iTrapHandler; + aFrame->iNext=t.iFrame; + t.iFrame=aFrame; + return t.iTrapHandler; +#endif + } + +TTrap* ExecHandler::PopTrapFrame() +// +// Pop the current frame. +// + { +#ifdef __LEAVE_EQUALS_THROW__ +#ifdef __WINS__ + // On WINS overload this function to recall when a TWin32SEHTrap is installed + // over another one + DThread& t=*TheCurrentThread; + return t.iFrame; +#else + InvalidFastExec(); + return 0; +#endif +#else + DThread& t=*TheCurrentThread; + TTrap* pF=t.iFrame; + if (pF) + t.iFrame=pF->iNext; + return pF; +#endif + } + +CActiveScheduler* ExecHandler::ActiveScheduler() +// +// Return the address of the current active scheduler +// + { + DThread& t=*TheCurrentThread; + return t.iScheduler; + } + +void ExecHandler::SetActiveScheduler(CActiveScheduler* aScheduler) +// +// Set the address of the current active scheduler +// + { + DThread& t=*TheCurrentThread; + t.iScheduler=aScheduler; + } + +TTrapHandler* ExecHandler::TrapHandler() +// +// Return the current trap handler. +// + { + DThread& t=*TheCurrentThread; + return t.iTrapHandler; + } + +TTrapHandler* ExecHandler::SetTrapHandler(TTrapHandler* aHandler) +// +// Set the current trap handler. +// + { + DThread& t=*TheCurrentThread; + TTrapHandler* pH=t.iTrapHandler; + t.iTrapHandler=aHandler; + return pH; + } + +void ExecHandler::SetReentryPoint(TLinAddr a) + { + DThread& t = *TheCurrentThread; + t.iOwningProcess->iReentryPoint = a; + } +#endif + +#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__ +void K::DoProcessIsolationFailure(const char* aContextText) + { + // enter with system locked + if(TheSuperPage().KernelConfigFlags() & EKernelConfigPlatSecProcessIsolation) + { + if(PlatSec::ProcessIsolationFail(aContextText)==KErrNone) + return; + LockedPlatformSecurityPanic(); + } + } +#endif // !__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__ + +void K::DoProcessIsolationFailure() + { + // enter with system locked +#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__ + DoProcessIsolationFailure(NULL); +#else //__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__ + if (TheSuperPage().KernelConfigFlags() & EKernelConfigPlatSecProcessIsolation) + { + if (PlatSec::EmitDiagnostic() == KErrNone) + return; + LockedPlatformSecurityPanic(); + } +#endif // !__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__ + } + + +void K::UnlockedPlatformSecurityPanic() + { + // enter with system unlocked + NKern::LockSystem(); + K::LockedPlatformSecurityPanic(); + } + +void K::LockedPlatformSecurityPanic() + { + // enter with system locked + K::PanicCurrentThread(EPlatformSecurityTrap); + } + +void ExecHandler::ThreadRendezvous(TInt aReason) + { + NKern::ThreadEnterCS(); + TheCurrentThread->Rendezvous(aReason); + NKern::ThreadLeaveCS(); + } + +void ExecHandler::ProcessRendezvous(TInt aReason) + { + NKern::ThreadEnterCS(); + TheCurrentThread->iOwningProcess->Rendezvous(aReason); + NKern::ThreadLeaveCS(); + } + +void ExecHandler::DebugPrint(TAny* aDes, TInt aMode) + { + TInt l, m; + const TText* p = Kern::KUDesInfo(*(const TDesC*)aDes, l, m); + +#ifdef __DEBUGGER_SUPPORT__ + TUint r = DKernelEventHandler::Dispatch(EEventUserTrace, (TAny*)p, (TAny*)l); + if (r & DKernelEventHandler::ETraceHandled) + l = 0; +#endif + + TBuf8<256> buffer; + l = Min(l,256); + buffer.SetLength(l); + kumemget((TUint8*)buffer.Ptr(), p, l); //Copy user-side data into kernel memory + K::TextTrace(buffer,EUserTrace,!aMode); + } + + +TInt ExecHandler::ProcessSetHandleParameter(DProcess* aProcess, TInt aSlot, TInt aHandle) + { + if (aProcess->iCreatorId != TheCurrentThread->iOwningProcess->iId) //check called by creator + K::LockedPlatformSecurityPanic(); + + if ((aSlot < 0) || (aSlot >= KArgIndex)) + K::PanicCurrentThread(EParameterSlotRange); + + if (aProcess->iEnvironmentData[aSlot] != 0) + K::PanicCurrentThread(EParameterSlotInUse); + + DObject* pObject = K::ObjectFromHandle(aHandle); + + if (pObject->Protection() == DObject::ELocal) + K::LockedPlatformSecurityPanic(); + pObject->CheckedOpen(); + + aProcess->iEnvironmentData[aSlot] = (TInt)pObject | EHandle; + return KErrNone; + } + +//no locks held on entry +TInt ExecHandler::ProcessSetDataParameter(TInt aProcess, TInt aSlot, const TUint8* aData, TInt aLen) + { + + if ((aSlot < 0) || (aSlot >= KArgIndex)) + K::PanicKernExec(EParameterSlotRange); + + if (aLen < 0) + K::PanicKernExec(EParameterSlotDataLength); + + NKern::ThreadEnterCS(); + HBuf8* pBuf = NULL; + if (aLen) + pBuf = HBuf8::New(aLen); + + DThread* currentThread = TheCurrentThread; + currentThread->iTempAlloc = pBuf; + NKern::ThreadLeaveCS(); + + if (aLen) + { + if (!pBuf) + return KErrNoMemory; + kumemget((void*)pBuf->Ptr(), aData, aLen); + pBuf->SetLength(aLen); + } + + + NKern::LockSystem(); + DProcess* pProc = (DProcess*)K::ObjectFromHandle(aProcess, EProcess); + + if (pProc->iCreatorId != currentThread->iOwningProcess->iId) //check called by creator + K::LockedPlatformSecurityPanic(); + + if (pProc->iEnvironmentData[aSlot] != 0) + K::PanicCurrentThread(EParameterSlotInUse); + + pProc->iEnvironmentData[aSlot] = (TInt)pBuf | EBinaryData; + currentThread->iTempAlloc = NULL; + NKern::UnlockSystem(); + + return KErrNone; + } + + + +//need to have sys locked on way in +TInt ExecHandler::ProcessGetHandleParameter(TInt aSlot, TObjectType aObjectType, TOwnerType aOwnerType) + { + + DThread * currentThread = TheCurrentThread; + DProcess * currentProcess = currentThread->iOwningProcess; + + if ((aSlot < 0) || (aSlot >= KArgIndex)) + K::PanicCurrentThread(EParameterSlotRange); + + TInt data = currentProcess->iEnvironmentData[aSlot]; + + if (!data) + return KErrNotFound; + + TProcessParameterType type = (TProcessParameterType)(data&3); + + if (type != EHandle) + return KErrArgument; + + DObject* pObject = (DObject*)(data&~3); + + if ((TInt)aObjectType+1 != pObject->UniqueID()) //check it's the correct type + return KErrArgument; + + // zero parameter to prevent race conditions while retrieving the object + currentProcess->iEnvironmentData[aSlot]=0; + + NKern::ThreadEnterCS(); + NKern::UnlockSystem(); + TInt handle = 0; + + TInt ret = currentThread->MakeHandle(aOwnerType, pObject, handle); + + NKern::LockSystem(); + NKern::ThreadLeaveCS(); + + if (ret != KErrNone) + { + // restore parameter data as 'nothing happened' + currentProcess->iEnvironmentData[aSlot]=data; + return ret; + } + return handle; + } + + +//enter with the system lock held, auto release on exit +TInt ExecHandler::ProcessGetDataParameter(TInt aSlot, TUint8* aData, TInt aLen) + { + + DThread * currentThread = TheCurrentThread; + DProcess * currentProcess = currentThread->iOwningProcess; + + if ((aSlot < 0) || (aSlot >= KArgIndex)) + K::PanicCurrentThread(EParameterSlotRange); + + TInt data = currentProcess->iEnvironmentData[aSlot]; + if (!data) + return KErrNotFound; + + TProcessParameterType type = (TProcessParameterType)(data&3); + if (type != EBinaryData) + return KErrArgument; + + HBuf8* p = (HBuf8*)(data&~3); + if (!p) //we've passed zero length binary data so nothing to copy + return 0; + + if (aLen < p->Length()) + return KErrArgument; + + currentThread->iTempAlloc = p; + currentProcess->iEnvironmentData[aSlot] = 0; + NKern::UnlockSystem(); + + TInt len = p->Length(); + kumemput((void*)aData, (void*)p->Ptr(), len); + + NKern::ThreadEnterCS(); + currentThread->iTempAlloc = NULL; + delete p; + NKern::ThreadLeaveCS(); + + NKern::LockSystem(); + return len; + } + +TInt ExecHandler::ProcessDataParameterLength(TInt aSlot) + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ProcessDesParameterLength")); + + DProcess * currentProcess = TheCurrentThread->iOwningProcess; + + if ((aSlot < 0) || (aSlot >= KArgIndex)) + K::PanicCurrentThread(EParameterSlotRange); + + TInt data = currentProcess->iEnvironmentData[aSlot]; + + if (!data) + return KErrNotFound; + + TProcessParameterType type = (TProcessParameterType)(data&3); + + if (type != EBinaryData) + return KErrArgument; + + const HBuf8* p = (const HBuf8*)(data&~3); + + return p ? p->Length() : 0; + } + + + +void ExecHandler::NotifyChanges(TUint aChanges) +// +// Check that the caller has permission to notify the requested changes, +// and pass it on to Kern::NotifyChanges if it's ok +// + { + __KTRACE_OPT(KEXEC,Kern::Printf("Exec::NotifyChanges")); + + if (aChanges & ~EChangesLocale) + K::UnlockedPlatformSecurityPanic(); + + NKern::ThreadEnterCS(); + Kern::NotifyChanges(aChanges); + NKern::ThreadLeaveCS(); + } + + + +static TInt GlobalUserData[EMaxGlobalUserData] = {0}; + +TInt ExecHandler::GetGlobalUserData(TInt aIndex) + { + if(TUint(aIndex)iOwningProcess; + + NKern::ThreadEnterCS(); + + // If the thread is process permanent then all other threads in the process will be killed - + // make sure this happens now, so that this thread has a chance to run global object destructors. + if (thread->iFlags & KThreadFlagProcessPermanent) + { + __NK_ASSERT_ALWAYS(process->WaitProcessLock() == KErrNone); + NKern::LockSystem(); + process->KillAllThreads(EExitKill, aReason, KNullDesC); + NKern::UnlockSystem(); + process->SignalProcessLock(); + } + + TBool lastThread = EFalse; + __NK_ASSERT_DEBUG(thread->iUserThreadState >= DThread::EUserThreadRunning); + if (thread->iUserThreadState == DThread::EUserThreadRunning) + { + thread->iUserThreadState = DThread::EUserThreadExiting; + lastThread = (__e32_atomic_tas_ord32(&process->iUserThreadsRunning, 1, -1, 0) == 1); + } + + NKern::ThreadLeaveCS(); + + return lastThread; + } + + +#include + +void ExecHandler::IMBRange(TAny* aStart, TUint aSize) + { + UNLOCK_USER_MEMORY(); + Cache::IMB_Range((TLinAddr)aStart,aSize); + LOCK_USER_MEMORY(); + }