- Finally figured out a way to make the old HAL IRQ implementation work with the...
[reactos.git] / reactos / ntoskrnl / ke / i386 / trap.s
1 /*
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.
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <asm.h>
12 #include <internal/i386/asmmacro.S>
13 .intel_syntax noprefix
14
15 /* GLOBALS *******************************************************************/
16
17 .data
18 .globl _KiIdt
19 _KiIdt:
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) */
41 .rept 22
42 idt _KiTrap0F, INT_32_DPL0 /* INT 14-29: UNDEFINED INTERRUPTS */
43 .endr
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 */
51
52 /* System call entrypoints: */
53 .globl _KiFastCallEntry
54 .globl _KiSystemService
55
56 /* And special system-defined software traps: */
57 .globl _NtRaiseException@12
58 .globl _NtContinue@8
59 .globl _KiCoprocessorError@0
60 .globl _KiDispatchInterrupt@0
61
62 /* Interrupt template entrypoints */
63 .globl _KiInterruptTemplate
64 .globl _KiInterruptTemplateObject
65 .globl _KiInterruptTemplateDispatch
66
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
71
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 */
77
78 .globl _KiIdtDescriptor
79 _KiIdtDescriptor:
80 .short 0x800
81 .long _KiIdt
82
83 .globl _KiUnexpectedEntrySize
84 _KiUnexpectedEntrySize:
85 .long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
86
87 _UnexpectedMsg:
88 .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
89
90 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
91 .text
92
93 _KiGetTickCount:
94 _KiCallbackReturn:
95 _KiRaiseAssertion:
96 int 3
97
98 .func KiSystemService
99 _KiSystemService:
100
101 /* Enter the shared system call prolog */
102 SYSCALL_PROLOG
103
104 /* Jump to the actual handler */
105 jmp SharedCode
106 .endfunc
107
108 .func KiFastCallEntry
109 _KiFastCallEntry:
110
111 /* Set FS to PCR */
112 mov ecx, KGDT_R0_PCR
113 mov fs, cx
114 //push KGDT_R0_PCR
115 //pop fs
116
117 /* Set user selector */
118 mov ecx, KGDT_R3_DATA | RPL_MASK
119
120 /* Set DS/ES to User Selector */
121 mov ds, cx
122 mov es, cx
123
124 /* Set the current stack to Kernel Stack */
125 mov ecx, [fs:KPCR_TSS]
126 mov esp, ss:[ecx+KTSS_ESP0]
127
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
138
139 /* Setup the Trap Frame stack */
140 push 0
141 push ebp
142 push ebx
143 push esi
144 push edi
145 push KGDT_R3_TEB + RPL_MASK
146
147 /* Save pointer to our PCR */
148 mov ebx, [fs:KPCR_SELF]
149
150 /* Get a pointer to the current thread */
151 mov esi, [ebx+KPCR_CURRENT_THREAD]
152
153 /* Set the exception handler chain terminator */
154 push [ebx+KPCR_EXCEPTION_LIST]
155 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
156
157 /* Use the thread's stack */
158 mov ebp, [esi+KTHREAD_INITIAL_STACK]
159
160 /* Push previous mode */
161 push UserMode
162
163 /* Skip the other registers */
164 sub esp, 0x48
165
166 /* Make space for us on the stack */
167 sub ebp, 0x29C
168
169 /* Write the previous mode */
170 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
171
172 /* Sanity check */
173 cmp ebp, esp
174 jnz BadStack
175
176 /* Flush DR7 */
177 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
178
179 /* Check if the thread was being debugged */
180 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
181
182 /* Set the thread's trap frame */
183 mov [esi+KTHREAD_TRAP_FRAME], ebp
184
185 /* Save DR registers if needed */
186 //jnz Dr_FastCallDrSave
187
188 /* Set the trap frame debug header */
189 SET_TF_DEBUG_HEADER
190
191 /* Enable interrupts */
192 sti
193
194 SharedCode:
195
196 /*
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
199 */
200 mov edi, eax
201 shr edi, SERVICE_TABLE_SHIFT
202 and edi, SERVICE_TABLE_MASK
203 mov ecx, edi
204
205 /* Now add the thread's base system table to the offset */
206 add edi, [esi+KTHREAD_SERVICE_TABLE]
207
208 /* Get the true syscall ID and check it */
209 mov ebx, eax
210 and eax, SERVICE_NUMBER_MASK
211 cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT]
212
213 /* Invalid ID, try to load Win32K Table */
214 jnb KiBBTUnexpectedRange
215
216 /* Check if this was Win32K */
217 cmp ecx, SERVICE_TABLE_TEST
218 jnz NotWin32K
219
220 /* Get the TEB */
221 mov ecx, [fs:KPCR_TEB]
222
223 /* Check if we should flush the User Batch */
224 xor ebx, ebx
225 or ebx, [ecx+TEB_GDI_BATCH_COUNT]
226 jz NotWin32K
227
228 /* Flush it */
229 push edx
230 push eax
231 //call [_KeGdiFlushUserBatch]
232 pop eax
233 pop edx
234
235 NotWin32K:
236 /* Increase total syscall count */
237 inc dword ptr fs:[KPCR_SYSTEM_CALLS]
238
239 #ifdef DBG
240 /* Increase per-syscall count */
241 mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT]
242 jecxz NoCountTable
243 inc dword ptr [ecx+eax*4]
244 #endif
245
246 /* Users's current stack frame pointer is source */
247 NoCountTable:
248 mov esi, edx
249
250 /* Allocate room for argument list from kernel stack */
251 mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER]
252 xor ecx, ecx
253 mov cl, [eax+ebx]
254
255 /* Get pointer to function */
256 mov edi, [edi+SERVICE_DESCRIPTOR_BASE]
257 mov ebx, [edi+eax*4]
258
259 /* Allocate space on our stack */
260 sub esp, ecx
261
262 /* Set the size of the arguments and the destination */
263 shr ecx, 2
264 mov edi, esp
265
266 /* Make sure we're within the User Probe Address */
267 cmp esi, _MmUserProbeAddress
268 jnb AccessViolation
269
270 CopyParams:
271 /* Copy the parameters */
272 rep movsd
273
274 #ifdef DBG
275 /*
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.
283 */
284 KiSystemService:
285 push ebp
286 mov ebp,esp
287 pop ebp
288 #endif
289
290 /* Do the System Call */
291 call ebx
292
293 AfterSysCall:
294 #ifdef DBG
295 /* Make sure the user-mode call didn't return at elevated IRQL */
296 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
297 jz SkipCheck
298 mov esi, eax /* We need to save the syscall's return val */
299 call _KeGetCurrentIrql@0
300 or al, al
301 jnz InvalidIrql
302 mov eax, esi /* Restore it */
303
304 /* Get our temporary current thread pointer for sanity check */
305 mov ecx, fs:[KPCR_CURRENT_THREAD]
306
307 /* Make sure that we are not attached and that APCs are not disabled */
308 mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
309 or dl, dl
310 jnz InvalidIndex
311 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
312 or edx, edx
313 jnz InvalidIndex
314 #endif
315
316 SkipCheck:
317
318 /* Deallocate the kernel stack frame */
319 mov esp, ebp
320
321 KeReturnFromSystemCall:
322
323 /* Get the Current Thread */
324 mov ecx, [fs:KPCR_CURRENT_THREAD]
325
326 /* Restore the old trap frame pointer */
327 mov edx, [ebp+KTRAP_FRAME_EDX]
328 mov [ecx+KTHREAD_TRAP_FRAME], edx
329 .endfunc
330
331 .func KiServiceExit
332 _KiServiceExit:
333 /* Disable interrupts */
334 cli
335
336 /* Check for, and deliver, User-Mode APCs if needed */
337 CHECK_FOR_APC_DELIVER 1
338
339 /* Exit and cleanup */
340 TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything
341 .endfunc
342
343 KiBBTUnexpectedRange:
344
345 /* If this isn't a Win32K call, fail */
346 cmp ecx, SERVICE_TABLE_TEST
347 jne InvalidCall
348
349 /* Set up Win32K Table */
350 push edx
351 push ebx
352 call _PsConvertToGuiThread@0
353
354 /* Check return code */
355 or eax, eax
356
357 /* Restore registers */
358 pop eax
359 pop edx
360
361 /* Reset trap frame address */
362 mov ebp, esp
363 mov [esi+KTHREAD_TRAP_FRAME], ebp
364
365 /* Try the Call again, if we suceeded */
366 jz SharedCode
367
368 /*
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.
371 */
372
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]
377
378 /* Get the table address and add our index into the array */
379 lea edx, [edx+ecx*4]
380 and eax, SERVICE_NUMBER_MASK
381 add edx, eax
382
383 /* Find out what we should return */
384 movsx eax, byte ptr [edx]
385 or eax, eax
386
387 /* Return either 0 or -1, we've set it in EAX */
388 jle KeReturnFromSystemCall
389
390 /* Set STATUS_INVALID_SYSTEM_SERVICE */
391 mov eax, STATUS_INVALID_SYSTEM_SERVICE
392 jmp KeReturnFromSystemCall
393
394 InvalidCall:
395
396 /* Invalid System Call */
397 mov eax, STATUS_INVALID_SYSTEM_SERVICE
398 jmp KeReturnFromSystemCall
399
400 AccessViolation:
401
402 /* Check if this came from kernel-mode */
403 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
404
405 /* It's fine, go ahead with it */
406 jz CopyParams
407
408 /* Caller sent invalid parameters, fail here */
409 mov eax, STATUS_ACCESS_VIOLATION
410 jmp AfterSysCall
411
412 BadStack:
413
414 /* Restore ESP0 stack */
415 mov ecx, [fs:KPCR_TSS]
416 mov esp, ss:[ecx+KTSS_ESP0]
417
418 /* Generate V86M Stack for Trap 6 */
419 push 0
420 push 0
421 push 0
422 push 0
423
424 /* Generate interrupt stack for Trap 6 */
425 push KGDT_R3_DATA + RPL_MASK
426 push 0
427 push 0x20202
428 push KGDT_R3_CODE + RPL_MASK
429 push 0
430 jmp _KiTrap6
431
432 #ifdef DBG
433 InvalidIrql:
434 /* Save current IRQL */
435 push fs:[KPCR_IRQL]
436
437 /* Set us at passive */
438 mov dword ptr fs:[KPCR_IRQL], 0
439 cli
440
441 /* Bugcheck */
442 push 0
443 push 0
444 push eax
445 push ebx
446 push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
447 call _KeBugCheckEx@20
448
449 InvalidIndex:
450
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]
454
455 /* Bugcheck */
456 push 0
457 push edx
458 push eax
459 push ebx
460 push APC_INDEX_MISMATCH
461 call _KeBugCheckEx@20
462 ret
463 #endif
464
465 .func KiServiceExit2
466 _KiServiceExit2:
467
468 /* Disable interrupts */
469 cli
470
471 /* Check for, and deliver, User-Mode APCs if needed */
472 CHECK_FOR_APC_DELIVER 0
473
474 /* Exit and cleanup */
475 TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
476 .endfunc
477
478 .func Kei386EoiHelper@0
479 _Kei386EoiHelper@0:
480
481 /* Disable interrupts */
482 cli
483
484 /* Check for, and deliver, User-Mode APCs if needed */
485 CHECK_FOR_APC_DELIVER 0
486
487 /* Exit and cleanup */
488 _Kei386EoiHelper2ndEntry:
489 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
490 .endfunc
491
492 V86_Exit:
493 /* Move to EDX position */
494 add esp, KTRAP_FRAME_EDX
495
496 /* Restore volatiles */
497 pop edx
498 pop ecx
499 pop eax
500
501 /* Move to non-volatiles */
502 lea esp, [ebp+KTRAP_FRAME_EDI]
503 pop edi
504 pop esi
505 pop ebx
506 pop ebp
507
508 /* Skip error code and return */
509 add esp, 4
510 iret
511
512 AbiosExit:
513 /* Not yet supported */
514 int 3
515
516 .func KiDebugService
517 _KiDebugService:
518
519 /* Push error code */
520 push 0
521
522 /* Enter trap */
523 TRAP_PROLOG(kids)
524
525 /* Increase EIP so we skip the INT3 */
526 //inc dword ptr [ebp+KTRAP_FRAME_EIP]
527
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]
532
533 /* Check for V86 mode */
534 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
535 jnz NotUserMode
536
537 /* Check if this is kernel or user-mode */
538 test byte ptr [ebp+KTRAP_FRAME_CS], 1
539 jz CallDispatch
540 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
541 jnz NotUserMode
542
543 /* Re-enable interrupts */
544 VdmProc:
545 sti
546
547 /* Call the debug routine */
548 CallDispatch:
549 mov esi, ecx
550 mov edi, edx
551 mov edx, eax
552 mov ecx, 3
553 push edi
554 push esi
555 push edx
556 call _KdpServiceDispatcher@12
557
558 NotUserMode:
559
560 /* Get the current process */
561 mov ebx, [fs:KPCR_CURRENT_THREAD]
562 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
563
564 /* Check if this is a VDM Process */
565 //cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
566 //jz VdmProc
567
568 /* Exit through common routine */
569 jmp _Kei386EoiHelper@0
570 .endfunc
571
572 .func NtRaiseException@12
573 _NtRaiseException@12:
574
575 /* NOTE: We -must- be called by Zw* to have the right frame! */
576 /* Push the stack frame */
577 push ebp
578
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
583
584 /* Set up stack frame */
585 mov ebp, esp
586
587 /* Get the Trap Frame in EBX */
588 mov ebx, [ebp+0]
589
590 /* Get the exception list and restore */
591 mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
592 mov [fs:KPCR_EXCEPTION_LIST], eax
593
594 /* Get the parameters */
595 mov edx, [ebp+16] /* Search frames */
596 mov ecx, [ebp+12] /* Context */
597 mov eax, [ebp+8] /* Exception Record */
598
599 /* Raise the exception */
600 push edx
601 push ebx
602 push 0
603 push ecx
604 push eax
605 call _KiRaiseException@20
606
607 /* Restore trap frame in EBP */
608 pop ebp
609 mov esp, ebp
610
611 /* Check the result */
612 or eax, eax
613 jz _KiServiceExit2
614
615 /* Restore debug registers too */
616 jmp _KiServiceExit
617 .endfunc
618
619 .func NtContinue@8
620 _NtContinue@8:
621
622 /* NOTE: We -must- be called by Zw* to have the right frame! */
623 /* Push the stack frame */
624 push ebp
625
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
630
631 /* Set up stack frame */
632 mov ebp, esp
633
634 /* Save the parameters */
635 mov eax, [ebp+0]
636 mov ecx, [ebp+8]
637
638 /* Call KiContinue */
639 push eax
640 push 0
641 push ecx
642 call _KiContinue@12
643
644 /* Check if we failed (bad context record) */
645 or eax, eax
646 jnz Error
647
648 /* Check if test alert was requested */
649 cmp dword ptr [ebp+12], 0
650 je DontTest
651
652 /* Test alert for the thread */
653 mov al, [ebx+KTHREAD_PREVIOUS_MODE]
654 push eax
655 call _KeTestAlertThread@4
656
657 DontTest:
658 /* Return to previous context */
659 pop ebp
660 mov esp, ebp
661 jmp _KiServiceExit2
662
663 Error:
664 pop ebp
665 mov esp, ebp
666 jmp _KiServiceExit
667 .endfunc
668
669 /* EXCEPTION DISPATCHERS *****************************************************/
670
671 .func CommonDispatchException
672 _CommonDispatchException:
673
674 /* Make space for an exception record */
675 sub esp, EXCEPTION_RECORD_LENGTH
676
677 /* Set it up */
678 mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
679 xor eax, 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
684
685 /* Check parameter count */
686 cmp eax, 0
687 jz NoParams
688
689 /* Get information */
690 lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
691 mov [ebx], edx
692 mov [ebx+4], esi
693 mov [ebx+8], edi
694
695 NoParams:
696
697 /* Set the record in ECX and check if this was V86 */
698 mov ecx, esp
699 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
700 jz SetPreviousMode
701
702 /* Set V86 mode */
703 mov eax, 0xFFFF
704 jmp MaskMode
705
706 SetPreviousMode:
707
708 /* Calculate the previous mode */
709 mov eax, [ebp+KTRAP_FRAME_CS]
710 MaskMode:
711 and eax, MODE_MASK
712
713 /* Dispatch the exception */
714 push 1
715 push eax
716 push ebp
717 push 0
718 push ecx
719 call _KiDispatchException@20
720
721 /* End the trap */
722 mov esp, ebp
723 jmp _Kei386EoiHelper@0
724 .endfunc
725
726 .func DispatchNoParam
727 _DispatchNoParam:
728 /* Call the common dispatcher */
729 xor ecx, ecx
730 call _CommonDispatchException
731 .endfunc
732
733 .func DispatchOneParam
734 _DispatchOneParam:
735 /* Call the common dispatcher */
736 xor edx, edx
737 mov ecx, 1
738 call _CommonDispatchException
739 .endfunc
740
741 .func DispatchTwoParam
742 _DispatchTwoParam:
743 /* Call the common dispatcher */
744 xor edx, edx
745 mov ecx, 2
746 call _CommonDispatchException
747 .endfunc
748
749 /* HARDWARE TRAP HANDLERS ****************************************************/
750
751 .func KiTrap0
752 _KiTrap0:
753 /* Push error code */
754 push 0
755
756 /* Enter trap */
757 TRAP_PROLOG(0)
758
759 /* Check for V86 */
760 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
761 jnz V86Int0
762
763 /* Check if the frame was from kernelmode */
764 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
765 jz SendException
766
767 /* Check the old mode */
768 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
769 jne VdmCheck
770
771 SendException:
772 /* Re-enable interrupts for user-mode and send the exception */
773 sti
774 mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
775 mov ebx, [ebp+KTRAP_FRAME_EIP]
776 jmp _DispatchNoParam
777
778 VdmCheck:
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
783 jz SendException
784
785 /* We don't support this yet! */
786 V86Int0:
787 int 3
788 .endfunc
789
790 .func KiTrap1
791 _KiTrap1:
792 /* Push error code */
793 push 0
794
795 /* Enter trap */
796 TRAP_PROLOG(1)
797
798 /* Check for V86 */
799 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
800 jnz V86Int1
801
802 /* Check if the frame was from kernelmode */
803 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
804 jz PrepInt1
805
806 /* Check the old mode */
807 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
808 jne V86Int1
809
810 EnableInterrupts:
811 /* Enable interrupts for user-mode */
812 sti
813
814 PrepInt1:
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
819 jmp _DispatchNoParam
820
821 V86Int1:
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
826 jz EnableInterrupts
827
828 /* We don't support VDM! */
829 int 3
830 .endfunc
831
832 .globl _KiTrap2
833 .func KiTrap2
834 _KiTrap2:
835
836 /* FIXME: This is an NMI, nothing like a normal exception */
837 mov eax, 2
838 jmp _KiSystemFatalException
839 .endfunc
840
841 .func KiTrap3
842 _KiTrap3:
843 /* Push error code */
844 push 0
845
846 /* Enter trap */
847 TRAP_PROLOG(3)
848
849 /* Check for V86 */
850 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
851 jnz V86Int3
852
853 /* Check if the frame was from kernelmode */
854 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
855 jz PrepInt3
856
857 /* Check the old mode */
858 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
859 jne V86Int3
860
861 EnableInterrupts3:
862 /* Enable interrupts for user-mode */
863 sti
864
865 PrepInt3:
866 /* Prepare the exception */
867 mov esi, ecx
868 mov edi, edx
869 mov edx, eax
870
871 /* Setup EIP, NTSTATUS and parameter count, then dispatch */
872 mov ebx, [ebp+KTRAP_FRAME_EIP]
873 dec ebx
874 mov eax, STATUS_BREAKPOINT
875 mov ecx, 3
876 call _CommonDispatchException
877
878 V86Int3:
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
883 jz EnableInterrupts3
884
885 /* We don't support VDM! */
886 int 3
887 .endfunc
888
889 .func KiTrap4
890 _KiTrap4:
891 /* Push error code */
892 push 0
893
894 /* Enter trap */
895 TRAP_PROLOG(4)
896
897 /* Check for V86 */
898 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
899 jnz V86Int4
900
901 /* Check if the frame was from kernelmode */
902 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
903 jz SendException4
904
905 /* Check the old mode */
906 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
907 jne VdmCheck4
908
909 SendException4:
910 /* Re-enable interrupts for user-mode and send the exception */
911 sti
912 mov eax, STATUS_INTEGER_OVERFLOW
913 mov ebx, [ebp+KTRAP_FRAME_EIP]
914 dec ebx
915 jmp _DispatchNoParam
916
917 VdmCheck4:
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
922 jz SendException4
923
924 /* We don't support this yet! */
925 V86Int4:
926 int 3
927 .endfunc
928
929 .func KiTrap5
930 _KiTrap5:
931 /* Push error code */
932 push 0
933
934 /* Enter trap */
935 TRAP_PROLOG(5)
936
937 /* Check for V86 */
938 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
939 jnz V86Int5
940
941 /* Check if the frame was from kernelmode */
942 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
943 jnz CheckMode
944
945 /* It did, and this should never happen */
946 mov eax, 5
947 jmp _KiSystemFatalException
948
949 /* Check the old mode */
950 CheckMode:
951 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
952 jne VdmCheck5
953
954 /* Re-enable interrupts for user-mode and send the exception */
955 SendException5:
956 sti
957 mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
958 mov ebx, [ebp+KTRAP_FRAME_EIP]
959 jmp _DispatchNoParam
960
961 VdmCheck5:
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
966 jz SendException5
967
968 /* We don't support this yet! */
969 V86Int5:
970 int 3
971 .endfunc
972
973 .func KiTrap6
974 _KiTrap6:
975
976 /* It this a V86 GPF? */
977 test dword ptr [esp+8], EFLAGS_V86_MASK
978 jz NotV86UD
979
980 /* Enter V86 Trap */
981 V86_TRAP_PROLOG kit6
982
983 /* Not yet supported (Invalid OPCODE from V86) */
984 int 3
985 jmp $
986
987 NotV86UD:
988 /* Push error code */
989 push 0
990
991 /* Enter trap */
992 TRAP_PROLOG(6)
993
994 /* Check if this happened in kernel mode */
995 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
996 jz KmodeOpcode
997
998 /* Check for VDM */
999 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1000 jz UmodeOpcode
1001
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
1006 jnz IsVdmOpcode
1007
1008 UmodeOpcode:
1009 /* Get EIP and enable interrupts at this point */
1010 mov esi, [ebp+KTRAP_FRAME_EIP]
1011 sti
1012
1013 /* Set intruction prefix length */
1014 mov ecx, 4
1015
1016 /* Setup a SEH frame */
1017 push ebp
1018 push OpcodeSEH
1019 push fs:[KPCR_EXCEPTION_LIST]
1020 mov fs:[KPCR_EXCEPTION_LIST], esp
1021
1022 OpcodeLoop:
1023 /* Get the instruction and check if it's LOCK */
1024 mov al, [esi]
1025 cmp al, 0xF0
1026 jz LockCrash
1027
1028 /* Keep moving */
1029 add esi, 1
1030 loop OpcodeLoop
1031
1032 /* Undo SEH frame */
1033 pop fs:[KPCR_EXCEPTION_LIST]
1034 add esp, 8
1035
1036 KmodeOpcode:
1037
1038 /* Re-enable interrupts */
1039 sti
1040
1041 /* Setup illegal instruction exception and dispatch it */
1042 mov ebx, [ebp+KTRAP_FRAME_EIP]
1043 mov eax, STATUS_ILLEGAL_INSTRUCTION
1044 jmp _DispatchNoParam
1045
1046 LockCrash:
1047
1048 /* Undo SEH Frame */
1049 pop fs:[KPCR_EXCEPTION_LIST]
1050 add esp, 8
1051
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
1056
1057 IsVdmOpcode:
1058
1059 /* Unhandled yet */
1060 int 3
1061 jmp $
1062
1063 /* Return to caller */
1064 jmp _Kei386EoiHelper@0
1065
1066 OpcodeSEH:
1067
1068 /* Get SEH frame */
1069 mov esp, [esp+8]
1070 pop fs:[KPCR_EXCEPTION_LIST]
1071 add esp, 4
1072 pop ebp
1073
1074 /* Check if this was user mode */
1075 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1076 jnz KmodeOpcode
1077
1078 /* Do a bugcheck */
1079 push ebp
1080 push 0
1081 push 0
1082 push 0
1083 push 0
1084 push KMODE_EXCEPTION_NOT_HANDLED
1085 call _KeBugCheckWithTf@24
1086 .endfunc
1087
1088 .func KiTrap7
1089 _KiTrap7:
1090 /* Push error code */
1091 push 0
1092
1093 /* Enter trap */
1094 TRAP_PROLOG(7)
1095
1096 /* Get the current thread and stack */
1097 StartTrapHandle:
1098 mov eax, [fs:KPCR_CURRENT_THREAD]
1099 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1100 sub ecx, NPX_FRAME_LENGTH
1101
1102 /* Check if emulation is enabled */
1103 test dword ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
1104 jnz EmulationEnabled
1105
1106 CheckState:
1107 /* Check if the NPX state is loaded */
1108 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1109 mov ebx, cr0
1110 jz IsLoaded
1111
1112 /* Remove flags */
1113 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
1114 mov cr0, ebx
1115
1116 /* Check the NPX thread */
1117 mov edx, [fs:KPCR_NPX_THREAD]
1118 or edx, edx
1119 jz NoNpxThread
1120
1121 /* Get the NPX Stack */
1122 mov esi, [edx+KTHREAD_INITIAL_STACK]
1123 sub esi, NPX_FRAME_LENGTH
1124
1125 /* Check if we have FXSR and check which operand to use */
1126 test byte ptr _KeI386FxsrPresent, 1
1127 jz FnSave
1128 fxsave [esi]
1129 jmp AfterSave
1130
1131 FnSave:
1132 fnsave [esi]
1133
1134 AfterSave:
1135 /* Set the thread's state to dirty */
1136 mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1137
1138 NoNpxThread:
1139 /* Check if we have FXSR and choose which operand to use */
1140 test byte ptr _KeI386FxsrPresent, 1
1141 jz FrRestore
1142 fxrstor [ecx]
1143 jmp AfterRestore
1144
1145 FrRestore:
1146 frstor [esi]
1147
1148 AfterRestore:
1149 /* Set state loaded */
1150 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1151 mov [fs:KPCR_NPX_THREAD], eax
1152
1153 /* Enable interrupts to happen now */
1154 sti
1155 nop
1156
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
1160
1161 /* We have to reload CR0... disable interrupts */
1162 cli
1163
1164 /* Get CR0 and update it */
1165 mov ebx, cr0
1166 or ebx, [ecx+FN_CR0_NPX_STATE]
1167 mov cr0, ebx
1168
1169 /* Restore interrupts and check if TS is back on */
1170 sti
1171 test bl, CR0_TS
1172 jz _Kei386EoiHelper@0
1173
1174 /* Clear TS, and loop handling again */
1175 clts
1176 cli
1177 jmp StartTrapHandle
1178
1179 KernelNpx:
1180
1181 /* Set delayed error */
1182 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
1183
1184 /* Check if this happened during restore */
1185 cmp dword ptr [ebp+KTRAP_FRAME_EIP], offset FrRestore
1186 jnz UserNpx
1187
1188 /* Skip instruction and dispatch the exception */
1189 add dword ptr [ebp+KTRAP_FRAME_EIP], 3
1190 jmp _Kei386EoiHelper@0
1191
1192 IsLoaded:
1193 /* Check if TS is set */
1194 test bl, CR0_TS
1195 jnz TsSetOnLoadedState
1196
1197 HandleNpxFault:
1198 /* Check if the trap came from V86 mode */
1199 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1200 jnz V86Npx
1201
1202 /* Check if it came from kernel mode */
1203 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1204 jz KernelNpx
1205
1206 /* Check if it came from a VDM */
1207 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1208 jne V86Npx
1209
1210 UserNpx:
1211 /* Get the current thread */
1212 mov eax, fs:[KPCR_CURRENT_THREAD]
1213
1214 /* Check NPX state */
1215 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1216
1217 /* Get the NPX save area */
1218 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1219 lea ecx, [ecx-NPX_FRAME_LENGTH]
1220 jz NoSaveRestore
1221
1222 HandleUserNpx:
1223
1224 /* Set new CR0 */
1225 mov ebx, cr0
1226 and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
1227 mov cr0, ebx
1228
1229 /* Check if we have FX support */
1230 test byte ptr _KeI386FxsrPresent, 1
1231 jz FnSave2
1232
1233 /* Save the state */
1234 fxsave [ecx]
1235 jmp MakeCr0Dirty
1236 FnSave2:
1237 fnsave [ecx]
1238 wait
1239
1240 MakeCr0Dirty:
1241 /* Make CR0 state not loaded */
1242 or ebx, NPX_STATE_NOT_LOADED
1243 or ebx, [ecx+FN_CR0_NPX_STATE]
1244 mov cr0, ebx
1245
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
1249
1250 NoSaveRestore:
1251 /* Clear the TS bit and re-enable interrupts */
1252 and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
1253 sti
1254
1255 /* Check if we have FX support */
1256 test byte ptr _KeI386FxsrPresent, 1
1257 jz FnError
1258
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]
1263
1264 /* Get the faulting opcode */
1265 mov esi, [ecx+FX_DATA_OFFSET]
1266 jmp CheckError
1267
1268 FnError:
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]
1273
1274 /* Get the faulting opcode */
1275 mov esi, [ecx+FP_DATA_OFFSET]
1276
1277 CheckError:
1278 /* Mask exceptions */
1279 and eax, 0x3F
1280 not eax
1281 and eax, edx
1282
1283 /* Check if what's left is invalid */
1284 test al, 1
1285 jz ValidNpxOpcode
1286
1287 /* Check if it was a stack fault */
1288 test al, 64
1289 jnz InvalidStack
1290
1291 /* Raise exception */
1292 mov eax, STATUS_FLOAT_INVALID_OPERATION
1293 jmp _DispatchOneParam
1294
1295 InvalidStack:
1296
1297 /* Raise exception */
1298 mov eax, STATUS_FLOAT_STACK_CHECK
1299 jmp _DispatchTwoParam
1300
1301 ValidNpxOpcode:
1302
1303 /* Check for divide by 0 */
1304 test al, 4
1305 jz 1f
1306
1307 /* Raise exception */
1308 mov eax, STATUS_FLOAT_DIVIDE_BY_ZERO
1309 jmp _DispatchOneParam
1310
1311 1:
1312 /* Check for denormal */
1313 test al, 2
1314 jz 1f
1315
1316 /* Raise exception */
1317 mov eax, STATUS_FLOAT_INVALID_OPERATION
1318 jmp _DispatchOneParam
1319
1320 1:
1321 /* Check for overflow */
1322 test al, 8
1323 jz 1f
1324
1325 /* Raise exception */
1326 mov eax, STATUS_FLOAT_OVERFLOW
1327 jmp _DispatchOneParam
1328
1329 1:
1330 /* Check for underflow */
1331 test al, 16
1332 jz 1f
1333
1334 /* Raise exception */
1335 mov eax, STATUS_FLOAT_UNDERFLOW
1336 jmp _DispatchOneParam
1337
1338 1:
1339 /* Check for precision fault */
1340 test al, 32
1341 jz UnexpectedNpx
1342
1343 /* Raise exception */
1344 mov eax, STATUS_FLOAT_INEXACT_RESULT
1345 jmp _DispatchOneParam
1346
1347 UnexpectedNpx:
1348
1349 /* Strange result, bugcheck the OS */
1350 sti
1351 push ebp
1352 push 0
1353 push 0
1354 push eax
1355 push 1
1356 push TRAP_CAUSE_UNKNOWN
1357 call _KeBugCheckWithTf@24
1358
1359 V86Npx:
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
1364 jz HandleUserNpx
1365
1366 /* V86 NPX not handled */
1367 int 3
1368 jmp $
1369
1370 EmulationEnabled:
1371 /* Did this come from kernel-mode? */
1372 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1373 jz CheckState
1374
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. */
1377 jmp UnexpectedNpx
1378
1379 TsSetOnLoadedState:
1380 /* TS shouldn't be set, unless this we don't have a Math Processor */
1381 test bl, CR0_MP
1382 jnz BogusTrap
1383
1384 /* Strange that we got a trap at all, but ignore and continue */
1385 clts
1386 jmp _Kei386EoiHelper@0
1387
1388 BogusTrap:
1389 /* Cause a bugcheck */
1390 push 0
1391 push 0
1392 push ebx
1393 push 2
1394 push TRAP_CAUSE_UNKNOWN
1395 call _KeBugCheckEx@20
1396 .endfunc
1397
1398 .globl _KiTrap8
1399 .func KiTrap8
1400 _KiTrap8:
1401
1402 /* Can't really do too much */
1403 mov eax, 8
1404 jmp _KiSystemFatalException
1405 .endfunc
1406
1407 .func KiTrap9
1408 _KiTrap9:
1409 /* Push error code */
1410 push 0
1411
1412 /* Enter trap */
1413 TRAP_PROLOG(9)
1414
1415 /* Enable interrupts and bugcheck */
1416 sti
1417 mov eax, 9
1418 jmp _KiSystemFatalException
1419 .endfunc
1420
1421 .func KiTrap10
1422 _KiTrap10:
1423 /* Enter trap */
1424 TRAP_PROLOG(10)
1425
1426 /* Check for V86 */
1427 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1428 jnz V86IntA
1429
1430 /* Check if the frame was from kernelmode */
1431 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1432 jz Fatal
1433
1434 V86IntA:
1435 /* Check if OF was set during iretd */
1436 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
1437 sti
1438 jz Fatal
1439
1440 /* It was, just mask it out */
1441 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
1442 jmp _Kei386EoiHelper@0
1443
1444 Fatal:
1445 /* TSS failure for some other reason: crash */
1446 mov eax, 10
1447 jmp _KiSystemFatalException
1448 .endfunc
1449
1450 .func KiTrap11
1451 _KiTrap11:
1452 /* Enter trap */
1453 TRAP_PROLOG(11)
1454
1455 /* FIXME: ROS Doesn't handle segment faults yet */
1456 mov eax, 11
1457 jmp _KiSystemFatalException
1458 .endfunc
1459
1460 .func KiTrap12
1461 _KiTrap12:
1462 /* Enter trap */
1463 TRAP_PROLOG(12)
1464
1465 /* FIXME: ROS Doesn't handle stack faults yet */
1466 mov eax, 12
1467 jmp _KiSystemFatalException
1468 .endfunc
1469
1470 .func KiTrap13
1471 _KiTrap13:
1472
1473 /* It this a V86 GPF? */
1474 test dword ptr [esp+12], EFLAGS_V86_MASK
1475 jz NotV86
1476
1477 /* Enter V86 Trap */
1478 V86_TRAP_PROLOG kitd
1479
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
1484 jnz RaiseIrql
1485
1486 /* Otherwise, something is very wrong, raise an exception */
1487 sti
1488 mov ebx, [ebp+KTRAP_FRAME_EIP]
1489 mov esi, -1
1490 mov eax, STATUS_ACCESS_VIOLATION
1491 jmp _DispatchTwoParam
1492
1493 RaiseIrql:
1494
1495 /* Go to APC level */
1496 mov ecx, APC_LEVEL
1497 call @KfRaiseIrql@4
1498
1499 /* Save old IRQL and enable interrupts */
1500 push eax
1501 sti
1502
1503 /* Handle the opcode */
1504 call _Ki386HandleOpcodeV86@0
1505
1506 /* Check if this was VDM */
1507 test al, 0xFF
1508 jnz NoReflect
1509
1510 /* FIXME: TODO */
1511 int 3
1512
1513 NoReflect:
1514
1515 /* Lower IRQL and disable interrupts */
1516 pop ecx
1517 call @KfLowerIrql@4
1518 cli
1519
1520 /* Check if this was a V86 trap */
1521 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1522 jz NotV86Trap
1523
1524 /* Exit the V86 Trap */
1525 V86_TRAP_EPILOG
1526
1527 NotV86Trap:
1528
1529 /* Either this wasn't V86, or it was, but an APC interrupted us */
1530 jmp _Kei386EoiHelper@0
1531
1532 NotV86:
1533 /* Enter trap */
1534 TRAP_PROLOG(13)
1535
1536 /* Check if this was from kernel-mode */
1537 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1538 jnz UserModeGpf
1539
1540 /* FIXME: Check for GPF during GPF */
1541
1542 /* Get the opcode and trap frame */
1543 mov eax, [ebp+KTRAP_FRAME_EIP]
1544 mov eax, [eax]
1545 mov edx, [ebp+KTRAP_FRAME_EBP]
1546
1547 /* We want to check if this was POP [DS/ES/FS/GS] */
1548 add edx, KTRAP_FRAME_DS
1549 cmp al, 0x1F
1550 jz SegPopGpf
1551 add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
1552 cmp al, 7
1553 jz SegPopGpf
1554 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1555 cmp ax, 0xA10F
1556 jz SegPopGpf
1557 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1558 cmp ax, 0xA90F
1559 jz SegPopGpf
1560
1561 /* It isn't, was it IRETD? */
1562 cmp al, 0xCF
1563 jne NotIretGpf
1564
1565 /* Get error code */
1566 lea edx, [ebp+KTRAP_FRAME_ESP]
1567 mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
1568 and ax, ~RPL_MASK
1569
1570 /* Get CS */
1571 mov cx, word ptr [edx+4]
1572 and cx, ~RPL_MASK
1573 cmp cx, ax
1574 jnz NotCsGpf
1575
1576 /* This should be a Ki386CallBios return */
1577 mov eax, offset _Ki386BiosCallReturnAddress
1578 cmp eax, [edx]
1579 jne NotBiosGpf
1580 mov eax, [edx+4]
1581 cmp ax, KGDT_R0_CODE + RPL_MASK
1582 jne NotBiosGpf
1583
1584 /* Jump to return address */
1585 jmp _Ki386BiosCallReturnAddress
1586
1587 NotBiosGpf:
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
1591 jz UserModeGpf
1592
1593 /* Set RPL_MASK for check below */
1594 or word ptr [edx+4], RPL_MASK
1595
1596 NotCsGpf:
1597 /* Check if the IRET goes to user-mode */
1598 test dword ptr [edx+4], RPL_MASK
1599 jz UserModeGpf
1600
1601 /* Setup trap frame to copy */
1602 mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
1603 lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
1604
1605 TrapCopy:
1606
1607 /* Copy each field */
1608 mov eax, [edx]
1609 mov [edx+12], eax
1610 sub edx, 4
1611 loop TrapCopy
1612
1613 /* Enable interrupts and adjust stack */
1614 sti
1615 add esp, 12
1616 add ebp, 12
1617
1618 /* Setup exception record */
1619 mov ebx, [ebp+KTRAP_FRAME_EIP]
1620 mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
1621 and esi, 0xFFFF
1622 mov eax, STATUS_ACCESS_VIOLATION
1623 jmp _DispatchTwoParam
1624
1625 MsrCheck:
1626
1627 /* FIXME: Handle RDMSR/WRMSR */
1628 int 3
1629 jmp $
1630
1631 NotIretGpf:
1632
1633 /* Check if this was an MSR opcode */
1634 cmp al, 0xF
1635 jz MsrCheck
1636
1637 /* Check if DS is Ring 3 */
1638 cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1639 jz CheckEs
1640
1641 /* Otherwise, fix it up */
1642 mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1643 jmp ExitGpfTrap
1644
1645 CheckEs:
1646
1647 /* Check if ES is Ring 3 */
1648 cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1649 jz UserModeGpf
1650
1651 /* Otherwise, fix it up */
1652 mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1653 jmp ExitGpfTrap
1654
1655 SegPopGpf:
1656
1657 /* Sanity check */
1658 lea eax, [ebp+KTRAP_FRAME_ESP]
1659 cmp edx, eax
1660 jz HandleSegPop
1661 int 3
1662
1663 /* Handle segment POP fault by setting it to 0 */
1664 HandleSegPop:
1665 xor eax, eax
1666 mov dword ptr [edx], eax
1667
1668 ExitGpfTrap:
1669
1670 /* Do a trap exit */
1671 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
1672
1673 UserModeGpf:
1674
1675 /* FIXME: Unhandled */
1676 int 3
1677 jmp $
1678 .endfunc
1679
1680 .func KiTrap14
1681 _KiTrap14:
1682 /* Enter trap */
1683 TRAP_PROLOG(14)
1684
1685 /* Call the C exception handler */
1686 push 14
1687 push ebp
1688 call _KiPageFaultHandler
1689 add esp, 8
1690
1691 /* Return to caller */
1692 jmp _Kei386EoiHelper@0
1693 .endfunc
1694
1695 .func KiTrap0F
1696 _KiTrap0F:
1697 /* Push error code */
1698 push 0
1699
1700 /* Enter trap */
1701 TRAP_PROLOG(15)
1702 sti
1703
1704 /* Raise a fatal exception */
1705 mov eax, 15
1706 jmp _KiSystemFatalException
1707 .endfunc
1708
1709 .func KiTrap16
1710 _KiTrap16:
1711 /* Push error code */
1712 push 0
1713
1714 /* Enter trap */
1715 TRAP_PROLOG(16)
1716
1717 /* Check if this is the NPX Thread */
1718 mov eax, fs:[KPCR_CURRENT_THREAD]
1719 cmp eax, fs:[KPCR_NPX_THREAD]
1720
1721 /* Get the initial stack and NPX frame */
1722 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1723 lea ecx, [ecx-NPX_FRAME_LENGTH]
1724
1725 /* If this is a valid fault, handle it */
1726 jz HandleNpxFault
1727
1728 /* Otherwise, re-enable interrupts and set delayed error */
1729 sti
1730 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
1731 jmp _Kei386EoiHelper@0
1732 .endfunc
1733
1734 .func KiTrap17
1735 _KiTrap17:
1736 /* Push error code */
1737 push 0
1738
1739 /* Enter trap */
1740 TRAP_PROLOG(17)
1741
1742 /* FIXME: ROS Doesn't handle alignment faults yet */
1743 mov eax, 17
1744 jmp _KiSystemFatalException
1745 .endfunc
1746
1747 .func KiSystemFatalException
1748 _KiSystemFatalException:
1749
1750 /* Push the trap frame */
1751 push ebp
1752
1753 /* Push empty parameters */
1754 push 0
1755 push 0
1756 push 0
1757
1758 /* Push trap number and bugcheck code */
1759 push eax
1760 push UNEXPECTED_KERNEL_MODE_TRAP
1761 call _KeBugCheckWithTf@24
1762 ret
1763 .endfunc
1764
1765 .func KiCoprocessorError@0
1766 _KiCoprocessorError@0:
1767
1768 /* Get the NPX Thread's Initial stack */
1769 mov eax, [fs:KPCR_NPX_THREAD]
1770 mov eax, [eax+KTHREAD_INITIAL_STACK]
1771
1772 /* Make space for the FPU Save area */
1773 sub eax, SIZEOF_FX_SAVE_AREA
1774
1775 /* Set the CR0 State */
1776 mov dword ptr [eax+FN_CR0_NPX_STATE], 8
1777
1778 /* Update it */
1779 mov eax, cr0
1780 or eax, 8
1781 mov cr0, eax
1782
1783 /* Return to caller */
1784 ret
1785 .endfunc
1786
1787 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
1788
1789 .globl _KiStartUnexpectedRange@0
1790 _KiStartUnexpectedRange@0:
1791
1792 GENERATE_INT_HANDLERS
1793
1794 .globl _KiEndUnexpectedRange@0
1795 _KiEndUnexpectedRange@0:
1796 jmp _KiUnexpectedInterruptTail
1797
1798 .func KiUnexpectedInterruptTail
1799 _KiUnexpectedInterruptTail:
1800
1801 /* Enter interrupt trap */
1802 INT_PROLOG kui, DoNotPushFakeErrorCode
1803
1804 /* Increase interrupt count */
1805 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1806
1807 /* Put vector in EBX and make space for KIRQL */
1808 mov ebx, [esp]
1809 sub esp, 4
1810
1811 /* Begin interrupt */
1812 push esp
1813 push ebx
1814 push HIGH_LEVEL
1815 call _HalBeginSystemInterrupt@12
1816
1817 /* Check if it was spurious or not */
1818 or al, al
1819 jnz Handled
1820
1821 /* Spurious, ignore it */
1822 add esp, 8
1823 jmp _Kei386EoiHelper2ndEntry
1824
1825 Handled:
1826 /* Unexpected interrupt, print a message on debug builds */
1827 #if DBG
1828 push [esp+4]
1829 push offset _UnexpectedMsg
1830 call _DbgPrint
1831 add esp, 8
1832 #endif
1833
1834 /* Exit the interrupt */
1835 mov esi, $
1836 cli
1837 call _HalEndSystemInterrupt@8
1838 jmp _Kei386EoiHelper@0
1839 .endfunc
1840
1841 .globl _KiUnexpectedInterrupt
1842 _KiUnexpectedInterrupt:
1843
1844 /* Bugcheck with invalid interrupt code */
1845 push TRAP_CAUSE_UNKNOWN
1846 call _KeBugCheck@4
1847
1848 /* INTERRUPT HANDLERS ********************************************************/
1849
1850 .func KiDispatchInterrupt@0
1851 _KiDispatchInterrupt@0:
1852
1853 /* Get the PCR and disable interrupts */
1854 mov ebx, [fs:KPCR_SELF]
1855 cli
1856
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]
1861 jz CheckQuantum
1862
1863 /* Save stack pointer and exception list, then clear it */
1864 push ebp
1865 push dword ptr [ebx+KPCR_EXCEPTION_LIST]
1866 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
1867
1868 /* Save the stack and switch to the DPC Stack */
1869 mov edx, esp
1870 //mov esp, [ebx+KPCR_PRCB_DPC_STACK]
1871 push edx
1872
1873 /* Deliver DPCs */
1874 mov ecx, [ebx+KPCR_PRCB]
1875 call @KiRetireDpcList@4
1876
1877 /* Restore stack and exception list */
1878 pop esp
1879 pop dword ptr [ebx]
1880 pop ebp
1881
1882 CheckQuantum:
1883
1884 /* Re-enable interrupts */
1885 sti
1886
1887 /* Check if we have quantum end */
1888 cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
1889 jnz QuantumEnd
1890
1891 /* Check if we have a thread to swap to */
1892 cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
1893 jz Return
1894
1895 /* FIXME: Schedule new thread */
1896 int 3
1897
1898 Return:
1899 /* All done */
1900 ret
1901
1902 QuantumEnd:
1903 /* Disable quantum end and process it */
1904 mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
1905 call _KiQuantumEnd@0
1906 ret
1907 .endfunc
1908
1909 .func KiInterruptTemplate
1910 _KiInterruptTemplate:
1911
1912 /* Enter interrupt trap */
1913 INT_PROLOG kit, DoPushFakeErrorCode
1914 .endfunc
1915
1916 _KiInterruptTemplate2ndDispatch:
1917 /* Dummy code, will be replaced by the address of the KINTERRUPT */
1918 mov edi, 0
1919
1920 _KiInterruptTemplateObject:
1921 /* Dummy jump, will be replaced by the actual jump */
1922 jmp _KeSynchronizeExecution@12
1923
1924 _KiInterruptTemplateDispatch:
1925 /* Marks the end of the template so that the jump above can be edited */
1926
1927 .func KiChainedDispatch2ndLvl@0
1928 _KiChainedDispatch2ndLvl@0:
1929
1930 /* Not yet supported */
1931 int 3
1932 .endfunc
1933
1934 .func KiChainedDispatch@0
1935 _KiChainedDispatch@0:
1936
1937 /* Increase interrupt count */
1938 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1939
1940 /* Save trap frame */
1941 mov ebp, esp
1942
1943 /* Save vector and IRQL */
1944 mov eax, [edi+KINTERRUPT_VECTOR]
1945 mov ecx, [edi+KINTERRUPT_IRQL]
1946
1947 /* Save old irql */
1948 push eax
1949 sub esp, 4
1950
1951 /* Begin interrupt */
1952 push esp
1953 push eax
1954 push ecx
1955 call _HalBeginSystemInterrupt@12
1956
1957 /* Check if it was handled */
1958 or al, al
1959 jz SpuriousInt
1960
1961 /* Call the 2nd-level handler */
1962 call _KiChainedDispatch2ndLvl@0
1963
1964 /* Exit the interrupt */
1965 mov esi, $
1966 cli
1967 call _HalEndSystemInterrupt@8
1968 jmp _Kei386EoiHelper@0
1969 .endfunc
1970
1971 .func KiInterruptDispatch@0
1972 _KiInterruptDispatch@0:
1973
1974 /* Increase interrupt count */
1975 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1976
1977 /* Save trap frame */
1978 mov ebp, esp
1979
1980 /* Save vector and IRQL */
1981 mov eax, [edi+KINTERRUPT_VECTOR]
1982 mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
1983
1984 /* Save old irql */
1985 push eax
1986 sub esp, 4
1987
1988 /* Begin interrupt */
1989 push esp
1990 push eax
1991 push ecx
1992 call _HalBeginSystemInterrupt@12
1993
1994 /* Check if it was handled */
1995 or al, al
1996 jz SpuriousInt
1997
1998 /* Acquire the lock */
1999 GetIntLock:
2000 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
2001 ACQUIRE_SPINLOCK(esi, IntSpin)
2002
2003 /* Call the ISR */
2004 mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
2005 push eax
2006 push edi
2007 call [edi+KINTERRUPT_SERVICE_ROUTINE]
2008
2009 /* Release the lock */
2010 RELEASE_SPINLOCK(esi)
2011
2012 /* Exit the interrupt */
2013 cli
2014 call _HalEndSystemInterrupt@8
2015 jmp _Kei386EoiHelper@0
2016
2017 SpuriousInt:
2018 /* Exit the interrupt */
2019 jmp $
2020 add esp, 8
2021 jmp _Kei386EoiHelper@0
2022
2023 #ifdef CONFIG_SMP
2024 IntSpin:
2025 SPIN_ON_LOCK esi, GetIntLock
2026 #endif
2027 .endfunc