mirror of
https://github.com/reactos/reactos.git
synced 2024-09-19 17:21:14 +00:00
29fa274d6d
- TSVN choked repeatedly when attempting to merge ~9000 revs into the branch (tried 3 times on 2 different computers) - If someone wants to delete aicom-network-fixes, they are welcome to - Lesson learned: Letting a branch get thousands of revs out of date is a horrible idea svn path=/branches/aicom-network-branch/; revision=44353
2859 lines
65 KiB
ArmAsm
2859 lines
65 KiB
ArmAsm
/*
|
|
* 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)
|
|
* NOTE: See asmmacro.S for the shared entry/exit code.
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <asm.h>
|
|
#include <internal/i386/asmmacro.S>
|
|
.intel_syntax noprefix
|
|
|
|
#define Running 2
|
|
#define WrDispatchInt 0x1F
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
.data
|
|
.globl _KiIdt
|
|
_KiIdt:
|
|
/* This is the Software Interrupt Table that we handle in this file: */
|
|
idt _KiTrap0, INT_32_DPL0 /* INT 00: Divide Error (#DE) */
|
|
idt _KiTrap1, INT_32_DPL0 /* INT 01: Debug Exception (#DB) */
|
|
idt _KiTrap2, INT_32_DPL0 /* INT 02: NMI Interrupt */
|
|
idt _KiTrap3, INT_32_DPL3 /* INT 03: Breakpoint Exception (#BP) */
|
|
idt _KiTrap4, INT_32_DPL3 /* INT 04: Overflow Exception (#OF) */
|
|
idt _KiTrap5, INT_32_DPL0 /* INT 05: BOUND Range Exceeded (#BR) */
|
|
idt _KiTrap6, INT_32_DPL0 /* INT 06: Invalid Opcode Code (#UD) */
|
|
idt _KiTrap7, INT_32_DPL0 /* INT 07: Device Not Available (#NM) */
|
|
idt _KiTrap8, INT_32_DPL0 /* INT 08: Double Fault Exception (#DF) */
|
|
idt _KiTrap9, INT_32_DPL0 /* INT 09: RESERVED */
|
|
idt _KiTrap10, INT_32_DPL0 /* INT 0A: Invalid TSS Exception (#TS) */
|
|
idt _KiTrap11, INT_32_DPL0 /* INT 0B: Segment Not Present (#NP) */
|
|
idt _KiTrap12, INT_32_DPL0 /* INT 0C: Stack Fault Exception (#SS) */
|
|
idt _KiTrap13, INT_32_DPL0 /* INT 0D: General Protection (#GP) */
|
|
idt _KiTrap14, INT_32_DPL0 /* INT 0E: Page-Fault Exception (#PF) */
|
|
idt _KiTrap0F, INT_32_DPL0 /* INT 0F: RESERVED */
|
|
idt _KiTrap16, INT_32_DPL0 /* INT 10: x87 FPU Error (#MF) */
|
|
idt _KiTrap17, 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 */
|
|
GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
|
|
|
|
/* System call entrypoints: */
|
|
.globl _KiFastCallEntry
|
|
.globl _KiSystemService
|
|
|
|
/* And special system-defined software traps: */
|
|
.globl _NtRaiseException@12
|
|
.globl _NtContinue@8
|
|
.globl _KiCoprocessorError@0
|
|
.globl _KiDispatchInterrupt@0
|
|
|
|
/* Interrupt template entrypoints */
|
|
.globl _KiInterruptTemplate
|
|
.globl _KiInterruptTemplateObject
|
|
.globl _KiInterruptTemplateDispatch
|
|
|
|
/* Chained and Normal generic interrupt handlers for 1st and 2nd level entry*/
|
|
.globl _KiChainedDispatch2ndLvl@0
|
|
.globl _KiInterruptDispatch@0
|
|
.globl _KiChainedDispatch@0
|
|
|
|
/* We implement the following trap exit points: */
|
|
.globl _KiServiceExit /* Exit from syscall */
|
|
.globl _KiServiceExit2 /* Exit from syscall with complete frame*/
|
|
.globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
|
|
.globl _Kei386EoiHelper2ndEntry /* Exit from unexpected interrupt */
|
|
|
|
.globl _KiIdtDescriptor
|
|
_KiIdtDescriptor:
|
|
.short 0
|
|
.short 0x7FF
|
|
.long _KiIdt
|
|
|
|
.globl _KiUnexpectedEntrySize
|
|
_KiUnexpectedEntrySize:
|
|
.long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
|
|
|
|
_UnexpectedMsg:
|
|
.asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
|
|
|
|
_UnhandledMsg:
|
|
.asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
|
|
|
|
_IsrTimeoutMsg:
|
|
.asciz "\n*** ISR at %lx took over .5 second\n"
|
|
|
|
_IsrOverflowMsg:
|
|
.asciz "\n*** ISR at %lx appears to have an interrupt storm\n"
|
|
|
|
_KiTrapPrefixTable:
|
|
.byte 0xF2 /* REP */
|
|
.byte 0xF3 /* REP INS/OUTS */
|
|
.byte 0x67 /* ADDR */
|
|
.byte 0xF0 /* LOCK */
|
|
.byte 0x66 /* OP */
|
|
.byte 0x2E /* SEG */
|
|
.byte 0x3E /* DS */
|
|
.byte 0x26 /* ES */
|
|
.byte 0x64 /* FS */
|
|
.byte 0x65 /* GS */
|
|
.byte 0x36 /* SS */
|
|
|
|
_KiTrapIoTable:
|
|
.byte 0xE4 /* IN */
|
|
.byte 0xE5 /* IN */
|
|
.byte 0xEC /* IN */
|
|
.byte 0xED /* IN */
|
|
.byte 0x6C /* INS */
|
|
.byte 0x6D /* INS */
|
|
.byte 0xE6 /* OUT */
|
|
.byte 0xE7 /* OUT */
|
|
.byte 0xEE /* OUT */
|
|
.byte 0xEF /* OUT */
|
|
.byte 0x6E /* OUTS */
|
|
.byte 0x6F /* OUTS */
|
|
|
|
/* SOFTWARE INTERRUPT SERVICES ***********************************************/
|
|
.text
|
|
|
|
_KiGetTickCount:
|
|
_KiCallbackReturn:
|
|
/* FIXME: TODO */
|
|
UNHANDLED_PATH
|
|
|
|
.func KiSystemService
|
|
TRAP_FIXUPS kss_a, kss_t, DoNotFixupV86, DoNotFixupAbios
|
|
_KiSystemService:
|
|
|
|
/* Enter the shared system call prolog */
|
|
SYSCALL_PROLOG kss_a, kss_t
|
|
|
|
/* Jump to the actual handler */
|
|
jmp SharedCode
|
|
.endfunc
|
|
|
|
.func KiFastCallEntry
|
|
TRAP_FIXUPS FastCallDrSave, FastCallDrReturn, DoNotFixupV86, DoNotFixupAbios
|
|
_KiFastCallEntry:
|
|
|
|
/* Enter the fast system call prolog */
|
|
FASTCALL_PROLOG FastCallDrSave, FastCallDrReturn
|
|
|
|
SharedCode:
|
|
|
|
/*
|
|
* Find out which table offset to use. Converts 0x1124 into 0x10.
|
|
* The offset is related to the Table Index as such: Offset = TableIndex x 10
|
|
*/
|
|
mov edi, eax
|
|
shr edi, SERVICE_TABLE_SHIFT
|
|
and edi, SERVICE_TABLE_MASK
|
|
mov ecx, edi
|
|
|
|
/* Now add the thread's base system table to the offset */
|
|
add edi, [esi+KTHREAD_SERVICE_TABLE]
|
|
|
|
/* Get the true syscall ID and check it */
|
|
mov ebx, eax
|
|
and eax, SERVICE_NUMBER_MASK
|
|
cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT]
|
|
|
|
/* Invalid ID, try to load Win32K Table */
|
|
jnb KiBBTUnexpectedRange
|
|
|
|
/* Check if this was Win32K */
|
|
cmp ecx, SERVICE_TABLE_TEST
|
|
jnz NotWin32K
|
|
|
|
/* Get the TEB */
|
|
mov ecx, PCR[KPCR_TEB]
|
|
|
|
/* Check if we should flush the User Batch */
|
|
xor ebx, ebx
|
|
ReadBatch:
|
|
or ebx, [ecx+TEB_GDI_BATCH_COUNT]
|
|
jz NotWin32K
|
|
|
|
/* Flush it */
|
|
push edx
|
|
push eax
|
|
call [_KeGdiFlushUserBatch]
|
|
pop eax
|
|
pop edx
|
|
|
|
NotWin32K:
|
|
/* Increase total syscall count */
|
|
inc dword ptr PCR[KPCR_SYSTEM_CALLS]
|
|
|
|
#if DBG
|
|
/* Increase per-syscall count */
|
|
mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT]
|
|
jecxz NoCountTable
|
|
inc dword ptr [ecx+eax*4]
|
|
#endif
|
|
|
|
/* Users's current stack frame pointer is source */
|
|
NoCountTable:
|
|
mov esi, edx
|
|
|
|
/* Allocate room for argument list from kernel stack */
|
|
mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER]
|
|
xor ecx, ecx
|
|
mov cl, [eax+ebx]
|
|
|
|
/* Get pointer to function */
|
|
mov edi, [edi+SERVICE_DESCRIPTOR_BASE]
|
|
mov ebx, [edi+eax*4]
|
|
|
|
/* Allocate space on our stack */
|
|
sub esp, ecx
|
|
|
|
/* Set the size of the arguments and the destination */
|
|
shr ecx, 2
|
|
mov edi, esp
|
|
|
|
/* Make sure we're within the User Probe Address */
|
|
cmp esi, _MmUserProbeAddress
|
|
jnb AccessViolation
|
|
|
|
CopyParams:
|
|
/* Copy the parameters */
|
|
rep movsd
|
|
|
|
/* Do the System Call */
|
|
call ebx
|
|
|
|
AfterSysCall:
|
|
#if DBG
|
|
/* Make sure the user-mode call didn't return at elevated IRQL */
|
|
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz SkipCheck
|
|
mov esi, eax /* We need to save the syscall's return val */
|
|
call _KeGetCurrentIrql@0
|
|
or al, al
|
|
jnz InvalidIrql
|
|
mov eax, esi /* Restore it */
|
|
|
|
/* Get our temporary current thread pointer for sanity check */
|
|
mov ecx, PCR[KPCR_CURRENT_THREAD]
|
|
|
|
/* Make sure that we are not attached and that APCs are not disabled */
|
|
mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
|
|
or dl, dl
|
|
jnz InvalidIndex
|
|
mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
|
|
or edx, edx
|
|
jnz InvalidIndex
|
|
#endif
|
|
|
|
SkipCheck:
|
|
|
|
/* Deallocate the kernel stack frame */
|
|
mov esp, ebp
|
|
|
|
KeReturnFromSystemCall:
|
|
|
|
/* Get the Current Thread */
|
|
mov ecx, PCR[KPCR_CURRENT_THREAD]
|
|
|
|
/* Restore the old trap frame pointer */
|
|
mov edx, [ebp+KTRAP_FRAME_EDX]
|
|
mov [ecx+KTHREAD_TRAP_FRAME], edx
|
|
.endfunc
|
|
|
|
.func KiServiceExit
|
|
_KiServiceExit:
|
|
/* Disable interrupts */
|
|
cli
|
|
|
|
/* Check for, and deliver, User-Mode APCs if needed */
|
|
CHECK_FOR_APC_DELIVER 1
|
|
|
|
/* Exit and cleanup */
|
|
TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything
|
|
.endfunc
|
|
|
|
KiBBTUnexpectedRange:
|
|
|
|
/* If this isn't a Win32K call, fail */
|
|
cmp ecx, SERVICE_TABLE_TEST
|
|
jne InvalidCall
|
|
|
|
/* Set up Win32K Table */
|
|
push edx
|
|
push ebx
|
|
call _PsConvertToGuiThread@0
|
|
|
|
/* Check return code */
|
|
or eax, eax
|
|
|
|
/* Restore registers */
|
|
pop eax
|
|
pop edx
|
|
|
|
/* Reset trap frame address */
|
|
mov ebp, esp
|
|
mov [esi+KTHREAD_TRAP_FRAME], ebp
|
|
|
|
/* Try the Call again, if we suceeded */
|
|
jz SharedCode
|
|
|
|
/*
|
|
* The Shadow Table should have a special byte table which tells us
|
|
* whether we should return FALSE, -1 or STATUS_INVALID_SYSTEM_SERVICE.
|
|
*/
|
|
|
|
/* Get the table limit and base */
|
|
lea edx, _KeServiceDescriptorTableShadow + SERVICE_TABLE_TEST
|
|
mov ecx, [edx+SERVICE_DESCRIPTOR_LIMIT]
|
|
mov edx, [edx+SERVICE_DESCRIPTOR_BASE]
|
|
|
|
/* Get the table address and add our index into the array */
|
|
lea edx, [edx+ecx*4]
|
|
and eax, SERVICE_NUMBER_MASK
|
|
add edx, eax
|
|
|
|
/* Find out what we should return */
|
|
movsx eax, byte ptr [edx]
|
|
or eax, eax
|
|
|
|
/* Return either 0 or -1, we've set it in EAX */
|
|
jle KeReturnFromSystemCall
|
|
|
|
/* Set STATUS_INVALID_SYSTEM_SERVICE */
|
|
mov eax, STATUS_INVALID_SYSTEM_SERVICE
|
|
jmp KeReturnFromSystemCall
|
|
|
|
InvalidCall:
|
|
|
|
/* Invalid System Call */
|
|
mov eax, STATUS_INVALID_SYSTEM_SERVICE
|
|
jmp KeReturnFromSystemCall
|
|
|
|
AccessViolation:
|
|
|
|
/* Check if this came from kernel-mode */
|
|
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
|
|
/* It's fine, go ahead with it */
|
|
jz CopyParams
|
|
|
|
/* Caller sent invalid parameters, fail here */
|
|
mov eax, STATUS_ACCESS_VIOLATION
|
|
jmp AfterSysCall
|
|
|
|
BadStack:
|
|
|
|
/* Restore ESP0 stack */
|
|
mov ecx, PCR[KPCR_TSS]
|
|
mov esp, ss:[ecx+KTSS_ESP0]
|
|
|
|
/* Generate V86M Stack for Trap 6 */
|
|
push 0
|
|
push 0
|
|
push 0
|
|
push 0
|
|
|
|
/* Generate interrupt stack for Trap 6 */
|
|
push KGDT_R3_DATA + RPL_MASK
|
|
push 0
|
|
push 0x20202
|
|
push KGDT_R3_CODE + RPL_MASK
|
|
push 0
|
|
jmp _KiTrap6
|
|
|
|
#if DBG
|
|
InvalidIrql:
|
|
/* Save current IRQL */
|
|
push PCR[KPCR_IRQL]
|
|
|
|
/* Set us at passive */
|
|
mov dword ptr PCR[KPCR_IRQL], 0
|
|
cli
|
|
|
|
/* Bugcheck */
|
|
push 0
|
|
push 0
|
|
push eax
|
|
push ebx
|
|
push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
|
|
call _KeBugCheckEx@20
|
|
|
|
InvalidIndex:
|
|
|
|
/* Get the index and APC state */
|
|
movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX]
|
|
mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
|
|
|
|
/* Bugcheck */
|
|
push 0
|
|
push edx
|
|
push eax
|
|
push ebx
|
|
push APC_INDEX_MISMATCH
|
|
call _KeBugCheckEx@20
|
|
ret
|
|
#endif
|
|
|
|
.func KiServiceExit2
|
|
_KiServiceExit2:
|
|
|
|
/* Disable interrupts */
|
|
cli
|
|
|
|
/* Check for, and deliver, User-Mode APCs if needed */
|
|
CHECK_FOR_APC_DELIVER 0
|
|
|
|
/* Exit and cleanup */
|
|
TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
|
|
.endfunc
|
|
|
|
.func Kei386EoiHelper@0
|
|
_Kei386EoiHelper@0:
|
|
|
|
/* Disable interrupts */
|
|
cli
|
|
|
|
/* Check for, and deliver, User-Mode APCs if needed */
|
|
CHECK_FOR_APC_DELIVER 0
|
|
|
|
/* Exit and cleanup */
|
|
_Kei386EoiHelper2ndEntry:
|
|
TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
|
|
.endfunc
|
|
|
|
V86_Exit:
|
|
/* Move to EDX position */
|
|
add esp, KTRAP_FRAME_EDX
|
|
|
|
/* Restore volatiles */
|
|
pop edx
|
|
pop ecx
|
|
pop eax
|
|
|
|
/* Move to non-volatiles */
|
|
lea esp, [ebp+KTRAP_FRAME_EDI]
|
|
pop edi
|
|
pop esi
|
|
pop ebx
|
|
pop ebp
|
|
|
|
/* Skip error code and return */
|
|
add esp, 4
|
|
iret
|
|
|
|
AbiosExit:
|
|
/* FIXME: TODO */
|
|
UNHANDLED_PATH
|
|
|
|
.func KiRaiseAssertion
|
|
TRAP_FIXUPS kira_a, kira_t, DoFixupV86, DoFixupAbios
|
|
_KiRaiseAssertion:
|
|
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kira_a, kira_t
|
|
|
|
/*
|
|
* Modify EIP so it points to the faulting instruction and set it as the
|
|
* exception address. Note that the 'int 2C' instruction used for this call
|
|
* is 2 bytes long as opposed to 1 byte 'int 3'.
|
|
*/
|
|
sub dword ptr [ebp+KTRAP_FRAME_EIP], 2
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
|
|
/* Raise an assertion failure */
|
|
mov eax, STATUS_ASSERTION_FAILURE
|
|
jmp _DispatchNoParam
|
|
.endfunc
|
|
|
|
.func KiDebugService
|
|
TRAP_FIXUPS kids_a, kids_t, DoFixupV86, DoFixupAbios
|
|
_KiDebugService:
|
|
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kids_a, kids_t
|
|
|
|
/* Increase EIP so we skip the INT3 */
|
|
inc dword ptr [ebp+KTRAP_FRAME_EIP]
|
|
|
|
/* Call debug service dispatcher */
|
|
mov eax, [ebp+KTRAP_FRAME_EAX]
|
|
mov ecx, [ebp+KTRAP_FRAME_ECX]
|
|
mov edx, [ebp+KTRAP_FRAME_EDX]
|
|
|
|
/* Jump to INT3 handler */
|
|
jmp PrepareInt3
|
|
.endfunc
|
|
|
|
.func NtRaiseException@12
|
|
_NtRaiseException@12:
|
|
|
|
/* NOTE: We -must- be called by Zw* to have the right frame! */
|
|
/* Push the stack frame */
|
|
push ebp
|
|
|
|
/* Get the current thread and restore its trap frame */
|
|
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
|
mov edx, [ebp+KTRAP_FRAME_EDX]
|
|
mov [ebx+KTHREAD_TRAP_FRAME], edx
|
|
|
|
/* Set up stack frame */
|
|
mov ebp, esp
|
|
|
|
/* Get the Trap Frame in EBX */
|
|
mov ebx, [ebp+0]
|
|
|
|
/* Get the exception list and restore */
|
|
mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
|
|
mov PCR[KPCR_EXCEPTION_LIST], eax
|
|
|
|
/* Get the parameters */
|
|
mov edx, [ebp+16] /* Search frames */
|
|
mov ecx, [ebp+12] /* Context */
|
|
mov eax, [ebp+8] /* Exception Record */
|
|
|
|
/* Raise the exception */
|
|
push edx
|
|
push ebx
|
|
push 0
|
|
push ecx
|
|
push eax
|
|
call _KiRaiseException@20
|
|
|
|
/* Restore trap frame in EBP */
|
|
pop ebp
|
|
mov esp, ebp
|
|
|
|
/* Check the result */
|
|
or eax, eax
|
|
jz _KiServiceExit2
|
|
|
|
/* Restore debug registers too */
|
|
jmp _KiServiceExit
|
|
.endfunc
|
|
|
|
.func NtContinue@8
|
|
_NtContinue@8:
|
|
|
|
/* NOTE: We -must- be called by Zw* to have the right frame! */
|
|
/* Push the stack frame */
|
|
push ebp
|
|
|
|
/* Get the current thread and restore its trap frame */
|
|
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
|
mov edx, [ebp+KTRAP_FRAME_EDX]
|
|
mov [ebx+KTHREAD_TRAP_FRAME], edx
|
|
|
|
/* Set up stack frame */
|
|
mov ebp, esp
|
|
|
|
/* Save the parameters */
|
|
mov eax, [ebp+0]
|
|
mov ecx, [ebp+8]
|
|
|
|
/* Call KiContinue */
|
|
push eax
|
|
push 0
|
|
push ecx
|
|
call _KiContinue@12
|
|
|
|
/* Check if we failed (bad context record) */
|
|
or eax, eax
|
|
jnz Error
|
|
|
|
/* Check if test alert was requested */
|
|
cmp dword ptr [ebp+12], 0
|
|
je DontTest
|
|
|
|
/* Test alert for the thread */
|
|
mov al, [ebx+KTHREAD_PREVIOUS_MODE]
|
|
push eax
|
|
call _KeTestAlertThread@4
|
|
|
|
DontTest:
|
|
/* Return to previous context */
|
|
pop ebp
|
|
mov esp, ebp
|
|
jmp _KiServiceExit2
|
|
|
|
Error:
|
|
pop ebp
|
|
mov esp, ebp
|
|
jmp _KiServiceExit
|
|
.endfunc
|
|
|
|
/* EXCEPTION DISPATCHERS *****************************************************/
|
|
|
|
.func CommonDispatchException
|
|
_CommonDispatchException:
|
|
|
|
/* Make space for an exception record */
|
|
sub esp, EXCEPTION_RECORD_LENGTH
|
|
|
|
/* Set it up */
|
|
mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
|
|
xor eax, eax
|
|
mov [esp+EXCEPTION_RECORD_EXCEPTION_FLAGS], eax
|
|
mov [esp+EXCEPTION_RECORD_EXCEPTION_RECORD], eax
|
|
mov [esp+EXCEPTION_RECORD_EXCEPTION_ADDRESS], ebx
|
|
mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
|
|
|
|
/* Check parameter count */
|
|
cmp ecx, 0
|
|
jz NoParams
|
|
|
|
/* Get information */
|
|
lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
|
|
mov [ebx], edx
|
|
mov [ebx+4], esi
|
|
mov [ebx+8], edi
|
|
|
|
NoParams:
|
|
|
|
/* Set the record in ECX and check if this was V86 */
|
|
mov ecx, esp
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jz SetPreviousMode
|
|
|
|
/* Set V86 mode */
|
|
mov eax, 0xFFFF
|
|
jmp MaskMode
|
|
|
|
SetPreviousMode:
|
|
|
|
/* Get the caller's CS */
|
|
mov eax, [ebp+KTRAP_FRAME_CS]
|
|
|
|
MaskMode:
|
|
/* Check if it was user-mode or kernel-mode */
|
|
and eax, MODE_MASK
|
|
|
|
/* Dispatch the exception */
|
|
push 1
|
|
push eax
|
|
push ebp
|
|
push 0
|
|
push ecx
|
|
call _KiDispatchException@20
|
|
|
|
/* End the trap */
|
|
mov esp, ebp
|
|
jmp _Kei386EoiHelper@0
|
|
.endfunc
|
|
|
|
.func DispatchNoParam
|
|
_DispatchNoParam:
|
|
/* Call the common dispatcher */
|
|
xor ecx, ecx
|
|
call _CommonDispatchException
|
|
.endfunc
|
|
|
|
.func DispatchOneParamZero
|
|
_DispatchOneParamZero:
|
|
/* Call the common dispatcher */
|
|
xor edx, edx
|
|
mov ecx, 1
|
|
call _CommonDispatchException
|
|
.endfunc
|
|
|
|
.func DispatchTwoParamZero
|
|
_DispatchTwoParamZero:
|
|
/* Call the common dispatcher */
|
|
xor edx, edx
|
|
mov ecx, 2
|
|
call _CommonDispatchException
|
|
.endfunc
|
|
|
|
.func DispatchTwoParam
|
|
_DispatchTwoParam:
|
|
/* Call the common dispatcher */
|
|
mov ecx, 2
|
|
call _CommonDispatchException
|
|
.endfunc
|
|
|
|
/* HARDWARE TRAP HANDLERS ****************************************************/
|
|
|
|
.func KiFixupFrame
|
|
_KiFixupFrame:
|
|
|
|
/* TODO: Routine to fixup a KTRAP_FRAME when faulting from a syscall. */
|
|
UNHANDLED_PATH
|
|
.endfunc
|
|
|
|
.func KiTrap0
|
|
TRAP_FIXUPS kit0_a, kit0_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap0:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit0_a, kit0_t
|
|
|
|
/* Check for V86 */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jnz V86Int0
|
|
|
|
/* Check if the frame was from kernelmode */
|
|
test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz SendException
|
|
|
|
/* Check the old mode */
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
|
jne VdmCheck
|
|
|
|
SendException:
|
|
/* Re-enable interrupts for user-mode and send the exception */
|
|
sti
|
|
mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
jmp _DispatchNoParam
|
|
|
|
VdmCheck:
|
|
/* Check if this is a VDM process */
|
|
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
|
mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
|
|
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
|
jz SendException
|
|
|
|
/* We don't support this yet! */
|
|
V86Int0:
|
|
/* FIXME: TODO */
|
|
UNHANDLED_PATH
|
|
.endfunc
|
|
|
|
.func KiTrap1
|
|
TRAP_FIXUPS kit1_a, kit1_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap1:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit1_a, kit1_t
|
|
|
|
/* Check for V86 */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jnz V86Int1
|
|
|
|
/* Check if the frame was from kernelmode */
|
|
test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz PrepInt1
|
|
|
|
/* Check the old mode */
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
|
jne V86Int1
|
|
|
|
EnableInterrupts:
|
|
/* Enable interrupts for user-mode */
|
|
sti
|
|
|
|
PrepInt1:
|
|
/* Prepare the exception */
|
|
and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAGS_TF
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
mov eax, STATUS_SINGLE_STEP
|
|
jmp _DispatchNoParam
|
|
|
|
V86Int1:
|
|
/* Check if this is a VDM process */
|
|
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
|
mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
|
|
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
|
jz EnableInterrupts
|
|
|
|
/* We don't support VDM! */
|
|
UNHANDLED_PATH
|
|
.endfunc
|
|
|
|
.globl _KiTrap2
|
|
.func KiTrap2
|
|
_KiTrap2:
|
|
|
|
/* FIXME: This is an NMI, nothing like a normal exception */
|
|
mov eax, 2
|
|
jmp _KiSystemFatalException
|
|
.endfunc
|
|
|
|
.func KiTrap3
|
|
TRAP_FIXUPS kit3_a, kit3_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap3:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit3_a, kit3_t
|
|
|
|
/*
|
|
* Set the special code to indicate that this is a software breakpoint
|
|
* and not a debug service call
|
|
*/
|
|
mov eax, BREAKPOINT_BREAK
|
|
|
|
/* Check for V86 */
|
|
PrepareInt3:
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jnz V86Int3
|
|
|
|
/* Check if the frame was from kernelmode */
|
|
test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz PrepInt3
|
|
|
|
/* Check the old mode */
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
|
jne V86Int3
|
|
|
|
EnableInterrupts3:
|
|
/* Enable interrupts for user-mode */
|
|
sti
|
|
|
|
PrepInt3:
|
|
|
|
/* Prepare the exception */
|
|
mov esi, ecx
|
|
mov edi, edx
|
|
mov edx, eax
|
|
|
|
/* Setup EIP, NTSTATUS and parameter count, then dispatch */
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
dec ebx
|
|
mov ecx, 3
|
|
mov eax, STATUS_BREAKPOINT
|
|
call _CommonDispatchException
|
|
|
|
V86Int3:
|
|
/* Check if this is a VDM process */
|
|
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
|
mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
|
|
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
|
jz EnableInterrupts3
|
|
|
|
/* We don't support VDM! */
|
|
UNHANDLED_PATH
|
|
.endfunc
|
|
|
|
.func KiTrap4
|
|
TRAP_FIXUPS kit4_a, kit4_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap4:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit4_a, kit4_t
|
|
|
|
/* Check for V86 */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jnz V86Int4
|
|
|
|
/* Check if the frame was from kernelmode */
|
|
test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz SendException4
|
|
|
|
/* Check the old mode */
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
|
jne VdmCheck4
|
|
|
|
SendException4:
|
|
/* Re-enable interrupts for user-mode and send the exception */
|
|
sti
|
|
mov eax, STATUS_INTEGER_OVERFLOW
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
dec ebx
|
|
jmp _DispatchNoParam
|
|
|
|
VdmCheck4:
|
|
/* Check if this is a VDM process */
|
|
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
|
mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
|
|
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
|
jz SendException4
|
|
|
|
/* We don't support this yet! */
|
|
V86Int4:
|
|
UNHANDLED_PATH
|
|
.endfunc
|
|
|
|
.func KiTrap5
|
|
TRAP_FIXUPS kit5_a, kit5_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap5:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit5_a, kit5_t
|
|
|
|
/* Check for V86 */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jnz V86Int5
|
|
|
|
/* Check if the frame was from kernelmode */
|
|
test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jnz CheckMode
|
|
|
|
/* It did, and this should never happen */
|
|
mov eax, 5
|
|
jmp _KiSystemFatalException
|
|
|
|
/* Check the old mode */
|
|
CheckMode:
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
|
jne VdmCheck5
|
|
|
|
/* Re-enable interrupts for user-mode and send the exception */
|
|
SendException5:
|
|
sti
|
|
mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
jmp _DispatchNoParam
|
|
|
|
VdmCheck5:
|
|
/* Check if this is a VDM process */
|
|
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
|
mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
|
|
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
|
jz SendException5
|
|
|
|
/* We don't support this yet! */
|
|
V86Int5:
|
|
UNHANDLED_PATH
|
|
.endfunc
|
|
|
|
.func KiTrap6
|
|
TRAP_FIXUPS kit6_a, kit6_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap6:
|
|
|
|
/* It this a V86 GPF? */
|
|
test dword ptr [esp+8], EFLAGS_V86_MASK
|
|
jz NotV86UD
|
|
|
|
/* Enter V86 Trap */
|
|
V86_TRAP_PROLOG kit6_a, kit6_v
|
|
|
|
VdmOpCodeFault:
|
|
/* Not yet supported (Invalid OPCODE from V86) */
|
|
UNHANDLED_PATH
|
|
|
|
NotV86UD:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit6_a, kit6_t
|
|
|
|
DispatchLockErrata:
|
|
/* Check if this happened in kernel mode */
|
|
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz KmodeOpcode
|
|
|
|
/* Check for VDM */
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
|
jz UmodeOpcode
|
|
|
|
/* Check if the process is vDM */
|
|
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
|
mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
|
|
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
|
jnz IsVdmOpcode
|
|
|
|
UmodeOpcode:
|
|
/* Get EIP and enable interrupts at this point */
|
|
mov esi, [ebp+KTRAP_FRAME_EIP]
|
|
sti
|
|
|
|
/* Set intruction prefix length */
|
|
mov ecx, 4
|
|
|
|
/* Setup a SEH frame */
|
|
push ebp
|
|
push OpcodeSEH
|
|
push PCR[KPCR_EXCEPTION_LIST]
|
|
mov PCR[KPCR_EXCEPTION_LIST], esp
|
|
|
|
OpcodeLoop:
|
|
/* Get the instruction and check if it's LOCK */
|
|
mov al, [esi]
|
|
cmp al, 0xF0
|
|
jz LockCrash
|
|
|
|
/* Keep moving */
|
|
add esi, 1
|
|
loop OpcodeLoop
|
|
|
|
/* Undo SEH frame */
|
|
pop PCR[KPCR_EXCEPTION_LIST]
|
|
add esp, 8
|
|
|
|
KmodeOpcode:
|
|
|
|
/* Re-enable interrupts */
|
|
sti
|
|
|
|
/* Setup illegal instruction exception and dispatch it */
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
mov eax, STATUS_ILLEGAL_INSTRUCTION
|
|
jmp _DispatchNoParam
|
|
|
|
LockCrash:
|
|
|
|
/* Undo SEH Frame */
|
|
pop PCR[KPCR_EXCEPTION_LIST]
|
|
add esp, 8
|
|
|
|
/* Setup invalid lock exception and dispatch it */
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
mov eax, STATUS_INVALID_LOCK_SEQUENCE
|
|
jmp _DispatchNoParam
|
|
|
|
IsVdmOpcode:
|
|
|
|
/* Unhandled yet */
|
|
UNHANDLED_PATH
|
|
|
|
/* Return to caller */
|
|
jmp _Kei386EoiHelper@0
|
|
|
|
OpcodeSEH:
|
|
|
|
/* Get SEH frame */
|
|
mov esp, [esp+8]
|
|
pop PCR[KPCR_EXCEPTION_LIST]
|
|
add esp, 4
|
|
pop ebp
|
|
|
|
/* Check if this was user mode */
|
|
test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jnz KmodeOpcode
|
|
|
|
/* Do a bugcheck */
|
|
push ebp
|
|
push 0
|
|
push 0
|
|
push 0
|
|
push 0
|
|
push KMODE_EXCEPTION_NOT_HANDLED
|
|
call _KeBugCheckWithTf@24
|
|
.endfunc
|
|
|
|
.func KiTrap7
|
|
TRAP_FIXUPS kit7_a, kit7_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap7:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit7_a, kit7_t
|
|
|
|
/* Get the current thread and stack */
|
|
StartTrapHandle:
|
|
mov eax, PCR[KPCR_CURRENT_THREAD]
|
|
mov ecx, [eax+KTHREAD_INITIAL_STACK]
|
|
sub ecx, NPX_FRAME_LENGTH
|
|
|
|
/* Check if emulation is enabled */
|
|
test byte ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
|
|
jnz EmulationEnabled
|
|
|
|
CheckState:
|
|
/* Check if the NPX state is loaded */
|
|
cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
|
|
mov ebx, cr0
|
|
jz IsLoaded
|
|
|
|
/* Remove flags */
|
|
and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
|
|
mov cr0, ebx
|
|
|
|
/* Check the NPX thread */
|
|
mov edx, PCR[KPCR_NPX_THREAD]
|
|
or edx, edx
|
|
jz NoNpxThread
|
|
|
|
/* Get the NPX Stack */
|
|
mov esi, [edx+KTHREAD_INITIAL_STACK]
|
|
sub esi, NPX_FRAME_LENGTH
|
|
|
|
/* Check if we have FXSR and check which operand to use */
|
|
test byte ptr _KeI386FxsrPresent, 1
|
|
jz FnSave
|
|
fxsave [esi]
|
|
jmp AfterSave
|
|
|
|
FnSave:
|
|
fnsave [esi]
|
|
|
|
AfterSave:
|
|
/* Set the thread's state to dirty */
|
|
mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
|
|
|
|
NoNpxThread:
|
|
/* Check if we have FXSR and choose which operand to use */
|
|
test byte ptr _KeI386FxsrPresent, 1
|
|
jz FrRestore
|
|
fxrstor [ecx]
|
|
jmp AfterRestore
|
|
|
|
FrRestore:
|
|
frstor [ecx]
|
|
|
|
AfterRestore:
|
|
/* Set state loaded */
|
|
mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
|
|
mov PCR[KPCR_NPX_THREAD], eax
|
|
|
|
/* Enable interrupts to happen now */
|
|
sti
|
|
nop
|
|
|
|
/* Check if CR0 needs to be reloaded due to a context switch */
|
|
cmp dword ptr [ecx+FN_CR0_NPX_STATE], 0
|
|
jz _Kei386EoiHelper@0
|
|
|
|
/* We have to reload CR0... disable interrupts */
|
|
cli
|
|
|
|
/* Get CR0 and update it */
|
|
mov ebx, cr0
|
|
or ebx, [ecx+FN_CR0_NPX_STATE]
|
|
mov cr0, ebx
|
|
|
|
/* Restore interrupts and check if TS is back on */
|
|
sti
|
|
test bl, CR0_TS
|
|
jz _Kei386EoiHelper@0
|
|
|
|
/* Clear TS, and loop handling again */
|
|
clts
|
|
cli
|
|
jmp StartTrapHandle
|
|
|
|
KernelNpx:
|
|
|
|
/* Set delayed error */
|
|
or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
|
|
|
|
/* Check if this happened during restore */
|
|
cmp dword ptr [ebp+KTRAP_FRAME_EIP], offset FrRestore
|
|
jnz UserNpx
|
|
|
|
/* Skip instruction and dispatch the exception */
|
|
add dword ptr [ebp+KTRAP_FRAME_EIP], 3
|
|
jmp _Kei386EoiHelper@0
|
|
|
|
IsLoaded:
|
|
/* Check if TS is set */
|
|
test bl, CR0_TS
|
|
jnz TsSetOnLoadedState
|
|
|
|
HandleNpxFault:
|
|
/* Check if the trap came from V86 mode */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jnz V86Npx
|
|
|
|
/* Check if it came from kernel mode */
|
|
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz KernelNpx
|
|
|
|
/* Check if it came from a VDM */
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
|
jne V86Npx
|
|
|
|
UserNpx:
|
|
/* Get the current thread */
|
|
mov eax, PCR[KPCR_CURRENT_THREAD]
|
|
|
|
/* Check NPX state */
|
|
cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
|
|
|
|
/* Get the NPX save area */
|
|
mov ecx, [eax+KTHREAD_INITIAL_STACK]
|
|
lea ecx, [ecx-NPX_FRAME_LENGTH]
|
|
jz NoSaveRestore
|
|
|
|
HandleUserNpx:
|
|
|
|
/* Set new CR0 */
|
|
mov ebx, cr0
|
|
and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
|
|
mov cr0, ebx
|
|
|
|
/* Check if we have FX support */
|
|
test byte ptr _KeI386FxsrPresent, 1
|
|
jz FnSave2
|
|
|
|
/* Save the state */
|
|
fxsave [ecx]
|
|
jmp MakeCr0Dirty
|
|
FnSave2:
|
|
fnsave [ecx]
|
|
wait
|
|
|
|
MakeCr0Dirty:
|
|
/* Make CR0 state not loaded */
|
|
or ebx, NPX_STATE_NOT_LOADED
|
|
or ebx, [ecx+FN_CR0_NPX_STATE]
|
|
mov cr0, ebx
|
|
|
|
/* Update NPX state */
|
|
mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
|
|
mov dword ptr PCR[KPCR_NPX_THREAD], 0
|
|
|
|
NoSaveRestore:
|
|
/* Clear the TS bit and re-enable interrupts */
|
|
and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
|
|
sti
|
|
|
|
/* Check if we have FX support */
|
|
test byte ptr _KeI386FxsrPresent, 1
|
|
jz FnError
|
|
|
|
/* Get error offset, control and status words */
|
|
mov ebx, [ecx+FX_ERROR_OFFSET]
|
|
movzx eax, word ptr [ecx+FX_CONTROL_WORD]
|
|
movzx edx, word ptr [ecx+FX_STATUS_WORD]
|
|
|
|
/* Get the faulting opcode */
|
|
mov esi, [ecx+FX_DATA_OFFSET]
|
|
jmp CheckError
|
|
|
|
FnError:
|
|
/* Get error offset, control and status words */
|
|
mov ebx, [ecx+FP_ERROR_OFFSET]
|
|
movzx eax, word ptr [ecx+FP_CONTROL_WORD]
|
|
movzx edx, word ptr [ecx+FP_STATUS_WORD]
|
|
|
|
/* Get the faulting opcode */
|
|
mov esi, [ecx+FP_DATA_OFFSET]
|
|
|
|
CheckError:
|
|
/* Mask exceptions */
|
|
and eax, 0x3F
|
|
not eax
|
|
and eax, edx
|
|
|
|
/* Check if what's left is invalid */
|
|
test al, 1
|
|
jz ValidNpxOpcode
|
|
|
|
/* Check if it was a stack fault */
|
|
test al, 64
|
|
jnz InvalidStack
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_INVALID_OPERATION
|
|
jmp _DispatchOneParamZero
|
|
|
|
InvalidStack:
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_STACK_CHECK
|
|
jmp _DispatchTwoParamZero
|
|
|
|
ValidNpxOpcode:
|
|
|
|
/* Check for divide by 0 */
|
|
test al, 4
|
|
jz 1f
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_DIVIDE_BY_ZERO
|
|
jmp _DispatchOneParamZero
|
|
|
|
1:
|
|
/* Check for denormal */
|
|
test al, 2
|
|
jz 1f
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_INVALID_OPERATION
|
|
jmp _DispatchOneParamZero
|
|
|
|
1:
|
|
/* Check for overflow */
|
|
test al, 8
|
|
jz 1f
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_OVERFLOW
|
|
jmp _DispatchOneParamZero
|
|
|
|
1:
|
|
/* Check for underflow */
|
|
test al, 16
|
|
jz 1f
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_UNDERFLOW
|
|
jmp _DispatchOneParamZero
|
|
|
|
1:
|
|
/* Check for precision fault */
|
|
test al, 32
|
|
jz UnexpectedNpx
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_INEXACT_RESULT
|
|
jmp _DispatchOneParamZero
|
|
|
|
UnexpectedNpx:
|
|
|
|
/* Strange result, bugcheck the OS */
|
|
sti
|
|
push ebp
|
|
push 0
|
|
push 0
|
|
push eax
|
|
push 1
|
|
push TRAP_CAUSE_UNKNOWN
|
|
call _KeBugCheckWithTf@24
|
|
|
|
V86Npx:
|
|
/* Check if this is a VDM */
|
|
mov eax, PCR[KPCR_CURRENT_THREAD]
|
|
mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
|
|
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
|
jz HandleUserNpx
|
|
|
|
/* V86 NPX not handled */
|
|
UNHANDLED_PATH
|
|
|
|
EmulationEnabled:
|
|
/* Did this come from kernel-mode? */
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
|
|
jz CheckState
|
|
|
|
/* It came from user-mode, so this would only be valid inside a VDM */
|
|
/* Since we don't actually have VDMs in ROS, bugcheck. */
|
|
jmp UnexpectedNpx
|
|
|
|
TsSetOnLoadedState:
|
|
/* TS shouldn't be set, unless this we don't have a Math Processor */
|
|
test bl, CR0_MP
|
|
jnz BogusTrap
|
|
|
|
/* Strange that we got a trap at all, but ignore and continue */
|
|
clts
|
|
jmp _Kei386EoiHelper@0
|
|
|
|
BogusTrap:
|
|
/* Cause a bugcheck */
|
|
push 0
|
|
push 0
|
|
push ebx
|
|
push 2
|
|
push TRAP_CAUSE_UNKNOWN
|
|
call _KeBugCheckEx@20
|
|
.endfunc
|
|
|
|
.globl _KiTrap8
|
|
.func KiTrap8
|
|
_KiTrap8:
|
|
/* Can't really do too much */
|
|
mov eax, 8
|
|
jmp _KiSystemFatalException
|
|
.endfunc
|
|
|
|
.func KiTrap9
|
|
TRAP_FIXUPS kit9_a, kit9_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap9:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit9_a, kit9_t
|
|
|
|
/* Enable interrupts and bugcheck */
|
|
sti
|
|
mov eax, 9
|
|
jmp _KiSystemFatalException
|
|
.endfunc
|
|
|
|
.func KiTrap10
|
|
TRAP_FIXUPS kita_a, kita_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap10:
|
|
/* Enter trap */
|
|
TRAP_PROLOG kita_a, kita_t
|
|
|
|
/* Check for V86 */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jnz V86IntA
|
|
|
|
/* Check if the frame was from kernelmode */
|
|
test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz Fatal
|
|
|
|
V86IntA:
|
|
/* Check if OF was set during iretd */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
|
|
sti
|
|
jz Fatal
|
|
|
|
/* It was, just mask it out */
|
|
and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
|
|
jmp _Kei386EoiHelper@0
|
|
|
|
Fatal:
|
|
/* TSS failure for some other reason: crash */
|
|
mov eax, 10
|
|
jmp _KiSystemFatalException
|
|
.endfunc
|
|
|
|
.func KiTrap11
|
|
TRAP_FIXUPS kitb_a, kitb_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap11:
|
|
/* Enter trap */
|
|
TRAP_PROLOG kitb_a, kitb_t
|
|
|
|
/* FIXME: ROS Doesn't handle segment faults yet */
|
|
mov eax, 11
|
|
jmp _KiSystemFatalException
|
|
.endfunc
|
|
|
|
.func KiTrap12
|
|
TRAP_FIXUPS kitc_a, kitc_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap12:
|
|
/* Enter trap */
|
|
TRAP_PROLOG kitc_a, kitc_t
|
|
|
|
/* FIXME: ROS Doesn't handle stack faults yet */
|
|
mov eax, 12
|
|
jmp _KiSystemFatalException
|
|
.endfunc
|
|
|
|
.func KiTrapExceptHandler
|
|
_KiTrapExceptHandler:
|
|
|
|
/* Setup SEH handler frame */
|
|
mov esp, [esp+8]
|
|
pop PCR[KPCR_EXCEPTION_LIST]
|
|
add esp, 4
|
|
pop ebp
|
|
|
|
/* Check if the fault came from user mode */
|
|
test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jnz SetException
|
|
|
|
/* Kernel fault, bugcheck */
|
|
push ebp
|
|
push 0
|
|
push 0
|
|
push 0
|
|
push 0
|
|
push KMODE_EXCEPTION_NOT_HANDLED
|
|
call _KeBugCheckWithTf@24
|
|
.endfunc
|
|
|
|
.func KiTrap13
|
|
TRAP_FIXUPS kitd_a, kitd_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap13:
|
|
|
|
/* It this a V86 GPF? */
|
|
test dword ptr [esp+12], EFLAGS_V86_MASK
|
|
jz NotV86
|
|
|
|
/* Enter V86 Trap */
|
|
V86_TRAP_PROLOG kitd_a, kitd_v
|
|
|
|
/* Make sure that this is a V86 process */
|
|
mov ecx, PCR[KPCR_CURRENT_THREAD]
|
|
mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
|
|
cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
|
|
jnz RaiseIrql
|
|
|
|
/* Otherwise, something is very wrong, raise an exception */
|
|
sti
|
|
jmp SetException
|
|
|
|
RaiseIrql:
|
|
|
|
/* Go to APC level */
|
|
mov ecx, APC_LEVEL
|
|
call @KfRaiseIrql@4
|
|
|
|
/* Save old IRQL and enable interrupts */
|
|
push eax
|
|
sti
|
|
|
|
/* Handle the opcode */
|
|
call _Ki386HandleOpcodeV86@0
|
|
|
|
/* Check if this was VDM */
|
|
test al, 0xFF
|
|
jnz NoReflect
|
|
|
|
/* FIXME: TODO */
|
|
UNHANDLED_PATH
|
|
|
|
NoReflect:
|
|
|
|
/* Lower IRQL and disable interrupts */
|
|
pop ecx
|
|
call @KfLowerIrql@4
|
|
cli
|
|
|
|
/* Check if this was a V86 trap */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jz NotV86Trap
|
|
|
|
/* Exit the V86 Trap */
|
|
V86_TRAP_EPILOG
|
|
|
|
NotV86Trap:
|
|
|
|
/* Either this wasn't V86, or it was, but an APC interrupted us */
|
|
jmp _Kei386EoiHelper@0
|
|
|
|
NotV86:
|
|
/* Enter trap */
|
|
TRAP_PROLOG kitd_a, kitd_t
|
|
|
|
/* Check if this was from kernel-mode */
|
|
test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jnz UserModeGpf
|
|
|
|
/* Check if we have a VDM alert */
|
|
cmp dword ptr PCR[KPCR_VDM_ALERT], 0
|
|
jnz VdmAlertGpf
|
|
|
|
/* Check for GPF during GPF */
|
|
mov eax, [ebp+KTRAP_FRAME_EIP]
|
|
cmp eax, offset CheckPrivilegedInstruction
|
|
jbe KmodeGpf
|
|
cmp eax, offset CheckPrivilegedInstruction2
|
|
jae KmodeGpf
|
|
|
|
/* FIXME: TODO */
|
|
UNHANDLED_PATH
|
|
|
|
/* Get the opcode and trap frame */
|
|
KmodeGpf:
|
|
mov eax, [ebp+KTRAP_FRAME_EIP]
|
|
mov eax, [eax]
|
|
mov edx, [ebp+KTRAP_FRAME_EBP]
|
|
|
|
/* We want to check if this was POP [DS/ES/FS/GS] */
|
|
add edx, KTRAP_FRAME_DS
|
|
cmp al, 0x1F
|
|
jz SegPopGpf
|
|
add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
|
|
cmp al, 7
|
|
jz SegPopGpf
|
|
add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
|
|
cmp ax, 0xA10F
|
|
jz SegPopGpf
|
|
add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
|
|
cmp ax, 0xA90F
|
|
jz SegPopGpf
|
|
|
|
/* It isn't, was it IRETD? */
|
|
cmp al, 0xCF
|
|
jne NotIretGpf
|
|
|
|
/* Get error code */
|
|
lea edx, [ebp+KTRAP_FRAME_ESP]
|
|
mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
|
|
and ax, ~RPL_MASK
|
|
|
|
/* Get CS */
|
|
mov cx, word ptr [edx+4]
|
|
and cx, ~RPL_MASK
|
|
cmp cx, ax
|
|
jnz NotCsGpf
|
|
|
|
/* This should be a Ki386CallBios return */
|
|
mov eax, offset _Ki386BiosCallReturnAddress
|
|
cmp eax, [edx]
|
|
jne NotBiosGpf
|
|
mov eax, [edx+4]
|
|
cmp ax, KGDT_R0_CODE + RPL_MASK
|
|
jne NotBiosGpf
|
|
|
|
/* Jump to return address */
|
|
jmp _Ki386BiosCallReturnAddress
|
|
|
|
NotBiosGpf:
|
|
/* Check if the thread was in kernel mode */
|
|
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
|
test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
|
|
jz UserModeGpf
|
|
|
|
/* Set RPL_MASK for check below */
|
|
or word ptr [edx+4], RPL_MASK
|
|
|
|
NotCsGpf:
|
|
/* Check if the IRET goes to user-mode */
|
|
test dword ptr [edx+4], RPL_MASK
|
|
jz UserModeGpf
|
|
|
|
/* Setup trap frame to copy */
|
|
mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
|
|
lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
|
|
|
|
TrapCopy:
|
|
|
|
/* Copy each field */
|
|
mov eax, [edx]
|
|
mov [edx+12], eax
|
|
sub edx, 4
|
|
loop TrapCopy
|
|
|
|
/* Enable interrupts and adjust stack */
|
|
sti
|
|
add esp, 12
|
|
add ebp, 12
|
|
|
|
/* Setup exception record */
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
|
|
and esi, 0xFFFF
|
|
mov eax, STATUS_ACCESS_VIOLATION
|
|
jmp _DispatchTwoParamZero
|
|
|
|
MsrCheck:
|
|
|
|
/* FIXME: Handle RDMSR/WRMSR */
|
|
UNHANDLED_PATH
|
|
|
|
NotIretGpf:
|
|
|
|
/* Check if this was an MSR opcode */
|
|
cmp al, 0xF
|
|
jz MsrCheck
|
|
|
|
/* Check if DS is Ring 3 */
|
|
cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
|
|
jz CheckEs
|
|
|
|
/* Otherwise, fix it up */
|
|
mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
|
|
jmp ExitGpfTrap
|
|
|
|
CheckEs:
|
|
|
|
/* Check if ES is Ring 3 */
|
|
cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
|
|
jz UserModeGpf
|
|
|
|
/* Otherwise, fix it up */
|
|
mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
|
|
jmp ExitGpfTrap
|
|
|
|
SegPopGpf:
|
|
|
|
/* Sanity check */
|
|
lea eax, [ebp+KTRAP_FRAME_ESP]
|
|
cmp edx, eax
|
|
jz HandleSegPop
|
|
int 3
|
|
|
|
/* Handle segment POP fault by setting it to 0 */
|
|
HandleSegPop:
|
|
xor eax, eax
|
|
mov dword ptr [edx], eax
|
|
|
|
ExitGpfTrap:
|
|
|
|
/* Do a trap exit */
|
|
TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
|
|
|
|
UserModeGpf:
|
|
|
|
/* If the previous mode was kernel, raise a fatal exception */
|
|
mov eax, 13
|
|
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz _KiSystemFatalException
|
|
|
|
/* Get the process and check which CS this came from */
|
|
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
|
mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
|
jz CheckVdmGpf
|
|
|
|
/* Check if this is a VDM */
|
|
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
|
jnz DispatchV86Gpf
|
|
|
|
/* Enable interrupts and check if we have an error code */
|
|
sti
|
|
cmp word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0
|
|
jnz SetException
|
|
jmp CheckPrivilegedInstruction
|
|
|
|
HandleSegPop2:
|
|
/* Update EIP (will be updated below again) */
|
|
add dword ptr [ebp+KTRAP_FRAME_EIP], 1
|
|
|
|
HandleEsPop:
|
|
/* Clear the segment, update EIP and ESP */
|
|
mov dword ptr [edx], 0
|
|
add dword ptr [ebp+KTRAP_FRAME_EIP], 1
|
|
add dword ptr [ebp+KTRAP_FRAME_ESP], 4
|
|
jmp _Kei386EoiHelper@0
|
|
|
|
CheckVdmGpf:
|
|
/* Check if this is a VDM */
|
|
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
|
jz CheckPrivilegedInstruction
|
|
|
|
/* Bring interrupts back */
|
|
sti
|
|
|
|
/* Check what kind of instruction this is */
|
|
mov eax, [ebp+KTRAP_FRAME_EIP]
|
|
mov eax, [eax]
|
|
|
|
/* FIXME: Check for BOP4 */
|
|
|
|
/* Check if this is POP ES */
|
|
mov edx, ebp
|
|
add edx, KTRAP_FRAME_ES
|
|
cmp al, 0x07
|
|
jz HandleEsPop
|
|
|
|
/* Check if this is POP FS */
|
|
add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
|
|
cmp ax, 0xA10F
|
|
jz HandleSegPop2
|
|
|
|
/* Check if this is POP GS */
|
|
add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
|
|
cmp ax, 0xA90F
|
|
jz HandleSegPop2
|
|
|
|
CheckPrivilegedInstruction:
|
|
/* Bring interrupts back */
|
|
sti
|
|
|
|
/* Setup a SEH handler */
|
|
push ebp
|
|
push offset _KiTrapExceptHandler
|
|
push PCR[KPCR_EXCEPTION_LIST]
|
|
mov PCR[KPCR_EXCEPTION_LIST], esp
|
|
|
|
/* Get EIP */
|
|
mov esi, [ebp+KTRAP_FRAME_EIP]
|
|
|
|
/* Setup loop count */
|
|
mov ecx, 15
|
|
|
|
InstLoop:
|
|
/* Save loop count */
|
|
push ecx
|
|
|
|
/* Get the instruction */
|
|
lods byte ptr [esi]
|
|
|
|
/* Now lookup in the prefix table */
|
|
mov ecx, 11
|
|
mov edi, offset _KiTrapPrefixTable
|
|
repnz scasb
|
|
|
|
/* Restore loop count */
|
|
pop ecx
|
|
|
|
/* If it's not a prefix byte, check other instructions */
|
|
jnz NotPrefixByte
|
|
|
|
/* Keep looping */
|
|
loop InstLoop
|
|
|
|
/* Fixup the stack */
|
|
pop PCR[KPCR_EXCEPTION_LIST]
|
|
add esp, 8
|
|
|
|
/* Illegal instruction */
|
|
jmp KmodeOpcode
|
|
|
|
NotPrefixByte:
|
|
/* Check if it's a HLT */
|
|
cmp al, 0x0F4
|
|
je IsPrivInstruction
|
|
|
|
/* Check if the instruction has two bytes */
|
|
cmp al, 0xF
|
|
jne CheckRing3Io
|
|
|
|
/* Check if this is a LLDT or LTR */
|
|
lods byte ptr [esi]
|
|
cmp al, 0
|
|
jne NotLldt
|
|
|
|
/* Check if this is an LLDT */
|
|
lods byte ptr [esi]
|
|
and al, 0x38
|
|
cmp al, 0x10
|
|
je IsPrivInstruction
|
|
|
|
/* Check if this is an LTR */
|
|
cmp al, 0x18
|
|
je IsPrivInstruction
|
|
|
|
/* Otherwise, access violation */
|
|
jmp NotIoViolation
|
|
|
|
NotLldt:
|
|
/* Check if this is LGDT or LIDT or LMSW */
|
|
cmp al, 0x01
|
|
jne NotGdt
|
|
|
|
/* Check if this is an LGDT */
|
|
lods byte ptr [esi]
|
|
and al, 0x38
|
|
cmp al, 0x10
|
|
je IsPrivInstruction
|
|
|
|
/* Check if this is an LIDT */
|
|
cmp al, 0x18
|
|
je IsPrivInstruction
|
|
|
|
/* Check if this is an LMSW */
|
|
cmp al, 0x30
|
|
je IsPrivInstruction
|
|
|
|
/* Otherwise, access violation */
|
|
jmp NotIoViolation
|
|
|
|
NotGdt:
|
|
/* Check if it's INVD or WBINVD */
|
|
cmp al, 0x8
|
|
je IsPrivInstruction
|
|
cmp al, 0x9
|
|
je IsPrivInstruction
|
|
|
|
/* Check if it's sysexit */
|
|
cmp al, 0x35
|
|
je IsPrivInstruction
|
|
|
|
/* Check if it's a DR move */
|
|
cmp al, 0x26
|
|
je IsPrivInstruction
|
|
|
|
/* Check if it's a CLTS */
|
|
cmp al, 0x6
|
|
je IsPrivInstruction
|
|
|
|
/* Check if it's a CR move */
|
|
cmp al, 0x20
|
|
jb NotIoViolation
|
|
|
|
/* Check if it's a DR move */
|
|
cmp al, 0x24
|
|
jbe IsPrivInstruction
|
|
|
|
/* Everything else is an access violation */
|
|
jmp NotIoViolation
|
|
|
|
CheckRing3Io:
|
|
/* Get EFLAGS and IOPL */
|
|
mov ebx, [ebp+KTRAP_FRAME_EFLAGS]
|
|
and ebx, EFLAGS_IOPL
|
|
shr ebx, 12
|
|
|
|
/* Check the CS's RPL mask */
|
|
mov ecx, [ebp+KTRAP_FRAME_CS]
|
|
and ecx, RPL_MASK
|
|
cmp ebx, ecx
|
|
jge NotIoViolation
|
|
|
|
CheckPrivilegedInstruction2:
|
|
/* Check if this is a CLI or STI */
|
|
cmp al, 0xFA
|
|
je IsPrivInstruction
|
|
cmp al, 0xFB
|
|
je IsPrivInstruction
|
|
|
|
/* Setup I/O table lookup */
|
|
mov ecx, 13
|
|
mov edi, offset _KiTrapIoTable
|
|
|
|
/* Loopup in the table */
|
|
repnz scasb
|
|
jnz NotIoViolation
|
|
|
|
/* FIXME: Check IOPM!!! */
|
|
|
|
IsPrivInstruction:
|
|
/* Cleanup the SEH frame */
|
|
pop PCR[KPCR_EXCEPTION_LIST]
|
|
add esp, 8
|
|
|
|
/* Setup the exception */
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
mov eax, STATUS_PRIVILEGED_INSTRUCTION
|
|
jmp _DispatchNoParam
|
|
|
|
NotIoViolation:
|
|
/* Cleanup the SEH frame */
|
|
pop PCR[KPCR_EXCEPTION_LIST]
|
|
add esp, 8
|
|
|
|
SetException:
|
|
/* Setup the exception */
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
mov esi, -1
|
|
mov eax, STATUS_ACCESS_VIOLATION
|
|
jmp _DispatchTwoParamZero
|
|
|
|
DispatchV86Gpf:
|
|
/* FIXME */
|
|
UNHANDLED_PATH
|
|
.endfunc
|
|
|
|
.func KiTrap14
|
|
TRAP_FIXUPS kite_a, kite_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap14:
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kite_a, kite_t
|
|
|
|
/* Check if we have a VDM alert */
|
|
cmp dword ptr PCR[KPCR_VDM_ALERT], 0
|
|
jnz VdmAlertGpf
|
|
|
|
/* Get the current thread */
|
|
mov edi, PCR[KPCR_CURRENT_THREAD]
|
|
|
|
/* Get the stack address of the frame */
|
|
lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH]
|
|
sub eax, [edi+KTHREAD_INITIAL_STACK]
|
|
jz NoFixUp
|
|
|
|
/* This isn't the base frame, check if it's the second */
|
|
cmp eax, -KTRAP_FRAME_EFLAGS
|
|
jb NoFixUp
|
|
|
|
/* Check if we have a TEB */
|
|
mov eax, PCR[KPCR_TEB]
|
|
or eax, eax
|
|
jle NoFixUp
|
|
|
|
/* Fixup the frame */
|
|
call _KiFixupFrame
|
|
|
|
/* Save CR2 */
|
|
NoFixUp:
|
|
mov edi, cr2
|
|
|
|
/* Check if this processor has the cmpxchg8b lock errata */
|
|
cmp byte ptr _KiI386PentiumLockErrataPresent, 0
|
|
jnz HandleLockErrata
|
|
|
|
NotLockErrata:
|
|
/* HACK: Handle page faults with interrupts disabled */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
|
|
je HandlePf
|
|
|
|
/* Enable interrupts and check if we got here with interrupts disabled */
|
|
sti
|
|
#ifdef HACK_ABOVE_FIXED
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
|
|
jz IllegalState
|
|
#endif
|
|
|
|
HandlePf:
|
|
/* Send trap frame and check if this is kernel-mode or usermode */
|
|
push ebp
|
|
mov eax, [ebp+KTRAP_FRAME_CS]
|
|
and eax, MODE_MASK
|
|
push eax
|
|
|
|
/* Send faulting address and check if this is read or write */
|
|
push edi
|
|
mov eax, [ebp+KTRAP_FRAME_ERROR_CODE]
|
|
and eax, 1
|
|
push eax
|
|
|
|
/* Call the access fault handler */
|
|
call _MmAccessFault@16
|
|
test eax, eax
|
|
jl AccessFail
|
|
|
|
/* Access fault handled, return to caller */
|
|
jmp _Kei386EoiHelper@0
|
|
|
|
AccessFail:
|
|
/* First check if this is a fault in the S-LIST functions */
|
|
mov ecx, offset _ExpInterlockedPopEntrySListFault@0
|
|
cmp [ebp+KTRAP_FRAME_EIP], ecx
|
|
jz SlistFault
|
|
|
|
/* Check if this is a fault in the syscall handler */
|
|
mov ecx, offset CopyParams
|
|
cmp [ebp+KTRAP_FRAME_EIP], ecx
|
|
jz SysCallCopyFault
|
|
mov ecx, offset ReadBatch
|
|
cmp [ebp+KTRAP_FRAME_EIP], ecx
|
|
jnz CheckVdmPf
|
|
|
|
/* FIXME: TODO */
|
|
UNHANDLED_PATH
|
|
jmp _Kei386EoiHelper@0
|
|
|
|
SysCallCopyFault:
|
|
/* FIXME: TODO */
|
|
UNHANDLED_PATH
|
|
jmp _Kei386EoiHelper@0
|
|
|
|
/* Check if the fault occured in a V86 mode */
|
|
CheckVdmPf:
|
|
mov ecx, [ebp+KTRAP_FRAME_ERROR_CODE]
|
|
shr ecx, 1
|
|
and ecx, 1
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jnz VdmPF
|
|
|
|
/* Check if the fault occured in a VDM */
|
|
mov esi, PCR[KPCR_CURRENT_THREAD]
|
|
mov esi, [esi+KTHREAD_APCSTATE_PROCESS]
|
|
cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0
|
|
jz CheckStatus
|
|
|
|
/* Check if we this was in kernel-mode */
|
|
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz CheckStatus
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
|
jz CheckStatus
|
|
|
|
VdmPF:
|
|
/* FIXME: TODO */
|
|
UNHANDLED_PATH
|
|
|
|
/* Save EIP and check what kind of status failure we got */
|
|
CheckStatus:
|
|
mov esi, [ebp+KTRAP_FRAME_EIP]
|
|
cmp eax, STATUS_ACCESS_VIOLATION
|
|
je AccessViol
|
|
cmp eax, STATUS_GUARD_PAGE_VIOLATION
|
|
je SpecialCode
|
|
cmp eax, STATUS_STACK_OVERFLOW
|
|
je SpecialCode
|
|
|
|
/* Setup an in-page exception to dispatch */
|
|
mov edx, ecx
|
|
mov ebx, esi
|
|
mov esi, edi
|
|
mov ecx, 3
|
|
mov edi, eax
|
|
mov eax, STATUS_IN_PAGE_ERROR
|
|
call _CommonDispatchException
|
|
|
|
AccessViol:
|
|
/* Use more proper status code */
|
|
mov eax, KI_EXCEPTION_ACCESS_VIOLATION
|
|
|
|
SpecialCode:
|
|
/* Setup a normal page fault exception */
|
|
mov ebx, esi
|
|
mov edx, ecx
|
|
mov esi, edi
|
|
jmp _DispatchTwoParam
|
|
|
|
SlistFault:
|
|
/* FIXME: TODO */
|
|
UNHANDLED_PATH
|
|
|
|
IllegalState:
|
|
|
|
/* This is completely illegal, bugcheck the system */
|
|
push ebp
|
|
push esi
|
|
push ecx
|
|
push eax
|
|
push edi
|
|
push IRQL_NOT_LESS_OR_EQUAL
|
|
call _KeBugCheckWithTf@24
|
|
|
|
VdmAlertGpf:
|
|
|
|
/* FIXME: NOT SUPPORTED */
|
|
UNHANDLED_PATH
|
|
|
|
HandleLockErrata:
|
|
|
|
/* Fail if this isn't a write fault */
|
|
test word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0x4
|
|
jnz NotLockErrata
|
|
|
|
/* Also make sure the page fault is for IDT entry 6 */
|
|
mov eax, PCR[KPCR_IDT]
|
|
add eax, 0x30
|
|
cmp eax, edi
|
|
jne NotLockErrata
|
|
|
|
/*
|
|
* This is a write fault to the Invalid Opcode handler entry.
|
|
* We assume this is the lock errata and not a real write fault.
|
|
*/
|
|
|
|
/* Clear the error code */
|
|
and dword ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0
|
|
|
|
/* Check if this happened in V86 mode */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jnz VdmOpCodeFault
|
|
|
|
/* Dispatch this to the invalid opcode handler */
|
|
jmp DispatchLockErrata
|
|
.endfunc
|
|
|
|
.func KiTrap0F
|
|
TRAP_FIXUPS kitf_a, kitf_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap0F:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kitf_a, kitf_t
|
|
sti
|
|
|
|
/* Raise a fatal exception */
|
|
mov eax, 15
|
|
jmp _KiSystemFatalException
|
|
.endfunc
|
|
|
|
.func KiTrap16
|
|
TRAP_FIXUPS kit10_a, kit10_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap16:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit10_a, kit10_t
|
|
|
|
/* Check if this is the NPX Thread */
|
|
mov eax, PCR[KPCR_CURRENT_THREAD]
|
|
cmp eax, PCR[KPCR_NPX_THREAD]
|
|
|
|
/* Get the initial stack and NPX frame */
|
|
mov ecx, [eax+KTHREAD_INITIAL_STACK]
|
|
lea ecx, [ecx-NPX_FRAME_LENGTH]
|
|
|
|
/* If this is a valid fault, handle it */
|
|
jz HandleNpxFault
|
|
|
|
/* Otherwise, re-enable interrupts and set delayed error */
|
|
sti
|
|
or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
|
|
jmp _Kei386EoiHelper@0
|
|
.endfunc
|
|
|
|
.func KiTrap17
|
|
TRAP_FIXUPS kit11_a, kit11_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap17:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit11_a, kit11_t
|
|
|
|
/* FIXME: ROS Doesn't handle alignment faults yet */
|
|
mov eax, 17
|
|
jmp _KiSystemFatalException
|
|
.endfunc
|
|
|
|
.globl _KiTrap19
|
|
.func KiTrap19
|
|
TRAP_FIXUPS kit19_a, kit19_t, DoFixupV86, DoNotFixupAbios
|
|
_KiTrap19:
|
|
/* Push error code */
|
|
push 0
|
|
|
|
/* Enter trap */
|
|
TRAP_PROLOG kit19_a, kit19_t
|
|
|
|
/* Check if this is the NPX Thread */
|
|
mov eax, PCR[KPCR_CURRENT_THREAD]
|
|
cmp eax, PCR[KPCR_NPX_THREAD]
|
|
|
|
/* If this is a valid fault, handle it */
|
|
jz HandleXmmiFault
|
|
|
|
/* Otherwise, bugcheck */
|
|
mov eax, 19
|
|
jmp _KiSystemFatalException
|
|
|
|
HandleXmmiFault:
|
|
/* Get the initial stack and NPX frame */
|
|
mov ecx, [eax+KTHREAD_INITIAL_STACK]
|
|
lea ecx, [ecx-NPX_FRAME_LENGTH]
|
|
|
|
/* Check if the trap came from V86 mode */
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jnz V86Xmmi
|
|
|
|
/* Check if it came from kernel mode */
|
|
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
|
jz KernelXmmi
|
|
|
|
/* Check if it came from a VDM */
|
|
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
|
jne VdmXmmi
|
|
|
|
HandleUserXmmi:
|
|
/* Set new CR0 */
|
|
mov ebx, cr0
|
|
and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
|
|
mov cr0, ebx
|
|
|
|
/* Check if we have FX support */
|
|
test byte ptr _KeI386FxsrPresent, 1
|
|
jz XmmiFnSave2
|
|
|
|
/* Save the state */
|
|
fxsave [ecx]
|
|
jmp XmmiMakeCr0Dirty
|
|
XmmiFnSave2:
|
|
fnsave [ecx]
|
|
wait
|
|
|
|
XmmiMakeCr0Dirty:
|
|
/* Make CR0 state not loaded */
|
|
or ebx, NPX_STATE_NOT_LOADED
|
|
or ebx, [ecx+FN_CR0_NPX_STATE]
|
|
mov cr0, ebx
|
|
|
|
/* Update NPX state */
|
|
mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
|
|
mov dword ptr PCR[KPCR_NPX_THREAD], 0
|
|
|
|
/* Clear the TS bit and re-enable interrupts */
|
|
and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
|
|
|
|
/* Re-enable interrupts for user-mode and send the exception */
|
|
sti
|
|
mov ebx, [ebp+KTRAP_FRAME_EIP]
|
|
|
|
/* Get MxCSR and get current mask (bits 7-12) */
|
|
movzx eax, word ptr [ecx+FX_MXCSR]
|
|
mov edx, eax
|
|
shr edx, 7
|
|
not edx
|
|
|
|
/* Set faulting opcode address to 0 */
|
|
mov esi, 0
|
|
|
|
/* Apply legal exceptions mask */
|
|
and eax, 0x3f
|
|
|
|
/* Apply the mask we got in MXCSR itself */
|
|
and eax, edx
|
|
|
|
/* Check for invalid operation */
|
|
test al, 1
|
|
jz 1f
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_MULTIPLE_TRAPS
|
|
jmp _DispatchOneParamZero
|
|
|
|
1:
|
|
/* Check for zero divide */
|
|
test al, 2
|
|
jz 1f
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_MULTIPLE_TRAPS
|
|
jmp _DispatchOneParamZero
|
|
|
|
1:
|
|
/* Check for denormal */
|
|
test al, 4
|
|
jz 1f
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_MULTIPLE_TRAPS
|
|
jmp _DispatchOneParamZero
|
|
|
|
1:
|
|
/* Check for overflow*/
|
|
test al, 8
|
|
jz 1f
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_MULTIPLE_FAULTS
|
|
jmp _DispatchOneParamZero
|
|
|
|
1:
|
|
/* Check for denormal */
|
|
test al, 16
|
|
jz 1f
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_MULTIPLE_FAULTS
|
|
jmp _DispatchOneParamZero
|
|
|
|
1:
|
|
/* Check for Precision */
|
|
test al, 32
|
|
jz UnexpectedXmmi
|
|
|
|
/* Raise exception */
|
|
mov eax, STATUS_FLOAT_MULTIPLE_FAULTS
|
|
jmp _DispatchOneParamZero
|
|
|
|
UnexpectedXmmi:
|
|
/* Strange result, bugcheck the OS */
|
|
sti
|
|
push ebp
|
|
push 1
|
|
push 0
|
|
push eax
|
|
push 13
|
|
push TRAP_CAUSE_UNKNOWN
|
|
call _KeBugCheckWithTf@24
|
|
|
|
VdmXmmi:
|
|
/* Check if this is a VDM */
|
|
mov eax, PCR[KPCR_CURRENT_THREAD]
|
|
mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
|
|
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
|
jz HandleUserXmmi
|
|
|
|
V86Xmmi:
|
|
/* V86 XMMI not handled */
|
|
UNHANDLED_PATH
|
|
|
|
KernelXmmi:
|
|
/* Another weird situation */
|
|
push ebp
|
|
push 2
|
|
push 0
|
|
push eax
|
|
push 13
|
|
push TRAP_CAUSE_UNKNOWN
|
|
call _KeBugCheckWithTf@24
|
|
.endfunc
|
|
|
|
|
|
.func KiSystemFatalException
|
|
_KiSystemFatalException:
|
|
|
|
/* Push the trap frame */
|
|
push ebp
|
|
|
|
/* Push empty parameters */
|
|
push 0
|
|
push 0
|
|
push 0
|
|
|
|
/* Push trap number and bugcheck code */
|
|
push eax
|
|
push UNEXPECTED_KERNEL_MODE_TRAP
|
|
call _KeBugCheckWithTf@24
|
|
ret
|
|
.endfunc
|
|
|
|
.func KiCoprocessorError@0
|
|
_KiCoprocessorError@0:
|
|
|
|
/* Get the NPX Thread's Initial stack */
|
|
mov eax, PCR[KPCR_NPX_THREAD]
|
|
mov eax, [eax+KTHREAD_INITIAL_STACK]
|
|
|
|
/* Make space for the FPU Save area */
|
|
sub eax, SIZEOF_FX_SAVE_AREA
|
|
|
|
/* Set the CR0 State */
|
|
mov dword ptr [eax+FN_CR0_NPX_STATE], 8
|
|
|
|
/* Update it */
|
|
mov eax, cr0
|
|
or eax, 8
|
|
mov cr0, eax
|
|
|
|
/* Return to caller */
|
|
ret
|
|
.endfunc
|
|
|
|
.func Ki16BitStackException
|
|
_Ki16BitStackException:
|
|
|
|
/* Save stack */
|
|
push ss
|
|
push esp
|
|
|
|
/* Go to kernel mode thread stack */
|
|
mov eax, PCR[KPCR_CURRENT_THREAD]
|
|
add esp, [eax+KTHREAD_INITIAL_STACK]
|
|
|
|
/* Switch to good stack segment */
|
|
UNHANDLED_PATH
|
|
.endfunc
|
|
|
|
/* UNEXPECTED INTERRUPT HANDLERS **********************************************/
|
|
|
|
.globl _KiStartUnexpectedRange@0
|
|
_KiStartUnexpectedRange@0:
|
|
|
|
GENERATE_INT_HANDLERS
|
|
|
|
.globl _KiEndUnexpectedRange@0
|
|
_KiEndUnexpectedRange@0:
|
|
jmp _KiUnexpectedInterruptTail
|
|
|
|
.func KiUnexpectedInterruptTail
|
|
TRAP_FIXUPS kui_a, kui_t, DoFixupV86, DoFixupAbios
|
|
_KiUnexpectedInterruptTail:
|
|
|
|
/* Enter interrupt trap */
|
|
INT_PROLOG kui_a, kui_t, DoNotPushFakeErrorCode
|
|
|
|
/* Increase interrupt count */
|
|
inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
|
|
|
|
/* Put vector in EBX and make space for KIRQL */
|
|
mov ebx, [esp]
|
|
sub esp, 4
|
|
|
|
/* Begin interrupt */
|
|
push esp
|
|
push ebx
|
|
push HIGH_LEVEL
|
|
call _HalBeginSystemInterrupt@12
|
|
|
|
/* Check if it was spurious or not */
|
|
or al, al
|
|
jnz Handled
|
|
|
|
/* Spurious, ignore it */
|
|
add esp, 8
|
|
jmp _Kei386EoiHelper2ndEntry
|
|
|
|
Handled:
|
|
/* Unexpected interrupt, print a message on debug builds */
|
|
#if DBG
|
|
push [esp+4]
|
|
push offset _UnexpectedMsg
|
|
call _DbgPrint
|
|
add esp, 8
|
|
#endif
|
|
|
|
/* Exit the interrupt */
|
|
mov esi, $
|
|
cli
|
|
call _HalEndSystemInterrupt@8
|
|
jmp _Kei386EoiHelper@0
|
|
.endfunc
|
|
|
|
.globl _KiUnexpectedInterrupt
|
|
_KiUnexpectedInterrupt:
|
|
|
|
/* Bugcheck with invalid interrupt code */
|
|
push TRAP_CAUSE_UNKNOWN
|
|
call _KeBugCheck@4
|
|
|
|
/* INTERRUPT HANDLERS ********************************************************/
|
|
|
|
.func KiDispatchInterrupt@0
|
|
_KiDispatchInterrupt@0:
|
|
|
|
/* Get the PCR and disable interrupts */
|
|
mov ebx, PCR[KPCR_SELF]
|
|
cli
|
|
|
|
/* Check if we have to deliver DPCs, timers, or deferred threads */
|
|
mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
|
|
or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
|
|
or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
|
|
jz CheckQuantum
|
|
|
|
/* Save stack pointer and exception list, then clear it */
|
|
push ebp
|
|
push dword ptr [ebx+KPCR_EXCEPTION_LIST]
|
|
mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
|
|
|
|
/* Save the stack and switch to the DPC Stack */
|
|
mov edx, esp
|
|
mov esp, [ebx+KPCR_PRCB_DPC_STACK]
|
|
push edx
|
|
|
|
/* Deliver DPCs */
|
|
mov ecx, [ebx+KPCR_PRCB]
|
|
call @KiRetireDpcList@4
|
|
|
|
/* Restore stack and exception list */
|
|
pop esp
|
|
pop dword ptr [ebx+KPCR_EXCEPTION_LIST]
|
|
pop ebp
|
|
|
|
CheckQuantum:
|
|
|
|
/* Re-enable interrupts */
|
|
sti
|
|
|
|
/* Check if we have quantum end */
|
|
cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
|
|
jnz QuantumEnd
|
|
|
|
/* Check if we have a thread to swap to */
|
|
cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
|
|
je Return
|
|
|
|
/* Make space on the stack to save registers */
|
|
sub esp, 3 * 4
|
|
mov [esp+8], esi
|
|
mov [esp+4], edi
|
|
mov [esp+0], ebp
|
|
|
|
/* Get the current thread */
|
|
mov edi, [ebx+KPCR_CURRENT_THREAD]
|
|
|
|
#ifdef CONFIG_SMP
|
|
/* Raise to synch level */
|
|
call _KeRaiseIrqlToSynchLevel@0
|
|
|
|
/* Set context swap busy */
|
|
mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1
|
|
|
|
/* Acquire the PRCB Lock */
|
|
lock bts dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
|
|
jnb GetNext
|
|
lea ecx, [ebx+KPCR_PRCB_PRCB_LOCK]
|
|
call @KefAcquireSpinLockAtDpcLevel@4
|
|
#endif
|
|
|
|
GetNext:
|
|
/* Get the next thread and clear it */
|
|
mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
|
|
and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
|
|
|
|
/* Set us as the current running thread */
|
|
mov [ebx+KPCR_CURRENT_THREAD], esi
|
|
mov byte ptr [esi+KTHREAD_STATE_], Running
|
|
mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt
|
|
|
|
/* Put thread in ECX and get the PRCB in EDX */
|
|
mov ecx, edi
|
|
lea edx, [ebx+KPCR_PRCB_DATA]
|
|
call @KiQueueReadyThread@8
|
|
|
|
/* Set APC_LEVEL and do the swap */
|
|
mov cl, APC_LEVEL
|
|
call @KiSwapContextInternal@0
|
|
|
|
#ifdef CONFIG_SMP
|
|
/* Lower IRQL back to dispatch */
|
|
mov cl, DISPATCH_LEVEL
|
|
call @KfLowerIrql@4
|
|
#endif
|
|
|
|
/* Restore registers */
|
|
mov ebp, [esp+0]
|
|
mov edi, [esp+4]
|
|
mov esi, [esp+8]
|
|
add esp, 3*4
|
|
|
|
Return:
|
|
/* All done */
|
|
ret
|
|
|
|
QuantumEnd:
|
|
/* Disable quantum end and process it */
|
|
mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
|
|
call _KiQuantumEnd@0
|
|
ret
|
|
.endfunc
|
|
|
|
.func KiInterruptTemplate
|
|
_KiInterruptTemplate:
|
|
|
|
/* Enter interrupt trap */
|
|
INT_PROLOG kit_a, kit_t, DoPushFakeErrorCode
|
|
|
|
_KiInterruptTemplate2ndDispatch:
|
|
/* Dummy code, will be replaced by the address of the KINTERRUPT */
|
|
mov edi, 0
|
|
|
|
_KiInterruptTemplateObject:
|
|
/* Dummy jump, will be replaced by the actual jump */
|
|
jmp _KeSynchronizeExecution@12
|
|
|
|
_KiInterruptTemplateDispatch:
|
|
/* Marks the end of the template so that the jump above can be edited */
|
|
|
|
TRAP_FIXUPS kit_a, kit_t, DoFixupV86, DoFixupAbios
|
|
.endfunc
|
|
|
|
.func KiChainedDispatch2ndLvl@0
|
|
_KiChainedDispatch2ndLvl@0:
|
|
|
|
NextSharedInt:
|
|
/* Raise IRQL if necessary */
|
|
mov cl, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
|
|
cmp cl, [edi+KINTERRUPT_IRQL]
|
|
je 1f
|
|
call @KfRaiseIrql@4
|
|
|
|
1:
|
|
/* Acquire the lock */
|
|
mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
|
|
GetIntLock2:
|
|
ACQUIRE_SPINLOCK(esi, IntSpin2)
|
|
|
|
/* Make sure that this interrupt isn't storming */
|
|
VERIFY_INT kid2
|
|
|
|
/* Save the tick count */
|
|
mov esi, _KeTickCount
|
|
|
|
/* Call the ISR */
|
|
mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
|
|
push eax
|
|
push edi
|
|
call [edi+KINTERRUPT_SERVICE_ROUTINE]
|
|
|
|
/* Save the ISR result */
|
|
mov bl, al
|
|
|
|
/* Check if the ISR timed out */
|
|
add esi, _KiISRTimeout
|
|
cmp _KeTickCount, esi
|
|
jnc ChainedIsrTimeout
|
|
|
|
ReleaseLock2:
|
|
/* Release the lock */
|
|
mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
|
|
RELEASE_SPINLOCK(esi)
|
|
|
|
/* Lower IRQL if necessary */
|
|
mov cl, [edi+KINTERRUPT_IRQL]
|
|
cmp cl, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
|
|
je 1f
|
|
call @KfLowerIrql@4
|
|
|
|
1:
|
|
/* Check if the interrupt is handled */
|
|
or bl, bl
|
|
jnz 1f
|
|
|
|
/* Try the next shared interrupt handler */
|
|
mov eax, [edi+KINTERRUPT_INTERRUPT_LIST_HEAD]
|
|
lea edi, [eax-KINTERRUPT_INTERRUPT_LIST_HEAD]
|
|
jmp NextSharedInt
|
|
|
|
1:
|
|
ret
|
|
|
|
#ifdef CONFIG_SMP
|
|
IntSpin2:
|
|
SPIN_ON_LOCK(esi, GetIntLock2)
|
|
#endif
|
|
|
|
ChainedIsrTimeout:
|
|
/* Print warning message */
|
|
push [edi+KINTERRUPT_SERVICE_ROUTINE]
|
|
push offset _IsrTimeoutMsg
|
|
call _DbgPrint
|
|
add esp,8
|
|
|
|
/* Break into debugger, then continue */
|
|
int 3
|
|
jmp ReleaseLock2
|
|
|
|
/* Cleanup verification */
|
|
VERIFY_INT_END kid2, 0
|
|
.endfunc
|
|
|
|
.func KiChainedDispatch@0
|
|
_KiChainedDispatch@0:
|
|
|
|
/* Increase interrupt count */
|
|
inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
|
|
|
|
/* Save trap frame */
|
|
mov ebp, esp
|
|
|
|
/* Save vector and IRQL */
|
|
mov eax, [edi+KINTERRUPT_VECTOR]
|
|
mov ecx, [edi+KINTERRUPT_IRQL]
|
|
|
|
/* Save old irql */
|
|
push eax
|
|
sub esp, 4
|
|
|
|
/* Begin interrupt */
|
|
push esp
|
|
push eax
|
|
push ecx
|
|
call _HalBeginSystemInterrupt@12
|
|
|
|
/* Check if it was handled */
|
|
or al, al
|
|
jz SpuriousInt
|
|
|
|
/* Call the 2nd-level handler */
|
|
call _KiChainedDispatch2ndLvl@0
|
|
|
|
/* Exit the interrupt */
|
|
INT_EPILOG 0
|
|
.endfunc
|
|
|
|
.func KiInterruptDispatch@0
|
|
_KiInterruptDispatch@0:
|
|
|
|
/* Increase interrupt count */
|
|
inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
|
|
|
|
/* Save trap frame */
|
|
mov ebp, esp
|
|
|
|
/* Save vector and IRQL */
|
|
mov eax, [edi+KINTERRUPT_VECTOR]
|
|
mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
|
|
|
|
/* Save old irql */
|
|
push eax
|
|
sub esp, 4
|
|
|
|
/* Begin interrupt */
|
|
push esp
|
|
push eax
|
|
push ecx
|
|
call _HalBeginSystemInterrupt@12
|
|
|
|
/* Check if it was handled */
|
|
or al, al
|
|
jz SpuriousInt
|
|
|
|
/* Acquire the lock */
|
|
mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
|
|
GetIntLock:
|
|
ACQUIRE_SPINLOCK(esi, IntSpin)
|
|
|
|
/* Make sure that this interrupt isn't storming */
|
|
VERIFY_INT kid
|
|
|
|
/* Save the tick count */
|
|
mov ebx, _KeTickCount
|
|
|
|
/* Call the ISR */
|
|
mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
|
|
push eax
|
|
push edi
|
|
call [edi+KINTERRUPT_SERVICE_ROUTINE]
|
|
|
|
/* Check if the ISR timed out */
|
|
add ebx, _KiISRTimeout
|
|
cmp _KeTickCount, ebx
|
|
jnc IsrTimeout
|
|
|
|
ReleaseLock:
|
|
/* Release the lock */
|
|
RELEASE_SPINLOCK(esi)
|
|
|
|
/* Exit the interrupt */
|
|
INT_EPILOG 0
|
|
|
|
SpuriousInt:
|
|
/* Exit the interrupt */
|
|
add esp, 8
|
|
INT_EPILOG 1
|
|
|
|
#ifdef CONFIG_SMP
|
|
IntSpin:
|
|
SPIN_ON_LOCK(esi, GetIntLock)
|
|
#endif
|
|
|
|
IsrTimeout:
|
|
/* Print warning message */
|
|
push [edi+KINTERRUPT_SERVICE_ROUTINE]
|
|
push offset _IsrTimeoutMsg
|
|
call _DbgPrint
|
|
add esp,8
|
|
|
|
/* Break into debugger, then continue */
|
|
int 3
|
|
jmp ReleaseLock
|
|
|
|
/* Cleanup verification */
|
|
VERIFY_INT_END kid, 0
|
|
.endfunc
|
|
|
|
.globl _KeSynchronizeExecution@12
|
|
.func KeSynchronizeExecution@12
|
|
_KeSynchronizeExecution@12:
|
|
|
|
/* Save EBX and put the interrupt object in it */
|
|
push ebx
|
|
mov ebx, [esp+8]
|
|
|
|
/* Go to DIRQL */
|
|
mov cl, [ebx+KINTERRUPT_SYNCHRONIZE_IRQL]
|
|
call @KfRaiseIrql@4
|
|
push eax
|
|
|
|
#ifdef CONFIG_SMP
|
|
/* Acquire the interrupt spinlock FIXME: Write this in assembly */
|
|
mov ecx, [ebx+KINTERRUPT_ACTUAL_LOCK]
|
|
call @KefAcquireSpinLockAtDpcLevel@4
|
|
#endif
|
|
|
|
/* Call the routine */
|
|
push [esp+20]
|
|
call [esp+20]
|
|
|
|
#ifdef CONFIG_SMP
|
|
/* Release the interrupt spinlock FIXME: Write this in assembly */
|
|
push eax
|
|
mov ecx, [ebx+KINTERRUPT_ACTUAL_LOCK]
|
|
call @KefReleaseSpinLockFromDpcLevel@4
|
|
pop eax
|
|
#endif
|
|
|
|
/* Lower IRQL */
|
|
mov ebx, eax
|
|
pop ecx
|
|
call @KfLowerIrql@4
|
|
|
|
/* Return status */
|
|
mov eax, ebx
|
|
pop ebx
|
|
ret 12
|
|
.endfunc
|
|
|
|
/*++
|
|
* Kii386SpinOnSpinLock
|
|
*
|
|
* FILLMEIN
|
|
*
|
|
* Params:
|
|
* SpinLock - FILLMEIN
|
|
*
|
|
* Flags - FILLMEIN
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
* Remarks:
|
|
* FILLMEIN
|
|
*
|
|
*--*/
|
|
.globl _Kii386SpinOnSpinLock@8
|
|
.func Kii386SpinOnSpinLock@8
|
|
_Kii386SpinOnSpinLock@8:
|
|
|
|
#ifdef CONFIG_SMP
|
|
/* FIXME: TODO */
|
|
int 3
|
|
#endif
|
|
|
|
ret 8
|
|
.endfunc
|