📄 trap.s
字号:
/*
* 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 0x800
.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:
_KiRaiseAssertion:
/* 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]
#ifdef 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:
#ifdef 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
#ifdef 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 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -