2 * FILE: ntoskrnl/ke/i386/trap.S
3 * COPYRIGHT: See COPYING in the top level directory
4 * PURPOSE: System Traps, Entrypoints and Exitpoints
5 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
6 * NOTE: See asmmacro.S for the shared entry/exit code.
9 /* INCLUDES ******************************************************************/
12 #include <internal/i386/asmmacro.S>
13 .intel_syntax noprefix
15 /* GLOBALS *******************************************************************/
20 /* This is the Software Interrupt Table that we handle in this file: */
21 idt _KiTrap0, INT_32_DPL0 /* INT 00: Divide Error (#DE) */
22 idt _KiTrap1, INT_32_DPL0 /* INT 01: Debug Exception (#DB) */
23 idt _KiTrap2, INT_32_DPL0 /* INT 02: NMI Interrupt */
24 idt _KiTrap3, INT_32_DPL3 /* INT 03: Breakpoint Exception (#BP) */
25 idt _KiTrap4, INT_32_DPL3 /* INT 04: Overflow Exception (#OF) */
26 idt _KiTrap5, INT_32_DPL0 /* INT 05: BOUND Range Exceeded (#BR) */
27 idt _KiTrap6, INT_32_DPL0 /* INT 06: Invalid Opcode Code (#UD) */
28 idt _KiTrap7, INT_32_DPL0 /* INT 07: Device Not Available (#NM) */
29 idt _KiTrap8, INT_32_DPL0 /* INT 08: Double Fault Exception (#DF) */
30 idt _KiTrap9, INT_32_DPL0 /* INT 09: RESERVED */
31 idt _KiTrap10, INT_32_DPL0 /* INT 0A: Invalid TSS Exception (#TS) */
32 idt _KiTrap11, INT_32_DPL0 /* INT 0B: Segment Not Present (#NP) */
33 idt _KiTrap12, INT_32_DPL0 /* INT 0C: Stack Fault Exception (#SS) */
34 idt _KiTrap13, INT_32_DPL0 /* INT 0D: General Protection (#GP) */
35 idt _KiTrap14, INT_32_DPL0 /* INT 0E: Page-Fault Exception (#PF) */
36 idt _KiTrap0F, INT_32_DPL0 /* INT 0F: RESERVED */
37 idt _KiTrap16, INT_32_DPL0 /* INT 10: x87 FPU Error (#MF) */
38 idt _KiTrap17, INT_32_DPL0 /* INT 11: Align Check Exception (#AC) */
39 idt _KiTrap0F, INT_32_DPL0 /* INT 12: Machine Check Exception (#MC)*/
40 idt _KiTrap0F, INT_32_DPL0 /* INT 13: SIMD FPU Exception (#XF) */
42 idt _KiTrap0F, INT_32_DPL0 /* INT 14-29: UNDEFINED INTERRUPTS */
44 idt _KiGetTickCount, INT_32_DPL3 /* INT 2A: Get Tick Count Handler */
45 idt _KiCallbackReturn, INT_32_DPL3 /* INT 2B: User-Mode Callback Return */
46 idt _KiRaiseAssertion, INT_32_DPL3 /* INT 2C: Debug Assertion Handler */
47 idt _KiDebugService, INT_32_DPL3 /* INT 2D: Debug Service Handler */
48 idt _KiSystemService, INT_32_DPL3 /* INT 2E: System Call Service Handler */
49 idt _KiTrap0F, INT_32_DPL0 /* INT 2F: RESERVED */
50 GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
52 /* System call entrypoints: */
53 .globl _KiFastCallEntry
54 .globl _KiSystemService
56 /* And special system-defined software traps: */
57 .globl _NtRaiseException@12
59 .globl _KiCoprocessorError@0
60 .globl _KiDispatchInterrupt@0
62 /* Interrupt template entrypoints */
63 .globl _KiInterruptTemplate
64 .globl _KiInterruptTemplateObject
65 .globl _KiInterruptTemplateDispatch
67 /* Chained and Normal generic interrupt handlers for 1st and 2nd level entry*/
68 .globl _KiChainedDispatch2ndLvl@0
69 .globl _KiInterruptDispatch@0
70 .globl _KiChainedDispatch@0
72 /* We implement the following trap exit points: */
73 .globl _KiServiceExit /* Exit from syscall */
74 .globl _KiServiceExit2 /* Exit from syscall with complete frame*/
75 .globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
76 .globl _Kei386EoiHelper2ndEntry /* Exit from unexpected interrupt */
78 .globl _KiIdtDescriptor
83 .globl _KiUnexpectedEntrySize
84 _KiUnexpectedEntrySize:
85 .long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
88 .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
90 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
101 /* Enter the shared system call prolog */
104 /* Jump to the actual handler */
108 .func KiFastCallEntry
117 /* Set user selector */
118 mov ecx, KGDT_R3_DATA | RPL_MASK
120 /* Set DS/ES to User Selector */
124 /* Set the current stack to Kernel Stack */
125 mov ecx, [fs:KPCR_TSS]
126 mov esp, ss:[ecx+KTSS_ESP0]
128 /* Set up a fake INT Stack. */
129 push KGDT_R3_DATA + RPL_MASK
130 push edx /* Ring 3 SS:ESP */
131 pushf /* Ring 3 EFLAGS */
132 push 2 /* Ring 0 EFLAGS */
133 add edx, 8 /* Skip user parameter list */
134 popf /* Set our EFLAGS */
135 or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */
136 push KGDT_R3_CODE + RPL_MASK
137 push dword ptr ds:KUSER_SHARED_SYSCALL_RET
139 /* Setup the Trap Frame stack */
145 push KGDT_R3_TEB + RPL_MASK
147 /* Save pointer to our PCR */
148 mov ebx, [fs:KPCR_SELF]
150 /* Get a pointer to the current thread */
151 mov esi, [ebx+KPCR_CURRENT_THREAD]
153 /* Set the exception handler chain terminator */
154 push [ebx+KPCR_EXCEPTION_LIST]
155 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
157 /* Use the thread's stack */
158 mov ebp, [esi+KTHREAD_INITIAL_STACK]
160 /* Push previous mode */
163 /* Skip the other registers */
166 /* Make space for us on the stack */
169 /* Write the previous mode */
170 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
177 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
179 /* Check if the thread was being debugged */
180 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
182 /* Set the thread's trap frame */
183 mov [esi+KTHREAD_TRAP_FRAME], ebp
185 /* Save DR registers if needed */
186 //jnz Dr_FastCallDrSave
188 /* Set the trap frame debug header */
191 /* Enable interrupts */
197 * Find out which table offset to use. Converts 0x1124 into 0x10.
198 * The offset is related to the Table Index as such: Offset = TableIndex x 10
201 shr edi, SERVICE_TABLE_SHIFT
202 and edi, SERVICE_TABLE_MASK
205 /* Now add the thread's base system table to the offset */
206 add edi, [esi+KTHREAD_SERVICE_TABLE]
208 /* Get the true syscall ID and check it */
210 and eax, SERVICE_NUMBER_MASK
211 cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT]
213 /* Invalid ID, try to load Win32K Table */
214 jnb KiBBTUnexpectedRange
216 /* Check if this was Win32K */
217 cmp ecx, SERVICE_TABLE_TEST
221 mov ecx, [fs:KPCR_TEB]
223 /* Check if we should flush the User Batch */
225 or ebx, [ecx+TEB_GDI_BATCH_COUNT]
231 //call [_KeGdiFlushUserBatch]
236 /* Increase total syscall count */
237 inc dword ptr fs:[KPCR_SYSTEM_CALLS]
240 /* Increase per-syscall count */
241 mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT]
243 inc dword ptr [ecx+eax*4]
246 /* Users's current stack frame pointer is source */
250 /* Allocate room for argument list from kernel stack */
251 mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER]
255 /* Get pointer to function */
256 mov edi, [edi+SERVICE_DESCRIPTOR_BASE]
259 /* Allocate space on our stack */
262 /* Set the size of the arguments and the destination */
266 /* Make sure we're within the User Probe Address */
267 cmp esi, _MmUserProbeAddress
271 /* Copy the parameters */
276 * The following lines are for the benefit of GDB. It will see the return
277 * address of the "call ebx" below, find the last label before it and
278 * thinks that that's the start of the function. It will then check to see
279 * if it starts with a standard function prolog (push ebp, mov ebp,esp1).
280 * When that standard function prolog is not found, it will stop the
281 * stack backtrace. Since we do want to backtrace into usermode, let's
282 * make GDB happy and create a standard prolog.
290 /* Do the System Call */
295 /* Make sure the user-mode call didn't return at elevated IRQL */
296 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
298 mov esi, eax /* We need to save the syscall's return val */
299 call _KeGetCurrentIrql@0
302 mov eax, esi /* Restore it */
304 /* Get our temporary current thread pointer for sanity check */
305 mov ecx, fs:[KPCR_CURRENT_THREAD]
307 /* Make sure that we are not attached and that APCs are not disabled */
308 mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
311 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
318 /* Deallocate the kernel stack frame */
321 KeReturnFromSystemCall:
323 /* Get the Current Thread */
324 mov ecx, [fs:KPCR_CURRENT_THREAD]
326 /* Restore the old trap frame pointer */
327 mov edx, [ebp+KTRAP_FRAME_EDX]
328 mov [ecx+KTHREAD_TRAP_FRAME], edx
333 /* Disable interrupts */
336 /* Check for, and deliver, User-Mode APCs if needed */
337 CHECK_FOR_APC_DELIVER 1
339 /* Exit and cleanup */
340 TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything
343 KiBBTUnexpectedRange:
345 /* If this isn't a Win32K call, fail */
346 cmp ecx, SERVICE_TABLE_TEST
349 /* Set up Win32K Table */
352 call _PsConvertToGuiThread@0
354 /* Check return code */
357 /* Restore registers */
361 /* Reset trap frame address */
363 mov [esi+KTHREAD_TRAP_FRAME], ebp
365 /* Try the Call again, if we suceeded */
369 * The Shadow Table should have a special byte table which tells us
370 * whether we should return FALSE, -1 or STATUS_INVALID_SYSTEM_SERVICE.
373 /* Get the table limit and base */
374 lea edx, _KeServiceDescriptorTableShadow + SERVICE_TABLE_TEST
375 mov ecx, [edx+SERVICE_DESCRIPTOR_LIMIT]
376 mov edx, [edx+SERVICE_DESCRIPTOR_BASE]
378 /* Get the table address and add our index into the array */
380 and eax, SERVICE_NUMBER_MASK
383 /* Find out what we should return */
384 movsx eax, byte ptr [edx]
387 /* Return either 0 or -1, we've set it in EAX */
388 jle KeReturnFromSystemCall
390 /* Set STATUS_INVALID_SYSTEM_SERVICE */
391 mov eax, STATUS_INVALID_SYSTEM_SERVICE
392 jmp KeReturnFromSystemCall
396 /* Invalid System Call */
397 mov eax, STATUS_INVALID_SYSTEM_SERVICE
398 jmp KeReturnFromSystemCall
402 /* Check if this came from kernel-mode */
403 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
405 /* It's fine, go ahead with it */
408 /* Caller sent invalid parameters, fail here */
409 mov eax, STATUS_ACCESS_VIOLATION
414 /* Restore ESP0 stack */
415 mov ecx, [fs:KPCR_TSS]
416 mov esp, ss:[ecx+KTSS_ESP0]
418 /* Generate V86M Stack for Trap 6 */
424 /* Generate interrupt stack for Trap 6 */
425 push KGDT_R3_DATA + RPL_MASK
428 push KGDT_R3_CODE + RPL_MASK
434 /* Save current IRQL */
437 /* Set us at passive */
438 mov dword ptr fs:[KPCR_IRQL], 0
446 push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
447 call _KeBugCheckEx@20
451 /* Get the index and APC state */
452 movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX]
453 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
460 push APC_INDEX_MISMATCH
461 call _KeBugCheckEx@20
468 /* Disable interrupts */
471 /* Check for, and deliver, User-Mode APCs if needed */
472 CHECK_FOR_APC_DELIVER 0
474 /* Exit and cleanup */
475 TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
478 .func Kei386EoiHelper@0
481 /* Disable interrupts */
484 /* Check for, and deliver, User-Mode APCs if needed */
485 CHECK_FOR_APC_DELIVER 0
487 /* Exit and cleanup */
488 _Kei386EoiHelper2ndEntry:
489 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
493 /* Move to EDX position */
494 add esp, KTRAP_FRAME_EDX
496 /* Restore volatiles */
501 /* Move to non-volatiles */
502 lea esp, [ebp+KTRAP_FRAME_EDI]
508 /* Skip error code and return */
513 /* Not yet supported */
519 /* Push error code */
525 /* Increase EIP so we skip the INT3 */
526 //inc dword ptr [ebp+KTRAP_FRAME_EIP]
528 /* Call debug service dispatcher */
529 mov eax, [ebp+KTRAP_FRAME_EAX]
530 mov ecx, [ebp+KTRAP_FRAME_ECX]
531 mov edx, [ebp+KTRAP_FRAME_EAX]
533 /* Check for V86 mode */
534 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
537 /* Check if this is kernel or user-mode */
538 test byte ptr [ebp+KTRAP_FRAME_CS], 1
540 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
543 /* Re-enable interrupts */
547 /* Call the debug routine */
556 call _KdpServiceDispatcher@12
560 /* Get the current process */
561 mov ebx, [fs:KPCR_CURRENT_THREAD]
562 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
564 /* Check if this is a VDM Process */
565 //cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
568 /* Exit through common routine */
569 jmp _Kei386EoiHelper@0
572 .func NtRaiseException@12
573 _NtRaiseException@12:
575 /* NOTE: We -must- be called by Zw* to have the right frame! */
576 /* Push the stack frame */
579 /* Get the current thread and restore its trap frame */
580 mov ebx, [fs:KPCR_CURRENT_THREAD]
581 mov edx, [ebp+KTRAP_FRAME_EDX]
582 mov [ebx+KTHREAD_TRAP_FRAME], edx
584 /* Set up stack frame */
587 /* Get the Trap Frame in EBX */
590 /* Get the exception list and restore */
591 mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
592 mov [fs:KPCR_EXCEPTION_LIST], eax
594 /* Get the parameters */
595 mov edx, [ebp+16] /* Search frames */
596 mov ecx, [ebp+12] /* Context */
597 mov eax, [ebp+8] /* Exception Record */
599 /* Raise the exception */
605 call _KiRaiseException@20
607 /* Restore trap frame in EBP */
611 /* Check the result */
615 /* Restore debug registers too */
622 /* NOTE: We -must- be called by Zw* to have the right frame! */
623 /* Push the stack frame */
626 /* Get the current thread and restore its trap frame */
627 mov ebx, [fs:KPCR_CURRENT_THREAD]
628 mov edx, [ebp+KTRAP_FRAME_EDX]
629 mov [ebx+KTHREAD_TRAP_FRAME], edx
631 /* Set up stack frame */
634 /* Save the parameters */
638 /* Call KiContinue */
644 /* Check if we failed (bad context record) */
648 /* Check if test alert was requested */
649 cmp dword ptr [ebp+12], 0
652 /* Test alert for the thread */
653 mov al, [ebx+KTHREAD_PREVIOUS_MODE]
655 call _KeTestAlertThread@4
658 /* Return to previous context */
669 /* EXCEPTION DISPATCHERS *****************************************************/
671 .func CommonDispatchException
672 _CommonDispatchException:
674 /* Make space for an exception record */
675 sub esp, EXCEPTION_RECORD_LENGTH
678 mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
680 mov [esp+EXCEPTION_RECORD_EXCEPTION_FLAGS], eax
681 mov [esp+EXCEPTION_RECORD_EXCEPTION_RECORD], eax
682 mov [esp+EXCEPTION_RECORD_EXCEPTION_ADDRESS], ebx
683 mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
685 /* Check parameter count */
689 /* Get information */
690 lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
697 /* Set the record in ECX and check if this was V86 */
699 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
708 /* Calculate the previous mode */
709 mov eax, [ebp+KTRAP_FRAME_CS]
713 /* Dispatch the exception */
719 call _KiDispatchException@20
723 jmp _Kei386EoiHelper@0
726 .func DispatchNoParam
728 /* Call the common dispatcher */
730 call _CommonDispatchException
733 .func DispatchOneParam
735 /* Call the common dispatcher */
738 call _CommonDispatchException
741 .func DispatchTwoParam
743 /* Call the common dispatcher */
746 call _CommonDispatchException
749 /* HARDWARE TRAP HANDLERS ****************************************************/
753 /* Push error code */
760 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
763 /* Check if the frame was from kernelmode */
764 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
767 /* Check the old mode */
768 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
772 /* Re-enable interrupts for user-mode and send the exception */
774 mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
775 mov ebx, [ebp+KTRAP_FRAME_EIP]
779 /* Check if this is a VDM process */
780 mov ebx, [fs:KPCR_CURRENT_THREAD]
781 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
782 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
785 /* We don't support this yet! */
792 /* Push error code */
799 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
802 /* Check if the frame was from kernelmode */
803 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
806 /* Check the old mode */
807 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
811 /* Enable interrupts for user-mode */
815 /* Prepare the exception */
816 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAGS_TF
817 mov ebx, [ebp+KTRAP_FRAME_EIP]
818 mov eax, STATUS_SINGLE_STEP
822 /* Check if this is a VDM process */
823 mov ebx, [fs:KPCR_CURRENT_THREAD]
824 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
825 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
828 /* We don't support VDM! */
836 /* FIXME: This is an NMI, nothing like a normal exception */
838 jmp _KiSystemFatalException
843 /* Push error code */
850 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
853 /* Check if the frame was from kernelmode */
854 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
857 /* Check the old mode */
858 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
862 /* Enable interrupts for user-mode */
866 /* Prepare the exception */
871 /* Setup EIP, NTSTATUS and parameter count, then dispatch */
872 mov ebx, [ebp+KTRAP_FRAME_EIP]
874 mov eax, STATUS_BREAKPOINT
876 call _CommonDispatchException
879 /* Check if this is a VDM process */
880 mov ebx, [fs:KPCR_CURRENT_THREAD]
881 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
882 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
885 /* We don't support VDM! */
891 /* Push error code */
898 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
901 /* Check if the frame was from kernelmode */
902 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
905 /* Check the old mode */
906 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
910 /* Re-enable interrupts for user-mode and send the exception */
912 mov eax, STATUS_INTEGER_OVERFLOW
913 mov ebx, [ebp+KTRAP_FRAME_EIP]
918 /* Check if this is a VDM process */
919 mov ebx, [fs:KPCR_CURRENT_THREAD]
920 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
921 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
924 /* We don't support this yet! */
931 /* Push error code */
938 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
941 /* Check if the frame was from kernelmode */
942 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
945 /* It did, and this should never happen */
947 jmp _KiSystemFatalException
949 /* Check the old mode */
951 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
954 /* Re-enable interrupts for user-mode and send the exception */
957 mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
958 mov ebx, [ebp+KTRAP_FRAME_EIP]
962 /* Check if this is a VDM process */
963 mov ebx, [fs:KPCR_CURRENT_THREAD]
964 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
965 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
968 /* We don't support this yet! */
976 /* It this a V86 GPF? */
977 test dword ptr [esp+8], EFLAGS_V86_MASK
983 /* Not yet supported (Invalid OPCODE from V86) */
988 /* Push error code */
994 /* Check if this happened in kernel mode */
995 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
999 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1002 /* Check if the process is vDM */
1003 mov ebx, fs:[KPCR_CURRENT_THREAD]
1004 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
1005 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1009 /* Get EIP and enable interrupts at this point */
1010 mov esi, [ebp+KTRAP_FRAME_EIP]
1013 /* Set intruction prefix length */
1016 /* Setup a SEH frame */
1019 push fs:[KPCR_EXCEPTION_LIST]
1020 mov fs:[KPCR_EXCEPTION_LIST], esp
1023 /* Get the instruction and check if it's LOCK */
1032 /* Undo SEH frame */
1033 pop fs:[KPCR_EXCEPTION_LIST]
1038 /* Re-enable interrupts */
1041 /* Setup illegal instruction exception and dispatch it */
1042 mov ebx, [ebp+KTRAP_FRAME_EIP]
1043 mov eax, STATUS_ILLEGAL_INSTRUCTION
1044 jmp _DispatchNoParam
1048 /* Undo SEH Frame */
1049 pop fs:[KPCR_EXCEPTION_LIST]
1052 /* Setup invalid lock exception and dispatch it */
1053 mov ebx, [ebp+KTRAP_FRAME_EIP]
1054 mov eax, STATUS_INVALID_LOCK_SEQUENCE
1055 jmp _DispatchNoParam
1063 /* Return to caller */
1064 jmp _Kei386EoiHelper@0
1070 pop fs:[KPCR_EXCEPTION_LIST]
1074 /* Check if this was user mode */
1075 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1084 push KMODE_EXCEPTION_NOT_HANDLED
1085 call _KeBugCheckWithTf@24
1090 /* Push error code */
1096 /* Get the current thread and stack */
1098 mov eax, [fs:KPCR_CURRENT_THREAD]
1099 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1100 sub ecx, NPX_FRAME_LENGTH
1102 /* Check if emulation is enabled */
1103 test dword ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
1104 jnz EmulationEnabled
1107 /* Check if the NPX state is loaded */
1108 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1113 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
1116 /* Check the NPX thread */
1117 mov edx, [fs:KPCR_NPX_THREAD]
1121 /* Get the NPX Stack */
1122 mov esi, [edx+KTHREAD_INITIAL_STACK]
1123 sub esi, NPX_FRAME_LENGTH
1125 /* Check if we have FXSR and check which operand to use */
1126 test byte ptr _KeI386FxsrPresent, 1
1135 /* Set the thread's state to dirty */
1136 mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1139 /* Check if we have FXSR and choose which operand to use */
1140 test byte ptr _KeI386FxsrPresent, 1
1149 /* Set state loaded */
1150 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1151 mov [fs:KPCR_NPX_THREAD], eax
1153 /* Enable interrupts to happen now */
1157 /* Check if CR0 needs to be reloaded due to a context switch */
1158 cmp dword ptr [ecx+FN_CR0_NPX_STATE], 0
1159 jz _Kei386EoiHelper@0
1161 /* We have to reload CR0... disable interrupts */
1164 /* Get CR0 and update it */
1166 or ebx, [ecx+FN_CR0_NPX_STATE]
1169 /* Restore interrupts and check if TS is back on */
1172 jz _Kei386EoiHelper@0
1174 /* Clear TS, and loop handling again */
1181 /* Set delayed error */
1182 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
1184 /* Check if this happened during restore */
1185 cmp dword ptr [ebp+KTRAP_FRAME_EIP], offset FrRestore
1188 /* Skip instruction and dispatch the exception */
1189 add dword ptr [ebp+KTRAP_FRAME_EIP], 3
1190 jmp _Kei386EoiHelper@0
1193 /* Check if TS is set */
1195 jnz TsSetOnLoadedState
1198 /* Check if the trap came from V86 mode */
1199 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1202 /* Check if it came from kernel mode */
1203 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1206 /* Check if it came from a VDM */
1207 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1211 /* Get the current thread */
1212 mov eax, fs:[KPCR_CURRENT_THREAD]
1214 /* Check NPX state */
1215 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1217 /* Get the NPX save area */
1218 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1219 lea ecx, [ecx-NPX_FRAME_LENGTH]
1226 and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
1229 /* Check if we have FX support */
1230 test byte ptr _KeI386FxsrPresent, 1
1233 /* Save the state */
1241 /* Make CR0 state not loaded */
1242 or ebx, NPX_STATE_NOT_LOADED
1243 or ebx, [ecx+FN_CR0_NPX_STATE]
1246 /* Update NPX state */
1247 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1248 mov dword ptr fs:[KPCR_NPX_THREAD], 0
1251 /* Clear the TS bit and re-enable interrupts */
1252 and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
1255 /* Check if we have FX support */
1256 test byte ptr _KeI386FxsrPresent, 1
1259 /* Get error offset, control and status words */
1260 mov ebx, [ecx+FX_ERROR_OFFSET]
1261 movzx eax, word ptr [ecx+FX_CONTROL_WORD]
1262 movzx edx, word ptr [ecx+FX_STATUS_WORD]
1264 /* Get the faulting opcode */
1265 mov esi, [ecx+FX_DATA_OFFSET]
1269 /* Get error offset, control and status words */
1270 mov ebx, [ecx+FP_ERROR_OFFSET]
1271 movzx eax, word ptr [ecx+FP_CONTROL_WORD]
1272 movzx edx, word ptr [ecx+FP_STATUS_WORD]
1274 /* Get the faulting opcode */
1275 mov esi, [ecx+FP_DATA_OFFSET]
1278 /* Mask exceptions */
1283 /* Check if what's left is invalid */
1287 /* Check if it was a stack fault */
1291 /* Raise exception */
1292 mov eax, STATUS_FLOAT_INVALID_OPERATION
1293 jmp _DispatchOneParam
1297 /* Raise exception */
1298 mov eax, STATUS_FLOAT_STACK_CHECK
1299 jmp _DispatchTwoParam
1303 /* Check for divide by 0 */
1307 /* Raise exception */
1308 mov eax, STATUS_FLOAT_DIVIDE_BY_ZERO
1309 jmp _DispatchOneParam
1312 /* Check for denormal */
1316 /* Raise exception */
1317 mov eax, STATUS_FLOAT_INVALID_OPERATION
1318 jmp _DispatchOneParam
1321 /* Check for overflow */
1325 /* Raise exception */
1326 mov eax, STATUS_FLOAT_OVERFLOW
1327 jmp _DispatchOneParam
1330 /* Check for underflow */
1334 /* Raise exception */
1335 mov eax, STATUS_FLOAT_UNDERFLOW
1336 jmp _DispatchOneParam
1339 /* Check for precision fault */
1343 /* Raise exception */
1344 mov eax, STATUS_FLOAT_INEXACT_RESULT
1345 jmp _DispatchOneParam
1349 /* Strange result, bugcheck the OS */
1356 push TRAP_CAUSE_UNKNOWN
1357 call _KeBugCheckWithTf@24
1360 /* Check if this is a VDM */
1361 mov eax, fs:[KPCR_CURRENT_THREAD]
1362 mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
1363 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1366 /* V86 NPX not handled */
1371 /* Did this come from kernel-mode? */
1372 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1375 /* It came from user-mode, so this would only be valid inside a VDM */
1376 /* Since we don't actually have VDMs in ROS, bugcheck. */
1380 /* TS shouldn't be set, unless this we don't have a Math Processor */
1384 /* Strange that we got a trap at all, but ignore and continue */
1386 jmp _Kei386EoiHelper@0
1389 /* Cause a bugcheck */
1394 push TRAP_CAUSE_UNKNOWN
1395 call _KeBugCheckEx@20
1402 /* Can't really do too much */
1404 jmp _KiSystemFatalException
1409 /* Push error code */
1415 /* Enable interrupts and bugcheck */
1418 jmp _KiSystemFatalException
1427 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1430 /* Check if the frame was from kernelmode */
1431 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1435 /* Check if OF was set during iretd */
1436 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
1440 /* It was, just mask it out */
1441 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
1442 jmp _Kei386EoiHelper@0
1445 /* TSS failure for some other reason: crash */
1447 jmp _KiSystemFatalException
1455 /* FIXME: ROS Doesn't handle segment faults yet */
1457 jmp _KiSystemFatalException
1465 /* FIXME: ROS Doesn't handle stack faults yet */
1467 jmp _KiSystemFatalException
1473 /* It this a V86 GPF? */
1474 test dword ptr [esp+12], EFLAGS_V86_MASK
1477 /* Enter V86 Trap */
1478 V86_TRAP_PROLOG kitd
1480 /* Make sure that this is a V86 process */
1481 mov ecx, [fs:KPCR_CURRENT_THREAD]
1482 mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
1483 cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
1486 /* Otherwise, something is very wrong, raise an exception */
1488 mov ebx, [ebp+KTRAP_FRAME_EIP]
1490 mov eax, STATUS_ACCESS_VIOLATION
1491 jmp _DispatchTwoParam
1495 /* Go to APC level */
1499 /* Save old IRQL and enable interrupts */
1503 /* Handle the opcode */
1504 call _Ki386HandleOpcodeV86@0
1506 /* Check if this was VDM */
1515 /* Lower IRQL and disable interrupts */
1520 /* Check if this was a V86 trap */
1521 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1524 /* Exit the V86 Trap */
1529 /* Either this wasn't V86, or it was, but an APC interrupted us */
1530 jmp _Kei386EoiHelper@0
1536 /* Check if this was from kernel-mode */
1537 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1540 /* FIXME: Check for GPF during GPF */
1542 /* Get the opcode and trap frame */
1543 mov eax, [ebp+KTRAP_FRAME_EIP]
1545 mov edx, [ebp+KTRAP_FRAME_EBP]
1547 /* We want to check if this was POP [DS/ES/FS/GS] */
1548 add edx, KTRAP_FRAME_DS
1551 add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
1554 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1557 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1561 /* It isn't, was it IRETD? */
1565 /* Get error code */
1566 lea edx, [ebp+KTRAP_FRAME_ESP]
1567 mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
1571 mov cx, word ptr [edx+4]
1576 /* This should be a Ki386CallBios return */
1577 mov eax, offset _Ki386BiosCallReturnAddress
1581 cmp ax, KGDT_R0_CODE + RPL_MASK
1584 /* Jump to return address */
1585 jmp _Ki386BiosCallReturnAddress
1588 /* Check if the thread was in kernel mode */
1589 mov ebx, [fs:KPCR_CURRENT_THREAD]
1590 test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
1593 /* Set RPL_MASK for check below */
1594 or word ptr [edx+4], RPL_MASK
1597 /* Check if the IRET goes to user-mode */
1598 test dword ptr [edx+4], RPL_MASK
1601 /* Setup trap frame to copy */
1602 mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
1603 lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
1607 /* Copy each field */
1613 /* Enable interrupts and adjust stack */
1618 /* Setup exception record */
1619 mov ebx, [ebp+KTRAP_FRAME_EIP]
1620 mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
1622 mov eax, STATUS_ACCESS_VIOLATION
1623 jmp _DispatchTwoParam
1627 /* FIXME: Handle RDMSR/WRMSR */
1633 /* Check if this was an MSR opcode */
1637 /* Check if DS is Ring 3 */
1638 cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1641 /* Otherwise, fix it up */
1642 mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1647 /* Check if ES is Ring 3 */
1648 cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1651 /* Otherwise, fix it up */
1652 mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1658 lea eax, [ebp+KTRAP_FRAME_ESP]
1663 /* Handle segment POP fault by setting it to 0 */
1666 mov dword ptr [edx], eax
1670 /* Do a trap exit */
1671 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
1675 /* FIXME: Unhandled */
1685 /* Call the C exception handler */
1688 call _KiPageFaultHandler
1691 /* Return to caller */
1692 jmp _Kei386EoiHelper@0
1697 /* Push error code */
1704 /* Raise a fatal exception */
1706 jmp _KiSystemFatalException
1711 /* Push error code */
1717 /* Check if this is the NPX Thread */
1718 mov eax, fs:[KPCR_CURRENT_THREAD]
1719 cmp eax, fs:[KPCR_NPX_THREAD]
1721 /* Get the initial stack and NPX frame */
1722 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1723 lea ecx, [ecx-NPX_FRAME_LENGTH]
1725 /* If this is a valid fault, handle it */
1728 /* Otherwise, re-enable interrupts and set delayed error */
1730 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
1731 jmp _Kei386EoiHelper@0
1736 /* Push error code */
1742 /* FIXME: ROS Doesn't handle alignment faults yet */
1744 jmp _KiSystemFatalException
1747 .func KiSystemFatalException
1748 _KiSystemFatalException:
1750 /* Push the trap frame */
1753 /* Push empty parameters */
1758 /* Push trap number and bugcheck code */
1760 push UNEXPECTED_KERNEL_MODE_TRAP
1761 call _KeBugCheckWithTf@24
1765 .func KiCoprocessorError@0
1766 _KiCoprocessorError@0:
1768 /* Get the NPX Thread's Initial stack */
1769 mov eax, [fs:KPCR_NPX_THREAD]
1770 mov eax, [eax+KTHREAD_INITIAL_STACK]
1772 /* Make space for the FPU Save area */
1773 sub eax, SIZEOF_FX_SAVE_AREA
1775 /* Set the CR0 State */
1776 mov dword ptr [eax+FN_CR0_NPX_STATE], 8
1783 /* Return to caller */
1787 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
1789 .globl _KiStartUnexpectedRange@0
1790 _KiStartUnexpectedRange@0:
1792 GENERATE_INT_HANDLERS
1794 .globl _KiEndUnexpectedRange@0
1795 _KiEndUnexpectedRange@0:
1796 jmp _KiUnexpectedInterruptTail
1798 .func KiUnexpectedInterruptTail
1799 _KiUnexpectedInterruptTail:
1801 /* Enter interrupt trap */
1802 INT_PROLOG kui, DoNotPushFakeErrorCode
1804 /* Increase interrupt count */
1805 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1807 /* Put vector in EBX and make space for KIRQL */
1811 /* Begin interrupt */
1815 call _HalBeginSystemInterrupt@12
1817 /* Check if it was spurious or not */
1821 /* Spurious, ignore it */
1823 jmp _Kei386EoiHelper2ndEntry
1826 /* Unexpected interrupt, print a message on debug builds */
1829 push offset _UnexpectedMsg
1834 /* Exit the interrupt */
1837 call _HalEndSystemInterrupt@8
1838 jmp _Kei386EoiHelper@0
1841 .globl _KiUnexpectedInterrupt
1842 _KiUnexpectedInterrupt:
1844 /* Bugcheck with invalid interrupt code */
1845 push TRAP_CAUSE_UNKNOWN
1848 /* INTERRUPT HANDLERS ********************************************************/
1850 .func KiDispatchInterrupt@0
1851 _KiDispatchInterrupt@0:
1853 /* Get the PCR and disable interrupts */
1854 mov ebx, [fs:KPCR_SELF]
1857 /* Check if we have to deliver DPCs, timers, or deferred threads */
1858 mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
1859 or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
1860 or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
1863 /* Save stack pointer and exception list, then clear it */
1865 push dword ptr [ebx+KPCR_EXCEPTION_LIST]
1866 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
1868 /* Save the stack and switch to the DPC Stack */
1870 //mov esp, [ebx+KPCR_PRCB_DPC_STACK]
1874 mov ecx, [ebx+KPCR_PRCB]
1875 call @KiRetireDpcList@4
1877 /* Restore stack and exception list */
1884 /* Re-enable interrupts */
1887 /* Check if we have quantum end */
1888 cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
1891 /* Check if we have a thread to swap to */
1892 cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
1895 /* FIXME: Schedule new thread */
1903 /* Disable quantum end and process it */
1904 mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
1905 call _KiQuantumEnd@0
1909 .func KiInterruptTemplate
1910 _KiInterruptTemplate:
1912 /* Enter interrupt trap */
1913 INT_PROLOG kit, DoPushFakeErrorCode
1916 _KiInterruptTemplate2ndDispatch:
1917 /* Dummy code, will be replaced by the address of the KINTERRUPT */
1920 _KiInterruptTemplateObject:
1921 /* Dummy jump, will be replaced by the actual jump */
1922 jmp _KeSynchronizeExecution@12
1924 _KiInterruptTemplateDispatch:
1925 /* Marks the end of the template so that the jump above can be edited */
1927 .func KiChainedDispatch2ndLvl@0
1928 _KiChainedDispatch2ndLvl@0:
1930 /* Not yet supported */
1934 .func KiChainedDispatch@0
1935 _KiChainedDispatch@0:
1937 /* Increase interrupt count */
1938 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1940 /* Save trap frame */
1943 /* Save vector and IRQL */
1944 mov eax, [edi+KINTERRUPT_VECTOR]
1945 mov ecx, [edi+KINTERRUPT_IRQL]
1951 /* Begin interrupt */
1955 call _HalBeginSystemInterrupt@12
1957 /* Check if it was handled */
1961 /* Call the 2nd-level handler */
1962 call _KiChainedDispatch2ndLvl@0
1964 /* Exit the interrupt */
1967 call _HalEndSystemInterrupt@8
1968 jmp _Kei386EoiHelper@0
1971 .func KiInterruptDispatch@0
1972 _KiInterruptDispatch@0:
1974 /* Increase interrupt count */
1975 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1977 /* Save trap frame */
1980 /* Save vector and IRQL */
1981 mov eax, [edi+KINTERRUPT_VECTOR]
1982 mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
1988 /* Begin interrupt */
1992 call _HalBeginSystemInterrupt@12
1994 /* Check if it was handled */
1998 /* Acquire the lock */
2000 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
2001 ACQUIRE_SPINLOCK(esi, IntSpin)
2004 mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
2007 call [edi+KINTERRUPT_SERVICE_ROUTINE]
2009 /* Release the lock */
2010 RELEASE_SPINLOCK(esi)
2012 /* Exit the interrupt */
2014 call _HalEndSystemInterrupt@8
2015 jmp _Kei386EoiHelper@0
2018 /* Exit the interrupt */
2021 jmp _Kei386EoiHelper@0
2025 SPIN_ON_LOCK esi, GetIntLock