// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32\kernel\x86\ckernel.cpp
//
//
#include <x86_mem.h>
#ifdef __SMP__
#include <apic.h>
#endif
#define iMState iWaitLink.iSpare1
#define iExiting iWaitLink.iSpare2
DX86PlatThread* TheCurrentFpuThread;
void DoFpuContextSwitch(DX86PlatThread*);
void SaveFpuContext(DX86PlatThread*);
void LoadFpuContext(DX86PlatThread*);
/********************************************
* Thread
********************************************/
DX86PlatThread::DX86PlatThread()
{
}
DX86PlatThread::~DX86PlatThread()
{
DThread::Destruct();
}
TInt DX86PlatThread::Context(TDes8& aDes)
{
#ifdef __SMP__
TX86RegSet& s=*(TX86RegSet*)aDes.Ptr();
aDes.SetLength(sizeof(s));
TInt r=KErrNone;
if (iThreadType!=EThreadUser || this==TheCurrentThread)
r=KErrAccessDenied;
else if (iExiting)
r=KErrDied;
else
{
TUint32 unused;
NKern::ThreadGetUserContext(&iNThread,&s,unused);
}
return r;
#else
return KErrNotSupported;
#endif
}
DProcess* P::NewProcess()
{
return new DX86PlatProcess;
}
TInt DX86PlatProcess::GetNewThread(DThread*& aThread, SThreadCreateInfo& anInfo)
//
// Create a new DX86PlatThread object
// If aThread=NULL on entry, allocate it on the kernel heap,
// otherwise do in-place construction.
//
{
DX86PlatThread* pT=(DX86PlatThread*)aThread;
if (pT)
new (pT) DX86PlatThread;
else
{
pT=new DX86PlatThread;
if (!pT)
return KErrNoMemory;
aThread=(DThread*)pT;
}
pT->iOwningProcess=this;
return KErrNone;
}
TExcType VectorToType(TInt aVector)
{
switch (aVector)
{
case 0:
return EExcIntegerDivideByZero;
case 3:
return EExcBreakPoint;
case 4:
return EExcIntegerOverflow;
case 5:
return EExcBoundsCheck;
case 6:
return EExcInvalidOpCode;
case 8:
return EExcDoubleFault;
case 11:
return EExcAccessViolation;
case 12:
return EExcStackFault;
case 13:
return EExcAccessViolation;
case 14:
return EExcPageFault;
case 16:
return EExcFloatDivideByZero;
case 17:
return EExcAlignment;
default:
return EExcGeneral;
}
}
GLREF_C void DumpExcInfo(TX86ExcInfo& a);
void __fastcall PushExcInfoOnUserStack(TX86ExcInfo*, TInt);
void Exc::Dispatch(TAny* aPtr, NThread*)
{
#ifdef __DEMAND_PAGING__
TInt paged = M::DemandPagingFault(aPtr);
if(paged==KErrNone)
return;
#endif
TX86ExcInfo* pR=(TX86ExcInfo*)aPtr;
TInt cpl=pR->iCs & 3;
DX86PlatThread* pT=(DX86PlatThread*)TheCurrentThread;
if (cpl==0 && pT->iMagicExcHandler && (*pT->iMagicExcHandler)(pR)==0)
{
// magic handler has handled the exception
return;
}
TExcTrap* xt=pT->iExcTrap;
if (xt)
{
// current thread wishes to handle exceptions
(*xt->iHandler)(xt,pT,aPtr);
}
if (NKern::HeldFastMutex()) // thread held fast mutex when exception occurred
Exc::Fault(aPtr);
NKern::LockSystem();
if (pT->iThreadType==EThreadUser && cpl==3)
{
TExcType type=VectorToType(pR->iExcId);
if (pT->IsExceptionHandled(type))
{
pT->iFlags |= KThreadFlagLastChance;
NKern::UnlockSystem();
// tweak context to call exception handler
__KTRACE_OPT(KSCRATCH,DumpExcInfo(*pR));
PushExcInfoOnUserStack(pR, type);
pR->iEip = (TUint32)pT->iOwningProcess->iReentryPoint;
pR->iEbx = KModuleEntryReasonException;
__KTRACE_OPT(KSCRATCH,DumpExcInfo(*pR));
return;
}
}
// Fault system before attempting to signal kernel event handler as going
// crash anyway so no point trying to handle the event. Also, stops
// D_EXC hanging system on crash of critical/permanent thread. (see INC093397)
if (pT->iFlags & (KThreadFlagSystemCritical|KThreadFlagSystemPermanent))
Exc::Fault(aPtr);
NKern::UnlockSystem();
TUint m = DKernelEventHandler::Dispatch(EEventHwExc, pR, NULL);
if (m & DKernelEventHandler::EExcHandled)
return;
// __KTRACE_OPT(KPANIC,DumpExcInfo(*pR));
DumpExcInfo(*pR);
// panic current thread
K::PanicKernExec(ECausedException);
}
EXPORT_C void Exc::Fault(TAny* aPtr)
{
TX86ExcInfo *pR=(TX86ExcInfo*)aPtr;
TExcInfo e;
e.iCodeAddress=(TAny*)pR->iEip;
e.iDataAddress=(TAny*)pR->iFaultAddress;
e.iExtraData=(TInt)pR->iExcErrorCode;
// __KTRACE_OPT(KPANIC,DumpExcInfo(*pR));
DumpExcInfo(*pR);
TheSuperPage().iKernelExcId=pR->iExcId;
TheSuperPage().iKernelExcInfo=e;
NKern::DisableAllInterrupts();
#ifdef __SMP__
SubScheduler().i_ExcInfo = aPtr;
#else
TheScheduler.i_ExcInfo = aPtr;
#endif
Kern::Fault("Exception",K::ESystemException);
}
extern "C" void ExcFault(TAny* aExcInfo)
{
Exc::Fault(aExcInfo);
}
extern "C" {
void DefaultExcTrapHandler(TExcTrap* xt, DThread*, TAny*)
{
xt->Exception(KErrBadDescriptor);
}
void IpcExcHandler(TExcTrap* xt, DThread* aThread, TAny* aContext)
{
DThread::IpcExcHandler(xt, aThread, aContext);
}
}
void DX86PlatThread::DoExit2()
{
}
#ifdef _DEBUG
extern "C" void __FaultIpcClientNotNull()
{
K::Fault(K::EIpcClientNotNull);
}
#endif