diff -r 000000000000 -r a41df078684a kernel/eka/nkern/x86/vectors.cia --- /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 +#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<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"); + } +