reactos/ntoskrnl/ke/i386/trap.s

158 lines
6 KiB
ArmAsm
Raw Normal View History

/*
* FILE: ntoskrnl/ke/i386/trap.S
* COPYRIGHT: See COPYING in the top level directory
* PURPOSE: System Traps, Entrypoints and Exitpoints
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
* Timo Kreuzer (timo.kreuzer@reactos.org)
* NOTE: See asmmacro.S for the shared entry/exit code.
*/
/* INCLUDES ******************************************************************/
#include <reactos/asm.h>
#include <ndk/i386/asm.h>
#include <internal/i386/asmmacro.S>
MACRO(GENERATE_IDT_STUB, Number)
idt _KiUnexpectedInterrupt&Number, INT_32_DPL0
ENDM
MACRO(GENERATE_INT_HANDLER, Number)
.func KiUnexpectedInterrupt&Number
_KiUnexpectedInterrupt&Number:
push PRIMARY_VECTOR_BASE + Number
jmp _KiEndUnexpectedRange@0
.endfunc
ENDM
/* GLOBALS *******************************************************************/
.data
PUBLIC _KiIdt
_KiIdt:
/* This is the Software Interrupt Table that we handle in this file: */
Patch that fixes VMWare boot (and should fix QEMu/KVM boot on the testbot): [NTOS]: A trap can get us into a state where DS/ES are invalid, making any pointer dereference (on DS/ES segmented memory, not SS, the stack) crash (and probably double-fault). Therefore, we have to be careful to switch to a good DS/ES before touching the TrapFrame pointer, which we don't have in ESP like the ASM code, but in a DS/ES-segmented register. For V8086 traps we can switch to the good DS/ES immediately, but for other kinds of traps, we actually need to save the current (bad) segments first. So we save them on the stack now, then switch to the good ones, then store the stack values into the trap frame. This is what happens on a non-optimized (-O0) build. On an optimized build, the segments will end up in registers instead, which is fine too (they'll be direct values). The order of instructions is guaranteed since the segment macros are volatile. [NTOS]: The GPF and Invalid Opcode handlers are performance critical when talking about V8086 traps, because they control the main flow of execution during that mode (GPFs will be issued for any privileged instruction we need to emulate, and invalid opcode might be generated for BOPs). Because of this, we employ a fast entry/exit macro into V8086 mode since we can make certain assumptions. We detect, and use, such scenarios when the V8086 flag is enabled in EFLAGS. However, because we can land in a GPF handler with an invalid DS/ES, as some V8086 code could trample this during BIOS calls for example, we must make sure that we are on a valid DS/ES before dereferencing any pointer. We fixup DS/ES either in KiEnterTrap (for normal entry/exit) or, for V86, in KiEnterV86Trap. Notice the problem: we need to detect which of these to use early on but we can't touch the EFLAGS in the frame because DS/ES could be invalid. Thankfully SS is always guaranteed valid, so stack dereferences are game! We therefore read the EFLAGS here, in assembly, where we can touch ESP as we please. We save this in EDX, which will be used as the second argument for the FASTCALL C trap entry. When we make the fast V86 check, we use the parameter instead of the trap frame, leading us to using the correct trap entry function, which fixes up DS/ES and lets us go on our merry way... [NTOS]: Make appropriate changes to GENERATE_TRAP_HANDLERS macro. [NTOS]: Switch to using well-known NT trap handler names (hex-based, double-zeroed) instead of decimal-based trap handler names which are confusing. [NTOS]: Clean up some debug spew. svn path=/trunk/; revision=45052
2010-01-12 05:50:45 +00:00
idt _KiTrap00, INT_32_DPL0 /* INT 00: Divide Error (#DE) */
idt _KiTrap01, INT_32_DPL0 /* INT 01: Debug Exception (#DB) */
idt _KiTrap02, INT_32_DPL0 /* INT 02: NMI Interrupt */
idt _KiTrap03, INT_32_DPL3 /* INT 03: Breakpoint Exception (#BP) */
idt _KiTrap04, INT_32_DPL3 /* INT 04: Overflow Exception (#OF) */
idt _KiTrap05, INT_32_DPL0 /* INT 05: BOUND Range Exceeded (#BR) */
idt _KiTrap06, INT_32_DPL0 /* INT 06: Invalid Opcode Code (#UD) */
idt _KiTrap07, INT_32_DPL0 /* INT 07: Device Not Available (#NM) */
idt _KiTrap08, INT_32_DPL0 /* INT 08: Double Fault Exception (#DF) */
idt _KiTrap09, INT_32_DPL0 /* INT 09: RESERVED */
idt _KiTrap0A, INT_32_DPL0 /* INT 0A: Invalid TSS Exception (#TS) */
idt _KiTrap0B, INT_32_DPL0 /* INT 0B: Segment Not Present (#NP) */
idt _KiTrap0C, INT_32_DPL0 /* INT 0C: Stack Fault Exception (#SS) */
idt _KiTrap0D, INT_32_DPL0 /* INT 0D: General Protection (#GP) */
idt _KiTrap0E, INT_32_DPL0 /* INT 0E: Page-Fault Exception (#PF) */
idt _KiTrap0F, INT_32_DPL0 /* INT 0F: RESERVED */
Patch that fixes VMWare boot (and should fix QEMu/KVM boot on the testbot): [NTOS]: A trap can get us into a state where DS/ES are invalid, making any pointer dereference (on DS/ES segmented memory, not SS, the stack) crash (and probably double-fault). Therefore, we have to be careful to switch to a good DS/ES before touching the TrapFrame pointer, which we don't have in ESP like the ASM code, but in a DS/ES-segmented register. For V8086 traps we can switch to the good DS/ES immediately, but for other kinds of traps, we actually need to save the current (bad) segments first. So we save them on the stack now, then switch to the good ones, then store the stack values into the trap frame. This is what happens on a non-optimized (-O0) build. On an optimized build, the segments will end up in registers instead, which is fine too (they'll be direct values). The order of instructions is guaranteed since the segment macros are volatile. [NTOS]: The GPF and Invalid Opcode handlers are performance critical when talking about V8086 traps, because they control the main flow of execution during that mode (GPFs will be issued for any privileged instruction we need to emulate, and invalid opcode might be generated for BOPs). Because of this, we employ a fast entry/exit macro into V8086 mode since we can make certain assumptions. We detect, and use, such scenarios when the V8086 flag is enabled in EFLAGS. However, because we can land in a GPF handler with an invalid DS/ES, as some V8086 code could trample this during BIOS calls for example, we must make sure that we are on a valid DS/ES before dereferencing any pointer. We fixup DS/ES either in KiEnterTrap (for normal entry/exit) or, for V86, in KiEnterV86Trap. Notice the problem: we need to detect which of these to use early on but we can't touch the EFLAGS in the frame because DS/ES could be invalid. Thankfully SS is always guaranteed valid, so stack dereferences are game! We therefore read the EFLAGS here, in assembly, where we can touch ESP as we please. We save this in EDX, which will be used as the second argument for the FASTCALL C trap entry. When we make the fast V86 check, we use the parameter instead of the trap frame, leading us to using the correct trap entry function, which fixes up DS/ES and lets us go on our merry way... [NTOS]: Make appropriate changes to GENERATE_TRAP_HANDLERS macro. [NTOS]: Switch to using well-known NT trap handler names (hex-based, double-zeroed) instead of decimal-based trap handler names which are confusing. [NTOS]: Clean up some debug spew. svn path=/trunk/; revision=45052
2010-01-12 05:50:45 +00:00
idt _KiTrap10, INT_32_DPL0 /* INT 10: x87 FPU Error (#MF) */
idt _KiTrap11, INT_32_DPL0 /* INT 11: Align Check Exception (#AC) */
idt _KiTrap0F, INT_32_DPL0 /* INT 12: Machine Check Exception (#MC)*/
idt _KiTrap0F, INT_32_DPL0 /* INT 13: SIMD FPU Exception (#XF) */
.rept 22
idt _KiTrap0F, INT_32_DPL0 /* INT 14-29: UNDEFINED INTERRUPTS */
.endr
idt _KiGetTickCount, INT_32_DPL3 /* INT 2A: Get Tick Count Handler */
idt _KiCallbackReturn, INT_32_DPL3 /* INT 2B: User-Mode Callback Return */
idt _KiRaiseAssertion, INT_32_DPL3 /* INT 2C: Debug Assertion Handler */
idt _KiDebugService, INT_32_DPL3 /* INT 2D: Debug Service Handler */
idt _KiSystemService, INT_32_DPL3 /* INT 2E: System Call Service Handler */
idt _KiTrap0F, INT_32_DPL0 /* INT 2F: RESERVED */
i = 0
.rept 208
GENERATE_IDT_STUB %i
i = i + 1
.endr
PUBLIC _KiIdtDescriptor
_KiIdtDescriptor:
.short 0
.short 0x7FF
.long _KiIdt
PUBLIC _KiUnexpectedEntrySize
_KiUnexpectedEntrySize:
.long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
/******************************************************************************/
.code32
.text
TRAP_ENTRY KiTrap00, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap01, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap03, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap04, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap05, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap06, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap07, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap08, 0
TRAP_ENTRY KiTrap09, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap0A, 0
TRAP_ENTRY KiTrap0B, 0
TRAP_ENTRY KiTrap0C, 0
TRAP_ENTRY KiTrap0D, 0
TRAP_ENTRY KiTrap0E, 0
TRAP_ENTRY KiTrap0F, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap10, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap11, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiTrap13, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiGetTickCount, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiCallbackReturn, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiRaiseAssertion, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiDebugService, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY KiUnexpectedInterruptTail, 0
ALIGN 4
EXTERN @KiInterruptTemplateHandler@8
PUBLIC _KiInterruptTemplate
_KiInterruptTemplate:
KiEnterTrap KI_PUSH_FAKE_ERROR_CODE
PUBLIC _KiInterruptTemplate2ndDispatch
_KiInterruptTemplate2ndDispatch:
mov edx, 0
PUBLIC _KiInterruptTemplateObject
_KiInterruptTemplateObject:
mov eax, offset @KiInterruptTemplateHandler@8
jmp eax
PUBLIC _KiInterruptTemplateDispatch
_KiInterruptTemplateDispatch:
EXTERN @KiSystemServiceHandler@8:PROC
PUBLIC _KiSystemService
_KiSystemService:
KiEnterTrap (KI_PUSH_FAKE_ERROR_CODE OR KI_NONVOLATILES_ONLY OR KI_DONT_SAVE_SEGS)
KiCallHandler @KiSystemServiceHandler@8
EXTERN @KiFastCallEntryHandler@8:PROC
PUBLIC _KiFastCallEntry
_KiFastCallEntry:
KiEnterTrap (KI_FAST_SYSTEM_CALL OR KI_NONVOLATILES_ONLY OR KI_DONT_SAVE_SEGS)
KiCallHandler @KiFastCallEntryHandler@8
PUBLIC _KiStartUnexpectedRange@0
_KiStartUnexpectedRange@0:
i = 0
.rept 208
GENERATE_INT_HANDLER %i
i = i + 1
.endr
PUBLIC _KiEndUnexpectedRange@0
_KiEndUnexpectedRange@0:
jmp _KiUnexpectedInterruptTail
/* EXIT CODE *****************************************************************/
KiTrapExitStub KiSystemCallReturn, (KI_RESTORE_EAX OR KI_RESTORE_EFLAGS OR KI_EXIT_JMP)
KiTrapExitStub KiSystemCallSysExitReturn, (KI_RESTORE_EAX OR KI_RESTORE_FS OR KI_RESTORE_EFLAGS OR KI_EXIT_SYSCALL)
KiTrapExitStub KiSystemCallTrapReturn, (KI_RESTORE_EAX OR KI_RESTORE_FS OR KI_EXIT_IRET)
KiTrapExitStub KiEditedTrapReturn, (KI_RESTORE_VOLATILES OR KI_RESTORE_EFLAGS OR KI_EDITED_FRAME OR KI_EXIT_RET)
KiTrapExitStub KiTrapReturn, (KI_RESTORE_VOLATILES OR KI_RESTORE_SEGMENTS OR KI_EXIT_IRET)
KiTrapExitStub KiTrapReturnNoSegments, (KI_RESTORE_VOLATILES OR KI_EXIT_IRET)
END