kernel/eka/nkern/x86/vectors.cia
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/nkern/x86/vectors.cia	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,619 @@
+// 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\nkern\x86\vectors.cia
+// 
+//
+
+#include <x86.h>
+#include "vectors.h"
+
+#ifdef __GCC32__
+#define DECLARE_X86_INT(n)			GLDEF_C __NAKED__ void __X86Vector##n() { asm("push 0x"#n);	asm("jmp %a0": :"i"(&__X86VectorIrq)); }
+#define DECLARE_X86_EXC_NOERR(n)	GLDEF_C __NAKED__ void __X86Vector##n() { asm("push 0"); asm("push 0x"#n); asm("jmp %a0": : "i"(&__X86VectorExc)); }
+#define DECLARE_X86_EXC_ERR(n)		GLDEF_C __NAKED__ void __X86Vector##n() { asm("push 0x"#n); asm("jmp %a0": : "i"(&__X86VectorExc)); }
+#else
+#define DECLARE_X86_INT(n)			GLDEF_C __NAKED__ void __X86Vector##n() { __asm push 0x##n __asm jmp __X86VectorIrq }
+#define DECLARE_X86_EXC_NOERR(n)	GLDEF_C __NAKED__ void __X86Vector##n() { __asm push 0 __asm push 0x##n __asm jmp __X86VectorExc }
+#define DECLARE_X86_EXC_ERR(n)		GLDEF_C __NAKED__ void __X86Vector##n() { __asm push 0x##n __asm jmp __X86VectorExc }
+#endif
+
+const TLinAddr NKern_WaitForAnyRequest = (TLinAddr)&NKern::WaitForAnyRequest;
+const TLinAddr NKern_LockSystem = (TLinAddr)&NKern::LockSystem;
+const TLinAddr NKern_UnlockSystem = (TLinAddr)&NKern::UnlockSystem;
+const TLinAddr NKern_Unlock = (TLinAddr)&NKern::Unlock;
+const TLinAddr TScheduler_Reschedule = (TLinAddr)&TScheduler::Reschedule;
+
+#ifdef __CHECK_LOCK_STATE__
+/******************************************************************************
+ * Check that the kernel is unlocked, no fast mutex is held and the thread
+ * is not in a critical section when returning to user mode.
+ ******************************************************************************/
+extern "C" __NAKED__ void check_lock_state()
+	{
+	asm("push ecx ");
+	asm("mov ecx, [%a0]" : : "i" (&TheScheduler.iCurrentThread));
+	asm("cmp dword ptr [%a0], 0" : : "i" (&TheScheduler.iKernCSLocked));
+	asm("jnz short bad_lock_state1 ");
+	asm("cmp dword ptr [ecx+%0], 0" : : "i" _FOFF(NThreadBase, iHeldFastMutex));
+	asm("jne short bad_lock_state2 ");
+	asm("cmp dword ptr [ecx+%0], 0" : : "i" _FOFF(NThreadBase, iCsCount));
+	asm("jne short bad_lock_state3 ");
+	asm("pop ecx ");
+	asm("ret ");
+	asm("bad_lock_state1: ");
+	asm("int 0xff ");
+	asm("bad_lock_state2: ");
+	asm("int 0xff ");
+	asm("bad_lock_state3: ");
+	asm("int 0xff ");
+	}
+#endif
+
+/******************************************************************************
+* Int 20h Handler - Fast Executive Calls
+* Enter with:
+*		Call number in EAX
+*		Parameter in ECX if any
+* On entry SS:ESP references current threads supervisor stack
+* [ESP+0] = return EIP
+* [ESP+4] = return CS
+* [ESP+8] = return EFLAGS
+* [ESP+12] = return ESP if privilege change occurred
+* [ESP+16] = return SS if privilege change occurred
+*******************************************************************************/
+GLDEF_C __NAKED__ void __X86Vector20()
+	{
+	// Interrupts enabled on entry
+	asm("cld");
+	asm("test eax, eax");
+	asm("je wait_for_any_request");
+	asm("push ds");
+	asm("push es");
+	asm("push gs");
+	asm("push ecx");
+	asm("mov cx, ds");
+	asm("mov dx, ss");
+	asm("mov ds, dx");
+	asm("mov gs, cx");
+	asm("mov ecx, [%a0]": :"i"(&TheScheduler.iCurrentThread));
+	asm("mov es, dx");
+	asm("mov edx, [ecx+%0]" : : "i"_FOFF(NThreadBase,iFastExecTable)); 
+	asm("cmp eax, [edx]");
+	asm("jae fast_exec_invalid");
+	asm("cli");
+	asm("call [edx+eax*4]");
+	asm("add esp, 4");
+	asm("fast_exec_exit:");
+	asm("test dword ptr [esp+16], 3 ");	// returning to user mode?
+	asm("jz short fast_exec_exit2 ");	// no - don't do lock check or user mode callbacks
+#ifdef __CHECK_LOCK_STATE__
+	asm("call %a0" : : "i" (&check_lock_state));
+#endif
+	asm("push eax");
+#ifdef __GCC32__
+	asm("mov ecx, [%a0]": : "i"(&TheScheduler.iCurrentThread));
+	asm("push ecx");
+	asm("call __ZN11NThreadBase21CallUserModeCallbacksEv ");
+	asm("add esp,4"); 
+#else
+	TheScheduler.iCurrentThread->CallUserModeCallbacks();
+#endif	
+	asm("pop eax");
+
+	asm("fast_exec_exit2: ");
+	asm("pop gs");
+	asm("pop es");
+	asm("pop ds");
+	asm("iretd");
+
+	asm("wait_for_any_request:");
+	asm("push ds");
+	asm("push es");
+	asm("mov cx, ss");
+	asm("mov ds, cx");
+	asm("mov es, cx");
+	asm("call %a0" : : "i" (NKern_WaitForAnyRequest));
+
+	asm("test dword ptr [esp+12], 3 ");	// returning to user mode?
+	asm("jz short wfar_exit2 ");		// no - don't do lock check or user mode callbacks
+	asm("push eax");
+	asm("cli");
+#ifdef __GCC32__
+	asm("mov ecx, [%a0]": : "i"(&TheScheduler.iCurrentThread));
+	asm("push ecx");
+	asm("call __ZN11NThreadBase21CallUserModeCallbacksEv");
+	asm("add esp,4"); 
+#else
+	TheScheduler.iCurrentThread->CallUserModeCallbacks();
+#endif	
+	asm("pop eax");
+#ifdef __CHECK_LOCK_STATE__
+	asm("call %a0" : : "i" (&check_lock_state));
+#endif
+
+	asm("wfar_exit2: ");
+	asm("pop es");
+	asm("pop ds");
+	asm("iretd");
+
+	asm("fast_exec_invalid:");
+	asm("pop ecx");
+	asm("push ebp");
+	asm("push edi");
+	asm("push esi");
+	asm("push ebx");
+	asm("push edx");
+	asm("push ecx");
+	asm("mov edi, [%a0]": :"i"(&TheScheduler.iCurrentThread));			// edi=TheCurrentThread
+	asm("mov esi, [edi+%0]" : : "i"_FOFF(NThreadBase,iSlowExecTable));	// esi=slow exec table base
+	asm("call [esi-8]");												// call invalid exec handler
+	asm("pop ecx");
+	asm("pop edx");
+	asm("pop ebx");
+	asm("pop esi");
+	asm("pop edi");
+	asm("pop ebp");
+	asm("jmp fast_exec_exit");
+	}
+
+/******************************************************************************
+* Int 21h Handler - Slow Executive Calls
+* Enter with:
+*		Call number in EAX
+*		Parameters in ECX, EDX, EBX, ESI in that order
+* On entry SS:ESP references current threads supervisor stack
+* Must preserve EBX, EBP, ESI, EDI
+* [ESP+0] = return EIP
+* [ESP+4] = return CS
+* [ESP+8] = return EFLAGS
+* [ESP+12] = return ESP if privilege change occurred
+* [ESP+16] = return SS if privilege change occurred
+*******************************************************************************/
+GLDEF_C __NAKED__ void __X86Vector21()
+	{
+	// Interrupts enabled on entry
+	asm("sub esp, 32");								// reserve space for additional arguments
+	asm("cld");
+	asm("push ds");
+	asm("push es");
+	asm("push gs");
+	asm("push ebp");
+	asm("mov bp, ds");
+	asm("mov gs, bp");
+	asm("mov bp, ss");
+	asm("mov ds, bp");
+	asm("mov es, bp");
+	asm("push edi");
+	asm("mov edi, [%a0]": : "i"(&TheScheduler.iCurrentThread));	// edi=TheCurrentThread
+	asm("push esi");
+	asm("mov esi, [edi+%0]" : : "i"_FOFF(NThreadBase,iSlowExecTable)); // esi=slow exec table base 
+	asm("push ebx");
+	asm("push edx");
+	asm("push ecx");
+	asm("lea ebp, [esi+eax*8]");					// ebp points to exec table entry
+	asm("cmp eax, [esi-12]");
+	asm("jae slow_exec_invalid");
+	asm("mov ebx, [ebp]");							// ebx=flags
+	asm("test ebx, 0x1c000000");					// additional arguments required?
+	asm("jz slow_exec_no_extra_args");
+	asm("mov edx, [esp+8]");						// edx points to additional args
+	asm("lea eax, [esp+36]");						// address of copied additional arguments
+	asm("mov [esp+8], eax");						// replace supplied address
+	asm("mov ecx, ebx");
+	asm("shr ecx, 26");
+	asm("and cl, 7");								// ecx=number of additional arguments-1
+	asm("test edx, edx");
+	asm("jnz slow_exec_extra_args_present");		// if arg ptr not NULL, copy args
+	asm("slow_exec_zero_args:");
+	asm("mov [esp+ecx*4+36], edx");					// else zero args
+	asm("dec ecx");
+	asm("jns slow_exec_zero_args");
+	asm("jmp slow_exec_no_extra_args");
+
+	asm("slow_exec_extra_args_present:");
+	asm("slow_exec_copy_args:");
+	asm("mov eax, gs:[edx+ecx*4]");					// get argument
+	asm("mov [esp+ecx*4+36], eax");					// copy it
+	asm("dec ecx");
+	asm("jns slow_exec_copy_args");
+
+	asm("slow_exec_no_extra_args:");
+	asm("test ebx, 0x80000000");					// test EClaim
+	asm("jz slow_exec_no_claim");
+	asm("call %a0" : : "i"(NKern_LockSystem)); 		// trashes eax, ecx, edx
+	asm("slow_exec_no_claim:");
+	asm("test ebx, 0x20000000");					// test EPreprocess
+	asm("jz slow_exec_no_preprocess");
+	asm("call [esi-4]");							// trashes eax, ecx, edx, edi
+	asm("slow_exec_no_preprocess:");
+	asm("call [ebp+4]");							// call exec function
+	asm("test ebx, 0x40000000");					// test ERelease
+	asm("jz slow_exec_no_release");
+	asm("mov edi, eax");							// save return value in EDI
+	asm("call %a0" : : "i"(NKern_UnlockSystem)); // trashes eax, ecx, edx
+	asm("mov eax, edi");							// restore return value
+	asm("slow_exec_no_release:");
+
+	asm("slow_exec_exit:");
+	asm("test dword ptr [esp+72], 3 ");				// returning to user mode?
+	asm("jz short slow_exec_exit2 ");				// no - don't do lock check or user mode callbacks
+#ifdef __CHECK_LOCK_STATE__
+	asm("call %a0" : : "i" (&check_lock_state));
+#endif
+	asm("push eax");
+	asm("cli");
+#ifdef __GCC32__
+	asm("mov ecx, [%a0]": : "i"(&TheScheduler.iCurrentThread));
+	asm("push ecx");
+	asm("call __ZN11NThreadBase21CallUserModeCallbacksEv");
+	asm("add esp,4"); 
+#else
+	TheScheduler.iCurrentThread->CallUserModeCallbacks();
+#endif
+	asm("pop eax");
+
+	asm("slow_exec_exit2: ");
+	asm("pop ecx");
+	asm("pop edx");
+	asm("pop ebx");
+	asm("pop esi");
+	asm("pop edi");
+	asm("pop ebp");
+	asm("pop gs");
+	asm("pop es");
+	asm("pop ds");
+	asm("add esp, 32");								// remove additional arguments
+	asm("iretd");
+
+	asm("slow_exec_invalid:");
+	asm("call [esi-8]");							// call invalid exec handler
+	asm("jmp slow_exec_exit");
+	}
+
+const TUint32 irq_start_trace_header = ((4<<BTrace::ESizeIndex) + (BTrace::ECpuUsage<<BTrace::ECategoryIndex*8) + (BTrace::EIrqStart<<BTrace::ESubCategoryIndex*8));
+const TUint32 irq_end_trace_header   = ((4<<BTrace::ESizeIndex) + (BTrace::ECpuUsage<<BTrace::ECategoryIndex*8) + (BTrace::EIrqEnd<<BTrace::ESubCategoryIndex*8));
+
+/******************************************************************************
+* IRQ Preamble/Postamble Common Code
+* On entry SS:ESP references current threads supervisor stack
+* [ESP+0] = vector number
+* [ESP+4] = return EIP
+* [ESP+8] = return CS
+* [ESP+12] = return EFLAGS
+* [ESP+16] = return ESP if privilege change occurred
+* [ESP+20] = return SS if privilege change occurred
+*******************************************************************************/
+__NAKED__ void __X86VectorIrq()
+	{
+	asm("push ds");
+	asm("push es");
+	asm("push eax");
+	asm("mov ax, ss");
+	asm("cld");
+	asm("push ecx");
+	asm("push edx");
+	asm("mov ds, ax");
+	asm("mov es, ax");
+	asm("mov eax, esp");									// eax points to saved stuff
+	asm("inc dword ptr [%a0]": : "i"(&X86_IrqNestCount));	// nest count starts at -1
+	asm("jnz nested_irq_entry");
+#ifdef __GCC32__
+	asm("mov esp, %0" : : "i"(&X86_IrqStack)); 
+	asm("add esp, %0" : : "i"(IRQ_STACK_SIZE));
+#else
+	_asm lea esp, X86_IrqStack[IRQ_STACK_SIZE]
+#endif
+	asm("push eax");
+	asm("nested_irq_entry:");
+
+#ifdef BTRACE_CPU_USAGE
+	asm("cmp byte ptr [%a0], 0": : "i"(&TheScheduler.iCpuUsageFilter));
+	asm("jz no_trace");
+	asm("push eax");
+	asm("push %0": :"i"(irq_start_trace_header));
+	asm("call dword ptr [%a0]": : "i"(&TheScheduler.iBTraceHandler));
+	asm("pop eax");
+	asm("pop eax");
+	asm("no_trace:");
+#endif
+	asm("call [%a0]": : "i"(&X86_IrqHandler));
+
+	// Postamble. Interrupts disabled here.
+	asm("xor eax, eax");
+	asm("dec dword ptr [%a0]": : "i"(&X86_IrqNestCount));
+	asm("jns nested_irq_exit");
+	asm("cmp eax, [%a0]": : "i"(&TheScheduler.iKernCSLocked));
+	asm("lea edx, %a0": : "i"(&TheScheduler.iRescheduleNeededFlag));
+	asm("jnz irq_kernel_locked_exit");
+	asm("cmp eax, [edx]");
+	asm("jz irq_kernel_locked_exit");
+	asm("inc eax");
+	asm("mov [%a0], eax": : "i"(&TheScheduler.iKernCSLocked));
+	asm("pop eax");
+	asm("mov esp, eax");
+	asm("sti");
+	asm("call %a0" : : "i"(TScheduler_Reschedule));
+	asm("jmp irq_exit");
+
+	asm("irq_kernel_locked_exit:");
+	asm("pop eax");
+	asm("mov esp, eax");
+
+	asm("nested_irq_exit:");
+#ifdef BTRACE_CPU_USAGE
+	asm("cmp byte ptr [%a0], 0": : "i"(&TheScheduler.iCpuUsageFilter));
+	asm("jz no_trace2");
+	asm("push %0": : "i"(irq_end_trace_header));
+	asm("call dword ptr [%a0]": : "i"(&TheScheduler.iBTraceHandler));
+	asm("pop eax");
+	asm("no_trace2:");
+#endif
+	asm("irq_exit:");
+	asm("test dword ptr [esp+28], 3 ");	// check if we came from kernel mode
+	asm("jz short irq_exit2 ");
+#ifdef __CHECK_LOCK_STATE__
+	asm("call %a0" : : "i" (&check_lock_state));
+#endif
+#ifdef __GCC32__
+	asm("mov ecx, [%a0]": : "i"(&TheScheduler.iCurrentThread));
+	asm("push ecx");
+	asm("call __ZN11NThreadBase21CallUserModeCallbacksEv");
+	asm("add esp,4"); 
+#else
+	TheScheduler.iCurrentThread->CallUserModeCallbacks();
+#endif
+	asm("irq_exit2:");
+	asm("pop edx");
+	asm("pop ecx");
+	asm("pop eax");
+	asm("pop es");
+	asm("pop ds");
+	asm("add esp, 4");
+	asm("iretd");
+	}
+
+
+/******************************************************************************
+* General Exception Handler
+* On entry SS:ESP references current threads supervisor stack
+* [ESP+0] = vector number
+* [ESP+4] = error code (filled with 0 for exceptions without error codes)
+* [ESP+8] = return EIP
+* [ESP+12] = return CS
+* [ESP+16] = return EFLAGS
+* [ESP+20] = return ESP if privilege change occurred
+* [ESP+24] = return SS if privilege change occurred
+*******************************************************************************/
+GLDEF_C __NAKED__ void __X86VectorExc()
+	{
+	asm("push ds");
+	asm("push es");
+	asm("push fs");
+	asm("push gs");
+	asm("cld");
+	asm("push ebp");
+	asm("mov bp, ds");
+	asm("push edi");
+	asm("mov gs, bp");
+	asm("mov bp, ss");
+	asm("push esi");
+	asm("push ebx");
+	asm("push ecx");
+	asm("push edx");
+	asm("push eax");
+	asm("mov eax, cr2");
+	asm("mov ds, bp");
+	asm("mov es, bp");
+	asm("push eax");
+	asm("sub esp, 8");
+	asm("mov ebp, esp");		// ebp points to exception info frame
+	asm("mov edi, [%a0]": : "i"(&TheScheduler.iCurrentThread));
+	asm("xor eax, eax");
+	asm("mov ax, ss");
+	asm("mov [ebp+4], eax");	// SS
+	asm("mov eax, ebp");
+	asm("add eax, 76");		// EAX = ESP at point of exception if ring 0
+	asm("test dword ptr [ebp+68], 3");	// check if we came from kernel mode
+	asm("jz ring0_exception");
+	asm("mov byte ptr [edi+11], 1");
+	asm("add eax, 8");		// EAX = ESP at point of exception if ring 3
+	asm("ring0_exception:");
+	asm("mov [ebp], eax");
+	asm("cmp dword ptr [%a0], -1": : "i"(&X86_IrqNestCount));
+	asm("jnz fatal_exception_irq");
+	asm("cmp dword ptr [%a0], 0": : "i"(&TheScheduler.iKernCSLocked));
+	asm("jnz fatal_exception_locked");
+	asm("cmp dword ptr [ebp+%0], 7": :"i"_FOFF(TX86ExcInfo,iExcId));	// check for device not available
+	asm("jne not_fpu");
+	asm("mov dword ptr [%a0], 1": :"i"(&TheScheduler.iKernCSLocked));
+	asm("clts");
+	asm("frstor [edi+%0]": :"i"_FOFF(NThread,iCoprocessorState));
+	asm("call %a0": :"i"(NKern_Unlock));
+	asm("add esp, 12");
+	asm("jmp proceed");
+
+	asm("not_fpu:");
+	asm("mov eax, [edi+%0]" : : "i"_FOFF(NThreadBase,iHandlers)); 
+	asm("push edi");		// pass current thread parameter
+	asm("push ebp");		// pass frame address
+	asm("call [eax+%0]" : : "i"_FOFF(SNThreadHandlers,iExceptionHandler)); 
+	asm("add esp, 20");		// remove parameters, esp, ss, fault address
+
+	asm("proceed:");
+	asm("mov byte ptr [edi+11], 0 ");
+	asm("test dword ptr [esp+56], 3 ");	// check if we came from kernel mode
+	asm("jz short proceed2 ");
+	asm("cli");
+#ifdef __CHECK_LOCK_STATE__
+	asm("call %a0" : : "i" (&check_lock_state));
+#endif
+#ifdef __GCC32__
+	asm("mov ecx, [%a0]": : "i"(&TheScheduler.iCurrentThread));
+	asm("push ecx");
+	asm("call __ZN11NThreadBase21CallUserModeCallbacksEv");
+	asm("add esp,4"); 
+#else
+	TheScheduler.iCurrentThread->CallUserModeCallbacks();
+#endif	
+	asm("proceed2:");
+	asm("pop eax");
+	asm("pop edx");
+	asm("pop ecx");
+	asm("pop ebx");
+	asm("pop esi");
+	asm("pop edi");
+	asm("pop ebp");
+	asm("pop gs");
+	asm("pop fs");
+	asm("pop es");
+	asm("pop ds");
+	asm("add esp, 8");		// skip vector number and error code
+	asm("iretd");
+
+	asm("fatal_exception_irq:");
+	asm("fatal_exception_locked:");
+	asm("lea eax, %a0": :"i"(&TheScheduler)); 
+	asm("lea eax, [eax+%0]": :"i"_FOFF(TScheduler,iMonitorExceptionHandler));
+	asm("mov eax,[eax]");
+
+	asm("test eax, eax");
+	asm("jnz monitor_exception");
+	asm("push ebp");
+	asm("call %a0": :"i"(&__X86ExcFault));	// doesn't return
+
+	asm("monitor_exception:");
+	asm("jmp eax");
+	}
+
+
+/******************************************************************************
+* Exception Handlers
+*******************************************************************************/
+
+DECLARE_X86_EXC_NOERR(00)
+DECLARE_X86_EXC_NOERR(01)
+DECLARE_X86_EXC_NOERR(02)
+DECLARE_X86_EXC_NOERR(03)
+DECLARE_X86_EXC_NOERR(04)
+DECLARE_X86_EXC_NOERR(05)
+DECLARE_X86_EXC_NOERR(06)
+DECLARE_X86_EXC_NOERR(07)
+DECLARE_X86_EXC_ERR(08)
+DECLARE_X86_EXC_NOERR(09)
+DECLARE_X86_EXC_ERR(0A)
+DECLARE_X86_EXC_ERR(0B)
+DECLARE_X86_EXC_ERR(0C)
+DECLARE_X86_EXC_ERR(0D)
+DECLARE_X86_EXC_ERR(0E)
+DECLARE_X86_EXC_NOERR(0F)
+DECLARE_X86_EXC_NOERR(10)
+DECLARE_X86_EXC_ERR(11)
+DECLARE_X86_EXC_NOERR(12)
+DECLARE_X86_EXC_NOERR(13)
+DECLARE_X86_EXC_NOERR(14)
+DECLARE_X86_EXC_NOERR(15)
+DECLARE_X86_EXC_NOERR(16)
+DECLARE_X86_EXC_NOERR(17)
+DECLARE_X86_EXC_NOERR(18)
+DECLARE_X86_EXC_NOERR(19)
+DECLARE_X86_EXC_NOERR(1A)
+DECLARE_X86_EXC_NOERR(1B)
+DECLARE_X86_EXC_NOERR(1C)
+DECLARE_X86_EXC_NOERR(1D)
+DECLARE_X86_EXC_NOERR(1E)
+DECLARE_X86_EXC_NOERR(1F)
+
+/******************************************************************************
+* Interrupt Handlers
+*******************************************************************************/
+
+DECLARE_X86_INT(30)
+DECLARE_X86_INT(31)
+DECLARE_X86_INT(32)
+DECLARE_X86_INT(33)
+DECLARE_X86_INT(34)
+DECLARE_X86_INT(35)
+DECLARE_X86_INT(36)
+DECLARE_X86_INT(37)
+DECLARE_X86_INT(38)
+DECLARE_X86_INT(39)
+DECLARE_X86_INT(3A)
+DECLARE_X86_INT(3B)
+DECLARE_X86_INT(3C)
+DECLARE_X86_INT(3D)
+DECLARE_X86_INT(3E)
+DECLARE_X86_INT(3F)
+
+/*const*/ PFV TheExcVectors[64]=
+{
+__X86Vector00,	__X86Vector01,	__X86Vector02,	__X86Vector03,
+__X86Vector04,	__X86Vector05,	__X86Vector06,	__X86Vector07,
+__X86Vector08,	__X86Vector09,	__X86Vector0A,	__X86Vector0B,
+__X86Vector0C,	__X86Vector0D,	__X86Vector0E,	__X86Vector0F,
+__X86Vector10,	__X86Vector11,	__X86Vector12,	__X86Vector13,
+__X86Vector14,	__X86Vector15,	__X86Vector16,	__X86Vector17,
+__X86Vector18,	__X86Vector19,	__X86Vector1A,	__X86Vector1B,
+__X86Vector1C,	__X86Vector1D,	__X86Vector1E,	__X86Vector1F,
+__X86Vector20,	__X86Vector21,	NULL,			NULL,
+NULL,			NULL,			NULL,			NULL,
+NULL,			NULL,			NULL,			NULL,
+NULL,			NULL,			NULL,			NULL,
+__X86Vector30,	__X86Vector31,	__X86Vector32,	__X86Vector33,
+__X86Vector34,	__X86Vector35,	__X86Vector36,	__X86Vector37,
+__X86Vector38,	__X86Vector39,	__X86Vector3A,	__X86Vector3B,
+__X86Vector3C,	__X86Vector3D,	__X86Vector3E,	__X86Vector3F
+};
+
+EXPORT_C __NAKED__ TUint32 X86::IrqReturnAddress()
+	{
+	asm("mov eax, %0": :"i"(&X86_IrqStack[0]));
+	asm("mov eax, [eax + %0]": :"i"(IRQ_STACK_SIZE - 4));	// pointer to saved supervisor stack pointer
+	asm("mov eax, [eax+24]");								// return address from original interrupt
+	asm("ret");
+	}
+
+__NAKED__ TUint32 get_cr0()
+	{
+	asm("mov eax, cr0");
+	asm("ret");
+	}
+
+__NAKED__ TUint32 get_cr3()
+	{
+	asm("mov eax, cr0");
+	asm("ret");
+	}
+
+__NAKED__ TUint32 get_esp()
+	{
+	asm("mov eax, esp");
+	asm("ret");
+	}
+
+__NAKED__ void __lidt(SX86Des* /*aTable*/, TInt /*aLimit*/)
+	{
+	asm("mov eax, [esp+4]");
+	asm("mov ecx, [esp+8]");
+	asm("shl ecx, 3");
+	asm("sub ecx, 1");
+	asm("sub esp, 8");
+	asm("mov word ptr [esp], cx");
+	asm("mov dword ptr [esp+2], eax");
+	asm("lidt [esp]"); 
+	asm("add esp, 8");
+	asm("mov eax, 0x28");
+	asm("ltr ax");
+	asm("ret");
+	}
+