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
16 #define WrDispatchInt 0x1F
18 /* GLOBALS *******************************************************************/
23 /* This is the Software Interrupt Table that we handle in this file: */
24 idt _KiTrap0, INT_32_DPL0 /* INT 00: Divide Error (#DE) */
25 idt _KiTrap1, INT_32_DPL0 /* INT 01: Debug Exception (#DB) */
26 idt _KiTrap2, INT_32_DPL0 /* INT 02: NMI Interrupt */
27 idt _KiTrap3, INT_32_DPL3 /* INT 03: Breakpoint Exception (#BP) */
28 idt _KiTrap4, INT_32_DPL3 /* INT 04: Overflow Exception (#OF) */
29 idt _KiTrap5, INT_32_DPL0 /* INT 05: BOUND Range Exceeded (#BR) */
30 idt _KiTrap6, INT_32_DPL0 /* INT 06: Invalid Opcode Code (#UD) */
31 idt _KiTrap7, INT_32_DPL0 /* INT 07: Device Not Available (#NM) */
32 idt _KiTrap8, INT_32_DPL0 /* INT 08: Double Fault Exception (#DF) */
33 idt _KiTrap9, INT_32_DPL0 /* INT 09: RESERVED */
34 idt _KiTrap10, INT_32_DPL0 /* INT 0A: Invalid TSS Exception (#TS) */
35 idt _KiTrap11, INT_32_DPL0 /* INT 0B: Segment Not Present (#NP) */
36 idt _KiTrap12, INT_32_DPL0 /* INT 0C: Stack Fault Exception (#SS) */
37 idt _KiTrap13, INT_32_DPL0 /* INT 0D: General Protection (#GP) */
38 idt _KiTrap14, INT_32_DPL0 /* INT 0E: Page-Fault Exception (#PF) */
39 idt _KiTrap0F, INT_32_DPL0 /* INT 0F: RESERVED */
40 idt _KiTrap16, INT_32_DPL0 /* INT 10: x87 FPU Error (#MF) */
41 idt _KiTrap17, INT_32_DPL0 /* INT 11: Align Check Exception (#AC) */
42 idt _KiTrap0F, INT_32_DPL0 /* INT 12: Machine Check Exception (#MC)*/
43 idt _KiTrap0F, INT_32_DPL0 /* INT 13: SIMD FPU Exception (#XF) */
45 idt _KiTrap0F, INT_32_DPL0 /* INT 14-29: UNDEFINED INTERRUPTS */
47 idt _KiGetTickCount, INT_32_DPL3 /* INT 2A: Get Tick Count Handler */
48 idt _KiCallbackReturn, INT_32_DPL3 /* INT 2B: User-Mode Callback Return */
49 idt _KiRaiseAssertion, INT_32_DPL3 /* INT 2C: Debug Assertion Handler */
50 idt _KiDebugService, INT_32_DPL3 /* INT 2D: Debug Service Handler */
51 idt _KiSystemService, INT_32_DPL3 /* INT 2E: System Call Service Handler */
52 idt _KiTrap0F, INT_32_DPL0 /* INT 2F: RESERVED */
53 GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
55 /* System call entrypoints: */
56 .globl _KiFastCallEntry
57 .globl _KiSystemService
59 /* And special system-defined software traps: */
60 .globl _NtRaiseException@12
62 .globl _KiCoprocessorError@0
63 .globl _KiDispatchInterrupt@0
65 /* Interrupt template entrypoints */
66 .globl _KiInterruptTemplate
67 .globl _KiInterruptTemplateObject
68 .globl _KiInterruptTemplateDispatch
70 /* Chained and Normal generic interrupt handlers for 1st and 2nd level entry*/
71 .globl _KiChainedDispatch2ndLvl@0
72 .globl _KiInterruptDispatch@0
73 .globl _KiChainedDispatch@0
75 /* We implement the following trap exit points: */
76 .globl _KiServiceExit /* Exit from syscall */
77 .globl _KiServiceExit2 /* Exit from syscall with complete frame*/
78 .globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
79 .globl _Kei386EoiHelper2ndEntry /* Exit from unexpected interrupt */
81 .globl _KiIdtDescriptor
87 .globl _KiUnexpectedEntrySize
88 _KiUnexpectedEntrySize:
89 .long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
92 .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
95 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
98 .asciz "\n*** ISR at %lx took over .5 second\n"
101 .asciz "\n*** ISR at %lx appears to have an interrupt storm\n"
105 .byte 0xF3 /* REP INS/OUTS */
106 .byte 0x67 /* ADDR */
107 .byte 0xF0 /* LOCK */
127 .byte 0x6E /* OUTS */
128 .byte 0x6F /* OUTS */
130 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
139 .func KiSystemService
140 TRAP_FIXUPS kss_a, kss_t, DoNotFixupV86, DoNotFixupAbios
143 /* Enter the shared system call prolog */
144 SYSCALL_PROLOG kss_a, kss_t
146 /* Jump to the actual handler */
150 .func KiFastCallEntry
151 TRAP_FIXUPS FastCallDrSave, FastCallDrReturn, DoNotFixupV86, DoNotFixupAbios
154 /* Enter the fast system call prolog */
155 FASTCALL_PROLOG FastCallDrSave, FastCallDrReturn
160 * Find out which table offset to use. Converts 0x1124 into 0x10.
161 * The offset is related to the Table Index as such: Offset = TableIndex x 10
164 shr edi, SERVICE_TABLE_SHIFT
165 and edi, SERVICE_TABLE_MASK
168 /* Now add the thread's base system table to the offset */
169 add edi, [esi+KTHREAD_SERVICE_TABLE]
171 /* Get the true syscall ID and check it */
173 and eax, SERVICE_NUMBER_MASK
174 cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT]
176 /* Invalid ID, try to load Win32K Table */
177 jnb KiBBTUnexpectedRange
179 /* Check if this was Win32K */
180 cmp ecx, SERVICE_TABLE_TEST
184 mov ecx, PCR[KPCR_TEB]
186 /* Check if we should flush the User Batch */
189 or ebx, [ecx+TEB_GDI_BATCH_COUNT]
195 call [_KeGdiFlushUserBatch]
200 /* Increase total syscall count */
201 inc dword ptr PCR[KPCR_SYSTEM_CALLS]
204 /* Increase per-syscall count */
205 mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT]
207 inc dword ptr [ecx+eax*4]
210 /* Users's current stack frame pointer is source */
214 /* Allocate room for argument list from kernel stack */
215 mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER]
219 /* Get pointer to function */
220 mov edi, [edi+SERVICE_DESCRIPTOR_BASE]
223 /* Allocate space on our stack */
226 /* Set the size of the arguments and the destination */
230 /* Make sure we're within the User Probe Address */
231 cmp esi, _MmUserProbeAddress
235 /* Copy the parameters */
238 /* Do the System Call */
243 /* Make sure the user-mode call didn't return at elevated IRQL */
244 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
246 mov esi, eax /* We need to save the syscall's return val */
247 call _KeGetCurrentIrql@0
250 mov eax, esi /* Restore it */
252 /* Get our temporary current thread pointer for sanity check */
253 mov ecx, PCR[KPCR_CURRENT_THREAD]
255 /* Make sure that we are not attached and that APCs are not disabled */
256 mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
259 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
266 /* Deallocate the kernel stack frame */
269 KeReturnFromSystemCall:
271 /* Get the Current Thread */
272 mov ecx, PCR[KPCR_CURRENT_THREAD]
274 /* Restore the old trap frame pointer */
275 mov edx, [ebp+KTRAP_FRAME_EDX]
276 mov [ecx+KTHREAD_TRAP_FRAME], edx
281 /* Disable interrupts */
284 /* Check for, and deliver, User-Mode APCs if needed */
285 CHECK_FOR_APC_DELIVER 1
287 /* Exit and cleanup */
288 TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything
291 KiBBTUnexpectedRange:
293 /* If this isn't a Win32K call, fail */
294 cmp ecx, SERVICE_TABLE_TEST
297 /* Set up Win32K Table */
300 call _PsConvertToGuiThread@0
302 /* Check return code */
305 /* Restore registers */
309 /* Reset trap frame address */
311 mov [esi+KTHREAD_TRAP_FRAME], ebp
313 /* Try the Call again, if we suceeded */
317 * The Shadow Table should have a special byte table which tells us
318 * whether we should return FALSE, -1 or STATUS_INVALID_SYSTEM_SERVICE.
321 /* Get the table limit and base */
322 lea edx, _KeServiceDescriptorTableShadow + SERVICE_TABLE_TEST
323 mov ecx, [edx+SERVICE_DESCRIPTOR_LIMIT]
324 mov edx, [edx+SERVICE_DESCRIPTOR_BASE]
326 /* Get the table address and add our index into the array */
328 and eax, SERVICE_NUMBER_MASK
331 /* Find out what we should return */
332 movsx eax, byte ptr [edx]
335 /* Return either 0 or -1, we've set it in EAX */
336 jle KeReturnFromSystemCall
338 /* Set STATUS_INVALID_SYSTEM_SERVICE */
339 mov eax, STATUS_INVALID_SYSTEM_SERVICE
340 jmp KeReturnFromSystemCall
344 /* Invalid System Call */
345 mov eax, STATUS_INVALID_SYSTEM_SERVICE
346 jmp KeReturnFromSystemCall
350 /* Check if this came from kernel-mode */
351 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
353 /* It's fine, go ahead with it */
356 /* Caller sent invalid parameters, fail here */
357 mov eax, STATUS_ACCESS_VIOLATION
362 /* Restore ESP0 stack */
363 mov ecx, PCR[KPCR_TSS]
364 mov esp, ss:[ecx+KTSS_ESP0]
366 /* Generate V86M Stack for Trap 6 */
372 /* Generate interrupt stack for Trap 6 */
373 push KGDT_R3_DATA + RPL_MASK
376 push KGDT_R3_CODE + RPL_MASK
382 /* Save current IRQL */
385 /* Set us at passive */
386 mov dword ptr PCR[KPCR_IRQL], 0
394 push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
395 call _KeBugCheckEx@20
399 /* Get the index and APC state */
400 movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX]
401 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
408 push APC_INDEX_MISMATCH
409 call _KeBugCheckEx@20
416 /* Disable interrupts */
419 /* Check for, and deliver, User-Mode APCs if needed */
420 CHECK_FOR_APC_DELIVER 0
422 /* Exit and cleanup */
423 TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
426 .func Kei386EoiHelper@0
429 /* Disable interrupts */
432 /* Check for, and deliver, User-Mode APCs if needed */
433 CHECK_FOR_APC_DELIVER 0
435 /* Exit and cleanup */
436 _Kei386EoiHelper2ndEntry:
437 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
441 /* Move to EDX position */
442 add esp, KTRAP_FRAME_EDX
444 /* Restore volatiles */
449 /* Move to non-volatiles */
450 lea esp, [ebp+KTRAP_FRAME_EDI]
456 /* Skip error code and return */
465 TRAP_FIXUPS kids_a, kids_t, DoFixupV86, DoFixupAbios
468 /* Push error code */
472 TRAP_PROLOG kids_a, kids_t
474 /* Increase EIP so we skip the INT3 */
475 inc dword ptr [ebp+KTRAP_FRAME_EIP]
477 /* Call debug service dispatcher */
478 mov eax, [ebp+KTRAP_FRAME_EAX]
479 mov ecx, [ebp+KTRAP_FRAME_ECX]
480 mov edx, [ebp+KTRAP_FRAME_EDX]
482 /* Jump to INT3 handler */
486 .func NtRaiseException@12
487 _NtRaiseException@12:
489 /* NOTE: We -must- be called by Zw* to have the right frame! */
490 /* Push the stack frame */
493 /* Get the current thread and restore its trap frame */
494 mov ebx, PCR[KPCR_CURRENT_THREAD]
495 mov edx, [ebp+KTRAP_FRAME_EDX]
496 mov [ebx+KTHREAD_TRAP_FRAME], edx
498 /* Set up stack frame */
501 /* Get the Trap Frame in EBX */
504 /* Get the exception list and restore */
505 mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
506 mov PCR[KPCR_EXCEPTION_LIST], eax
508 /* Get the parameters */
509 mov edx, [ebp+16] /* Search frames */
510 mov ecx, [ebp+12] /* Context */
511 mov eax, [ebp+8] /* Exception Record */
513 /* Raise the exception */
519 call _KiRaiseException@20
521 /* Restore trap frame in EBP */
525 /* Check the result */
529 /* Restore debug registers too */
536 /* NOTE: We -must- be called by Zw* to have the right frame! */
537 /* Push the stack frame */
540 /* Get the current thread and restore its trap frame */
541 mov ebx, PCR[KPCR_CURRENT_THREAD]
542 mov edx, [ebp+KTRAP_FRAME_EDX]
543 mov [ebx+KTHREAD_TRAP_FRAME], edx
545 /* Set up stack frame */
548 /* Save the parameters */
552 /* Call KiContinue */
558 /* Check if we failed (bad context record) */
562 /* Check if test alert was requested */
563 cmp dword ptr [ebp+12], 0
566 /* Test alert for the thread */
567 mov al, [ebx+KTHREAD_PREVIOUS_MODE]
569 call _KeTestAlertThread@4
572 /* Return to previous context */
583 /* EXCEPTION DISPATCHERS *****************************************************/
585 .func CommonDispatchException
586 _CommonDispatchException:
588 /* Make space for an exception record */
589 sub esp, EXCEPTION_RECORD_LENGTH
592 mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
594 mov [esp+EXCEPTION_RECORD_EXCEPTION_FLAGS], eax
595 mov [esp+EXCEPTION_RECORD_EXCEPTION_RECORD], eax
596 mov [esp+EXCEPTION_RECORD_EXCEPTION_ADDRESS], ebx
597 mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
599 /* Check parameter count */
603 /* Get information */
604 lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
611 /* Set the record in ECX and check if this was V86 */
613 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
622 /* Get the caller's CS */
623 mov eax, [ebp+KTRAP_FRAME_CS]
626 /* Check if it was user-mode or kernel-mode */
629 /* Dispatch the exception */
635 call _KiDispatchException@20
639 jmp _Kei386EoiHelper@0
642 .func DispatchNoParam
644 /* Call the common dispatcher */
646 call _CommonDispatchException
649 .func DispatchOneParamZero
650 _DispatchOneParamZero:
651 /* Call the common dispatcher */
654 call _CommonDispatchException
657 .func DispatchTwoParamZero
658 _DispatchTwoParamZero:
659 /* Call the common dispatcher */
662 call _CommonDispatchException
665 .func DispatchTwoParam
667 /* Call the common dispatcher */
669 call _CommonDispatchException
672 /* HARDWARE TRAP HANDLERS ****************************************************/
677 /* TODO: Routine to fixup a KTRAP_FRAME when faulting from a syscall. */
682 TRAP_FIXUPS kit0_a, kit0_t, DoFixupV86, DoNotFixupAbios
684 /* Push error code */
688 TRAP_PROLOG kit0_a, kit0_t
691 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
694 /* Check if the frame was from kernelmode */
695 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
698 /* Check the old mode */
699 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
703 /* Re-enable interrupts for user-mode and send the exception */
705 mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
706 mov ebx, [ebp+KTRAP_FRAME_EIP]
710 /* Check if this is a VDM process */
711 mov ebx, PCR[KPCR_CURRENT_THREAD]
712 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
713 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
716 /* We don't support this yet! */
723 TRAP_FIXUPS kit1_a, kit1_t, DoFixupV86, DoNotFixupAbios
725 /* Push error code */
729 TRAP_PROLOG kit1_a, kit1_t
732 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
735 /* Check if the frame was from kernelmode */
736 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
739 /* Check the old mode */
740 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
744 /* Enable interrupts for user-mode */
748 /* Prepare the exception */
749 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAGS_TF
750 mov ebx, [ebp+KTRAP_FRAME_EIP]
751 mov eax, STATUS_SINGLE_STEP
755 /* Check if this is a VDM process */
756 mov ebx, PCR[KPCR_CURRENT_THREAD]
757 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
758 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
761 /* We don't support VDM! */
769 /* FIXME: This is an NMI, nothing like a normal exception */
771 jmp _KiSystemFatalException
775 TRAP_FIXUPS kit3_a, kit3_t, DoFixupV86, DoNotFixupAbios
777 /* Push error code */
781 TRAP_PROLOG kit3_a, kit3_t
783 /* Set status code */
784 mov eax, 0 //STATUS_SUCCESS
788 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
791 /* Check if the frame was from kernelmode */
792 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
795 /* Check the old mode */
796 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
800 /* Enable interrupts for user-mode */
805 /* Prepare the exception */
810 /* Setup EIP, NTSTATUS and parameter count, then dispatch */
811 mov ebx, [ebp+KTRAP_FRAME_EIP]
814 mov eax, STATUS_BREAKPOINT
815 call _CommonDispatchException
818 /* Check if this is a VDM process */
819 mov ebx, PCR[KPCR_CURRENT_THREAD]
820 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
821 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
824 /* We don't support VDM! */
829 TRAP_FIXUPS kit4_a, kit4_t, DoFixupV86, DoNotFixupAbios
831 /* Push error code */
835 TRAP_PROLOG kit4_a, kit4_t
838 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
841 /* Check if the frame was from kernelmode */
842 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
845 /* Check the old mode */
846 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
850 /* Re-enable interrupts for user-mode and send the exception */
852 mov eax, STATUS_INTEGER_OVERFLOW
853 mov ebx, [ebp+KTRAP_FRAME_EIP]
858 /* Check if this is a VDM process */
859 mov ebx, PCR[KPCR_CURRENT_THREAD]
860 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
861 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
864 /* We don't support this yet! */
870 TRAP_FIXUPS kit5_a, kit5_t, DoFixupV86, DoNotFixupAbios
872 /* Push error code */
876 TRAP_PROLOG kit5_a, kit5_t
879 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
882 /* Check if the frame was from kernelmode */
883 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
886 /* It did, and this should never happen */
888 jmp _KiSystemFatalException
890 /* Check the old mode */
892 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
895 /* Re-enable interrupts for user-mode and send the exception */
898 mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
899 mov ebx, [ebp+KTRAP_FRAME_EIP]
903 /* Check if this is a VDM process */
904 mov ebx, PCR[KPCR_CURRENT_THREAD]
905 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
906 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
909 /* We don't support this yet! */
915 TRAP_FIXUPS kit6_a, kit6_t, DoFixupV86, DoNotFixupAbios
918 /* It this a V86 GPF? */
919 test dword ptr [esp+8], EFLAGS_V86_MASK
923 V86_TRAP_PROLOG kit6_a, kit6_v
925 /* Not yet supported (Invalid OPCODE from V86) */
929 /* Push error code */
933 TRAP_PROLOG kit6_a, kit6_t
935 /* Check if this happened in kernel mode */
936 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
940 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
943 /* Check if the process is vDM */
944 mov ebx, PCR[KPCR_CURRENT_THREAD]
945 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
946 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
950 /* Get EIP and enable interrupts at this point */
951 mov esi, [ebp+KTRAP_FRAME_EIP]
954 /* Set intruction prefix length */
957 /* Setup a SEH frame */
960 push PCR[KPCR_EXCEPTION_LIST]
961 mov PCR[KPCR_EXCEPTION_LIST], esp
964 /* Get the instruction and check if it's LOCK */
974 pop PCR[KPCR_EXCEPTION_LIST]
979 /* Re-enable interrupts */
982 /* Setup illegal instruction exception and dispatch it */
983 mov ebx, [ebp+KTRAP_FRAME_EIP]
984 mov eax, STATUS_ILLEGAL_INSTRUCTION
990 pop PCR[KPCR_EXCEPTION_LIST]
993 /* Setup invalid lock exception and dispatch it */
994 mov ebx, [ebp+KTRAP_FRAME_EIP]
995 mov eax, STATUS_INVALID_LOCK_SEQUENCE
1003 /* Return to caller */
1004 jmp _Kei386EoiHelper@0
1010 pop PCR[KPCR_EXCEPTION_LIST]
1014 /* Check if this was user mode */
1015 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1024 push KMODE_EXCEPTION_NOT_HANDLED
1025 call _KeBugCheckWithTf@24
1029 TRAP_FIXUPS kit7_a, kit7_t, DoFixupV86, DoNotFixupAbios
1031 /* Push error code */
1035 TRAP_PROLOG kit7_a, kit7_t
1037 /* Get the current thread and stack */
1039 mov eax, PCR[KPCR_CURRENT_THREAD]
1040 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1041 sub ecx, NPX_FRAME_LENGTH
1043 /* Check if emulation is enabled */
1044 test byte ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
1045 jnz EmulationEnabled
1048 /* Check if the NPX state is loaded */
1049 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1054 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
1057 /* Check the NPX thread */
1058 mov edx, PCR[KPCR_NPX_THREAD]
1062 /* Get the NPX Stack */
1063 mov esi, [edx+KTHREAD_INITIAL_STACK]
1064 sub esi, NPX_FRAME_LENGTH
1066 /* Check if we have FXSR and check which operand to use */
1067 test byte ptr _KeI386FxsrPresent, 1
1076 /* Set the thread's state to dirty */
1077 mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1080 /* Check if we have FXSR and choose which operand to use */
1081 test byte ptr _KeI386FxsrPresent, 1
1090 /* Set state loaded */
1091 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1092 mov PCR[KPCR_NPX_THREAD], eax
1094 /* Enable interrupts to happen now */
1098 /* Check if CR0 needs to be reloaded due to a context switch */
1099 cmp dword ptr [ecx+FN_CR0_NPX_STATE], 0
1100 jz _Kei386EoiHelper@0
1102 /* We have to reload CR0... disable interrupts */
1105 /* Get CR0 and update it */
1107 or ebx, [ecx+FN_CR0_NPX_STATE]
1110 /* Restore interrupts and check if TS is back on */
1113 jz _Kei386EoiHelper@0
1115 /* Clear TS, and loop handling again */
1122 /* Set delayed error */
1123 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
1125 /* Check if this happened during restore */
1126 cmp dword ptr [ebp+KTRAP_FRAME_EIP], offset FrRestore
1129 /* Skip instruction and dispatch the exception */
1130 add dword ptr [ebp+KTRAP_FRAME_EIP], 3
1131 jmp _Kei386EoiHelper@0
1134 /* Check if TS is set */
1136 jnz TsSetOnLoadedState
1139 /* Check if the trap came from V86 mode */
1140 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1143 /* Check if it came from kernel mode */
1144 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1147 /* Check if it came from a VDM */
1148 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1152 /* Get the current thread */
1153 mov eax, PCR[KPCR_CURRENT_THREAD]
1155 /* Check NPX state */
1156 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1158 /* Get the NPX save area */
1159 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1160 lea ecx, [ecx-NPX_FRAME_LENGTH]
1167 and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
1170 /* Check if we have FX support */
1171 test byte ptr _KeI386FxsrPresent, 1
1174 /* Save the state */
1182 /* Make CR0 state not loaded */
1183 or ebx, NPX_STATE_NOT_LOADED
1184 or ebx, [ecx+FN_CR0_NPX_STATE]
1187 /* Update NPX state */
1188 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1189 mov dword ptr PCR[KPCR_NPX_THREAD], 0
1192 /* Clear the TS bit and re-enable interrupts */
1193 and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
1196 /* Check if we have FX support */
1197 test byte ptr _KeI386FxsrPresent, 1
1200 /* Get error offset, control and status words */
1201 mov ebx, [ecx+FX_ERROR_OFFSET]
1202 movzx eax, word ptr [ecx+FX_CONTROL_WORD]
1203 movzx edx, word ptr [ecx+FX_STATUS_WORD]
1205 /* Get the faulting opcode */
1206 mov esi, [ecx+FX_DATA_OFFSET]
1210 /* Get error offset, control and status words */
1211 mov ebx, [ecx+FP_ERROR_OFFSET]
1212 movzx eax, word ptr [ecx+FP_CONTROL_WORD]
1213 movzx edx, word ptr [ecx+FP_STATUS_WORD]
1215 /* Get the faulting opcode */
1216 mov esi, [ecx+FP_DATA_OFFSET]
1219 /* Mask exceptions */
1224 /* Check if what's left is invalid */
1228 /* Check if it was a stack fault */
1232 /* Raise exception */
1233 mov eax, STATUS_FLOAT_INVALID_OPERATION
1234 jmp _DispatchOneParamZero
1238 /* Raise exception */
1239 mov eax, STATUS_FLOAT_STACK_CHECK
1240 jmp _DispatchTwoParamZero
1244 /* Check for divide by 0 */
1248 /* Raise exception */
1249 mov eax, STATUS_FLOAT_DIVIDE_BY_ZERO
1250 jmp _DispatchOneParamZero
1253 /* Check for denormal */
1257 /* Raise exception */
1258 mov eax, STATUS_FLOAT_INVALID_OPERATION
1259 jmp _DispatchOneParamZero
1262 /* Check for overflow */
1266 /* Raise exception */
1267 mov eax, STATUS_FLOAT_OVERFLOW
1268 jmp _DispatchOneParamZero
1271 /* Check for underflow */
1275 /* Raise exception */
1276 mov eax, STATUS_FLOAT_UNDERFLOW
1277 jmp _DispatchOneParamZero
1280 /* Check for precision fault */
1284 /* Raise exception */
1285 mov eax, STATUS_FLOAT_INEXACT_RESULT
1286 jmp _DispatchOneParamZero
1290 /* Strange result, bugcheck the OS */
1297 push TRAP_CAUSE_UNKNOWN
1298 call _KeBugCheckWithTf@24
1301 /* Check if this is a VDM */
1302 mov eax, PCR[KPCR_CURRENT_THREAD]
1303 mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
1304 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1307 /* V86 NPX not handled */
1311 /* Did this come from kernel-mode? */
1312 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1315 /* It came from user-mode, so this would only be valid inside a VDM */
1316 /* Since we don't actually have VDMs in ROS, bugcheck. */
1320 /* TS shouldn't be set, unless this we don't have a Math Processor */
1324 /* Strange that we got a trap at all, but ignore and continue */
1326 jmp _Kei386EoiHelper@0
1329 /* Cause a bugcheck */
1334 push TRAP_CAUSE_UNKNOWN
1335 call _KeBugCheckEx@20
1342 /* Can't really do too much */
1344 jmp _KiSystemFatalException
1348 TRAP_FIXUPS kit9_a, kit9_t, DoFixupV86, DoNotFixupAbios
1350 /* Push error code */
1354 TRAP_PROLOG kit9_a, kit9_t
1356 /* Enable interrupts and bugcheck */
1359 jmp _KiSystemFatalException
1363 TRAP_FIXUPS kita_a, kita_t, DoFixupV86, DoNotFixupAbios
1366 TRAP_PROLOG kita_a, kita_t
1369 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1372 /* Check if the frame was from kernelmode */
1373 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1377 /* Check if OF was set during iretd */
1378 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
1382 /* It was, just mask it out */
1383 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
1384 jmp _Kei386EoiHelper@0
1387 /* TSS failure for some other reason: crash */
1389 jmp _KiSystemFatalException
1393 TRAP_FIXUPS kitb_a, kitb_t, DoFixupV86, DoNotFixupAbios
1396 TRAP_PROLOG kitb_a, kitb_t
1398 /* FIXME: ROS Doesn't handle segment faults yet */
1400 jmp _KiSystemFatalException
1404 TRAP_FIXUPS kitc_a, kitc_t, DoFixupV86, DoNotFixupAbios
1407 TRAP_PROLOG kitc_a, kitc_t
1409 /* FIXME: ROS Doesn't handle stack faults yet */
1411 jmp _KiSystemFatalException
1414 .func KiTrapExceptHandler
1415 _KiTrapExceptHandler:
1417 /* Setup SEH handler frame */
1419 pop PCR[KPCR_EXCEPTION_LIST]
1423 /* Check if the fault came from user mode */
1424 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1427 /* Kernel fault, bugcheck */
1433 push KMODE_EXCEPTION_NOT_HANDLED
1434 call _KeBugCheckWithTf@24
1438 TRAP_FIXUPS kitd_a, kitd_t, DoFixupV86, DoNotFixupAbios
1441 /* It this a V86 GPF? */
1442 test dword ptr [esp+12], EFLAGS_V86_MASK
1445 /* Enter V86 Trap */
1446 V86_TRAP_PROLOG kitd_a, kitd_v
1448 /* Make sure that this is a V86 process */
1449 mov ecx, PCR[KPCR_CURRENT_THREAD]
1450 mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
1451 cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
1454 /* Otherwise, something is very wrong, raise an exception */
1460 /* Go to APC level */
1464 /* Save old IRQL and enable interrupts */
1468 /* Handle the opcode */
1469 call _Ki386HandleOpcodeV86@0
1471 /* Check if this was VDM */
1480 /* Lower IRQL and disable interrupts */
1485 /* Check if this was a V86 trap */
1486 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1489 /* Exit the V86 Trap */
1494 /* Either this wasn't V86, or it was, but an APC interrupted us */
1495 jmp _Kei386EoiHelper@0
1499 TRAP_PROLOG kitd_a, kitd_t
1501 /* Check if this was from kernel-mode */
1502 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1505 /* Check if we have a VDM alert */
1506 cmp dword ptr PCR[KPCR_VDM_ALERT], 0
1509 /* Check for GPF during GPF */
1510 mov eax, [ebp+KTRAP_FRAME_EIP]
1511 cmp eax, offset CheckPrivilegedInstruction
1513 cmp eax, offset CheckPrivilegedInstruction2
1518 /* Get the opcode and trap frame */
1520 mov eax, [ebp+KTRAP_FRAME_EIP]
1522 mov edx, [ebp+KTRAP_FRAME_EBP]
1524 /* We want to check if this was POP [DS/ES/FS/GS] */
1525 add edx, KTRAP_FRAME_DS
1528 add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
1531 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1534 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1538 /* It isn't, was it IRETD? */
1542 /* Get error code */
1543 lea edx, [ebp+KTRAP_FRAME_ESP]
1544 mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
1548 mov cx, word ptr [edx+4]
1553 /* This should be a Ki386CallBios return */
1554 mov eax, offset _Ki386BiosCallReturnAddress
1558 cmp ax, KGDT_R0_CODE + RPL_MASK
1561 /* Jump to return address */
1562 jmp _Ki386BiosCallReturnAddress
1565 /* Check if the thread was in kernel mode */
1566 mov ebx, PCR[KPCR_CURRENT_THREAD]
1567 test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
1570 /* Set RPL_MASK for check below */
1571 or word ptr [edx+4], RPL_MASK
1574 /* Check if the IRET goes to user-mode */
1575 test dword ptr [edx+4], RPL_MASK
1578 /* Setup trap frame to copy */
1579 mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
1580 lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
1584 /* Copy each field */
1590 /* Enable interrupts and adjust stack */
1595 /* Setup exception record */
1596 mov ebx, [ebp+KTRAP_FRAME_EIP]
1597 mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
1599 mov eax, STATUS_ACCESS_VIOLATION
1600 jmp _DispatchTwoParamZero
1604 /* FIXME: Handle RDMSR/WRMSR */
1609 /* Check if this was an MSR opcode */
1613 /* Check if DS is Ring 3 */
1614 cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1617 /* Otherwise, fix it up */
1618 mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1623 /* Check if ES is Ring 3 */
1624 cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1627 /* Otherwise, fix it up */
1628 mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1634 lea eax, [ebp+KTRAP_FRAME_ESP]
1639 /* Handle segment POP fault by setting it to 0 */
1642 mov dword ptr [edx], eax
1646 /* Do a trap exit */
1647 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
1651 /* If the previous mode was kernel, raise a fatal exception */
1653 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1654 jz _KiSystemFatalException
1656 /* Get the process and check which CS this came from */
1657 mov ebx, PCR[KPCR_CURRENT_THREAD]
1658 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
1659 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1662 /* Check if this is a VDM */
1663 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1666 /* Enable interrupts and check if we have an error code */
1668 cmp word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0
1670 jmp CheckPrivilegedInstruction
1673 /* Update EIP (will be updated below again) */
1674 add dword ptr [ebp+KTRAP_FRAME_EIP], 1
1677 /* Clear the segment, update EIP and ESP */
1678 mov dword ptr [edx], 0
1679 add dword ptr [ebp+KTRAP_FRAME_EIP], 1
1680 add dword ptr [ebp+KTRAP_FRAME_ESP], 4
1681 jmp _Kei386EoiHelper@0
1684 /* Check if this is a VDM */
1685 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1686 jz CheckPrivilegedInstruction
1688 /* Bring interrupts back */
1691 /* Check what kind of instruction this is */
1692 mov eax, [ebp+KTRAP_FRAME_EIP]
1695 /* FIXME: Check for BOP4 */
1697 /* Check if this is POP ES */
1699 add edx, KTRAP_FRAME_ES
1703 /* Check if this is POP FS */
1704 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1708 /* Check if this is POP GS */
1709 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1713 CheckPrivilegedInstruction:
1714 /* Bring interrupts back */
1717 /* Setup a SEH handler */
1719 push offset _KiTrapExceptHandler
1720 push PCR[KPCR_EXCEPTION_LIST]
1721 mov PCR[KPCR_EXCEPTION_LIST], esp
1724 mov esi, [ebp+KTRAP_FRAME_EIP]
1726 /* Setup loop count */
1730 /* Save loop count */
1733 /* Get the instruction */
1736 /* Now lookup in the prefix table */
1738 mov edi, offset _KiTrapPrefixTable
1741 /* Restore loop count */
1744 /* If it's not a prefix byte, check other instructions */
1750 /* Fixup the stack */
1751 pop PCR[KPCR_EXCEPTION_LIST]
1754 /* Illegal instruction */
1758 /* Check if it's a HLT */
1760 je IsPrivInstruction
1762 /* Check if the instruction has two bytes */
1766 /* Check if this is a LLDT or LTR */
1771 /* Check if this is an LLDT */
1775 je IsPrivInstruction
1777 /* Check if this is an LTR */
1779 je IsPrivInstruction
1781 /* Otherwise, access violation */
1785 /* Check if this is LGDT or LIDT or LMSW */
1789 /* Check if this is an LGDT */
1793 je IsPrivInstruction
1795 /* Check if this is an LIDT */
1797 je IsPrivInstruction
1799 /* Check if this is an LMSW */
1801 je IsPrivInstruction
1803 /* Otherwise, access violation */
1807 /* Check if it's INVD or WBINVD */
1809 je IsPrivInstruction
1811 je IsPrivInstruction
1813 /* Check if it's sysexit */
1815 je IsPrivInstruction
1817 /* Check if it's a DR move */
1819 je IsPrivInstruction
1821 /* Check if it's a CLTS */
1823 je IsPrivInstruction
1825 /* Check if it's a CR move */
1829 /* Check if it's a DR move */
1831 jbe IsPrivInstruction
1833 /* Everything else is an access violation */
1837 /* Get EFLAGS and IOPL */
1838 mov ebx, [ebp+KTRAP_FRAME_EFLAGS]
1839 and ebx, EFLAGS_IOPL
1842 /* Check the CS's RPL mask */
1843 mov ecx, [ebp+KTRAP_FRAME_CS]
1848 CheckPrivilegedInstruction2:
1849 /* Check if this is a CLI or STI */
1851 je IsPrivInstruction
1853 je IsPrivInstruction
1855 /* Setup I/O table lookup */
1857 mov edi, offset _KiTrapIoTable
1859 /* Loopup in the table */
1863 /* FIXME: Check IOPM!!! */
1866 /* Cleanup the SEH frame */
1867 pop PCR[KPCR_EXCEPTION_LIST]
1870 /* Setup the exception */
1871 mov ebx, [ebp+KTRAP_FRAME_EIP]
1872 mov eax, STATUS_PRIVILEGED_INSTRUCTION
1873 jmp _DispatchNoParam
1876 /* Cleanup the SEH frame */
1877 pop PCR[KPCR_EXCEPTION_LIST]
1881 /* Setup the exception */
1882 mov ebx, [ebp+KTRAP_FRAME_EIP]
1884 mov eax, STATUS_ACCESS_VIOLATION
1885 jmp _DispatchTwoParamZero
1893 TRAP_FIXUPS kite_a, kite_t, DoFixupV86, DoNotFixupAbios
1897 TRAP_PROLOG kite_a, kite_t
1899 /* Check if we have a VDM alert */
1900 cmp dword ptr PCR[KPCR_VDM_ALERT], 0
1903 /* Get the current thread */
1904 mov edi, PCR[KPCR_CURRENT_THREAD]
1906 /* Get the stack address of the frame */
1907 lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH]
1908 sub eax, [edi+KTHREAD_INITIAL_STACK]
1911 /* This isn't the base frame, check if it's the second */
1912 cmp eax, -KTRAP_FRAME_EFLAGS
1915 /* Check if we have a TEB */
1916 mov eax, PCR[KPCR_TEB]
1920 /* Fixup the frame */
1927 /* REACTOS Mm Hack of Doom */
1928 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
1931 /* Enable interrupts and check if we got here with interrupts disabled */
1933 /* test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
1937 /* Send trap frame and check if this is kernel-mode or usermode */
1939 mov eax, [ebp+KTRAP_FRAME_CS]
1943 /* Send faulting address and check if this is read or write */
1945 mov eax, [ebp+KTRAP_FRAME_ERROR_CODE]
1949 /* Call the access fault handler */
1950 call _MmAccessFault@16
1954 /* Access fault handled, return to caller */
1955 jmp _Kei386EoiHelper@0
1958 /* First check if this is a fault in the S-LIST functions */
1959 mov ecx, offset _ExpInterlockedPopEntrySListFault@0
1960 cmp [ebp+KTRAP_FRAME_EIP], ecx
1963 /* Check if this is a fault in the syscall handler */
1964 mov ecx, offset CopyParams
1965 cmp [ebp+KTRAP_FRAME_EIP], ecx
1967 mov ecx, offset ReadBatch
1968 cmp [ebp+KTRAP_FRAME_EIP], ecx
1973 jmp _Kei386EoiHelper@0
1978 jmp _Kei386EoiHelper@0
1980 /* Check if the fault occured in a V86 mode */
1982 mov ecx, [ebp+KTRAP_FRAME_ERROR_CODE]
1985 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1988 /* Check if the fault occured in a VDM */
1989 mov esi, PCR[KPCR_CURRENT_THREAD]
1990 mov esi, [esi+KTHREAD_APCSTATE_PROCESS]
1991 cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0
1994 /* Check if we this was in kernel-mode */
1995 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1997 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
2004 /* Save EIP and check what kind of status failure we got */
2006 mov esi, [ebp+KTRAP_FRAME_EIP]
2007 cmp eax, STATUS_ACCESS_VIOLATION
2009 cmp eax, STATUS_GUARD_PAGE_VIOLATION
2011 cmp eax, STATUS_STACK_OVERFLOW
2014 /* Setup an in-page exception to dispatch */
2020 mov eax, STATUS_IN_PAGE_ERROR
2021 call _CommonDispatchException
2024 /* Use more proper status code */
2025 mov eax, KI_EXCEPTION_ACCESS_VIOLATION
2028 /* Setup a normal page fault exception */
2032 jmp _DispatchTwoParam
2040 /* This is completely illegal, bugcheck the system */
2046 push IRQL_NOT_LESS_OR_EQUAL
2047 call _KeBugCheckWithTf@24
2051 /* FIXME: NOT SUPPORTED */
2056 TRAP_FIXUPS kitf_a, kitf_t, DoFixupV86, DoNotFixupAbios
2058 /* Push error code */
2062 TRAP_PROLOG kitf_a, kitf_t
2065 /* Raise a fatal exception */
2067 jmp _KiSystemFatalException
2071 TRAP_FIXUPS kit10_a, kit10_t, DoFixupV86, DoNotFixupAbios
2073 /* Push error code */
2077 TRAP_PROLOG kit10_a, kit10_t
2079 /* Check if this is the NPX Thread */
2080 mov eax, PCR[KPCR_CURRENT_THREAD]
2081 cmp eax, PCR[KPCR_NPX_THREAD]
2083 /* Get the initial stack and NPX frame */
2084 mov ecx, [eax+KTHREAD_INITIAL_STACK]
2085 lea ecx, [ecx-NPX_FRAME_LENGTH]
2087 /* If this is a valid fault, handle it */
2090 /* Otherwise, re-enable interrupts and set delayed error */
2092 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
2093 jmp _Kei386EoiHelper@0
2097 TRAP_FIXUPS kit11_a, kit11_t, DoFixupV86, DoNotFixupAbios
2099 /* Push error code */
2103 TRAP_PROLOG kit11_a, kit11_t
2105 /* FIXME: ROS Doesn't handle alignment faults yet */
2107 jmp _KiSystemFatalException
2112 TRAP_FIXUPS kit19_a, kit19_t, DoFixupV86, DoNotFixupAbios
2114 /* Push error code */
2118 TRAP_PROLOG kit19_a, kit19_t
2120 /* Check if this is the NPX Thread */
2121 mov eax, PCR[KPCR_CURRENT_THREAD]
2122 cmp eax, PCR[KPCR_NPX_THREAD]
2124 /* If this is a valid fault, handle it */
2127 /* Otherwise, bugcheck */
2129 jmp _KiSystemFatalException
2132 /* Get the initial stack and NPX frame */
2133 mov ecx, [eax+KTHREAD_INITIAL_STACK]
2134 lea ecx, [ecx-NPX_FRAME_LENGTH]
2136 /* Check if the trap came from V86 mode */
2137 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
2140 /* Check if it came from kernel mode */
2141 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
2144 /* Check if it came from a VDM */
2145 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
2151 and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
2154 /* Check if we have FX support */
2155 test byte ptr _KeI386FxsrPresent, 1
2158 /* Save the state */
2160 jmp XmmiMakeCr0Dirty
2166 /* Make CR0 state not loaded */
2167 or ebx, NPX_STATE_NOT_LOADED
2168 or ebx, [ecx+FN_CR0_NPX_STATE]
2171 /* Update NPX state */
2172 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
2173 mov dword ptr PCR[KPCR_NPX_THREAD], 0
2175 /* Clear the TS bit and re-enable interrupts */
2176 and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
2178 /* Re-enable interrupts for user-mode and send the exception */
2180 mov ebx, [ebp+KTRAP_FRAME_EIP]
2182 /* Get MxCSR and get current mask (bits 7-12) */
2183 movzx eax, word ptr [ecx+FX_MXCSR]
2188 /* Set faulting opcode address to 0 */
2191 /* Apply legal exceptions mask */
2194 /* Apply the mask we got in MXCSR itself */
2197 /* Check for invalid operation */
2201 /* Raise exception */
2202 mov eax, STATUS_FLOAT_MULTIPLE_TRAPS
2203 jmp _DispatchOneParamZero
2206 /* Check for zero divide */
2210 /* Raise exception */
2211 mov eax, STATUS_FLOAT_MULTIPLE_TRAPS
2212 jmp _DispatchOneParamZero
2215 /* Check for denormal */
2219 /* Raise exception */
2220 mov eax, STATUS_FLOAT_MULTIPLE_TRAPS
2221 jmp _DispatchOneParamZero
2224 /* Check for overflow*/
2228 /* Raise exception */
2229 mov eax, STATUS_FLOAT_MULTIPLE_FAULTS
2230 jmp _DispatchOneParamZero
2233 /* Check for denormal */
2237 /* Raise exception */
2238 mov eax, STATUS_FLOAT_MULTIPLE_FAULTS
2239 jmp _DispatchOneParamZero
2242 /* Check for Precision */
2246 /* Raise exception */
2247 mov eax, STATUS_FLOAT_MULTIPLE_FAULTS
2248 jmp _DispatchOneParamZero
2251 /* Strange result, bugcheck the OS */
2258 push TRAP_CAUSE_UNKNOWN
2259 call _KeBugCheckWithTf@24
2262 /* Check if this is a VDM */
2263 mov eax, PCR[KPCR_CURRENT_THREAD]
2264 mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
2265 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
2269 /* V86 XMMI not handled */
2273 /* Another weird situation */
2279 push TRAP_CAUSE_UNKNOWN
2280 call _KeBugCheckWithTf@24
2284 .func KiSystemFatalException
2285 _KiSystemFatalException:
2287 /* Push the trap frame */
2290 /* Push empty parameters */
2295 /* Push trap number and bugcheck code */
2297 push UNEXPECTED_KERNEL_MODE_TRAP
2298 call _KeBugCheckWithTf@24
2302 .func KiCoprocessorError@0
2303 _KiCoprocessorError@0:
2305 /* Get the NPX Thread's Initial stack */
2306 mov eax, PCR[KPCR_NPX_THREAD]
2307 mov eax, [eax+KTHREAD_INITIAL_STACK]
2309 /* Make space for the FPU Save area */
2310 sub eax, SIZEOF_FX_SAVE_AREA
2312 /* Set the CR0 State */
2313 mov dword ptr [eax+FN_CR0_NPX_STATE], 8
2320 /* Return to caller */
2324 .func Ki16BitStackException
2325 _Ki16BitStackException:
2331 /* Go to kernel mode thread stack */
2332 mov eax, PCR[KPCR_CURRENT_THREAD]
2333 add esp, [eax+KTHREAD_INITIAL_STACK]
2335 /* Switch to good stack segment */
2339 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
2341 .globl _KiStartUnexpectedRange@0
2342 _KiStartUnexpectedRange@0:
2344 GENERATE_INT_HANDLERS
2346 .globl _KiEndUnexpectedRange@0
2347 _KiEndUnexpectedRange@0:
2348 jmp _KiUnexpectedInterruptTail
2350 .func KiUnexpectedInterruptTail
2351 TRAP_FIXUPS kui_a, kui_t, DoFixupV86, DoFixupAbios
2352 _KiUnexpectedInterruptTail:
2354 /* Enter interrupt trap */
2355 INT_PROLOG kui_a, kui_t, DoNotPushFakeErrorCode
2357 /* Increase interrupt count */
2358 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2360 /* Put vector in EBX and make space for KIRQL */
2364 /* Begin interrupt */
2368 call _HalBeginSystemInterrupt@12
2370 /* Check if it was spurious or not */
2374 /* Spurious, ignore it */
2376 jmp _Kei386EoiHelper2ndEntry
2379 /* Unexpected interrupt, print a message on debug builds */
2382 push offset _UnexpectedMsg
2387 /* Exit the interrupt */
2390 call _HalEndSystemInterrupt@8
2391 jmp _Kei386EoiHelper@0
2394 .globl _KiUnexpectedInterrupt
2395 _KiUnexpectedInterrupt:
2397 /* Bugcheck with invalid interrupt code */
2398 push TRAP_CAUSE_UNKNOWN
2401 /* INTERRUPT HANDLERS ********************************************************/
2403 .func KiDispatchInterrupt@0
2404 _KiDispatchInterrupt@0:
2406 /* Get the PCR and disable interrupts */
2407 mov ebx, PCR[KPCR_SELF]
2410 /* Check if we have to deliver DPCs, timers, or deferred threads */
2411 mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
2412 or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
2413 or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
2416 /* Save stack pointer and exception list, then clear it */
2418 push dword ptr [ebx+KPCR_EXCEPTION_LIST]
2419 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
2421 /* Save the stack and switch to the DPC Stack */
2423 mov esp, [ebx+KPCR_PRCB_DPC_STACK]
2427 mov ecx, [ebx+KPCR_PRCB]
2428 call @KiRetireDpcList@4
2430 /* Restore stack and exception list */
2432 pop dword ptr [ebx+KPCR_EXCEPTION_LIST]
2437 /* Re-enable interrupts */
2440 /* Check if we have quantum end */
2441 cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
2444 /* Check if we have a thread to swap to */
2445 cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
2448 /* Make space on the stack to save registers */
2454 /* Get the current thread */
2455 mov edi, [ebx+KPCR_CURRENT_THREAD]
2458 /* Raise to synch level */
2459 call _KeRaiseIrqlToSynchLevel@0
2461 /* Set context swap busy */
2462 mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1
2464 /* Acquire the PRCB Lock */
2465 lock bts dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
2467 lea ecx, [ebx+KPCR_PRCB_PRCB_LOCK]
2468 call @KefAcquireSpinLockAtDpcLevel@4
2472 /* Get the next thread and clear it */
2473 mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
2474 and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
2476 /* Set us as the current running thread */
2477 mov [ebx+KPCR_CURRENT_THREAD], esi
2478 mov byte ptr [esi+KTHREAD_STATE_], Running
2479 mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt
2481 /* Put thread in ECX and get the PRCB in EDX */
2483 lea edx, [ebx+KPCR_PRCB_DATA]
2484 call @KiQueueReadyThread@8
2486 /* Set APC_LEVEL and do the swap */
2488 call @KiSwapContextInternal@0
2491 /* Lower IRQL back to dispatch */
2492 mov cl, DISPATCH_LEVEL
2496 /* Restore registers */
2507 /* Disable quantum end and process it */
2508 mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
2509 call _KiQuantumEnd@0
2513 .func KiInterruptTemplate
2514 _KiInterruptTemplate:
2516 /* Enter interrupt trap */
2517 INT_PROLOG kit_a, kit_t, DoPushFakeErrorCode
2519 _KiInterruptTemplate2ndDispatch:
2520 /* Dummy code, will be replaced by the address of the KINTERRUPT */
2523 _KiInterruptTemplateObject:
2524 /* Dummy jump, will be replaced by the actual jump */
2525 jmp _KeSynchronizeExecution@12
2527 _KiInterruptTemplateDispatch:
2528 /* Marks the end of the template so that the jump above can be edited */
2530 TRAP_FIXUPS kit_a, kit_t, DoFixupV86, DoFixupAbios
2533 .func KiChainedDispatch2ndLvl@0
2534 _KiChainedDispatch2ndLvl@0:
2537 /* Raise IRQL if necessary */
2538 mov cl, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
2539 cmp cl, [edi+KINTERRUPT_IRQL]
2544 /* Acquire the lock */
2545 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
2547 ACQUIRE_SPINLOCK(esi, IntSpin2)
2549 /* Make sure that this interrupt isn't storming */
2552 /* Save the tick count */
2553 mov esi, _KeTickCount
2556 mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
2559 call [edi+KINTERRUPT_SERVICE_ROUTINE]
2561 /* Save the ISR result */
2564 /* Check if the ISR timed out */
2565 add esi, _KiISRTimeout
2566 cmp _KeTickCount, esi
2567 jnc ChainedIsrTimeout
2570 /* Release the lock */
2571 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
2572 RELEASE_SPINLOCK(esi)
2574 /* Lower IRQL if necessary */
2575 mov cl, [edi+KINTERRUPT_IRQL]
2576 cmp cl, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
2581 /* Check if the interrupt is handled */
2585 /* Try the next shared interrupt handler */
2586 mov eax, [edi+KINTERRUPT_INTERRUPT_LIST_HEAD]
2587 lea edi, [eax-KINTERRUPT_INTERRUPT_LIST_HEAD]
2595 SPIN_ON_LOCK(esi, GetIntLock2)
2599 /* Print warning message */
2600 push [edi+KINTERRUPT_SERVICE_ROUTINE]
2601 push offset _IsrTimeoutMsg
2605 /* Break into debugger, then continue */
2609 /* Cleanup verification */
2610 VERIFY_INT_END kid2, 0
2613 .func KiChainedDispatch@0
2614 _KiChainedDispatch@0:
2616 /* Increase interrupt count */
2617 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2619 /* Save trap frame */
2622 /* Save vector and IRQL */
2623 mov eax, [edi+KINTERRUPT_VECTOR]
2624 mov ecx, [edi+KINTERRUPT_IRQL]
2630 /* Begin interrupt */
2634 call _HalBeginSystemInterrupt@12
2636 /* Check if it was handled */
2640 /* Call the 2nd-level handler */
2641 call _KiChainedDispatch2ndLvl@0
2643 /* Exit the interrupt */
2647 .func KiInterruptDispatch@0
2648 _KiInterruptDispatch@0:
2650 /* Increase interrupt count */
2651 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2653 /* Save trap frame */
2656 /* Save vector and IRQL */
2657 mov eax, [edi+KINTERRUPT_VECTOR]
2658 mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
2664 /* Begin interrupt */
2668 call _HalBeginSystemInterrupt@12
2670 /* Check if it was handled */
2674 /* Acquire the lock */
2675 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
2677 ACQUIRE_SPINLOCK(esi, IntSpin)
2679 /* Make sure that this interrupt isn't storming */
2682 /* Save the tick count */
2683 mov ebx, _KeTickCount
2686 mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
2689 call [edi+KINTERRUPT_SERVICE_ROUTINE]
2691 /* Check if the ISR timed out */
2692 add ebx, _KiISRTimeout
2693 cmp _KeTickCount, ebx
2697 /* Release the lock */
2698 RELEASE_SPINLOCK(esi)
2700 /* Exit the interrupt */
2704 /* Exit the interrupt */
2710 SPIN_ON_LOCK(esi, GetIntLock)
2714 /* Print warning message */
2715 push [edi+KINTERRUPT_SERVICE_ROUTINE]
2716 push offset _IsrTimeoutMsg
2720 /* Break into debugger, then continue */
2724 /* Cleanup verification */
2725 VERIFY_INT_END kid, 0
2728 .globl _KeSynchronizeExecution@12
2729 .func KeSynchronizeExecution@12
2730 _KeSynchronizeExecution@12:
2732 /* Save EBX and put the interrupt object in it */
2737 mov cl, [ebx+KINTERRUPT_SYNCHRONIZE_IRQL]
2740 /* Call the routine */