// Copyright (c) 2007-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\cmonitor.cia
// Kernel crash debugger - X86 (GCC) specific portion
// 
//

#include <kernel/monitor.h>
#include <x86_mem.h>


GLDEF_D TUint32 MonitorStack[1024];

void MonitorInit(TAny* fc, TInt fr);


__NAKED__ TInt TTrapM::Trap(TInt& /*aResult*/)
//
// Save the enter frame state and return 0.
//
	{
	THISCALL_PROLOG1()
	// ecx->TTrapM, [esp+4]=&aResult	
	asm("mov eax, [esp+4]");		// initialize aResult
	asm("mov dword ptr [eax], 0");	// to zero.
#ifdef __GCC32__					// Store &aResult in this->iResult
	asm("mov [ecx+%0], eax": : "i"_FOFF(TTrapM,iResult));
#else
	_asm mov [ecx]this.iResult, eax
#endif
	asm("pop edx");					// EDX = retaddr
	asm("mov [ecx+0], edx");		// store retaddr in iState[0]
	asm("mov [ecx+4], ebx");
	asm("mov [ecx+8], ebp");
	asm("mov [ecx+12], esp");		// store ESP as if we'd returned from this function
	asm("mov [ecx+16], esi");
	asm("mov [ecx+20], edi");
	asm("mov [ecx+24], ds");
	asm("mov [ecx+28], es");
	asm("mov [ecx+32], fs");
	asm("mov [ecx+36], gs");
	asm("push edx");
	asm("mov eax, [%a0]": :"i"(&TheMonitorPtr));
	asm("mov eax, [eax+%0]": : "i"_FOFF(Monitor,iFrame));
#ifdef __GCC32__
	asm("mov [ecx+%0], eax": : "i"_FOFF(TTrapM,iNext));
#else
	_asm mov [ecx]this.iNext, eax
#endif
	asm("mov eax, [%a0]": :"i"(&TheMonitorPtr));
	asm("mov [eax+%0], ecx" : : "i"_FOFF(Monitor,iFrame));
	asm("xor eax, eax");
	THISCALL_EPILOG1()
	}



extern "C" __NAKED__ void Monitor_Leave()
//
// Leave to the current control region.
//
	{
	// [esp+4]=aReason
	asm("mov edx, [%a0]": : "i"(&TheMonitorPtr));
#ifdef __GCC32__					// ECX = TTrapM*
	asm("mov ecx, [edx+%0]": : "i"_FOFF(Monitor,iFrame));
#else
	_asm mov ecx, [edx]Monitor.iFrame
#endif
	asm("lea edx, [ecx+%0]": : "i"_FOFF(TTrapM,iResult));
	asm("mov eax, [esp+4]");		// EAX = leave reason
	asm("mov [edx], eax");			// TTrapM->iResult = leave reason
	asm("mov edx, [ecx+0]");		// EDX = trap point
	asm("mov eax, [ecx+%0]": : "i"_FOFF(TTrapM,iNext)); // unlink the trap
	asm("mov [ecx+0], eax");
	asm("mov ebx, [ecx+4]");
	asm("mov ebp, [ecx+8]");
	asm("mov esp, [ecx+12]");
	//asm("sub esp, 4"); // GCC-specific thing
	asm("mov esi, [ecx+16]");
	asm("mov edi, [ecx+20]");
	asm("mov ds, [ecx+24]");
	asm("mov es, [ecx+28]");
	asm("mov fs, [ecx+32]");
	asm("mov gs, [ecx+36]");
	asm("push edx");
	asm("mov eax, 1");
	asm("ret");
	}

__NAKED__ void Monitor::Leave(TInt /*aReason*/)
//
// Leave to the current control region.
//
	{
	asm("jmp %a0": :"i"(Monitor_Leave));
	}

extern "C" __NAKED__ void Monitor_Entry()
//
// Monitor entry point
// Pointer to saved registers is at [esp+4]
// Fault category and fault reason are included with saved registers.
//
	{
	asm("cli");
	asm("cld");
	asm("mov edx, [esp+4]");
	asm("lea esp, %a0": : "i"(MonitorStack));
	asm("add esp, 0x1000");					// make sure we have a valid stack
	asm("mov eax, dword ptr [%a0]": : "i"(&TheMonitorPtr));
#ifndef __SMP__
	asm("mov [eax+%0], edx": : "i"_FOFF(Monitor,iRegs));
#endif
	asm("lea eax, [eax+%0]": : "i"_FOFF(Monitor,iPageSize));
	asm("mov dword ptr [eax], 0x1000");
	asm("push dword ptr [edx+%0]": : "i"_FOFF(SFullX86RegSet,iFaultReason));
	asm("push dword ptr [edx+%0]": : "i"_FOFF(SFullX86RegSet,iFaultCategory));
	asm("call %a0": :"i"(&MonitorInit));
	}

__NAKED__ void Monitor::Entry(TAny* /*aRegs*/)
//
// Monitor entry point
// Pointer to saved registers is at [esp+4]
// Fault category and fault reason are included with saved registers.
//
	{
	asm("jmp %a0": :"i"(Monitor_Entry));
	}
