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 *******************************************************************/
19 /* This is the Software Interrupt Table that we handle in this file: */
20 idt _KiTrap0, INT_32_DPL0 /* INT 00: Divide Error (#DE) */
21 idt _KiTrap1, INT_32_DPL0 /* INT 01: Debug Exception (#DB) */
22 idt _KiTrap2, INT_32_DPL0 /* INT 02: NMI Interrupt */
23 idt _KiTrap3, INT_32_DPL3 /* INT 03: Breakpoint Exception (#BP) */
24 idt _KiTrap4, INT_32_DPL3 /* INT 04: Overflow Exception (#OF) */
25 idt _KiTrap5, INT_32_DPL0 /* INT 05: BOUND Range Exceeded (#BR) */
26 idt _KiTrap6, INT_32_DPL0 /* INT 06: Invalid Opcode Code (#UD) */
27 idt _KiTrap7, INT_32_DPL0 /* INT 07: Device Not Available (#NM) */
28 idt _KiTrap8, INT_32_DPL0 /* INT 08: Double Fault Exception (#DF) */
29 idt _KiTrap9, INT_32_DPL0 /* INT 09: RESERVED */
30 idt _KiTrap10, INT_32_DPL0 /* INT 0A: Invalid TSS Exception (#TS) */
31 idt _KiTrap11, INT_32_DPL0 /* INT 0B: Segment Not Present (#NP) */
32 idt _KiTrap12, INT_32_DPL0 /* INT 0C: Stack Fault Exception (#SS) */
33 idt _KiTrap13, INT_32_DPL0 /* INT 0D: General Protection (#GP) */
34 idt _KiTrap14, INT_32_DPL0 /* INT 0E: Page-Fault Exception (#PF) */
35 idt _KiTrap0F, INT_32_DPL0 /* INT 0F: RESERVED */
36 idt _KiTrap16, INT_32_DPL0 /* INT 10: x87 FPU Error (#MF) */
37 idt _KiTrap17, INT_32_DPL0 /* INT 11: Align Check Exception (#AC) */
38 idt _KiTrap0F, INT_32_DPL0 /* INT 12: Machine Check Exception (#MC)*/
39 idt _KiTrap0F, INT_32_DPL0 /* INT 13: SIMD FPU Exception (#XF) */
41 idt _KiTrap0F, INT_32_DPL0 /* INT 14-29: UNDEFINED INTERRUPTS */
43 idt _KiGetTickCount, INT_32_DPL3 /* INT 2A: Get Tick Count Handler */
44 idt _KiCallbackReturn, INT_32_DPL3 /* INT 2B: User-Mode Callback Return */
45 idt _KiRaiseAssertion, INT_32_DPL3 /* INT 2C: Debug Assertion Handler */
46 idt _KiDebugService, INT_32_DPL3 /* INT 2D: Debug Service Handler */
47 idt _KiSystemService, INT_32_DPL3 /* INT 2E: System Call Service Handler */
48 idt _KiTrap0F, INT_32_DPL0 /* INT 2F: RESERVED */
49 GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
51 /* System call entrypoints: */
52 .globl _KiFastCallEntry
53 .globl _KiSystemService
55 /* And special system-defined software traps: */
56 .globl _NtRaiseException@12
58 .globl _KiCoprocessorError@0
59 .globl _KiDispatchInterrupt@0
61 /* Interrupt template entrypoints */
62 .globl _KiInterruptTemplate
63 .globl _KiInterruptTemplateObject
64 .globl _KiInterruptTemplateDispatch
66 /* Chained and Normal generic interrupt handlers for 1st and 2nd level entry*/
67 .globl _KiChainedDispatch2ndLvl@0
68 .globl _KiInterruptDispatch@0
69 .globl _KiChainedDispatch@0
71 /* We implement the following trap exit points: */
72 .globl _KiServiceExit /* Exit from syscall */
73 .globl _KiServiceExit2 /* Exit from syscall with complete frame*/
74 .globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
75 .globl _Kei386EoiHelper2ndEntry /* Exit from unexpected interrupt */
77 .globl _KiIdtDescriptor
82 .globl _KiUnexpectedEntrySize
83 _KiUnexpectedEntrySize:
84 .long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
87 .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
89 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
99 /* Enter the shared system call prolog */
102 /* Jump to the actual handler */
106 .func KiFastCallEntry
113 /* Set DS/ES to User Selector */
114 mov ecx, KGDT_R3_DATA | RPL_MASK
118 /* Set the current stack to Kernel Stack */
119 mov ecx, [fs:KPCR_TSS]
120 mov esp, ss:[ecx+KTSS_ESP0]
122 /* Set up a fake INT Stack. */
123 push KGDT_R3_DATA + RPL_MASK
124 push edx /* Ring 3 SS:ESP */
125 pushf /* Ring 3 EFLAGS */
126 push 2 /* Ring 0 EFLAGS */
127 add edx, 8 /* Skip user parameter list */
128 popf /* Set our EFLAGS */
129 or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */
130 push KGDT_R3_CODE + RPL_MASK
131 push KUSER_SHARED_SYSCALL_RET
133 /* Setup the Trap Frame stack */
139 push KGDT_R3_TEB + RPL_MASK
141 /* Save pointer to our PCR */
142 mov ebx, [fs:KPCR_SELF]
144 /* Get a pointer to the current thread */
145 mov esi, [ebx+KPCR_CURRENT_THREAD]
147 /* Set the exception handler chain terminator */
148 push [ebx+KPCR_EXCEPTION_LIST]
149 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
151 /* Use the thread's stack */
152 mov ebp, [esi+KTHREAD_INITIAL_STACK]
154 /* Push previous mode */
157 /* Skip the other registers */
160 /* Make space for us on the stack */
163 /* Write the previous mode */
164 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
171 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
173 /* Check if the thread was being debugged */
174 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
176 /* Set the thread's trap frame */
177 mov [esi+KTHREAD_TRAP_FRAME], ebp
179 /* Save DR registers if needed */
180 //jnz Dr_FastCallDrSave
182 /* Set the trap frame debug header */
185 /* Enable interrupts */
191 * Find out which table offset to use. Converts 0x1124 into 0x10.
192 * The offset is related to the Table Index as such: Offset = TableIndex x 10
195 shr edi, SERVICE_TABLE_SHIFT
196 and edi, SERVICE_TABLE_MASK
199 /* Now add the thread's base system table to the offset */
200 add edi, [esi+KTHREAD_SERVICE_TABLE]
202 /* Get the true syscall ID and check it */
204 and eax, SERVICE_NUMBER_MASK
205 cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT]
207 /* Invalid ID, try to load Win32K Table */
208 jnb KiBBTUnexpectedRange
210 /* Check if this was Win32K */
211 cmp ecx, SERVICE_TABLE_TEST
215 mov ecx, [fs:KPCR_TEB]
217 /* Check if we should flush the User Batch */
219 or ebx, [ecx+TEB_GDI_BATCH_COUNT]
225 //call [_KeGdiFlushUserBatch]
230 /* Increase total syscall count */
231 inc dword ptr fs:[KPCR_SYSTEM_CALLS]
234 /* Increase per-syscall count */
235 mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT]
237 inc dword ptr [ecx+eax*4]
240 /* Users's current stack frame pointer is source */
244 /* Allocate room for argument list from kernel stack */
245 mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER]
249 /* Get pointer to function */
250 mov edi, [edi+SERVICE_DESCRIPTOR_BASE]
253 /* Allocate space on our stack */
256 /* Set the size of the arguments and the destination */
260 /* Make sure we're within the User Probe Address */
261 cmp esi, _MmUserProbeAddress
265 /* Copy the parameters */
270 * The following lines are for the benefit of GDB. It will see the return
271 * address of the "call ebx" below, find the last label before it and
272 * thinks that that's the start of the function. It will then check to see
273 * if it starts with a standard function prolog (push ebp, mov ebp,esp1).
274 * When that standard function prolog is not found, it will stop the
275 * stack backtrace. Since we do want to backtrace into usermode, let's
276 * make GDB happy and create a standard prolog.
284 /* Do the System Call */
289 /* Make sure the user-mode call didn't return at elevated IRQL */
290 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
292 mov esi, eax /* We need to save the syscall's return val */
293 call _KeGetCurrentIrql@0
296 mov eax, esi /* Restore it */
298 /* Get our temporary current thread pointer for sanity check */
299 mov ecx, fs:[KPCR_CURRENT_THREAD]
301 /* Make sure that we are not attached and that APCs are not disabled */
302 mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
305 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
312 /* Deallocate the kernel stack frame */
315 KeReturnFromSystemCall:
317 /* Get the Current Thread */
318 mov ecx, [fs:KPCR_CURRENT_THREAD]
320 /* Restore the old trap frame pointer */
321 mov edx, [ebp+KTRAP_FRAME_EDX]
322 mov [ecx+KTHREAD_TRAP_FRAME], edx
327 /* Disable interrupts */
330 /* Check for, and deliver, User-Mode APCs if needed */
331 CHECK_FOR_APC_DELIVER 1
333 /* Exit and cleanup */
334 TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything
337 KiBBTUnexpectedRange:
339 /* If this isn't a Win32K call, fail */
340 cmp ecx, SERVICE_TABLE_TEST
343 /* Set up Win32K Table */
346 call _PsConvertToGuiThread@0
348 /* Check return code */
351 /* Restore registers */
355 /* Reset trap frame address */
357 mov [esi+KTHREAD_TRAP_FRAME], ebp
359 /* Try the Call again, if we suceeded */
363 * The Shadow Table should have a special byte table which tells us
364 * whether we should return FALSE, -1 or STATUS_INVALID_SYSTEM_SERVICE.
367 /* Get the table limit and base */
368 lea edx, _KeServiceDescriptorTableShadow + SERVICE_TABLE_TEST
369 mov ecx, [edx+SERVICE_DESCRIPTOR_LIMIT]
370 mov edx, [edx+SERVICE_DESCRIPTOR_BASE]
372 /* Get the table address and add our index into the array */
374 and eax, SERVICE_NUMBER_MASK
377 /* Find out what we should return */
378 movsx eax, byte ptr [edx]
381 /* Return either 0 or -1, we've set it in EAX */
382 jle KeReturnFromSystemCall
384 /* Set STATUS_INVALID_SYSTEM_SERVICE */
385 mov eax, STATUS_INVALID_SYSTEM_SERVICE
386 jmp KeReturnFromSystemCall
390 /* Invalid System Call */
391 mov eax, STATUS_INVALID_SYSTEM_SERVICE
392 jmp KeReturnFromSystemCall
396 /* Check if this came from kernel-mode */
397 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
399 /* It's fine, go ahead with it */
402 /* Caller sent invalid parameters, fail here */
403 mov eax, STATUS_ACCESS_VIOLATION
408 /* Restore ESP0 stack */
409 mov ecx, [fs:KPCR_TSS]
410 mov esp, ss:[ecx+KTSS_ESP0]
412 /* Generate V86M Stack for Trap 6 */
418 /* Generate interrupt stack for Trap 6 */
419 push KGDT_R3_DATA + RPL_MASK
422 push KGDT_R3_CODE + RPL_MASK
428 /* Save current IRQL */
431 /* Set us at passive */
432 mov dword ptr fs:[KPCR_IRQL], 0
440 push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
441 call _KeBugCheckEx@20
445 /* Get the index and APC state */
446 movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX]
447 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
454 push APC_INDEX_MISMATCH
455 call _KeBugCheckEx@20
462 /* Disable interrupts */
465 /* Check for, and deliver, User-Mode APCs if needed */
466 CHECK_FOR_APC_DELIVER 0
468 /* Exit and cleanup */
469 TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
472 .func Kei386EoiHelper@0
475 /* Disable interrupts */
478 /* Check for, and deliver, User-Mode APCs if needed */
479 CHECK_FOR_APC_DELIVER 0
481 /* Exit and cleanup */
482 _Kei386EoiHelper2ndEntry:
483 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
487 /* Move to EDX position */
488 add esp, KTRAP_FRAME_EDX
490 /* Restore volatiles */
495 /* Move to non-volatiles */
496 lea esp, [ebp+KTRAP_FRAME_EDI]
502 /* Skip error code and return */
507 /* Not yet supported */
513 /* Push error code */
519 /* Increase EIP so we skip the INT3 */
520 //inc dword ptr [ebp+KTRAP_FRAME_EIP]
522 /* Call debug service dispatcher */
523 mov eax, [ebp+KTRAP_FRAME_EAX]
524 mov ecx, [ebp+KTRAP_FRAME_ECX]
525 mov edx, [ebp+KTRAP_FRAME_EAX]
527 /* Check for V86 mode */
528 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
531 /* Check if this is kernel or user-mode */
532 test byte ptr [ebp+KTRAP_FRAME_CS], 1
534 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
537 /* Re-enable interrupts */
541 /* Call the debug routine */
550 call _KdpServiceDispatcher@12
554 /* Get the current process */
555 mov ebx, [fs:KPCR_CURRENT_THREAD]
556 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
558 /* Check if this is a VDM Process */
559 //cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
562 /* Exit through common routine */
563 jmp _Kei386EoiHelper@0
566 .func NtRaiseException@12
567 _NtRaiseException@12:
569 /* NOTE: We -must- be called by Zw* to have the right frame! */
570 /* Push the stack frame */
573 /* Get the current thread and restore its trap frame */
574 mov ebx, [fs:KPCR_CURRENT_THREAD]
575 mov edx, [ebp+KTRAP_FRAME_EDX]
576 mov [ebx+KTHREAD_TRAP_FRAME], edx
578 /* Set up stack frame */
581 /* Get the Trap Frame in EBX */
584 /* Get the exception list and restore */
585 mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
586 mov [fs:KPCR_EXCEPTION_LIST], eax
588 /* Get the parameters */
589 mov edx, [ebp+16] /* Search frames */
590 mov ecx, [ebp+12] /* Context */
591 mov eax, [ebp+8] /* Exception Record */
593 /* Raise the exception */
599 call _KiRaiseException@20
601 /* Restore trap frame in EBP */
605 /* Check the result */
609 /* Restore debug registers too */
616 /* NOTE: We -must- be called by Zw* to have the right frame! */
617 /* Push the stack frame */
620 /* Get the current thread and restore its trap frame */
621 mov ebx, [fs:KPCR_CURRENT_THREAD]
622 mov edx, [ebp+KTRAP_FRAME_EDX]
623 mov [ebx+KTHREAD_TRAP_FRAME], edx
625 /* Set up stack frame */
628 /* Save the parameters */
632 /* Call KiContinue */
638 /* Check if we failed (bad context record) */
642 /* Check if test alert was requested */
643 cmp dword ptr [ebp+12], 0
646 /* Test alert for the thread */
647 mov al, [ebx+KTHREAD_PREVIOUS_MODE]
649 call _KeTestAlertThread@4
652 /* Return to previous context */
663 /* EXCEPTION DISPATCHERS *****************************************************/
665 .func CommonDispatchException
666 _CommonDispatchException:
668 /* Make space for an exception record */
669 sub esp, EXCEPTION_RECORD_LENGTH
672 mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
674 mov [esp+EXCEPTION_RECORD_EXCEPTION_FLAGS], eax
675 mov [esp+EXCEPTION_RECORD_EXCEPTION_RECORD], eax
676 mov [esp+EXCEPTION_RECORD_EXCEPTION_ADDRESS], ebx
677 mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
679 /* Check parameter count */
683 /* Get information */
684 lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
691 /* Set the record in ECX and check if this was V86 */
693 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
702 /* Calculate the previous mode */
703 mov eax, [ebp+KTRAP_FRAME_CS]
707 /* Dispatch the exception */
713 call _KiDispatchException@20
717 jmp _Kei386EoiHelper@0
720 .func DispatchNoParam
722 /* Call the common dispatcher */
724 call _CommonDispatchException
727 .func DispatchOneParam
729 /* Call the common dispatcher */
732 call _CommonDispatchException
735 .func DispatchTwoParam
737 /* Call the common dispatcher */
740 call _CommonDispatchException
743 /* HARDWARE TRAP HANDLERS ****************************************************/
747 /* Push error code */
754 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
757 /* Check if the frame was from kernelmode */
758 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
761 /* Check the old mode */
762 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
766 /* Re-enable interrupts for user-mode and send the exception */
768 mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
769 mov ebx, [ebp+KTRAP_FRAME_EIP]
773 /* Check if this is a VDM process */
774 mov ebx, [fs:KPCR_CURRENT_THREAD]
775 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
776 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
779 /* We don't support this yet! */
786 /* Push error code */
793 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
796 /* Check if the frame was from kernelmode */
797 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
800 /* Check the old mode */
801 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
805 /* Enable interrupts for user-mode */
809 /* Prepare the exception */
810 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAGS_TF
811 mov ebx, [ebp+KTRAP_FRAME_EIP]
812 mov eax, STATUS_SINGLE_STEP
816 /* Check if this is a VDM process */
817 mov ebx, [fs:KPCR_CURRENT_THREAD]
818 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
819 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
822 /* We don't support VDM! */
830 /* FIXME: This is an NMI, nothing like a normal exception */
832 jmp _KiSystemFatalException
837 /* Push error code */
844 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
847 /* Check if the frame was from kernelmode */
848 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
851 /* Check the old mode */
852 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
856 /* Enable interrupts for user-mode */
860 /* Prepare the exception */
865 /* Setup EIP, NTSTATUS and parameter count, then dispatch */
866 mov ebx, [ebp+KTRAP_FRAME_EIP]
868 mov eax, STATUS_BREAKPOINT
870 call _CommonDispatchException
873 /* Check if this is a VDM process */
874 mov ebx, [fs:KPCR_CURRENT_THREAD]
875 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
876 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
879 /* We don't support VDM! */
885 /* Push error code */
892 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
895 /* Check if the frame was from kernelmode */
896 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
899 /* Check the old mode */
900 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
904 /* Re-enable interrupts for user-mode and send the exception */
906 mov eax, STATUS_INTEGER_OVERFLOW
907 mov ebx, [ebp+KTRAP_FRAME_EIP]
912 /* Check if this is a VDM process */
913 mov ebx, [fs:KPCR_CURRENT_THREAD]
914 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
915 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
918 /* We don't support this yet! */
925 /* Push error code */
932 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
935 /* Check if the frame was from kernelmode */
936 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
939 /* It did, and this should never happen */
941 jmp _KiSystemFatalException
943 /* Check the old mode */
945 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
948 /* Re-enable interrupts for user-mode and send the exception */
951 mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
952 mov ebx, [ebp+KTRAP_FRAME_EIP]
956 /* Check if this is a VDM process */
957 mov ebx, [fs:KPCR_CURRENT_THREAD]
958 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
959 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
962 /* We don't support this yet! */
970 /* It this a V86 GPF? */
971 test dword ptr [esp+8], EFLAGS_V86_MASK
977 /* Not yet supported (Invalid OPCODE from V86) */
982 /* Push error code */
988 /* Check if this happened in kernel mode */
989 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
993 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
996 /* Check if the process is vDM */
997 mov ebx, fs:[KPCR_CURRENT_THREAD]
998 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
999 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1003 /* Get EIP and enable interrupts at this point */
1004 mov esi, [ebp+KTRAP_FRAME_EIP]
1007 /* Set intruction prefix length */
1010 /* Setup a SEH frame */
1013 push fs:[KPCR_EXCEPTION_LIST]
1014 mov fs:[KPCR_EXCEPTION_LIST], esp
1017 /* Get the instruction and check if it's LOCK */
1026 /* Undo SEH frame */
1027 pop fs:[KPCR_EXCEPTION_LIST]
1032 /* Re-enable interrupts */
1035 /* Setup illegal instruction exception and dispatch it */
1036 mov ebx, [ebp+KTRAP_FRAME_EIP]
1037 mov eax, STATUS_ILLEGAL_INSTRUCTION
1038 jmp _DispatchNoParam
1042 /* Undo SEH Frame */
1043 pop fs:[KPCR_EXCEPTION_LIST]
1046 /* Setup invalid lock exception and dispatch it */
1047 mov ebx, [ebp+KTRAP_FRAME_EIP]
1048 mov eax, STATUS_INVALID_LOCK_SEQUENCE
1049 jmp _DispatchNoParam
1057 /* Return to caller */
1058 jmp _Kei386EoiHelper@0
1064 pop fs:[KPCR_EXCEPTION_LIST]
1068 /* Check if this was user mode */
1069 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1078 push KMODE_EXCEPTION_NOT_HANDLED
1079 call _KeBugCheckWithTf@24
1084 /* Push error code */
1090 /* Get the current thread and stack */
1092 mov eax, [fs:KPCR_CURRENT_THREAD]
1093 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1094 sub ecx, NPX_FRAME_LENGTH
1096 /* Check if emulation is enabled */
1097 test dword ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
1098 jnz EmulationEnabled
1101 /* Check if the NPX state is loaded */
1102 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1107 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
1110 /* Check the NPX thread */
1111 mov edx, [fs:KPCR_NPX_THREAD]
1115 /* Get the NPX Stack */
1116 mov esi, [edx+KTHREAD_INITIAL_STACK]
1117 sub esi, NPX_FRAME_LENGTH
1119 /* Check if we have FXSR and check which operand to use */
1120 test byte ptr _KeI386FxsrPresent, 1
1129 /* Set the thread's state to dirty */
1130 mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1133 /* Check if we have FXSR and choose which operand to use */
1134 test byte ptr _KeI386FxsrPresent, 1
1143 /* Set state loaded */
1144 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1145 mov [fs:KPCR_NPX_THREAD], eax
1147 /* Enable interrupts to happen now */
1151 /* Check if CR0 needs to be reloaded due to a context switch */
1152 cmp dword ptr [ecx+FN_CR0_NPX_STATE], 0
1153 jz _Kei386EoiHelper@0
1155 /* We have to reload CR0... disable interrupts */
1158 /* Get CR0 and update it */
1160 or ebx, [ecx+FN_CR0_NPX_STATE]
1163 /* Restore interrupts and check if TS is back on */
1166 jz _Kei386EoiHelper@0
1168 /* Clear TS, and loop handling again */
1174 /* Check if TS is set */
1176 jnz TsSetOnLoadedState
1178 /* Check if the trap came from user-mode */
1182 /* Did this come from kernel-mode? */
1183 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1186 /* It came from user-mode, so this would only be valid inside a VDM */
1187 /* Since we don't actually have VDMs in ROS, bugcheck. */
1191 /* TS shouldn't be set, unless this we don't have a Math Processor */
1195 /* Strange that we got a trap at all, but ignore and continue */
1197 jmp _Kei386EoiHelper@0
1200 /* Cause a bugcheck */
1206 push TRAP_CAUSE_UNKNOWN
1207 call _KeBugCheckEx@20
1210 /* Cause a bugcheck */
1215 push TRAP_CAUSE_UNKNOWN
1216 call _KeBugCheckEx@20
1223 /* Can't really do too much */
1225 jmp _KiSystemFatalException
1230 /* Push error code */
1236 /* Enable interrupts and bugcheck */
1239 jmp _KiSystemFatalException
1248 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1251 /* Check if the frame was from kernelmode */
1252 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1256 /* Check if OF was set during iretd */
1257 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
1261 /* It was, just mask it out */
1262 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
1263 jmp _Kei386EoiHelper@0
1266 /* TSS failure for some other reason: crash */
1268 jmp _KiSystemFatalException
1276 /* FIXME: ROS Doesn't handle segment faults yet */
1278 jmp _KiSystemFatalException
1286 /* FIXME: ROS Doesn't handle stack faults yet */
1288 jmp _KiSystemFatalException
1294 /* It this a V86 GPF? */
1295 test dword ptr [esp+12], EFLAGS_V86_MASK
1298 /* Enter V86 Trap */
1299 V86_TRAP_PROLOG kitd
1301 /* Make sure that this is a V86 process */
1302 mov ecx, [fs:KPCR_CURRENT_THREAD]
1303 mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
1304 cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
1307 /* Otherwise, something is very wrong, raise an exception */
1309 mov ebx, [ebp+KTRAP_FRAME_EIP]
1311 mov eax, STATUS_ACCESS_VIOLATION
1312 jmp _DispatchTwoParam
1316 /* Go to APC level */
1320 /* Save old IRQL and enable interrupts */
1324 /* Handle the opcode */
1325 call _Ki386HandleOpcodeV86@0
1327 /* Check if this was VDM */
1336 /* Lower IRQL and disable interrupts */
1341 /* Check if this was a V86 trap */
1342 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1345 /* Exit the V86 Trap */
1350 /* Either this wasn't V86, or it was, but an APC interrupted us */
1351 jmp _Kei386EoiHelper@0
1357 /* Check if this was from kernel-mode */
1358 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1361 /* FIXME: Check for GPF during GPF */
1363 /* Get the opcode and trap frame */
1364 mov eax, [ebp+KTRAP_FRAME_EIP]
1366 mov edx, [ebp+KTRAP_FRAME_EBP]
1368 /* We want to check if this was POP [DS/ES/FS/GS] */
1369 add edx, KTRAP_FRAME_DS
1372 add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
1375 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1378 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1382 /* It isn't, was it IRETD? */
1386 /* Get error code */
1387 lea edx, [ebp+KTRAP_FRAME_ESP]
1388 mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
1392 mov cx, word ptr [edx+4]
1397 /* This should be a Ki386CallBios return */
1398 mov eax, offset _Ki386BiosCallReturnAddress
1402 cmp ax, KGDT_R0_CODE + RPL_MASK
1405 /* Jump to return address */
1406 jmp _Ki386BiosCallReturnAddress
1409 /* Check if the thread was in kernel mode */
1410 mov ebx, [fs:KPCR_CURRENT_THREAD]
1411 test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
1414 /* Set RPL_MASK for check below */
1415 or word ptr [edx+4], RPL_MASK
1418 /* Check if the IRET goes to user-mode */
1419 test dword ptr [edx+4], RPL_MASK
1422 /* Setup trap frame to copy */
1423 mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
1424 lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
1428 /* Copy each field */
1434 /* Enable interrupts and adjust stack */
1439 /* Setup exception record */
1440 mov ebx, [ebp+KTRAP_FRAME_EIP]
1441 mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
1443 mov eax, STATUS_ACCESS_VIOLATION
1444 jmp _DispatchTwoParam
1448 /* FIXME: Handle RDMSR/WRMSR */
1454 /* Check if this was an MSR opcode */
1458 /* Check if DS is Ring 3 */
1459 cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1462 /* Otherwise, fix it up */
1463 mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1468 /* Check if ES is Ring 3 */
1469 cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1472 /* Otherwise, fix it up */
1473 mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1479 lea eax, [ebp+KTRAP_FRAME_ESP]
1484 /* Handle segment POP fault by setting it to 0 */
1487 mov dword ptr [edx], eax
1491 /* Do a trap exit */
1492 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
1496 /* FIXME: Unhandled */
1506 /* Call the C exception handler */
1509 call _KiPageFaultHandler
1512 /* Return to caller */
1513 jmp _Kei386EoiHelper@0
1518 /* Push error code */
1525 /* Raise a fatal exception */
1527 jmp _KiSystemFatalException
1532 /* Push error code */
1538 /* FIXME: ROS Doesn't handle FPU faults yet */
1540 jmp _KiSystemFatalException
1545 /* Push error code */
1551 /* FIXME: ROS Doesn't handle alignment faults yet */
1553 jmp _KiSystemFatalException
1556 .func KiSystemFatalException
1557 _KiSystemFatalException:
1559 /* Push the trap frame */
1562 /* Push empty parameters */
1567 /* Push trap number and bugcheck code */
1569 push UNEXPECTED_KERNEL_MODE_TRAP
1570 call _KeBugCheckWithTf@24
1574 .func KiCoprocessorError@0
1575 _KiCoprocessorError@0:
1577 /* Get the NPX Thread's Initial stack */
1578 mov eax, [fs:KPCR_NPX_THREAD]
1579 mov eax, [eax+KTHREAD_INITIAL_STACK]
1581 /* Make space for the FPU Save area */
1582 sub eax, SIZEOF_FX_SAVE_AREA
1584 /* Set the CR0 State */
1585 mov dword ptr [eax+FN_CR0_NPX_STATE], 8
1592 /* Return to caller */
1596 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
1598 .globl _KiStartUnexpectedRange@0
1599 _KiStartUnexpectedRange@0:
1601 GENERATE_INT_HANDLERS
1603 .globl _KiEndUnexpectedRange@0
1604 _KiEndUnexpectedRange@0:
1605 jmp _KiUnexpectedInterruptTail
1607 .func KiUnexpectedInterruptTail
1608 _KiUnexpectedInterruptTail:
1610 /* Enter interrupt trap */
1611 INT_PROLOG kui, DoNotPushFakeErrorCode
1613 /* Increase interrupt count */
1614 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1616 /* Put vector in EBX and make space for KIRQL */
1620 /* Begin interrupt */
1624 call _HalBeginSystemInterrupt@12
1626 /* Check if it was spurious or not */
1630 /* Spurious, ignore it */
1632 jmp _Kei386EoiHelper2ndEntry
1635 /* Unexpected interrupt, print a message on debug builds */
1638 push offset _UnexpectedMsg
1643 /* Exit the interrupt */
1646 call _HalEndSystemInterrupt@8
1647 jmp _Kei386EoiHelper@0
1650 .globl _KiUnexpectedInterrupt
1651 _KiUnexpectedInterrupt:
1653 /* Bugcheck with invalid interrupt code */
1654 push TRAP_CAUSE_UNKNOWN
1657 /* INTERRUPT HANDLERS ********************************************************/
1659 .func KiDispatchInterrupt@0
1660 _KiDispatchInterrupt@0:
1662 /* Get the PCR and disable interrupts */
1663 mov ebx, [fs:KPCR_SELF]
1666 /* Check if we have to deliver DPCs, timers, or deferred threads */
1667 mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
1668 or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
1669 or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
1672 /* Save stack pointer and exception list, then clear it */
1674 push dword ptr [ebx+KPCR_EXCEPTION_LIST]
1675 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
1677 /* Save the stack and switch to the DPC Stack */
1679 //mov esp, [ebx+KPCR_PRCB_DPC_STACK]
1683 mov ecx, [ebx+KPCR_PRCB]
1684 call @KiRetireDpcList@4
1686 /* Restore stack and exception list */
1693 /* Re-enable interrupts */
1696 /* Check if we have quantum end */
1697 cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
1700 /* Check if we have a thread to swap to */
1701 cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
1704 /* FIXME: Schedule new thread */
1712 /* Disable quantum end and process it */
1713 mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
1714 call _KiQuantumEnd@0
1718 .func KiInterruptTemplate
1719 _KiInterruptTemplate:
1721 /* Enter interrupt trap */
1722 INT_PROLOG kit, DoPushFakeErrorCode
1725 _KiInterruptTemplate2ndDispatch:
1726 /* Dummy code, will be replaced by the address of the KINTERRUPT */
1729 _KiInterruptTemplateObject:
1730 /* Dummy jump, will be replaced by the actual jump */
1731 jmp _KeSynchronizeExecution@12
1733 _KiInterruptTemplateDispatch:
1734 /* Marks the end of the template so that the jump above can be edited */
1736 .func KiChainedDispatch2ndLvl@0
1737 _KiChainedDispatch2ndLvl@0:
1739 /* Not yet supported */
1743 .func KiChainedDispatch@0
1744 _KiChainedDispatch@0:
1746 /* Increase interrupt count */
1747 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1749 /* Save trap frame */
1752 /* Save vector and IRQL */
1753 mov eax, [edi+KINTERRUPT_VECTOR]
1754 mov ecx, [edi+KINTERRUPT_IRQL]
1760 /* Begin interrupt */
1764 call _HalBeginSystemInterrupt@12
1766 /* Check if it was handled */
1770 /* Call the 2nd-level handler */
1771 call _KiChainedDispatch2ndLvl@0
1773 /* Exit the interrupt */
1776 call _HalEndSystemInterrupt@8
1777 jmp _Kei386EoiHelper@0
1780 .func KiInterruptDispatch@0
1781 _KiInterruptDispatch@0:
1783 /* Increase interrupt count */
1784 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1786 /* Save trap frame */
1789 /* Save vector and IRQL */
1790 mov eax, [edi+KINTERRUPT_VECTOR]
1791 mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
1797 /* Begin interrupt */
1801 call _HalBeginSystemInterrupt@12
1803 /* Check if it was handled */
1807 /* Acquire the lock */
1809 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
1810 ACQUIRE_SPINLOCK(esi, IntSpin)
1813 mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
1816 call [edi+KINTERRUPT_SERVICE_ROUTINE]
1818 /* Release the lock */
1819 RELEASE_SPINLOCK(esi)
1821 /* Exit the interrupt */
1824 call _HalEndSystemInterrupt@8
1825 jmp _Kei386EoiHelper@0
1828 /* Exit the interrupt */
1831 jmp _Kei386EoiHelper@0
1835 SPIN_ON_LOCK esi, GetIntLock