// Copyright (c) 1998-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\include\kernel\kern_priv.h
//
// WARNING: This file contains some APIs which are internal and are subject
// to change without notice. Such APIs should therefore not be used
// outside the Kernel and Hardware Services package.
//
/**
@file
@internalComponent
*/
#ifndef __K32KERN_H__
#define __K32KERN_H__
#include <kernel/kernel.h>
#include <nk_priv.h>
#include <kernel/kpower.h>
#include <platform.h>
#include <e32uid.h>
#include <kernel/kernboot.h>
#include <e32def_private.h>
#include <e32const_private.h>
#include <e32des8_private.h>
#include <e32event_private.h>
#ifndef __MINIMUM_MACHINE_CODE__
#ifdef __MARM__
#ifndef __BIG_ENDIAN__
#ifdef __SMP__
#define __FASTEXEC_MACHINE_CODED__
#define __TBMA_MACHINE_CODED__
#else
// These macros are intended for Symbian use only.
// It may not be possible to build the kernel if particular combinations
// of these macros are undefined
#define __FASTEXEC_MACHINE_CODED__
#define __MMU_MACHINE_CODED__
#define __PROCESS_MACHINE_CODED__
#define __TBMA_MACHINE_CODED__
#define __MESSAGE_MACHINE_CODED_2__
#define __HANDLES_MACHINE_CODED__
#define __REQUEST_COMPLETE_MACHINE_CODED__
#define __MESSAGE_MACHINE_CODED__
#endif
#endif
#endif
#endif
// size of each buffer used to store entropy data before it is passed to the RNG
const TUint KEntropyBufferSizeWords = 1024;// maximum size of 1024 words (32Kbit);
const TInt KKernelServerDefaultPriority=16;
const TInt KDefaultExitPriority=KKernelServerDefaultPriority;
// counter to ensure that priority inheritance has bounded execution time
const TInt KMaxPriorityInheritanceNesting=10;
const TInt KArgIndex = 16; //number of slots in DProcess for passing info to child process on creation
const TInt KDefaultMaxMemCopyInOneGo = 512;
// Forward declare Shareable data buffer classes
class DShPool;
class TShPoolCreateInfo;
//Forward declare Debug namespace for StopMode API
namespace Debug { class StopModeDebug; }
/***************************************************
* Kernel-side trap harness for catching exceptions
* Not nestable, one per thread only
***************************************************/
class TExcTrap;
typedef void (*TExcTrapHandler)(TExcTrap*,DThread*,TAny*);
class TExcTrap
{
public:
IMPORT_C TInt Trap(); // use default exception handler
IMPORT_C TInt Trap(TExcTrapHandler aHandler);
inline void UnTrap();
IMPORT_C void Exception(TInt aResult);
public:
TUint32 iState[EXC_TRAP_CTX_SZ];
TExcTrapHandler iHandler;
DThread* iThread;
};
class TPagingExcTrap
{
public:
TInt Trap();
inline void UnTrap();
void Exception(TInt aResult);
public:
TUint32 iState[EXC_TRAP_CTX_SZ];
DThread* iThread;
};
#define XT_DEFAULT
#define XTRAP(_r,_h,_s) { \
TExcTrap __t; \
if (((_r)=__t.Trap(_h))==0) \
{ \
_s; \
__t.UnTrap(); \
} \
}
#define XTRAPD(_r,_h,_s) TInt _r; \
{ \
TExcTrap __t; \
if (((_r)=__t.Trap(_h))==0) \
{ \
_s; \
__t.UnTrap(); \
} \
}
#ifdef __DEMAND_PAGING__
#define CHECK_PAGING_SAFE __NK_ASSERT_DEBUG(M::CheckPagingSafe(EFalse))
#define CHECK_PAGING_SAFE_RANGE(s, l) __NK_ASSERT_DEBUG(M::CheckPagingSafe(EFalse, (s), (l)))
#define CHECK_DATA_PAGING_SAFE __NK_ASSERT_DEBUG(M::CheckPagingSafe(ETrue))
#define CHECK_DATA_PAGING_SAFE_RANGE(s, l) __NK_ASSERT_DEBUG(M::CheckPagingSafe(ETrue, (s), (l)))
//
// Important - Do not use XTRAP inside an XTRAP_PAGING
// I.e.
// XTRAP(XTRAP_PAGING(foo))
// is OK, but
// XTRAP_PAGING(XTRAP(foo))
// will put the system into a bad state when a paging exception happens
// because TExcTrap::UnTrap won't get called.
//
#define XTRAP_PAGING(_r,_s) { \
TPagingExcTrap __t; \
if (((_r)=__t.Trap())==0) \
{ \
_s; \
__t.UnTrap(); \
} \
}
#define XTRAP_PAGING_START(_r) { \
TPagingExcTrap __t; \
if (((_r)=__t.Trap())==0) \
{
#define XTRAP_PAGING_END __t.UnTrap(); \
} \
}
#define XTRAP_PAGING_RETRY(_s) { \
_retry: \
TInt _exc; \
XTRAP_PAGING_START(_exc); \
_s; \
XTRAP_PAGING_END; \
if(_exc) goto _retry; \
}
#else
#define XTRAP_PAGING(_r,_s) { _s }
#define XTRAP_PAGING_START(_r) {_r=0;{
#define XTRAP_PAGING_END }}
#define CHECK_PAGING_SAFE
#define CHECK_PAGING_SAFE_RANGE(s, l)
#define CHECK_DATA_PAGING_SAFE
#define CHECK_DATA_PAGING_SAFE_RANGE(s, l)
#define XTRAP_PAGING_RETRY(_s) { _s }
#endif
class TIpcExcTrap : public TExcTrap
{
public:
TInt Trap(DThread* aClientThread); // use default ipc exception handler
inline void UnTrap();
enum TExcLocation { EExcUnknown, EExcLocal, EExcRemote };
TExcLocation ExcLocation(DThread* aThread, TAny* aContext);
TBool IsTIpcExcTrap();
public:
TLinAddr iLocalBase;
TLinAddr iRemoteBase;
TUint32 iSize;
TInt iDir; // 0=read, 1=write
};
/**************************************************
* Structure used for miscellaneous notifications
**************************************************/
class TMiscNotifier : public TClientRequest
{
public:
SDblQueLink iThreadLink;
SDblQueLink iObjLink;
DThread* iThread; // doesn't need to be reference counted since all notifiers are removed when thread terminates
private:
~TMiscNotifier(); // call Close(), don't delete
};
struct SMiscNotifierQ : public SDblQue
{
};
class TMiscNotifierMgr
{
public:
TMiscNotifierMgr();
void Init2();
void CompleteNotifications(SDblQue& aQ);
static void CompletionDfcFn(TAny* aMgr);
static void IdleDfcFn(TAny* aMgr);
inline void Lock()
{NKern::FMWait(&iLock);}
inline void Unlock()
{NKern::FMSignal(&iLock);}
TInt NewMiscNotifier(TRequestStatus* aStatus, TBool aObj, TAny* aPtr, TMiscNotifier*& aN, SMiscNotifierQ*& aQ);
public:
SDblQue iCompleted;
TDfc iCompletionDfc;
SMiscNotifierQ* iIdleNotifierQ;
TDfc iIdleDfc;
NFastMutex iLock;
};
/********************************************
* Kernel object index (handles array)
********************************************/
class DMutex;
/** Handle analysis and synthesis
@internalComponent
*/
inline TBool HandleIsSpecial(TInt aHandle)
{ return aHandle<0; }
inline TBool HandleIsThreadLocal(TInt aHandle)
{ return aHandle&0x40000000; }
inline TBool HandleNoClose(TInt aHandle)
{ return aHandle&0x00008000; }
inline TInt HandleIndex(TInt aHandle)
{ return aHandle&0x00007FFF; }
inline TInt HandleInstance(TInt aHandle)
{ return (aHandle&0x3FFF0000)>>16; }
inline TInt MakeHandle(TInt aIndex, TInt aInstance)
{ return ((aInstance&0x3FFF)<<16)|(aIndex&0x7FFF); }
/**
@internalComponent
*/
class RObjectIx
{
public:
enum {ENoClose=KHandleNoClose,ELocalHandle=0x40000000};
enum {EReserved=0x80000000u, EAttributeMask=0xfffu};
enum {EMinSlots=8, EMaxSlots=32768};
public:
enum {ENumFreeQ=6, EModCount=4, EBitMapSize=128, EMaxLockedIter=8};
private:
// queue numbers
enum {EQFree=-6, EQAltFree=-5, EQTempFree=-4, EQRsvd=-3, EQAltRsvd=-2, EQTempRsvd=-1};
// iObjR, iRsvd fields
enum {EObjROccupied=4u, EObjRObjMask=0xfffffffcu, EObjRRsvd=1u};
// states
enum {ENormal=0u, ETidying=1u, EFindingLast=2u, ECounting=3u, ESearching=4u, ETerminated=5u};
struct SSlotQLink
{
TInt16 iNext; // pointer to next free slot, -n if no next
TInt16 iPrev; // pointer to previous free slot, -n if no previous
};
struct SFreeSlot : public SSlotQLink
{
TUint32 iRsvd; // 0 for normal, 1 for reserved slot
};
struct SUsedSlot
{
TUint32 iAttr; // bits 0-13 = instance (nonzero), bits 14-19 = object type, bits 20-31 = handle attributes
TUint32 iObjR; // pointer to object (nonzero), bit 0=1 if reserved slot
};
union SSlot
{
SFreeSlot iFree;
SUsedSlot iUsed;
};
struct SMonitorObj
{
DObject* iObj;
TInt iBoundary;
TInt iResult;
};
union SModList
{
TInt16 iIndex[EModCount];
TUint32 iBitMap[EBitMapSize/32];
SMonitorObj iMonitor;
};
private:
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
// Beginning of support for spinlock-only protection (i.e. not requiring the system lock)
// for access to handles. Requires changes everywhere objects returned from handles are
// used, and some additional work in the handle lookup code in cutils.cia.
#error "spinlocks for handle lookup not supported"
inline void AcquireReadLock()
{ __SPIN_LOCK_IRQ_R(iRWL); }
inline void ReleaseReadLock()
{ __SPIN_UNLOCK_IRQ_R(iRWL); }
inline void AcquireWriteLock()
{ __SPIN_LOCK_IRQ_W(iRWL); }
inline void ReleaseWriteLock()
{ __SPIN_UNLOCK_IRQ_W(iRWL); }
#else
/* Places which use a read lock would already have the system lock held */
inline void AcquireReadLock()
{ __ASSERT_SYSTEM_LOCK; }
inline void ReleaseReadLock()
{ }
inline void AcquireWriteLock()
{ NKern::LockSystem(); }
inline void ReleaseWriteLock()
{ NKern::UnlockSystem(); }
#endif
private:
static inline DObject* Occupant(SSlot* aS)
{ return (DObject*)(aS->iUsed.iObjR & EObjRObjMask); }
static inline TBool IsReserved(SSlot* aS)
{ return aS->iUsed.iObjR & EObjRRsvd; }
static inline TBool IsFreeReserved(SSlot* aS)
{ return (aS->iUsed.iObjR & EObjRRsvd) && (aS->iUsed.iObjR<EObjROccupied); }
void Empty(TInt aQueue);
SSlot* Dequeue(TInt aSlotIndex);
inline void AddHead(TInt aQueue, TInt aSlotIndex);
inline void AddTail(TInt aQueue, TInt aSlotIndex);
void AddBefore(TInt aBase, TInt aSlotIndex);
void AddAfter(TInt aBase, TInt aSlotIndex);
void AppendList(TInt aSrcQ, TInt aDestQ);
void PrependList(TInt aSrcQ, TInt aDestQ);
TInt DoAdd(DObject* aObj, TUint32 aAttr, SSlot* aSlot); // add aObj using an existing slot (don't grow)
TInt DoRemove(TInt aHandle, DObject*& aObject, TUint32& aAttr); // remove a handle (don't shrink)
void MarkModified(TInt aSlotIndex);
static TUint32 GetNextInstanceValue();
TInt UnReserveSlots(TInt aCount, TBool aAmortize);
TInt ReserveSlots(TInt aCount);
TInt Grow(TInt aReserve, SSlot* aSlotData);
void TidyAndCompact();
inline SSlotQLink* Link(TInt aIndex)
{ return (aIndex<0) ? (iFreeQ+ENumFreeQ+aIndex) : &(iSlots+aIndex)->iFree; }
public:
// common operations
RObjectIx();
TInt Close(TAny* aPtr);
TInt Add(DObject* aObj, TUint32 aAttr);
TInt Remove(TInt aHandle, DObject*& aObject, TUint32& aAttr);
TInt Reserve(TInt aCount);
DObject* At(TInt aHandle, TInt aUniqueID, TUint32 aRequiredAttr);
DObject* At(TInt aHandle, TInt aUniqueID, TUint32* aAttr);
DObject* At(TInt aHandle, TInt aUniqueID);
DObject* At(TInt aHandle);
static void Wait();
static void Signal();
inline TInt Count()
{ return iCount; }
inline TInt ActiveCount()
{ return iActiveCount; }
public:
// uncommon operations
DObject* operator[](TInt aIndex);
TInt At(DObject* aObject);
TInt Count(DObject* aObject);
TInt LastHandle();
#ifdef DOBJECT_TEST_CODE
typedef void (*TValidateEntry)(TInt, TInt, TInt, TInt, TUint, DObject*);
void Check(TValidateEntry aV);
#endif
private:
TRWSpinLock iRWL;
TInt iAllocated; // Max entries before realloc needed
volatile TInt iCount; // Points to at least 1 above the highest occupied slot or unoccupied reserved slot
volatile TInt iActiveCount; // Number of occupied entries in the index (reserved or normal)
volatile TInt iReservedFree; // Number of unoccupied reserved slots
volatile TInt iReservedTotal; // Number of reserved slots (occupied or unoccupied)
volatile TInt iReservedFreeHWM; // Points to at least 1 above the last unoccupied reserved slot
SSlotQLink iFreeQ[ENumFreeQ]; // queues of free slots
SSlot* iSlots; // array of handle slots
TInt iAmortize; // Number of handle removals before we see if we can shrink
TUint8 iState;
TUint8 iModCount; // 255=not in use, 0...EModCount->use iModList.iIndex[], EModCount+1->use iModList.iBitMap
TUint8 iModListShift;
TUint8 iSpare1;
SModList iModList; // Entries modified while array moving
public:
static volatile TUint32 NextInstance;
static DMutex* HandleMutex;
public:
friend void PreprocessHandler();
friend class DThread;
friend class K;
friend class Monitor;
};
//
// These are the same as their e32base.h versions
/*inline TBool IsLocalHandle(TInt aHandle)
{return(aHandle&RObjectIx::ELocalHandle);}
inline void SetLocalHandle(TInt &aHandle)
{aHandle|=RObjectIx::ELocalHandle;}
inline void UnSetLocalHandle(TInt &aHandle)
{aHandle&=(~RObjectIx::ELocalHandle);}
*/
/********************************************
* Kernel object container
********************************************/
class DObjectCon : public DBase
{
protected:
enum {ENotOwnerID};
public:
~DObjectCon();
static DObjectCon* New(TInt aUniqueID);
IMPORT_C void Remove(DObject* aObj);
IMPORT_C TInt Add(DObject* aObj);
IMPORT_C DObject* operator[](TInt aIndex);
IMPORT_C DObject* At(const TFindHandle& aFindHandle);
IMPORT_C TInt CheckUniqueFullName(DObject* aOwner, const TDesC& aName);
IMPORT_C TInt CheckUniqueFullName(DObject* aObject);
IMPORT_C TInt FindByName(TFindHandle& aFindHandle, const TDesC& aMatch, TKName& aName);
IMPORT_C TInt FindByFullName(TFindHandle& aFindHandle, const TDesC& aMatch, TFullName& aFullName);
IMPORT_C TInt OpenByFullName(DObject*& aObject, const TDesC& aMatch);
inline TInt UniqueID() {return iUniqueID;}
inline TInt Count() {return iCount;}
inline void Wait() {Kern::MutexWait(*iMutex);}
inline void Signal() {Kern::MutexSignal(*iMutex);}
inline DMutex* Lock() {return iMutex;}
protected:
DObjectCon(TInt aUniqueID);
TBool NamesMatch(DObject* aObject, const TDesC& aObjectName, DObject* aCurrentObject);
public:
TInt iUniqueID;
private:
TInt iAllocated;
TInt iCount;
DObject** iObjects;
DMutex* iMutex;
public:
friend class Monitor;
friend class Debugger;
friend class SCMonitor;
friend class Debug::StopModeDebug;
};
/********************************************
* Process and process-relative thread priorities
********************************************/
enum TThrdPriority
{
EThrdPriorityIdle=-8,
EThrdPriorityMuchLess=-7,
EThrdPriorityLess=-6,
EThrdPriorityNormal=-5,
EThrdPriorityMore=-4,
EThrdPriorityMuchMore=-3,
EThrdPriorityRealTime=-2,
EThrdPriorityNull=0,
EThrdPriorityAbsoluteVeryLow=1,
EThrdPriorityAbsoluteLowNormal=3,
EThrdPriorityAbsoluteLow=5,
EThrdPriorityAbsoluteBackgroundNormal=7,
EThrdPriorityAbsoluteBackground=10,
EThrdPriorityAbsoluteForegroundNormal=12,
EThrdPriorityAbsoluteForeground=15,
EThrdPriorityAbsoluteHighNormal=19,
EThrdPriorityAbsoluteHigh=23,
EThrdPriorityAbsoluteRealTime1=24,
EThrdPriorityAbsoluteRealTime2=25,
EThrdPriorityAbsoluteRealTime3=26,
EThrdPriorityAbsoluteRealTime4=27,
EThrdPriorityAbsoluteRealTime5=28,
EThrdPriorityAbsoluteRealTime6=29,
EThrdPriorityAbsoluteRealTime7=30,
EThrdPriorityAbsoluteRealTime8=31
};
enum TProcPriority
{
EProcPriorityLow=0,
EProcPriorityBackground=1,
EProcPriorityForeground=2,
EProcPriorityHigh=3,
EProcPrioritySystemServer1=4,
EProcPrioritySystemServer2=5,
EProcPrioritySystemServer3=6,
EProcPriorityRealTimeServer=7,
};
/********************************************
* Multipurpose timer
********************************************/
#ifndef MAX
#define MAX(a,b) ((a)<(b)?(b):(a))
#endif
#ifndef MAX3
#define MAX3(a,b,c) MAX(MAX(a,b),c)
#endif
#ifndef MAX4
#define MAX4(a,b,c,d) MAX(MAX(a,b),MAX(c,d))
#endif
#define TIMER_SIZE MAX4(sizeof(TTickLink),sizeof(TSecondLink),sizeof(NTimer),sizeof(TInactivityLink))
class TTimer
{
public:
enum TTimerType {ERelative=1,EAbsolute=2,ELocked=4,EHighRes=8,EInactivity=16};
enum TTimerState {EIdle,EWaiting,EWaitHighRes};
public:
TInt Create();
inline TTimer();
~TTimer();
TInt After(TInt aInterval, TTickCallBack aFunction, TRequestStatus& aStatus);
TInt At(const TTimeK& aTime, TSecondCallBack aFunction, TRequestStatus& aStatus);
TInt AfterHighRes(TInt aInterval, NTimerFn aFunction, TRequestStatus& aStatus);
TInt Inactivity(TInt aSeconds, TInactivityCallBack aFunction, TRequestStatus& aStatus);
void Cancel(DThread* aThread);
void Abort(DThread* aThread, TInt aTypeMask);
void SetType(TTimerType aType);
public:
inline TTickLink& TickLink()
{ return *(TTickLink*)iUnion; }
inline TSecondLink& SecondLink()
{ return *(TSecondLink*)iUnion; }
inline NTimer& Ms()
{ return *(NTimer*)iUnion; }
inline TInactivityLink& Inact()
{ return *(TInactivityLink*)iUnion; }
inline TTimerType Type()
{ return (TTimerType)iType; }
public:
TUint32 iUnion[TIMER_SIZE/sizeof(TUint32)]; // this field must always be 8-byte aligned
TClientRequest* iRequest;
TUint8 iState;
TUint8 iType;
};
inline TTimer::TTimer()
: iState(EIdle)
{}
/********************************************
* Timer control block
********************************************/
class DTimer : public DObject
{
public:
TInt Create(DThread* aThread);
public:
DTimer();
~DTimer();
public:
void Cancel();
TInt After(TRequestStatus& aStatus, TInt aInterval);
TInt At(TRequestStatus& aStatus, const TTimeK& aTime);
TInt Lock(TRequestStatus& aStatus, TTimerLockSpec aLock);
void HighRes(TRequestStatus& aStatus, TInt aInterval);
TInt Inactivity(TRequestStatus& aStatus, TInt aSeconds);
void Abort(TBool aAbortAbsolute);
virtual TInt RequestUserHandle(DThread* aThread, TOwnerType aType);
private:
inline DThread* Owner();
static void TimerComplete(TAny* aPtr);
static void SecondComplete(TAny* aPtr);
static void LockComplete(TAny* aPtr);
static void LockSynchronize(TAny* aPtr);
static void MsComplete(TAny* aTimer);
inline static DTimer* FromPtr(TAny* aPtr);
public:
// TAny* __padding; // for alignment
TTimer iTimer;
public:
friend class Monitor;
};
__ASSERT_COMPILE((_FOFF(DTimer,iTimer.iUnion) & 7)==0);
inline DTimer* DTimer::FromPtr(TAny* aPtr)
{ return _LOFF(aPtr,DTimer,iTimer); }
inline DThread* DTimer::Owner()
{return (DThread*)DObject::Owner();}
/********************************************
* Thread cleanup entries
********************************************/
class DThread;
class TThreadCleanup : public TPriListLink
{
public:
IMPORT_C TThreadCleanup();
void ChangePriority(TInt aNewPriority);
IMPORT_C void Remove();
virtual void Cleanup()=0;
public:
DThread* iThread;
public:
friend class Monitor;
};
class TThreadMutexCleanup : public TThreadCleanup
{
public:
inline TThreadMutexCleanup(DMutex* aMutex);
virtual void Cleanup();
DMutex *iMutex;
public:
friend class Monitor;
};
/********************************************
* Deterministic thread wait queue
********************************************/
class TThreadWaitList
{
private:
enum { EEmpty=0u, EFlagList=1u, EInitValue=3u, ENonEmptyMask=0xfffffffcu };
private:
class TList : public TPriListBase
{
private:
TList() : TPriListBase(KNumPriorities) {}
inline TList*& Next()
{ return *(TList**)this; }
private:
SDblQueLink* iExtraQueues[KNumPriorities-1];
friend class TThreadWaitList;
friend class Monitor;
};
public:
inline TThreadWaitList()
{ iWaitPtr=EInitValue; }
~TThreadWaitList();
TInt Construct();
inline TBool NonEmpty() const
{ return (iWaitPtr & ENonEmptyMask); }
DThread* First() const;
TInt HighestPriority() const;
void Add(DThread* aThread);
void Remove(DThread* aThread);
void ChangePriority(DThread* aThread, TInt aNewPriority);
static TInt ThreadCreated();
static void ThreadDestroyed();
private:
static TInt Up(TBool aThread);
static void Down(TBool aThread);
#ifdef _DEBUG
void Check() const;
#endif
private:
TLinAddr iWaitPtr;
static TList* FirstFree; // first free list
static TInt NLists; // number of TLists in existence
static TInt NWaitObj; // number of wait objects in existence which use TThreadWaitList
static TInt NThrd; // number of DThreads in existence
};
/********************************************
* Semaphore control block
********************************************/
class DSemaphore : public DObject
{
public:
TInt Create(DObject* aOwner, const TDesC* aName, TInt aInitialCount, TBool aVisible=ETrue);
public:
~DSemaphore();
void WaitCancel(DThread* aThread);
void WaitCancelSuspended(DThread* aThread);
void SuspendWaitingThread(DThread* aThread);
void ResumeWaitingThread(DThread* aThread);
void ChangeWaitingThreadPriority(DThread* aThread, TInt aNewPriority);
public:
TInt Wait(TInt aNTicks);
void Signal();
void SignalN(TInt aCount);
void Reset();
public:
TInt iCount;
TUint8 iResetting;
TUint8 iPad1;
TUint8 iPad2;
TUint8 iPad3;
SDblQue iSuspendedQ;
TThreadWaitList iWaitQ;
public:
friend class Monitor;
};
/********************************************
* Mutex control block
********************************************/
class DMutex : public DObject
{
public:
TInt Create(DObject* aOwner, const TDesC* aName, TBool aVisible, TUint aOrder);
public:
DMutex();
~DMutex();
TInt HighestWaitingPriority();
void WaitCancel(DThread* aThread);
void WaitCancelSuspended(DThread* aThread);
void SuspendWaitingThread(DThread* aThread);
void ResumeWaitingThread(DThread* aThread);
void ChangeWaitingThreadPriority(DThread* aThread, TInt aNewPriority);
void SuspendPendingThread(DThread* aThread);
void RemovePendingThread(DThread* aThread);
void ChangePendingThreadPriority(DThread* aThread, TInt aNewPriority);
void WakeUpNextThread();
public:
TInt Wait();
void Signal();
void Reset();
public:
TInt iHoldCount; // number of times held by current thread
TInt iWaitCount; // number of waiting threads
TUint8 iResetting;
TUint8 iOrder;
TUint8 iPad1;
TUint8 iPad2;
TThreadMutexCleanup iCleanup;
SDblQue iSuspendedQ;
SDblQue iPendingQ;
TThreadWaitList iWaitQ;
#ifdef _DEBUG
SDblQueLink iOrderLink; // used for acquisition order checking
#endif
public:
friend class Monitor;
};
/********************************************
* Condition variable control block
********************************************/
class DCondVar : public DObject
{
public:
TInt Create(DObject* aOwner, const TDesC* aName, TBool aVisible);
public:
DCondVar();
~DCondVar();
void WaitCancel(DThread* aThread);
void WaitCancelSuspended(DThread* aThread);
void SuspendWaitingThread(DThread* aThread);
void ResumeWaitingThread(DThread* aThread);
void ChangeWaitingThreadPriority(DThread* aThread, TInt aNewPriority);
public:
TInt Wait(DMutex* aMutex, TInt aTimeout);
void Signal();
void Broadcast(DMutex* aMutex);
void Reset();
void UnBlockThread(DThread* aThread, TBool aUnlock);
public:
TUint8 iResetting;
TUint8 iPad1;
TUint8 iPad2;
TUint8 iPad3;
DMutex* iMutex;
TInt iWaitCount;
SDblQue iSuspendedQ;
TThreadWaitList iWaitQ;
public:
friend class Monitor;
};
/********************************************
* Kernel representation of session message
********************************************/
class DSession;
class RMessageK : public TClientRequest
{
public:
inline TInt Arg(TInt aParam) const;
inline TAny* Ptr(TInt aParam) const;
inline TInt ArgType(TInt aParam) const;
inline TUint IsDescriptor(TInt aParam) const;
inline const TDesHeader& Descriptor(TInt aParam) const;
inline TDesHeader& Descriptor(TInt aParam);
inline TInt DesLength(TInt aParam) const;
inline TInt DesMaxLength(TInt aParam) const;
IMPORT_C DThread* Thread() const;
IMPORT_C static RMessageK* MessageK(TInt aHandle);
static RMessageK* MessageK(TInt aHandle, DThread* aThread);
void OpenRef();
void CloseRef();
public:
// message is always in one of the following message states,
// a change of state requires the system lock.
inline TBool IsFree() const;
inline TBool IsInitialising() const;
inline TBool IsDelivered() const;
inline TBool IsAccepted() const;
inline TBool IsCompleting() const;
inline void SetFree();
inline void SetInitialising();
inline void SetDelivered(SDblQue& aDeliveredQ);
inline void SetAccepted(DProcess* aServerProcess);
inline void SetCompleting();
// WARNING: Some ARM assembler code makes assumptions about the *ordering* of these enum values!
enum TMsgType {EDisc=32, ESync, ESession, EGlobal};
static RMessageK* GetNextFreeMessage(DSession* aSession);
static RMessageK* ClaimMessagePool(enum TMsgType aType, TInt aCount, DSession* aSession);
void ReleaseMessagePool(enum TMsgType aType, TInt aMax);
private:
friend class DSession;
friend class ExecHandler;
class TMsgArgs
{
friend class RMessageK;
friend class DSession;
friend class ExecHandler;
friend class TServerMessage;
void ReadDesHeaders(const TInt aArgsPtr[KMaxMessageArguments+1]);
inline TInt ArgType(TInt aParam) const;
inline TUint IsDescriptor(TInt aParam) const;
inline TUint AllDescriptorFlags() const;
inline TUint AllPinFlags() const;
inline TUint AllDesWritten() const;
inline void SetArgUndefined(TInt aParam);
inline void SetDesWritten(TInt aParam);
inline TBool IsDesWritten(TInt aParam) const;
TUint iArgFlags; // describes which arguments are descriptors/handles etc.
TInt iArgs[KMaxMessageArguments]; // the arguments themselves
TDesHeader iDesInfo[KMaxMessageArguments]; // info for any descriptor args
// The iArgFlags words has a strange layout. The bottom 16 bits have to match those
// TIpcArgs::iFlags, which -- from LSB upwards -- is KMaxMessageArguments (4) fields
// of KBitsPerType (3) each, describing arguments 0-3, followed by 4 bits requesting
// pinning of the corresponding (descriptor) argument. We then use the next 4 bits
// to record whether each (descriptor) argument has been written.
enum
{
KArgFlagMask = (1 << TIpcArgs::KBitsPerType) - 1,
KAllArgTypesMask = (1 << (TIpcArgs::KBitsPerType*KMaxMessageArguments)) - 1,
KAllIpcFlagsMask = (KAllArgTypesMask | TIpcArgs::KPinMask),
KAllDesArgMask = (TIpcArgs::EFlagDes << (0 * TIpcArgs::KBitsPerType)) |
(TIpcArgs::EFlagDes << (1 * TIpcArgs::KBitsPerType)) |
(TIpcArgs::EFlagDes << (2 * TIpcArgs::KBitsPerType)) |
(TIpcArgs::EFlagDes << (3 * TIpcArgs::KBitsPerType)),
KDesWrittenShift = (TIpcArgs::KBitsPerType*KMaxMessageArguments + TIpcArgs::KPinArgShift),
KDesWrittenMask = ((1 << KMaxMessageArguments) - 1) << KDesWrittenShift
};
};
private:
RMessageK(); // call GetNextFreeMessage() or ClaimMessagePool() instead
~RMessageK(); // Don't delete, call CloseRef()
void Free(); // only called from last CloseRef()
static TInt ExpandMessagePool();
static void CallbackFunc(TAny* aData, TUserModeCallbackReason aReason);
TInt PinDescriptors(DSession* aSession, TBool aPinningServer);
public:
TUint8 iMsgType; // where this message belongs - one of the TMsgType values above
TUint8 iAccessCount;
DSession* iSession; // pointer to session
SDblQueLink iSessionLink; // attaches message to session or freelist
// WARNING: Some ARM assembler code makes assumptions about the layout of this structure!
SDblQueLink iServerLink; // Also represents message state!
TInt iFunction;
TMsgArgs iMsgArgs;
DThread* iClient; // pointer to client thread (not reference counted, see below)
// An encapsulated array of pointers to pin objects associated with any descriptor arguments.
struct TPinArray
{
TVirtualPinObject* iPinPtrs[KMaxMessageArguments];
} *iPinArray; // Pointer to (heap-allocated) array of pointers to pin objects
public:
enum { KMessageSize = 128 }; // sizeof(RMessageK) rounded up to a power of 2
};
inline TInt RMessageK::TMsgArgs::ArgType(TInt aParam) const
{
return (iArgFlags >> (aParam * TIpcArgs::KBitsPerType)) & KArgFlagMask;
}
inline TUint RMessageK::TMsgArgs::IsDescriptor(TInt aParam) const
{
return (iArgFlags >> (aParam * TIpcArgs::KBitsPerType)) & TIpcArgs::EFlagDes;
}
inline TUint RMessageK::TMsgArgs::AllDescriptorFlags() const
{
return iArgFlags & KAllDesArgMask;
}
inline TUint RMessageK::TMsgArgs::AllPinFlags() const
{
return (iArgFlags & TIpcArgs::KPinMask) >> TIpcArgs::KPinArgShift;
}
inline TUint RMessageK::TMsgArgs::AllDesWritten() const
{
return (iArgFlags & KDesWrittenMask) >> KDesWrittenShift;
}
inline void RMessageK::TMsgArgs::SetArgUndefined(TInt aParam)
{
iArgFlags &= ~(KArgFlagMask << (aParam * TIpcArgs::KBitsPerType));
iArgFlags |= TIpcArgs::EUnspecified << (aParam * TIpcArgs::KBitsPerType);
}
inline void RMessageK::TMsgArgs::SetDesWritten(TInt aParam)
{
iArgFlags |= 1 << (aParam + KDesWrittenShift);
}
inline TInt RMessageK::Arg(TInt aParam) const
{
return iMsgArgs.iArgs[aParam];
}
inline TAny* RMessageK::Ptr(TInt aParam) const
{
return (TAny*)Arg(aParam);
}
inline TInt RMessageK::ArgType(TInt aParam) const
{
return iMsgArgs.ArgType(aParam);
}
inline TUint RMessageK::IsDescriptor(TInt aParam) const
{
return iMsgArgs.IsDescriptor(aParam);
}
inline const TDesHeader& RMessageK::Descriptor(TInt aParam) const
{
return iMsgArgs.iDesInfo[aParam];
}
inline TDesHeader& RMessageK::Descriptor(TInt aParam)
{
return iMsgArgs.iDesInfo[aParam];
}
inline TInt RMessageK::DesLength(TInt aParam) const
{
return Descriptor(aParam).Length();
}
inline TInt RMessageK::DesMaxLength(TInt aParam) const
{
return Descriptor(aParam).MaxLength();
}
inline TBool RMessageK::IsFree() const
{
__ASSERT_SYSTEM_LOCK;
return !iServerLink.iNext;
}
inline TBool RMessageK::IsInitialising() const
{
__ASSERT_SYSTEM_LOCK;
return iServerLink.iNext == (TAny*)2;
}
inline TBool RMessageK::IsDelivered() const
{
__ASSERT_SYSTEM_LOCK;
return iServerLink.iNext != 0 && (TLinAddr(iServerLink.iNext) & 3) == 0;
}
inline TBool RMessageK::IsAccepted() const
{
__ASSERT_SYSTEM_LOCK;
return ((TLinAddr)iServerLink.iNext & 3) == 3;
}
inline TBool RMessageK::IsCompleting() const
{
__ASSERT_SYSTEM_LOCK;
return iServerLink.iNext == (TAny*)1;
}
inline void RMessageK::SetFree()
{
__ASSERT_SYSTEM_LOCK;
iServerLink.iNext = 0;
}
inline void RMessageK::SetInitialising()
{
__ASSERT_SYSTEM_LOCK;
iServerLink.iNext = (SDblQueLink*)2;
}
inline void RMessageK::SetDelivered(SDblQue& aDeliveredQ)
{
__ASSERT_SYSTEM_LOCK;
aDeliveredQ.Add(&iServerLink);
}
inline void RMessageK::SetAccepted(DProcess* aServerProcess)
{
__ASSERT_SYSTEM_LOCK;
iServerLink.iNext = (SDblQueLink*)~TUint32(this);
iServerLink.iPrev = (SDblQueLink*)~TUint32(aServerProcess);
}
inline void RMessageK::SetCompleting()
{
__ASSERT_SYSTEM_LOCK;
iServerLink.iNext = (SDblQueLink*)1;
}
/********************************************
* Thread control block
********************************************/
class DChunk;
class DProcess;
class TTrap;
const TInt KMaxThreadContext=256;
typedef void (*TUnknownStateHandler)(DThread*,TInt,TInt);
class DThread : public DObject
{
public:
enum {EDefaultUserTimeSliceMs = 20};
enum TThreadState
{
ECreated,
EDead,
EReady,
EWaitSemaphore,
EWaitSemaphoreSuspended,
EWaitMutex,
EWaitMutexSuspended,
EHoldMutexPending,
EWaitCondVar,
EWaitCondVarSuspended,
};
enum TOperation
{
ESuspend=0,
EResume=1,
EForceResume=2,
EReleaseWait=3,
EChangePriority=4,
};
enum TUserThreadState
{
EUserThreadNone,
EUserThreadCreated,
EUserThreadRunning,
EUserThreadExiting,
};
public:
DThread();
void Destruct();
TInt Create(SThreadCreateInfo& aInfo);
TInt SetPriority(TThreadPriority aPriority);
TInt MakeHandle(TOwnerType aType, DObject* aObject, TInt& aHandle);
TInt MakeHandle(TOwnerType aType, DObject* aObject, TInt& aHandle, TUint aAttr);
TInt MakeHandleAndOpen(TOwnerType aType, DObject* aObject, TInt& aHandle);
TInt MakeHandleAndOpen(TOwnerType aType, DObject* aObject, TInt& aHandle, TUint aAttr);
TInt HandleClose(TInt aHandle);
TInt OpenFindHandle(TOwnerType aType, const TFindHandle& aFindHandle, TInt& aHandle);
TInt OpenObject(TOwnerType aType, const TDesC& aName, TInt& aHandle, DObject*& aObj, TInt aObjType);
IMPORT_C DObject* ObjectFromHandle(TInt aHandle);
IMPORT_C DObject* ObjectFromHandle(TInt aHandle, TInt aObjType);
IMPORT_C DObject* ObjectFromHandle(TInt aHandle, TInt aObjType, TUint& aAttr);
void RequestComplete(TRequestStatus*& aStatus, TInt aReason);
TInt SetTls(TInt aHandle, TInt aDllUid, TAny* aPtr);
TAny* Tls(TInt aHandle, TInt aDllUid);
void FreeTls(TInt aHandle);
TInt Rename(const TDesC& aName);
TBool IsExceptionHandled(TExcType aType);
TInt RaiseException(TExcType aType);
void SetExitInfo(TExitType aType, TInt aReason, const TDesC& aCategory);
void CloseCreatedHeap();
void RemoveClosingLibs();
inline TBool HasCapability(/*TInt aCapability*/);
TBool IsRealtime();
void SetRealtimeState(TThreadRealtimeState aNewState);
#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
inline TBool HasCapability(TCapability aCapability, const char* aDiagnosticText=0);
#else //__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
// Only available to NULL arguments
inline TBool HasCapability(TCapability aCapability, OnlyCreateWithNull aDiagnostic=NULL);
#endif // !__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
private:
IMPORT_C TBool DoHasCapability(TCapability aCapability, const char* aDiagnosticText);
IMPORT_C TBool DoHasCapability(TCapability aCapability);
public:
// not memory model dependent
virtual TInt Context(TDes8& aDes)=0;
public:
inline void Stillborn();
void Release();
TInt CalcDefaultThreadPriority();
IMPORT_C void AddCleanup(TThreadCleanup* aCleanup);
void SetRequiredPriority();
void SetActualPriority(TInt aActualPriority);
void RevertPriority();
void SvKill();
IMPORT_C TInt ReleaseWait(TInt aReturnCode);
IMPORT_C void CancelTimer();
void ExtractMiscNotifiers(SDblQue& aQ, TRequestStatus* aStatus);
void KillMiscNotifiers();
public:
// not memory model dependent
TInt DoCreate(SThreadCreateInfo& aInfo);
IMPORT_C void SetThreadPriority(TInt aThreadPriority);
void SetDefaultPriority(TInt aDefaultPriority);
void AbortTimer(TBool aAbortAbsolute);
void Suspend(TInt aCount);
void Resume();
void ForceResume();
void Exit();
void Die(TExitType aType, TInt aReason, const TDesC& aCategory);
TInt Logon(TRequestStatus* aStatus, TBool aRendezvous);
void Rendezvous(TInt aReason);
void CleanupLeave(TInt aDepth = 1);
#ifdef __SMP__
static void SMPSafeCallback(TAny* aThisPtr, TUserModeCallbackReason aReasonCode);
#endif
public:
// memory model dependent
TInt AllocateSupervisorStack();
void FreeSupervisorStack();
void FreeUserStack();
TInt AllocateUserStack(TInt aSize, TBool aPaged);
DChunk* OpenSharedChunk(const TAny* aAddress, TBool aWrite, TInt& aOffset);
DChunk* OpenSharedChunk(TInt aHandle,TBool aWrite);
TInt PrepareMemoryForDMA(const TAny* aAddress, TInt aSize, TPhysAddr* aPageList);
TInt ReleaseMemoryFromDMA(const TAny* aAddress, TInt aSize, TPhysAddr* aPageList);
static void IpcExcHandler(TExcTrap* aTrap, DThread* aThread, TAny* aContext);
virtual void DoExit1();
public:
// pure virtual
virtual TInt SetupContext(SThreadCreateInfo& aInfo)=0;
virtual void DoExit2()=0;
protected:
virtual void SetPaging(TUint& aCreateFlags);
public:
inline void UnknownState(TInt aOperation, TInt aParameter);
inline static DThread* FromTimer(TAny* aPtr);
static void ExitCurrentThread();
static void DefaultUnknownStateHandler(DThread* aThread, TInt aOperation, TInt aParameter);
static void EpocThreadFunction(TAny* aPtr);
static TDfc* EpocThreadExitHandler(NThread* aThread);
static void EpocThreadTimeoutHandler(NThread* aThread, TInt aOp);
public:
virtual void BTracePrime(TInt aCategory);
private:
// Functions that access user-side memory
TInt GetDesInfo(const TAny* aDes, TInt& aLength, TInt& aMaxLength, TUint8*& aPtr, TBool aWriteable);
TInt GetDesLength(const TAny* aPtr);
TInt GetDesMaxLength(const TAny* aPtr);
TInt DesRead(const TAny* aPtr, TUint8* aDes, TInt aMax, TInt aOffset, TInt aMode);
TInt DesWrite(const TAny* aPtr, const TUint8* aDes, TInt aLength, TInt aOffset, TInt aMode, DThread* aOriginatingThread);
TInt DoDesRead(const TDesHeader& aDesInfo, TUint8* aDes, TInt aMax, TInt aOffset, TInt aMode);
TInt DoDesWrite(const TAny* aPtr, TDesHeader& aDesInfo, const TUint8* aDes, TInt aLength, TInt aOffset, TInt aMode, DThread* aOriginatingThread);
// (the following are memory model dependent)
TInt RawRead(const TAny* aSrc, TAny* aDest, TInt aLength, TInt aFlags, TIpcExcTrap* aExcTrap);
TInt RawWrite(const TAny* aDest, const TAny* aSrc, TInt aLength, TInt aFlags, DThread* aOriginatingThread, TIpcExcTrap* aExcTrap);
TInt ReadAndParseDesHeader(const TAny* aSrc, TDesHeader& aDest);
public:
TUint32 iIpcCount;
TLinAddr iUserStackRunAddress;
TInt iUserStackSize;
TUint32 iFlags;
DProcess* iOwningProcess;
SDblQueLink iProcessLink;
TInt iThreadPriority;
RObjectIx iHandles;
TUint iId;
RAllocator* iAllocator;
RAllocator* iCreatedAllocator;
TTrap* iFrame;
TTrapHandler* iTrapHandler;
RArray<STls> iTls;
CActiveScheduler* iScheduler;
TExceptionHandler iExceptionHandler;
TUint iExceptionMask;
TExcTrap* iExcTrap;
TInt iDebugMask;
TThreadMessage iKernMsg;
DObject* iTempObj;
DObject* iExtTempObj;
TAny* iTempAlloc;
SDblQue iOwnedLogons;
SDblQue iTargetLogons;
RMessageK* iSyncMsgPtr;
TDfc iKillDfc;
SDblQue iClosingLibs;
TPriListLink iWaitLink;
// TUint8 iMState; // use iSpare1 for iMState
// TUint8 iExiting; // use iSpare2 for iExiting
// TUint8 iWaitListReserved; // use iSpare3 for iWaitListReserved
TInt iDefaultPriority; // default scheduling priority
TAny* iWaitObj; // object on which this thread is waiting
TUnknownStateHandler iUnknownStateHandler; // handler for extra thread states - used by RTOS personality layers
TAny* iExtras; // pointer to extra data used by RTOS personality layers
TAny* iSupervisorStack; // thread's supervisor mode stack
TInt iSupervisorStackSize;
TUint8 iSupervisorStackAllocated;
TUint8 iThreadType;
TUint8 iExitType;
TUint8 iEmiFlags;
TInt iExitReason;
TBufC<KMaxExitCategoryName> iExitCategory;
SDblQue iMutexList; // list of held mutexes, used only for acquisition order checking
TPriList<TThreadCleanup,KNumPriorities> iCleanupQ; // things to clean up when we die
TTimer iTimer;
TInt iLeaveDepth; // recursive depth of User::Leave() calls
TAny* iEmiStartMonitor;
NThread iNThread;
TPagingExcTrap* iPagingExcTrap;
TUserThreadState iUserThreadState;
SDblQue iMiscNotifiers; // miscellaneous notifiers owned by this thread
DThread* iIpcClient; // client thread when doing IPC, used if realtime therad takes fault
#ifdef __SMP__
TUserModeCallback iSMPSafeCallback;
#endif
RMessageK* iTempMsg;
public:
#ifndef __REMOVE_PLATSEC_DIAGNOSTICS__
#ifdef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
// This exported Kern:: function takes diagnostic strings that
// should still work by calling the DoHasCapability function here even
// though we have removed diagnostic strings from ekern proper
friend TBool Kern::DoCurrentThreadHasCapability(TCapability aCapability, const char* aContextText);
#endif //__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
#endif // !__REMOVE_PLATSEC_DIAGNOSTICS__
friend class Monitor;
friend class Kern;
friend class ExecHandler;
friend class TClientBuffer;
};
__ASSERT_COMPILE((_FOFF(DThread,iTimer.iUnion) & 7)==0);
inline DThread* DThread::FromTimer(TAny* aPtr)
{ return _LOFF(aPtr,DThread,iTimer); }
inline void DThread::UnknownState(TInt aOperation, TInt aParameter)
{ (*iUnknownStateHandler)(this,aOperation,aParameter); }
inline void DThread::Stillborn()
{iNThread.Stillborn();Release();}
#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
inline TBool DThread::HasCapability(TCapability aCapability, const char* aDiagnosticText)
{
return DoHasCapability(aCapability, aDiagnosticText);
}
#else //__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
// Only available to NULL arguments
inline TBool DThread::HasCapability(TCapability aCapability, OnlyCreateWithNull /*aDiagnostic*/)
{
return DoHasCapability(aCapability);
}
#endif // !__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
#define TheCurrentThread _LOFF(NCurrentThread(),DThread,iNThread)
class TLogon : public TClientRequest
{
public:
enum TType
{
ETargetThread=0,
ETargetProcess=1,
ERendezvous=0x80,
};
TInt Attach(SDblQue& aList, DThread* aOwner, DObject* aTarget, TRequestStatus* aStatus, TUint32 aType);
static TInt Cancel(SDblQue& aList, DObject* aTarget, TRequestStatus* aStatus, TUint32 aType);
enum TComplete { ETargetRendezvous, ETarget, EOwned };
static void CompleteAll(SDblQue& aList, TComplete aAction, TInt aReason);
static NFastMutex LogonLock;
private:
inline static void Lock()
{ NKern::FMWait(&LogonLock); }
inline static void Unlock()
{ NKern::FMSignal(&LogonLock); }
TUint32 iType;
inline TBool IsRendezvous()
{ return (iType & ERendezvous); }
DThread* iOwningThread;
DObject* iTarget;
SDblQueLink iOwningThreadLink;
SDblQueLink iTargetLink;
private:
~TLogon(); // call Close(), don't delete
};
/********************************************
* Platform-independent chunk type abstraction
********************************************/
enum TChunkType
{
// these never change or move or anything
EKernelData = 0, // Supervisor,Rw,Cacheable
EKernelStack = 1, // Supervisor,Rw,Cacheable
EKernelCode = 2, // Supervisor,Rw,Cacheable
EDll = 3, // User,Ro,Cacheable
EUserCode = 4,
// This changes on a PDE basis when the file server runs
ERamDrive = 5, // Supervisor,Rw,Cacheable
// these change on PDE basis when run
EUserData = 6,
EDllData = 7,
EUserSelfModCode = 8,
ESharedKernelSingle = 9, // Must be same value as TChunkCreateInfo::ESharedKernelSingle
ESharedKernelMultiple = 10, // Must be same value as TChunkCreateInfo::ESharedKernelMultiple
ESharedIo = 11,
ESharedKernelMirror = 12,
EKernelMessage = 13, // Dedicated chunk for RMessageK objects
ENumChunkTypes // Keep as last value
};
/********************************************
* Chunk creation info block
********************************************/
struct SChunkCreateInfo
{
enum {EAdjust=1, EAdd=2}; // iOperations
TBool iGlobal;
TInt iAtt; // Set with values from TChunkCreate::TChunkCreateAtt NOT DChunk::TChunkAttributes
TBool iForceFixed;
TUint iOperations;
TLinAddr iRunAddress;
TChunkType iType;
TInt iMaxSize;
TInt iInitialBottom;
TInt iInitialTop;
TInt iPreallocated;
TPtrC iName;
DObject* iOwner;
TUint32 iMapAttr;
TDfc* iDestroyedDfc;
TUint8 iClearByte;
public:
SChunkCreateInfo();
};
/** The different types of pages that the allocator should consider
*/
enum TZonePageType
{
EPageUnknown = 0, /**<Pages that are at physical addresses the kernel has no knowledge of*/
EPageFixed, /**<Pages that shouldn't be physically moved*/
EPageMovable, /**<Pages that may be physically moved*/
EPageDiscard, /**<Pages that may be removed*/
EPageTypes /**<The no of different page types*/
};
/********************************************
* Chunk control block
********************************************/
class DChunk : public DObject
{
public:
/**
@see DMemModelChunk::TMemModelChunkAttributes for memory model specific attribute flags
*/
enum TChunkAttributes
{
ENormal =0x00,
EDoubleEnded =0x01,
EDisconnected =0x02,
EConstructed =0x04,
EMemoryNotOwned =0x08,
ETrustedChunk =0x10,
EDataPaged =0x20, // Set when the chunk is data paged.
ECache =0x40,
EReadOnly =0x80,
EChunkAttributesMask = 0xff,
};
enum TCommitType
{
ECommitDiscontiguous = 0,
ECommitContiguous = 1,
ECommitPhysicalMask = 2,
ECommitDiscontiguousPhysical = ECommitDiscontiguous|ECommitPhysicalMask,
ECommitContiguousPhysical = ECommitContiguous|ECommitPhysicalMask,
ECommitVirtual = 4, // only supported by moving and multiple memory models on arm
};
enum TDecommitType
{
EDecommitNormal = 0,
EDecommitVirtual = 1,
};
DChunk();
~DChunk();
TInt Create(SChunkCreateInfo& aInfo);
inline TInt Size() const {return iSize;}
inline TInt MaxSize() const {return iMaxSize;}
#ifndef __MEMMODEL_FLEXIBLE__
inline TUint8 *Base() const {return iBase;}
#endif
inline TInt Bottom() const {return iStartPos;}
inline TInt Top() const {return iStartPos+iSize;}
inline DProcess* OwningProcess() const {return iOwningProcess;}
protected:
virtual void SetPaging(TUint aCreateAtt);
public:
virtual TInt AddToProcess(DProcess* aProcess);
virtual TInt DoCreate(SChunkCreateInfo& aInfo)=0;
virtual TInt Adjust(TInt aNewSize)=0;
virtual TInt AdjustDoubleEnded(TInt aBottom, TInt aTop)=0;
virtual TInt CheckAccess()=0;
virtual TInt Commit(TInt aOffset, TInt aSize, TCommitType aCommitType=DChunk::ECommitDiscontiguous, TUint32* aExtraArg=0)=0;
virtual TInt Allocate(TInt aSize, TInt aGuard=0, TInt aAlign=0)=0;
virtual TInt Decommit(TInt aOffset, TInt aSize)=0;
virtual TInt Lock(TInt aOffset, TInt aSize)=0;
virtual TInt Unlock(TInt aOffset, TInt aSize)=0;
virtual TInt Address(TInt aOffset, TInt aSize, TLinAddr& aKernelAddress)=0;
virtual TInt PhysicalAddress(TInt aOffset, TInt aSize, TLinAddr& aKernelAddress, TUint32& aPhysicalAddress, TUint32* aPhysicalPageList=NULL)=0;
virtual void BTracePrime(TInt aCategory);
virtual void Substitute(TInt aOffset, TPhysAddr aOldAddr, TPhysAddr aNewAddr)=0;
virtual TUint8* Base(DProcess* aProcess)=0;
public:
DProcess* iOwningProcess; // NULL for global chunks
TInt iSize; // always the committed size (i.e. gaps not included)
TInt iMaxSize;
#ifndef __MEMMODEL_FLEXIBLE__
TUint8* iBase;
#else
TLinAddr iFixedBase;
#endif
TInt iAttributes;
TInt iStartPos; // start of committed area for double-ended chunks
TUint iControllingOwner; // ProcessID of process which set protection
TUint iRestrictions;
TUint iMapAttr; // only for shared kernel chunks
TDfc* iDestroyedDfc;
TChunkType iChunkType;
TUint8 iClearByte; // The byte value to clear all memory committed to the chunk to.
public:
friend class Monitor;
};
/********************************************
* Platform security
********************************************/
/**
@deprecated
*/
#define __SECURE_KERNEL(p) { p; };
/**
@deprecated
*/
#define __KERNEL_CAPABILITY_CHECK(p) { p; };
/** TCompiledSecurityPolicy uses the upper two bits in iCaps to store a reduced
version of TSecurityPolicy's iType. This constant is the number of free bits.
@internalTechnology
*/
const TUint32 KCSPBitsFree = 30;
/** TCompiledSecurityPolicy can only represent capabilities less than
KCSPBitsFree-1
*/
__ASSERT_COMPILE(ECapability_Limit <= KCSPBitsFree);
/** A precompiled security policy useful for fast checking of policies.
@internalComponent
*/
class TCompiledSecurityPolicy
{
public:
enum TType
{
ETypeFail = 0,
ETypeCapsOnly = 1,
ETypeSecureId= 2,
ETypeVendorId= 3,
};
enum TMask
{
EMaskFail = ETypeFail << KCSPBitsFree,
EMaskCapsOnly = ETypeCapsOnly << KCSPBitsFree,
EMaskSecureId = ETypeSecureId << KCSPBitsFree,
EMaskVendorId = ETypeVendorId << KCSPBitsFree,
};
TInt Set(const TSecurityPolicy& aPolicy);
#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
inline TBool CheckPolicy(DProcess* aProcess, const char* aDiagnostic=0) const
{
return DoCheckPolicy(aProcess, aDiagnostic);
}
inline TBool CheckPolicy(DThread* aThread, const char* aDiagnostic=0) const
{
return DoCheckPolicy(aThread, aDiagnostic);
}
#else //__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
// Only available to NULL arguments
inline TBool CheckPolicy(DProcess* aProcess, OnlyCreateWithNull /*aDiagnostic*/=NULL) const
{
return DoCheckPolicy(aProcess);
}
inline TBool CheckPolicy(DThread* aThread, OnlyCreateWithNull /*aDiagnostic*/=NULL) const
{
return DoCheckPolicy(aThread);
}
#endif // !__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
private:
#ifndef __REMOVE_PLATSEC_DIAGNOSTICS__
TBool DoCheckPolicy(DProcess* aProcess, const char* aDiagnostic) const;
TBool DoCheckPolicy(DThread* aThread, const char* aDiagnostic) const;
#endif // !__REMOVE_PLATSEC_DIAGNOSTICS__
TBool DoCheckPolicy(DProcess* aProcess) const;
TBool DoCheckPolicy(DThread* aThread) const;
TBool CheckPolicy(const SSecurityInfo& aSecInfo, SSecurityInfo& aMissing) const;
void AddCapability(TCapability aCap);
inline void SetETypeFail() { /* Yes, it's a NOP */iCaps |= EMaskFail; }
inline void SetETypePass() { iCaps |= EMaskCapsOnly; }
inline void SetETypeCapsOnly() { iCaps |= EMaskCapsOnly; }
inline void SetETypeSecureId() { iCaps |= (TUint32)EMaskSecureId; }
inline void SetETypeVendorId() { iCaps |= (TUint32)EMaskVendorId; }
inline TUint32 Caps() const { return iCaps & ~EMaskVendorId; }
inline TUint32 Type() const { return iCaps >> KCSPBitsFree; }
union
{
TUint32 iSecureId;
TUint32 iVendorId;
};
TUint32 iCaps;
};
/********************************************
* Process control block
********************************************/
struct SCodeSegEntry
{
DCodeSeg* iSeg; // code segment in use
DLibrary* iLib; // client representation object (DLibrary or DxxDevice)
};
class DProcess : public DObject
{
public:
/** Possible values for bitmask specifying how to iterate dependency graph.
@see TraverseCodeSegs
@publishedPartner
@released
*/
enum TTraverseFlags
{
/** Add code segment to queue if set, remove it if cleared */
ETraverseFlagAdd=1,
/** Restrict iteration to dynamic dependencies in ELoaded state if set,
iterate everything if cleared */
ETraverseFlagRestrict=2
};
public:
DProcess();
~DProcess();
TInt Create(TBool aKernelProcess, TProcessCreateInfo& aInfo, HBuf* aCommandLine);
TInt SetPriority(TProcessPriority aPriority);
TInt ConvertPriority(TProcessPriority aPriority);
void Destruct();
TInt Rename(const TDesC& aName);
TInt Logon(TRequestStatus* aStatus, TBool aRendezvous);
void Rendezvous(TInt aReason);
IMPORT_C TInt TraverseCodeSegs(SDblQue* aQ, DCodeSeg* aExclude, TUint32 aMark, TUint32 aFlags);
TInt OpenDeps();
TInt AddCodeSeg(DCodeSeg* aSeg, DLibrary* aLib, SDblQue& aQ);
void RemoveCodeSeg(DCodeSeg* aCodeSeg, SDblQue* aQ);
TInt CallList(SDblQue& aQ, DCodeSeg* aSeg, TUint32 aFlag);
DCodeSeg* CodeSeg();
TBool HasCapabilityNoDiagnostic(TCapability aCapability);
inline TBool HasCapability(/*TInt aCapability*/);
#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
inline TBool HasCapability(TCapability aCapability, const char* aDiagnosticText=0);
#else //__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
// Only available to NULL arguments
inline TBool HasCapability(TCapability aCapability, OnlyCreateWithNull aDiagnostic=NULL);
#endif // !__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
private:
IMPORT_C TBool DoHasCapability(TCapability aCapability, const char* aDiagnostic);
IMPORT_C TBool DoHasCapability(TCapability aCapability);
protected:
virtual TInt SetPaging(const TProcessCreateInfo& aInfo);
public:
virtual void DoAppendName(TDes& aName);
virtual TInt NewChunk(DChunk*& aChunk, SChunkCreateInfo& aInfo, TLinAddr& aRunAddr)=0;
virtual TInt AddChunk(DChunk* aChunk,TBool isReadOnly)=0;
virtual TInt NewShPool(DShPool*& aPool, TShPoolCreateInfo& aInfo)=0;
virtual TInt DoCreate(TBool aKernelProcess, TProcessCreateInfo& aInfo)=0;
virtual TInt AttachExistingCodeSeg(TProcessCreateInfo& aInfo)=0;
virtual TInt Loaded(TProcessCreateInfo& aInfo);
virtual void FinalRelease()=0;
public:
TInt NewThread(DThread*& aThread, SThreadCreateInfo& aInfo, TInt* aHandle, TOwnerType aType);
virtual void Resume();
void Die(TExitType aType,TInt aReason,const TDesC &aCategory);
virtual void Release();
TBool KillAllThreads(TExitType aType, TInt aReason, const TDesC &aCategory);
public:
virtual TInt GetNewThread(DThread*& aThread, SThreadCreateInfo& aInfo)=0;
virtual TInt CreateDataBssStackArea(TProcessCreateInfo& aInfo)=0;
virtual TInt MapCodeSeg(DCodeSeg* aCodeSeg)=0;
virtual void UnmapCodeSeg(DCodeSeg* aCodeSeg)=0;
virtual void RemoveDllData()=0;
virtual void BTracePrime(TInt aCategory);
public:
TInt WaitProcessLock();
TInt SignalProcessLock();
TInt WaitDllLock();
void SignalDllLock();
void AddThread(DThread &aThread);
#ifdef __SMP__
TInt UpdateSMPSafe();
#endif
inline DThread* FirstThread()
{ return _LOFF(iThreadQ.First(),DThread,iProcessLink); }
public:
TInt iPriority;
SDblQue iThreadQ;
TUint8 iExitType;
TUint8 iFinalReleaseFlag;
TUint8 iPad2;
TUint8 iDebugAttributes;
TInt iExitReason;
TBufC<KMaxExitCategoryName> iExitCategory;
RObjectIx iHandles;
TUidType iUids;
TInt iGeneration;
TUint iId;
TUint32 iFlags;
HBuf* iCommandLine;
DProcess* iOwningProcess;
SDblQue iTargetLogons;
RArray<SCodeSegEntry> iDynamicCode;
// RPointerArray<DLibrary> iDynamicCode;
SSecurityInfo iS;
SSecurityInfo iCreatorInfo;
TUint iCreatorId;
TUint iSecurityZone;
TInt iEnvironmentData[KArgIndex];
public:
enum TProcessAttributes {
EPrivate = 0x00000002,
ESupervisor = (TInt)0x80000000,
EBeingLoaded = 0x08000000,
EResumed = 0x00010000,
EDataPaged = 0x00000004, // Set when the process is data paged
};
TInt iAttributes;
TLinAddr iDataBssRunAddress;
DChunk* iDataBssStackChunk;
DCodeSeg* iCodeSeg;
DCodeSeg* iTempCodeSeg;
DMutex* iProcessLock;
DMutex* iDllLock; // can be held while in user mode
TLinAddr iReentryPoint; // user address to jump to for new threads, exceptions
SDblQue iGarbageList; // list of DLibrary containing code which will be unmapped later
TInt iThreadsLeaving; // count of threads currently leaving [only w/C++ exceptions]
TInt iUserThreadsRunning; // count of running user threads that have not yet called User::Exit
volatile TInt iSMPUnsafeCount; // count of top level codesegs that are SMP unsafe
// i.e. the exe itself or things RLibrary::Load'ed - not deps
#ifdef __SMP__
NThreadGroup* iSMPUnsafeGroup; // group used to keep unsafe threads scheduled together
#endif
public:
friend class Monitor;
};
inline TBool DProcess::HasCapabilityNoDiagnostic(TCapability aCapability)
{
if(aCapability==ECapability_None)
return ETrue;
if((TUint32)aCapability<(TUint32)ECapability_Limit)
return (iS.iCaps[aCapability>>5]>>(aCapability&31))&1;
return EFalse;
}
inline TBool DProcess::HasCapability(/*TInt aCapability*/)
{ return iS.iCaps[0]!=~1u; } // Always return true for now
inline TBool DThread::HasCapability(/*TInt aCapability*/)
{ return iOwningProcess->HasCapability(/*aCapability*/); }
#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
inline TBool DProcess::HasCapability(TCapability aCapability, const char* aDiagnosticText)
{
return DoHasCapability(aCapability, aDiagnosticText);
}
#else //__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
// Only available to NULL arguments
inline TBool DProcess::HasCapability(TCapability aCapability, OnlyCreateWithNull /*aDiagnostic*/)
{
return DoHasCapability(aCapability);
}
#endif // !__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
/********************************************
* Session control block
********************************************/
class DServer;
class DSession : public DObject
{
public:
DSession();
virtual ~DSession();
TInt Add(DServer* aSvr, const TSecurityPolicy* aSecurityPolicy);
void Transfer(DServer* aServer, RMessageK* aMsg);
TInt MakeHandle();
virtual TInt RequestUserHandle(DThread* aThread, TOwnerType aType);
virtual TInt Close(TAny*);
void Detach(TInt aReason);
void CloseFromDisconnect();
inline TBool IsClosing();
inline void TotalAccessInc()
{__ASSERT_SYSTEM_LOCK; iTotalAccessCount++;};
TInt TotalAccessDec();
TInt TotalAccessDecRel();
void BTracePrime(TInt aCategory);
public:
// Static methods called from exec handlers
static TInt New(DSession*& aS, TInt aMsgSlots, TInt aMode);
static TInt Send(TInt aHandle, TInt aFunction, const TInt* aPtr, TRequestStatus* aStatus);
static TInt SendSync(TInt aHandle, TInt aFunction, const TInt* aPtr, TRequestStatus* aStatus);
private:
TInt Send(RMessageK* aMsg, TInt aFunction, const RMessageK::TMsgArgs* aArgs, TRequestStatus* aStatus);
RMessageK* GetNextFreeMessage();
public:
DServer* iServer; // pointer to kernel-side server object
SDblQueLink iServerLink; // link to attach session to server
const TAny* iSessionCookie; // pointer to server-side CSession2 (user cookie)
TUint8 iSessionType; // TIpcSessionType
TUint8 iSvrSessionType; // TIpcSessionType
TUint8 iHasSessionPool; // TIpcSessionType
TUint8 iTotalAccessCount; // all client accesses together contribute 1, modify with system locked
TInt iPoolSize; // number of messages in private pool
TInt iMsgCount; // total number of outstanding messages on this session
TInt iMsgLimit; // maximum number of outstanding messages on this session
SDblQue iMsgQ; // queue of all outstanding messages on this session (by iSessionLink)
RMessageK* iDisconnectMsgPtr; // preallocated disconnect message
RMessageK* volatile iConnectMsgPtr; // pointer to connect message, if any
RMessageK* volatile iNextFreeMessage; // pointer to next free message in per-session message pool, if any
};
inline TBool DSession::IsClosing()
{ return !AccessCount(); }
/********************************************
* Server control block
********************************************/
class TServerMessage : public TClientRequest
{
public:
TServerMessage();
private:
static void CallbackFunc(TAny* aData, TUserModeCallbackReason aReason);
private:
TAny* iMessagePtr; // where to deliver messages
RMessageK* iMessageData; // message to deliver
friend class DServer;
private:
~TServerMessage(); // call Close(), don't delete
};
class DServer : public DObject
{
public:
DServer();
TInt Create();
virtual ~DServer();
virtual TInt Close(TAny*);
virtual TInt RequestUserHandle(DThread* aThread, TOwnerType aType);
void Receive(TRequestStatus& aStatus, TAny* aMessage); // aMessage bit 0 = 0 -> RMessage, bit 0 = 1 -> RMessage2
void Cancel();
void Accept(RMessageK* aMsg);
void Deliver(RMessageK* aMsg);
void BTracePrime(TInt aCategory);
public:
inline TBool IsClosing();
public:
DThread* iOwningThread; // thread which receives messages
TServerMessage* iMessage;
SDblQue iSessionQ; // list of sessions
SDblQue iDeliveredQ; // list of messages delivered but not yet accepted
TUint8 iSessionType; // TIpcSessionType
TUint8 iPinClientDescriptors; // Set to 1 to make the server pin client descriptor
// arguments it receives, 0 otherwise.
TUint8 iServerRole; // TIpcServerRole: Standalone, Master, or Slave?
TUint8 iPadding;
};
inline TBool DServer::IsClosing()
{ return !AccessCount(); }
struct TCodeSegLoaderCookieList
{
TCodeSegLoaderCookieList* iNext;
TCodeSegLoaderCookie iCookie;
};
/********************************************
* Code segment
********************************************/
/** Code segment
Low-level abstraction describing an executable or DLL used by one or more
processes. Higher-level abstraction (DLibrary, DPhysicalDevice,
DLogicalDevice and DProcess) use code segments internally.
Each code segment maintains a table of all code segments it directly
depends on, thus forming a dependency graph.
Note that dependency information about ROM-based DLLs without static
data is lost during the ROM building process. Therefore These DLLs are not
included in the dependency graph.
@internalTechnology
*/
class DCodeSeg : public DBase
{
public:
/** Possible values for DCodeSeg::iMark bitmask.
All values except explicitly specified are reserved for internal
kernel use.
*/
enum TMark
{
EMarkListDeps=0x01,
EMarkUnListDeps=0x02,
EMarkLdr=0x04,
EMarkProfilerTAG=0x08, // used by profiler tool to mark processed non-XIP objects.
EMarkLoaded=0x10, // this code segment is reloadable
EMarkRecursiveFlagsValid=0x20, // the recursively computed bits are valid
EMarkRecursiveFlagsCheck=0x40, // the recursively computed bits are being checked or are valid
EMarkData=0x04000000u, // image has data and is not extension or variant (=KRomImageFlagData)
EMarkDataInit=0x02000000u, // graph below and including image requires user init (=KRomImageFlagDataInit)
EMarkDataPresent=0x01000000u, // graph below and including image has data (=KRomImageFlagDataPresent)
EMarkDebug=0x08000000u, // reserved for debug agents
};
public:
DCodeSeg();
void Destruct();
inline void Open() {++iAccessCount;}
void Close();
void CheckedClose();
void CheckedOpen();
void WaitCheckedOpen();
TInt Create(TCodeSegCreateInfo& aInfo, DProcess* aProcess);
TInt ListDeps(SDblQue* aQ, TUint32 aMark);
TInt UnListDeps(TUint32 aMark);
TInt MarkAndOpenDeps(TUint32 aMark);
void FinaliseRecursiveFlags();
void CalcRecursiveFlags();
void SetAttachProcess(DProcess* aProcess);
public:
// virtual
virtual void Info(TCodeSegCreateInfo& aInfo);
virtual TInt Loaded(TCodeSegCreateInfo& aInfo);
virtual TInt AddDependency(DCodeSeg* aExporter);
virtual void BTracePrime(TInt aCategory);
// Pure virtual
virtual TLibraryFunction Lookup(TInt aOrdinal) =0;
virtual TInt GetMemoryInfo(TModuleMemoryInfo& aInfo, DProcess* aProcess) =0;
virtual TInt DoCreate(TCodeSegCreateInfo& aInfo, DProcess* aProcess)=0;
virtual void InitData()=0;
virtual void ReadExportDir(TUint32* aDest)=0;
virtual TBool FindCheck(DProcess* aProcess)=0;
virtual TBool OpenCheck(DProcess* aProcess)=0;
public:
static void Wait();
static void Signal();
IMPORT_C static DCodeSeg* VerifyHandle(TAny* aHandle);
static DCodeSeg* VerifyHandleP(TAny* aHandle);
static DCodeSeg* VerifyCallerAndHandle(TAny* aHandle);
static DCodeSeg* FindCodeSeg(const TFindCodeSeg& aFind);
static DCodeSeg* FindRomCode(const TAny* aRomImgHdr);
IMPORT_C static void UnmarkAll(TUint32 aMask);
static void UnmarkAndCloseAll(TUint32 aMask);
static TInt ListMarked(SDblQue& aQ, TUint32 aMask);
IMPORT_C static void EmptyQueue(SDblQue& aQ, TUint32 aMask);
static void EmptyGarbageList();
static void DeferDeletes();
static void EndDeferDeletes();
static TInt WriteCallList(SDblQue& aList, TLinAddr* aEpList, TBool aInitData);
IMPORT_C static DCodeSeg* CodeSegFromEntryPoint(TInt aEntryPoint);
static void DoKernelCleanup(TAny*);
void ScheduleKernelCleanup(TBool aImmed);
static void QueueKernelCleanup();
static void DeferKernelCleanup();
static void EndDeferKernelCleanup();
void AppendFullRootName(TDes& aDes);
void AppendFullFileName(TDes& aDes);
void AppendVerExt(TDes& aDes);
void TraceAppendFullName(TDes& aDes);
TLinAddr ExceptionDescriptor();
public:
inline TBool IsDll() const
{return iUids.iUid[0].iUid==KDynamicLibraryUidValue;}
inline TBool IsExe() const
{return iUids.iUid[0].iUid==KExecutableImageUidValue;}
public:
SDblQueLink iLink; // link to global list
SDblQueLink iTempLink; // temporary link for computing lists
SDblQueLink iGbgLink; // link to garbage list
TUint32 iGbgIdleGenerationCount;
TInt iAccessCount;
TLinAddr iEntryPtVeneer; // address of first instruction to be called
TLinAddr iFileEntryPoint; // address of entry point within this code segment
HBuf* iFileName; // Full path name
TPtrC iRootName; // Filename.Ext - points into iFileName
TInt iExtOffset; // Offset of extension in iFileName
TUidType iUids;
DCodeSeg** iDeps; // code segments on which this one depends (not reference counted)
TInt iDepCount; // number of dependencies
TInt iNextDep;
TUint32 iMark;
TUint32 iAttr;
DCodeSeg* iExeCodeSeg; // EXE code segment with which this can be used
DProcess* iAttachProcess; // Process with which this can be used (NULL if several)
TUint32 iModuleVersion;
SSecurityInfo iS;
TLinAddr iRunAddress;
TUint32 iSize;
public:
static SDblQue GlobalList; // list of all existing DCodeSeg
static SDblQue GarbageList; // list of DCodeSeg whose deletion is pending due to DeferDeletes()
static SDblQue KernelGarbageList; // list of DCodeSeg containing kernel code which will be unmapped when the system goes idle
static SDblQue DeferredKernelGarbageList;
static TDfc KernelCleanupDfc;
static TInt KernelCleanupLock;
static DMutex* CodeSegLock;
static TInt DeleteLock;
static RPointerArray<DCodeSeg> CodeSegsByName; // list of code segments in name order
class RCodeSegsByAddress
{
public:
RCodeSegsByAddress(TInt aMinGrowBy, TInt aFactor);
TInt Add(DCodeSeg* aCodeSeg);
TInt Remove(DCodeSeg* aCodeseg);
DCodeSeg* Find(TLinAddr aAddress);
private:
static TInt Compare(const DCodeSeg& aA, const DCodeSeg& aB);
private:
TInt iActive;
RPointerArray<DCodeSeg> iArray[2];
};
static RCodeSegsByAddress CodeSegsByAddress; // list of code segments in run address order
static TClientRequest* DestructNotifyRequest; // Used to complete NotifyIfCodeSegDestroyed
static DThread* DestructNotifyThread; // Used to complete NotifyIfCodeSegDestroyed
static TCodeSegLoaderCookieList* DestructNotifyList; //Used to hold the list of cookie for destroyed codsegs.
};
/********************************************
* Library control block
********************************************/
class DLibrary : public DObject
{
public:
enum TState
{
ECreated=0, // initial state
ELoaded=1, // code segment loaded
EAttaching=2, // calling constructors
EAttached=3, // all constructors done
EDetachPending=4, // about to call destructors
EDetaching=5, // calling destructors
};
public:
static TInt New(DLibrary*& aLib, DProcess* aProcess, DCodeSeg* aSeg);
DLibrary();
void RemoveFromProcess();
void ReallyRemoveFromProcess();
virtual ~DLibrary();
virtual TInt Close(TAny* aPtr);
virtual TInt AddToProcess(DProcess* aProcess);
virtual void DoAppendName(TDes& aName);
public:
TInt iMapCount;
TUint8 iState;
SDblQueLink iThreadLink; // attaches to opening or closing thread
DCodeSeg* iCodeSeg;
SDblQueLink iGbgLink;
};
/********************************************
* Change notifier control block
********************************************/
class DChangeNotifier : public DObject
{
public:
DChangeNotifier();
~DChangeNotifier();
TInt Create();
void Notify(TUint aChanges);
TInt Logon(TRequestStatus& aStatus, DThread* aThread);
TInt LogonCancel(DThread* aThread);
void Complete(TInt aResult);
public:
TUint iChanges;
TClientRequest* iRequest;
DThread* iThread;
public:
friend class Monitor;
};
/********************************************
* Undertaker control block
********************************************/
class DUndertaker : public DObject
{
public:
TInt Create();
~DUndertaker();
void Notify(DThread* aDeadThread);
TInt Logon(TRequestStatus *aStatus, TInt* aDeadThreadHandle);
TInt LogonCancel();
void Complete(TInt aValue, DThread* aDeadThread);
public:
TClientDataRequest<TInt>* iRequest;
DThread* iOwningThread;
public:
friend class Monitor;
};
/********************************************
* Shared Io Buffers
********************************************/
/**
@publishedPartner
@released
A kernel object for sharing memory between kernel code and user space code.
It is used to avoid an extra copy when handling large amounts of data between
kernel and user space code. Used in device drivers that will handle instances
of this class and pass pointers to the buffer to user space clients.
Each buffer can be mapped into a single process.
The lifetime of this object is maintained by the device driver.
These objects are intended for use where speed is essential, such as for
streaming media data.
*/
class DSharedIoBuffer : public DBase
{
public:
/**
@internalComponent
*/
enum TPanic
{
EAlreadyCreated=1,
EAlreadyMapped
};
IMPORT_C ~DSharedIoBuffer();
IMPORT_C static TInt New(DSharedIoBuffer*& aBuffer, TUint32 aSize, TUint aAttribs);
#if defined(__EPOC32__)
IMPORT_C static TInt New(DSharedIoBuffer*& aBuffer, TPhysAddr aPhysAddr, TUint32 aSize, TUint aAttribs);
#endif
IMPORT_C TInt UserMap(DProcess* aUserProcess);
IMPORT_C TInt UserUnmap();
IMPORT_C TLinAddr UserToKernel(TLinAddr aUserAddress, TUint32 aSize);
IMPORT_C TLinAddr KernelToUser(TLinAddr aKernelAddress);
public:
/**
The address of the shared buffer that code running on the kernel side uses
to access the buffer.
@see DSharedIoBuffer::UserToKernel()
@see DSharedIoBuffer::KernelToUser()
*/
TLinAddr iAddress;
/**
The size of the shared buffer.
After mapping the buffer into the user-side address space via a call
to DSharedIoBuffer::UserMap(), this value must be returned to
the user-side via normal logical channel operations so that user
code can start using the buffer.
@see DSharedIoBuffer::UserMap()
*/
TUint32 iSize;
/**
The address of the shared buffer that code running in the user process
will use to access that buffer.
After mapping the buffer into the user-side address space via a call
to DSharedIoBuffer::UserMap(), this value must be returned to
the user-side via normal logical channel operations so that user
code can start using the buffer.
@see DSharedIoBuffer::UserMap()
@see DSharedIoBuffer::UserToKernel()
@see DSharedIoBuffer::KernelToUser()
*/
TLinAddr iUserAddress;
/**
@internalComponent
*/
DProcess* iUserProcess;
private:
/**
@internalComponent
*/
DChunk* iChunk;
private:
TInt DoCreate(TUint32 aSize, TUint aAttribs); /**< @internalComponent */
TInt DoCreate(TUint32 aPhysAddr, TUint32 aSize, TUint aAttribs); /**< @internalComponent */
private:
DSharedIoBuffer(); /**< @internalComponent */
};
/********************************************
* System tick-based timer queues
********************************************/
/********************************************
* Timers based on the system tick
* Platform layer code
********************************************/
class TTickQ : public SDeltaQue
{
public:
TTickQ();
void Tick();
static TInt Init();
static void Wait();
static void Signal();
public:
// In platform layer
void Add(TTickLink* aLink, TInt aPeriod);
void StartTimer();
void Update();
void Synchronise(); // update everything as if a tick has just occurred
void Check();
public:
TInt iLastDelta; // delta ticks at next ms timer expiry
TUint32 iLastTicks; // tick count at last expiry
Int64 iRtc; // tick count acting as RTC (ticks from 00:00:00 01-01-0000 UTC)
TInt iTickPeriod; // tick period in microseconds
TInt iTicksPerSecond; // ticks per second, rounded up
TInt iNominalTickPeriod; // nominal tick period in microseconds
TBool iInTick;
static DMutex* Mutex;
public:
TInt iRounding; // rounding applied to current ms timer in us
TInt iPrevRounding; // rounding applied to last ms timer in us
TUint32 iLastMs; // ms count at last expiry
TInt iMsTickPeriod; // in microseconds
TDfc iTickDfc;
NTimer iMsTimer;
};
class TSecondQ : public SDblQue
{
public:
TSecondQ();
void Tick();
void WakeUp();
static void TickCallBack(TAny* aPtr);
static void WakeUpDfc(TAny* aPtr);
public:
void Add(TSecondLink* aLink);
void StartTimer();
TInt FirstDelta();
TTimeK WakeupTime();
public:
TBool iInTick;
Int64 iNextTrigger; // next trigger time in ticks from 00:00:00 01-01-0000 UTC
Int64 iMidnight; // next midnight (home time) in ticks from 00:00:00 01-01-0000 UTC
TInt iTicksPerDay;
TTickLink iTimer;
TDfc iWakeUpDfc;
};
class TInactivityQ : public SDblQue
{
public:
TInactivityQ();
void Reset();
TInt InactiveTime();
public:
void Expired(TBool aTicksUpdated);
void EventDfc();
static void TimerCallBack(TAny* aPtr);
static void EventDfcFn(TAny* aPtr);
public:
SDblQue iPending;
TUint32 iLastEventTime;
TBool iInTick;
TTickLink iTimer;
TDfc iEventDfc;
};
/********************************************
* Kernel heap
********************************************/
class RHeapK : public RHeap
{
public:
static RHeapK* FixedHeap(TAny* aBase, TInt aMaxLength);
TInt CreateMutex();
void Mutate(TInt aOffset, TInt aMaxLength);
public:
RHeapK(TInt aInitialSize);
virtual TInt Compress();
virtual void Reset();
virtual TInt AllocSize(TInt& aTotalAllocSize) const;
virtual TInt Available(TInt& aBiggestBlock) const;
public:
inline TInt TotalAllocSize() const
{ return iTotalAllocSize; }
static void CheckThreadState();
static void Fault(TInt aFault);
inline TBool CheckForSimulatedAllocFail()
{ return RHeap::CheckForSimulatedAllocFail(); }
inline DMutex* Mutex() const; /**< @internalComponent */
public:
friend class Monitor;
};
inline void RHeap::Lock() const
{
DMutex* m = *(DMutex**)&iLock;
if (m)
Kern::MutexWait(*m);
}
inline void RHeap::Unlock() const
{
DMutex* m = *(DMutex**)&iLock;
if (m)
Kern::MutexSignal(*m);
}
/**
@internalComponent
*/
inline DMutex* RHeapK::Mutex() const
{ return *(DMutex**)&iLock; }
inline TInt RHeap::SetBrk(TInt aBrk)
{
return ((DChunk*)iChunkHandle)->Adjust(aBrk);
}
enum TSecureClockStatusFlags
{
ESecureClockPresent = 1, // signals a trusted time source has been found
ESecureClockOffsetPresent = 2, // signals nonsecure offset was read from HAL
ESecureClockOk = ESecureClockPresent | ESecureClockOffsetPresent
};
/**
An unparsed descriptor header.
@see TDesHeader.
@prototype
@internalTechnology
*/
class TRawDesHeader
{
public:
const TUint32& operator[](TInt aIndex) const { return iData[aIndex]; }
TUint32& operator[](TInt aIndex) { return iData[aIndex]; }
private:
TUint32 iData[3];
};
/********************************************
* Functions defined in kernel layer 1
********************************************/
extern "C" {
extern TLinAddr SuperPageAddress;
}
class DObjectCon;
struct SExtInit1EntryPoint;
class K
{
public:
enum TFault
{
EBadPriListPriority=0,
EKillWhileCSLocked=1,
ESvrStraySignal=2,
ESvrBadMessage=3,
ESystemThreadPanic=4,
EThreadDiedInCS=5,
ECodeDependenciesInconsistent=6,
EUnTrapWithoutTrap=7,
EThrdEventHookDied=8,
ECreateEventQueueFailed=9,
EInvalidDfcPriority=10,
EMessageBadWriteAddress=11,
EMessageAlreadyPending=12,
EKernelMsgNotFree=13,
EKernelMsgNotAccepted=14,
EPanicWhileKernelLocked=15,
EPoweredChannelNoDfcQ=16,
EKernelHeapCorrupted=17,
EBadObjectType=18,
ESessionDestruct=19,
EMessageNotFree=20,
ESessionCreateBadServerTAC=21,
ESessionDestructMsgCount=22,
EServerDestructMsgCount=23,
EServerDestructSessionsRemain=24,
EServerDestructMessagesRemain=25,
EServerCloseLeftoverMsg=26,
EInvalidSessionAccessCount=27,
EMsgFreeBadPool=28,
ESessionDestructMsgQ=29,
EKHeapBadCellAddress=30,
EKHeapBadAllocatedCellSize=31,
EKHeapBadAllocatedCellAddress=32,
EKHeapBadFreeCellAddress=33,
EKHeapFreeBadNextCell=34,
EKHeapFreeBadPrevCell=35,
EKHeapReAllocBadNextCell=36,
EKHeapAllocSizeNegative=37,
EKHeapReAllocSizeNegative=38,
EKHeapDebugUnmatchedCallToCheckHeap=39,
EKHeapAllocCheckFailed=40,
ETickQNotLocked=41,
ELogicalChannelMsgUncompleted=42,
ESessionDestructStillRef=43,
ETHeapMaxLengthNegative=44,
ETHeapMutateNotSame=45,
EKernLeaveNoTrap=46,
EProcResumeNotLoaded=47,
EMachineConfigMutexCreateFailed=48,
ERamDriveChunkCreateFailed=49,
EInitMicrokernelFailed=50,
EInit3Failed=51,
EStartExtensionsFailed=52,
ETBmaFreeNotAllocated=53,
ETBmaBlockAllocNotFree=54,
ETBmaBlockFreeNotAllocated=55,
ETBmaAllocConsecBadLength=56,
ERamDriveInitFailed=57,
EKernelHeapOperationWithKernelLocked=58,
EKernelHeapOperationNotCritical=59,
EWaitMsTimerNotIdle=60,
EThreadDieWhileExit=61,
EThreadSvKillNotDead=62,
EDeadThreadRunning=63,
EBadTimerType=64,
ESynchroniseMsDeltaTooBig=65,
EBadThreadPriority=66,
EMutexSignalWrongThread=67,
EMutexSignalBadState=68,
EMutexWaitBadState=69,
EMutexWaitBadWaitObj=70,
ESemSignalBadState=71,
ESemWaitBadState=72,
ESemWaitBadWaitObj=73,
EInvalidKernHeapCPtr=74,
ELibDestructBadMapCount=75,
ECodeStillMapped=76,
EProcessDataAddressInvalid=77,
ECodeSegBadExeCodeSeg=78,
ECodeSegAttachProcess=79,
EPermanentThreadExit=80,
EJitCrashHandlerCreation=81,
EMsqQueueLengthInvalid=82,
EProcessFromIdNoLock=83,
EThreadFromIdNoLock=84,
EMutexWaitNotInCs=85,
EMutexSignalNotInCs=86,
EDebugEventHandlerBadCallBack=87,
EMutexOrderingViolation=88,
ECondVarWaitBadState1=89,
ECondVarWaitBadState2=90,
ECondVarWaitBadState3=91,
ECondVarUnBlockBadState=92,
ESharedIoBufferBadInternalState=93,
ENonUserThreadKilled=94,
EOutOfIds=95,
EBadLogSize=96,
EAlreadyCalled=97,
EMutexWaitNotDThread=98,
EBadKernelHookType=99,
EKernelHookAlreadySet=100,
EMsgCompleteDiscNotSent=101,
ESystemProcessPanic=102,
EPermanentProcessExit=103,
ECodeSegBadFixupAddress=104,
ECodeSegBadFixupTables=105,
EAPInitialThreadCreateFailed=106,
EInit2APTimeout=107,
EChunkCommitBadType = 108,
EBadSetRamZoneConfig = 109, /**< SetRamZoneConfig can only be invoked during boot*/
ETooManyExtensions = 110,
EExtensionArrayAllocationFailed = 111,
EInsertExtensionFailed = 112,
EExtensionArrayOverflowed = 113,
EThreadWaitListDestroy = 114,
EThreadWaitListCheck = 115,
EThreadWaitListUp = 116,
EThreadWaitListChangePriority = 117,
EThreadWaitListRemove = 118,
EThreadWaitListRemove2 = 119,
EClientRequestDeletedNotClosed=120,
EClientRequestSetStatusInWrongState=121,
EClientRequestCompleteInWrongState=122,
EClientRequestResetInWrongState=123,
EClientRequestCallbackInWrongState=124,
EClientRequestCloseInWrongState=126,
EMessageInUse=127,
EVirtualPinObjectBad=128,
EIpcClientNotNull=129,
EBufferRequestAddInWrongState=130,
EBufferRequestEndSetupInWrongState=131,
EBufferRequestResetInWrongState=132,
EThreadBufReadWithNullPointer=133,
EThreadBufWriteWithNullPointer=134,
ECodeSegRemoveAbsent=135,
EPhysicalPinObjectBad=136,
EShBufVirtualNotDefined=137, //< A required virtual method is not present in a shared buffer derived class (internal error)
ESecureRNGInitializationFailed = 138,
ESecureRNGInternalStateNotSecure = 139,
ESecureRNGOutputsInBadState = 140,
ESystemException=0x10000000,
ESoftwareWarmReset=0x10000001
};
static void Fault(TFault aFault);
public:
static TMachineConfig* MachineConfig;
static RAllocator* Allocator;
static struct SHeapInfo
{
DChunk* iChunk;
TUint8* iBase;
TUint iMaxSize;
} HeapInfo;
static struct SMsgInfo
{
DChunk* iChunk;
TUint8* iBase;
TUint iMaxSize;
TUint iCurrSize;
DMutex* iMsgChunkLock;
RMessageK* iNextMessage;
TInt iFreeMessageCount;
} MsgInfo;
static DThread* TheKernelThread;
static DProcess* TheKernelProcess;
static DThread* TheNullThread;
static DThread* SvThread;
static TDfcQue* SvMsgQ;
static TMessageQue SvBarrierQ;
static NFastMutex EventQueueMutex;
static TRawEvent *EventHeadPtr;
static TRawEvent *EventTailPtr;
static TRawEvent *EventBufferStart;
static TRawEvent *EventBufferEnd;
static TClientDataRequest<TRawEvent>* EventRequest;
static DThread *EventThread;
static TDfcQue* DfcQ0;
static TDfcQue* DfcQ1;
static TDfcQue* TimerDfcQ;
static TTickQ* TickQ;
static TSecondQ* SecondQ;
static TInactivityQ* InactivityQ;
static TInt HomeTimeOffsetSeconds;
static TInt NonSecureOffsetSeconds;
static TInt SecureClockStatus;
static TInt64 Year2000InSeconds;
static DPowerModel* PowerModel;
static TBool PowerGood;
static TInt MaxMemCopyInOneGo;
static TInt MaxFreeRam;
public:
static DObjectCon* Containers[ENumObjectTypes];
public:
static TInt NextId;
static TInt DfcQId;
static volatile TUint DynamicDfcQId;
static SHalEntry2* HalEntryArray;
static DMutex* MachineConfigMutex;
static TAny* volatile AsyncFreeHead;
static DBase* volatile AsyncDeleteHead;
static TDfc AsyncFreeDfc;
static TInt MemoryLowThreshold;
static TInt MemoryGoodThreshold;
static TUint AsyncChanges;
static TDfc AsyncChangeNotifierDfc;
public:
static TBool Initialising;
static TBool ColdStart;
static TInt ExtensionCount;
static RArray<SExtInit1EntryPoint>* ExtensionArray;
static DProcess* TheFileServerProcess;
static DProcess* TheWindowServerProcess;
static TInt PINestLevel;
static TInt SupervisorThreadStackSize;
static TUint32 MemModelAttributes;
static TKernelHookFn KernelHooks[ENumKernelHooks];
static TMiscNotifierMgr TheMiscNotifierMgr;
static TAny* VariantData[31];
static TUint32 EntropyBufferStatus[KMaxCpus];
static TUint32* EntropyBuffer[KMaxCpus];
static TUint32 TempEntropyBuffer[KEntropyBufferSizeWords];
static TDfc EntropyBufferDfc;
public:
static TInt InitialiseMicrokernel();
#ifdef __SMP__
static void InitAP(TInt aCpu, volatile SAPBootInfo* aInfo, TInt aTimeout);
#endif
static TInt Init3();
static void InitNvRam();
static void InitLocaleData();
static void SetDefaultLocaleData1();
static void SetDefaultLocaleData2();
static void InitHalEntryArray();
static TInt CreateObjectContainers();
static DObjectCon* ContainerFromFindHandle(const TFindHandle& aFindHandle);
static void LockContainer(TInt aObjType);
static void UnlockContainer(TInt aObjType);
static TInt AddObject(DObject* aObj, TInt aObjType);
static TInt StartTickQueue();
static void PanicKernExec(TInt aReason);
static void PanicCurrentThread(TInt aReason);
static void UnmarkAllLibraries();
static void CreateEventQueue(TInt aSize);
static void TryDeliverEvent();
static DObject* ObjectFromHandle(TInt aHandle);
static DObject* ObjectFromHandle(TInt aHandle, TInt aObjType);
static DObject* ObjectFromHandle(TInt aHandle, TInt aObjType, TUint& aAttr);
static TInt OpenObjectFromHandle(TInt aHandle, DObject*& aObject);
static TInt MakeHandle(TOwnerType aType, DObject* aObject);
static TInt MakeHandle(TOwnerType aType, DObject* aObject, TUint aAttr);
static TInt MakeHandleAndOpen(TOwnerType aType, DObject* aObject, TInt& aHandle);
static TInt MakeHandleAndOpen(TOwnerType aType, DObject* aObject, TInt& aHandle, TUint aAttr);
static TInt HandleClose(TInt aHandle);
static void ObjDelete(DObject* aObj);
static TInt SecondsFrom2000(const TTimeK& aTime, TInt& aSeconds);
static TInt SetSystemTime(TInt aSecondsFrom2000, TInt aUTCOffset, TUint& aChanges, TUint aMode);
static TInt SetSystemTimeAndOffset(const TTimeK& aTime, TInt aOffset, TUint aTimeSetMode, TUint& aChanges, TUint aMode);
static void StartKernelServer();
static TInt MutexCreate(DMutex*& aMutex, const TDesC& aName, DObject* aOwner, TBool aVisible, TUint aOrder);
static void Randomize();
static void DoAsyncFree(TAny*);
static void DoAsyncNotify(TAny*);
static TUint CheckFreeMemoryLevel(TInt aInitial, TInt aFinal, TBool aFailed);
static TBool CheckForSimulatedAllocFail();
static void DoSvBarrier(TAny*);
//
static void CheckKernelUnlocked();
static TInt KernelHal(TInt aFunction, TAny* a1, TAny* a2);
static void SetMachineConfiguration(const TDesC8& aConfig);
static DThread* ThreadEnterCS();
static DThread* ThreadLeaveCS();
static DObject* ThreadEnterCS(TInt aHandle, TInt aObjType);
static void CheckFileServerAccess();
#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
inline static void ProcessIsolationFailure(const char* aContextText);
#else //__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
// Only available to NULL arguments
inline static void ProcessIsolationFailure(OnlyCreateWithNull aContextText);
#endif // !__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
static void LockedPlatformSecurityPanic();
static void UnlockedPlatformSecurityPanic();
static TBool IsInKernelHeap(const TAny* aPtr, TInt aSize);
static TUint32 CompressKHeapPtr(const TAny* aPtr);
static const TAny* RestoreKHeapPtr(TUint32 aCPtr);
static TBool CheckUids(const TUidType& aUids, const TUidType& aRequestedUids);
static TUint NewId();
inline static TTraceHandler TraceHandler();
inline static TNanoWaitHandler NanoWaitHandler();
static TInt FloatingPointTypes(TUint32& aTypes);
static TInt FloatingPointSystemId(TUint32& aSysId);
inline static TInitialTimeHandler InitialTimeHandler();
static void TextTrace(const TDesC8& aText, TTraceSource aTraceSource, TBool aNewLine=ETrue);
static TUint TextTraceMode;
static void CheckThreadNotRealtime(const char* aTraceMessage=NULL);
static TBool IllegalFunctionForRealtimeThread(DThread* aThread,const char* aTraceMessage=NULL);
static TAny* USafeRead(const TAny* aSrc, TAny* aDest, TInt aSize);
static TAny* USafeWrite(TAny* aDest, const TAny* aSrc, TInt aSize);
static TInt ParseDesHeader(const TAny* aDesPtr, const TRawDesHeader& aIn, TDesHeader& aOut);
static TInt USafeReadAndParseDesHeader(TAny* aDesPtr, TDesHeader& aOut);
static TUint32 KernelConfigFlags();
static void DoFault(const TAny* a0, TInt a1);
static TInt ShPoolCreate(DShPool*& aPool, TShPoolCreateInfo& aInfo);
private:
#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
static void DoProcessIsolationFailure(const char* aContextText);
#endif // !__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
static void DoProcessIsolationFailure();
static void DoNanoWait(TUint32 aInterval);
};
#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
inline void K::ProcessIsolationFailure(const char* aContextText)
{
DoProcessIsolationFailure(aContextText);
}
#else //__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
// Only available to NULL arguments
inline void K::ProcessIsolationFailure(OnlyCreateWithNull /*aContextText*/)
{
DoProcessIsolationFailure();
}
#endif // !__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
inline TTraceHandler K::TraceHandler()
{
return (TTraceHandler)KernelHooks[EHookTrace];
}
inline TNanoWaitHandler K::NanoWaitHandler()
{
return (TNanoWaitHandler)KernelHooks[EHookNanoWait];
}
inline TInitialTimeHandler K::InitialTimeHandler()
{
return (TInitialTimeHandler)KernelHooks[EHookInitialTime];
}
#ifdef __DEBUGGER_SUPPORT__
#define __DEBUG_EVENT(aEvent, a1) DKernelEventHandler::Dispatch((aEvent),(a1),NULL)
#define __DEBUG_EVENT2(aEvent, a1, a2) DKernelEventHandler::Dispatch((aEvent),(a1),(a2))
#define __COND_DEBUG_EVENT(aCond, aEvent, a1) {if (aCond) DKernelEventHandler::Dispatch((aEvent),(a1),NULL);}
#ifdef __EPOC32__
//Setting breakpoints is only available on target and if kernel is built with __DEBUGGER_SUPPORT__ option
#define __REMOVE_CODESEG_FROM_CODEMODIFIER(segment, process) CodeModifier::CodeSegRemoved((segment),(process))
#else
#define __REMOVE_CODESEG_FROM_CODEMODIFIER(segment, process)
#endif
#else
#define __DEBUG_EVENT(aEvent, a1)
#define __DEBUG_EVENT2(aEvent, a1, a2)
#define __COND_DEBUG_EVENT(aCond, aEvent, a1)
#define __REMOVE_CODESEG_FROM_CODEMODIFIER(segment, process)
#endif
/********************************************
* Functions defined in layer 1M or below of
* the kernel and available to layer 1.
********************************************/
class P
{
public:
static TInt InitSystemTime();
static TInt DefaultInitialTime();
static void CreateVariant();
static void StartExtensions();
static void KernelInfo(TProcessCreateInfo& aInfo, TAny*& aStack, TAny*& aHeap);
static void NormalizeExecutableFileName(TDes& aFileName);
static void SetSuperPageSignature();
static TBool CheckSuperPageSignature();
//
static DProcess* NewProcess();
};
struct SCacheInfo;
/*
Symbian OS currently supports 5 memory models one for the WIN32 platform (the emulator model)
and three for the EPOC platform (moving, multiple, direct and flexible).
Model layer is the third layer in EKA2 software layer which consist of 6 layers,
There are two static interfaces to the memory model, the first to be in Class Epoc and the second in Class M.
Class M consists of functions provided by the memory model to the independent layer which is
the first layer in EKA2 software layer, M denotes the API exposed by the model layer
*/
struct SCacheInfo;
struct SPageInfo;
struct SZone;
class M
{
public:
static void Init1();
static void Init2();
#ifdef __SMP__
static void GetAPBootInfo(TInt aCpu, volatile SAPBootInfo* aInfo);
static void Init2AP();
#endif
static void Init3();
static void Init4();
static TInt InitSvHeapChunk(DChunk* aChunk, TInt aSize);
static TInt InitSvStackChunk();
static TBool IsRomAddress(const TAny* aPtr);
static TInt PageSizeInBytes();
static TInt PageShift();
static void SetupCacheFlushPtr(TInt aCache, SCacheInfo& c);
static void FsRegisterThread();
static DCodeSeg* NewCodeSeg(TCodeSegCreateInfo& aInfo);
static void DemandPagingInit();
static TInt DemandPagingFault(TAny* aExceptionInfo);
static TBool CheckPagingSafe(TBool aDataPaging, TLinAddr aStartAddr=0, TUint aLength=KMaxTUint);
static TInt LockRegion(TLinAddr aStart,TInt aSize);
static TInt UnlockRegion(TLinAddr aStart,TInt aSize);
static void BTracePrime(TUint aCategory);
static void LockUserMemory();
static void UnlockUserMemory();
static TInt CreateVirtualPinObject(TVirtualPinObject*& aPinObject);
static TInt PinVirtualMemory(TVirtualPinObject* aPinObject, TLinAddr aStart, TUint aSize, DThread* DThread);
static TInt CreateAndPinVirtualMemory(TVirtualPinObject*& aPinObject, TLinAddr aStart, TUint aSize);
static void UnpinVirtualMemory(TVirtualPinObject* aPinObject);
static void DestroyVirtualPinObject(TVirtualPinObject*& aPinObject);
static TInt CreatePhysicalPinObject(TPhysicalPinObject*& aPinObject);
static TInt PinPhysicalMemory(TPhysicalPinObject* aPinObject, TLinAddr aStart, TUint aSize, TBool aReadOnly, TPhysAddr& aAddress, TPhysAddr* aPages, TUint32& aMapAttr, TUint& aColour, DThread* aThread);
static void UnpinPhysicalMemory(TPhysicalPinObject* aPinObject);
static void DestroyPhysicalPinObject(TPhysicalPinObject*& aPinObject);
static TInt CreateKernelMapObject(TKernelMapObject*& aMapObject, TUint aMaxReserveSize);
static TInt MapAndPinMemory(TKernelMapObject* aMapObject, DThread* aThread, TLinAddr aStart, TUint aSize, TUint aMapAttributes, TLinAddr& aKernelAddr, TPhysAddr* aPages);
static void UnmapAndUnpinMemory(TKernelMapObject* aMapObject);
static void DestroyKernelMapObject(TKernelMapObject*& aMapObject);
// RAM allocator and defrag interfaces.
static void RamAllocLock();
static void RamAllocUnlock();
static void RamAllocIsLocked();
static TUint NumberOfFreeDpPages();
static TUint NumberOfDirtyDpPages();
static TInt MovePage(TPhysAddr aOld, TPhysAddr& aNew, TUint aBlockZoneId, TBool aBlockRest);
static TInt DiscardPage(TPhysAddr aAddr, TUint aBlockZoneId, TBool aBlockRest);
static void RamZoneClaimed(SZone* aZone);
static TInt RamDefragFault(TAny* aExceptionInfo);
};
#ifdef __USER_MEMORY_GUARDS_ENABLED__
#define LOCK_USER_MEMORY() M::LockUserMemory()
#define UNLOCK_USER_MEMORY() M::UnlockUserMemory()
#define COND_LOCK_USER_MEMORY(c) ((void)((c)&&(M::LockUserMemory(),0)))
#define COND_UNLOCK_USER_MEMORY(c) ((void)((c)&&(M::UnlockUserMemory(),0)))
#else
#define LOCK_USER_MEMORY()
#define UNLOCK_USER_MEMORY()
#define COND_LOCK_USER_MEMORY(c)
#define COND_UNLOCK_USER_MEMORY(c)
#endif
/********************************************
* Functions defined in layer 3 or below and
* available to layer 2
********************************************/
class DPlatChunkHw;
class A
{
public:
static void Init1();
static void Init2();
#ifdef __SMP__
static void InitAPs();
static void Init2AP();
#endif
static void Init3();
static void DebugPrint(const TText* aPtr, TInt aLen, TBool aNewLine=ETrue);
static TInt CreateVariant(const TAny* aFile, TInt aMode);
static DPlatChunkHw* NewHwChunk();
static TPtr8 MachineConfiguration();
static void StartCrashDebugger(const TAny* a0, TInt a1);
static TInt CallSupervisorFunction(TSupervisorFunction aFunction, TAny* aParameter);
static TInt VariantHal(TInt aFunction, TAny* a1, TAny* a2);
static TInt SystemTimeInSecondsFrom2000(TInt& aTime);
static TInt SetSystemTimeInSecondsFrom2000(TInt aTime);
};
class Exc
{
public:
static void Dispatch(TAny* aPtr, NThread*);
IMPORT_C static void Fault(TAny* aPtr);
static TBool IsMagic(TLinAddr aAddress);
#ifdef __ATOMIC64_USE_SLOW_EXEC__
static TBool IsMagicAtomic64(TLinAddr aAddress);
#endif //__ATOMIC64_USE_SLOW_EXEC__
};
/********************************************
* Super page definition
********************************************/
class DDebuggerInfo;
class TSuperPage : public SSuperPageBase
{
public:
TInt iDebugMask[KNumTraceMaskWords]; // kernel trace mask
TInt iKernelExcId;
TExcInfo iKernelExcInfo;
TUint32 iSignature[2];
TMachineStartupType iStartupReason;
DDebuggerInfo* iDebuggerInfo;
TUint32 iDisabledCapabilities[(((TInt)ECapability_HardLimit + 7)>>3) / sizeof(TUint32)];
TUint32 iInitialBTraceFilter[8];
TInt iInitialBTraceBuffer;
TInt iInitialBTraceMode;
private:
TUint32 iKernelConfigFlags;
public:
/*
* Unless __PLATSEC_UNLOCKED__ is defined, __PLATSEC_FORCED_FLAGS__ is set to a
* bitmask of platsec flags which must always be considered to be set, even if
* they are not really set in iKernelConfigFlags. Therefore, use this function
* to access iKernelConfigFlags.
*
* __PLATSEC_UNLOCKED__, if set, is set by the base port.
*
* __PLATSEC_FORCED_FLAGS__ is defined in u32std.h near the TKernelConfigFlags enumeration.
*/
inline TUint32 KernelConfigFlags()
{
#ifdef __PLATSEC_UNLOCKED__
return (iKernelConfigFlags | __PLATSEC_FORCED_FLAGS__) & ~EKernelConfigPlatSecLocked;
#else
return (iKernelConfigFlags | __PLATSEC_FORCED_FLAGS__ | EKernelConfigPlatSecLocked);
#endif
}
inline void SetKernelConfigFlags(TUint32 aKernelConfigFlags)
{
iKernelConfigFlags = aKernelConfigFlags;
}
};
inline TSuperPage& TheSuperPage() {return *(TSuperPage*)SuperPageAddress;}
inline TMachineConfig& TheMachineConfig() {return *(TMachineConfig*)K::MachineConfig; }
#define TEST_DEBUG_MASK_BIT(n) ( TheSuperPage().iDebugMask[(n)>>5] & (1<<((n)&31)) )
/********************************************
* Miscellaneous stuff
********************************************/
inline void TExcTrap::UnTrap()
{iThread->iExcTrap=NULL;}
inline void TIpcExcTrap::UnTrap()
{iThread->iExcTrap=NULL;iThread->iIpcClient=NULL;}
inline void TPagingExcTrap::UnTrap()
{iThread->iPagingExcTrap=NULL;}
GLREF_D const TUint32 EpocFastExecTable[];
GLREF_D const TUint32 EpocSlowExecTable[];
inline SMiscNotifierQ* DObject::NotifierQ() const
{
TUint32 cptr = ((TUint32(iObjectId)<<14)>>6) | iNotQLow;
return cptr ? (SMiscNotifierQ*)K::RestoreKHeapPtr(cptr) : (SMiscNotifierQ*)0;
}
inline void DObject::SetNotifierQ(SMiscNotifierQ* aQ)
{
TUint32 cptr = aQ ? K::CompressKHeapPtr(aQ) : 0;
iNotQLow = (TUint8)cptr;
volatile TUint32& x = (volatile TUint32&)iObjectId;
x = ((x>>18)<<18) | (cptr>>8);
}
inline TBool DObject::HasNotifierQ() const
{
return (TUint32(iObjectId)<<14) | iNotQLow;
}
#ifdef _DEBUG
/**
@publishedPartner
@released
*/
#define __ASSERT_CRITICAL { \
DThread& t=Kern::CurrentThread(); \
__NK_ASSERT_DEBUG(t.iThreadType!=EThreadUser || t.iNThread.iCsCount>0); \
}
/**
@publishedPartner
@released
*/
#define __ASSERT_MUTEX(m) { \
DThread& t=Kern::CurrentThread(); \
__NK_ASSERT_DEBUG((m)->iCleanup.iThread==&t); \
}
#else
/**
@publishedPartner
@released
*/
#define __ASSERT_CRITICAL
/**
@publishedPartner
@released
*/
#define __ASSERT_MUTEX(m)
#endif
#define LOGICAL_XOR(a,b) (((a)==0)^((b)==0))
#if defined(__GCC32__)
#define __RETURN_ADDRESS() __builtin_return_address(0)
#elif defined (__ARMCC__)
#define __RETURN_ADDRESS() ((TAny*)__return_address())
#else
#define __RETURN_ADDRESS() 0 // not supported
#endif
#ifdef _DEBUG
#if defined(__STANDALONE_NANOKERNEL__) || (!defined (__KERNEL_APIS_CONTEXT_CHECKS_WARNING__)&&!defined (__KERNEL_APIS_CONTEXT_CHECKS_FAULT__))
#define __ASSERT_WITH_MESSAGE_MUTEX(m,message,function )
#else
/**
@internalComponent
*/
#define __ASSERT_WITH_MESSAGE_MUTEX(m,message,function ) \
{ \
DThread& t=Kern::CurrentThread(); \
__ASSERT_WITH_MESSAGE_DEBUG((NKern::Crashed() || ((m)->iCleanup.iThread==&t)),message,function); \
}
#endif//(!defined (__KERNEL_APIS_CONTEXT_CHECKS_WARNING__)&&!defined (__KERNEL_APIS_CONTEXT_CHECKS_FAULT__))
#else//if !DEBUG
#define __ASSERT_WITH_MESSAGE_MUTEX(m,message,function )
#endif//_DEBUG
// Implementation constants for TClientRequest
const T_UintPtr KClientRequestFlagClosing = 1 << 0;
const T_UintPtr KClientRequestFlagInUse = 1 << 1;
const T_UintPtr KClientRequestFlagMask = KClientRequestFlagClosing | KClientRequestFlagInUse;
const T_UintPtr KClientRequestNullStatus = 0x00000004; // must be non-zero but never a valid TRequestStatus pointer
#endif