- Merge 25572 (except the NTLPC related part), this fixes VMWare detection.
[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 _UnhandledMsg:
91 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
92
93 _KiTrapPrefixTable:
94 .byte 0xF2 /* REP */
95 .byte 0xF3 /* REP INS/OUTS */
96 .byte 0x67 /* ADDR */
97 .byte 0xF0 /* LOCK */
98 .byte 0x66 /* OP */
99 .byte 0x2E /* SEG */
100 .byte 0x3E /* DS */
101 .byte 0x26 /* ES */
102 .byte 0x64 /* FS */
103 .byte 0x65 /* GS */
104 .byte 0x36 /* SS */
105
106 _KiTrapIoTable:
107 .byte 0xE4 /* IN */
108 .byte 0xE5 /* IN */
109 .byte 0xEC /* IN */
110 .byte 0xED /* IN */
111 .byte 0x6C /* INS */
112 .byte 0x6D /* INS */
113 .byte 0xE6 /* OUT */
114 .byte 0xE7 /* OUT */
115 .byte 0xEE /* OUT */
116 .byte 0xEF /* OUT */
117 .byte 0x6E /* OUTS */
118 .byte 0x6F /* OUTS */
119
120 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
121 .text
122
123 _KiGetTickCount:
124 _KiCallbackReturn:
125 _KiRaiseAssertion:
126 /* FIXME: TODO */
127 UNHANDLED_PATH
128
129 .func KiSystemService
130 Dr_kss: DR_TRAP_FIXUP
131 _KiSystemService:
132
133 /* Enter the shared system call prolog */
134 SYSCALL_PROLOG kss
135
136 /* Jump to the actual handler */
137 jmp SharedCode
138 .endfunc
139
140 .func KiFastCallEntry
141 Dr_FastCallDrSave: DR_TRAP_FIXUP
142 _KiFastCallEntry:
143
144 /* Enter the fast system call prolog */
145 FASTCALL_PROLOG FastCallDrSave
146
147 SharedCode:
148
149 /*
150 * Find out which table offset to use. Converts 0x1124 into 0x10.
151 * The offset is related to the Table Index as such: Offset = TableIndex x 10
152 */
153 mov edi, eax
154 shr edi, SERVICE_TABLE_SHIFT
155 and edi, SERVICE_TABLE_MASK
156 mov ecx, edi
157
158 /* Now add the thread's base system table to the offset */
159 add edi, [esi+KTHREAD_SERVICE_TABLE]
160
161 /* Get the true syscall ID and check it */
162 mov ebx, eax
163 and eax, SERVICE_NUMBER_MASK
164 cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT]
165
166 /* Invalid ID, try to load Win32K Table */
167 jnb KiBBTUnexpectedRange
168
169 /* Check if this was Win32K */
170 cmp ecx, SERVICE_TABLE_TEST
171 jnz NotWin32K
172
173 /* Get the TEB */
174 mov ecx, [fs:KPCR_TEB]
175
176 /* Check if we should flush the User Batch */
177 xor ebx, ebx
178 ReadBatch:
179 or ebx, [ecx+TEB_GDI_BATCH_COUNT]
180 jz NotWin32K
181
182 /* Flush it */
183 push edx
184 push eax
185 //call [_KeGdiFlushUserBatch]
186 pop eax
187 pop edx
188
189 NotWin32K:
190 /* Increase total syscall count */
191 inc dword ptr fs:[KPCR_SYSTEM_CALLS]
192
193 #ifdef DBG
194 /* Increase per-syscall count */
195 mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT]
196 jecxz NoCountTable
197 inc dword ptr [ecx+eax*4]
198 #endif
199
200 /* Users's current stack frame pointer is source */
201 NoCountTable:
202 mov esi, edx
203
204 /* Allocate room for argument list from kernel stack */
205 mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER]
206 xor ecx, ecx
207 mov cl, [eax+ebx]
208
209 /* Get pointer to function */
210 mov edi, [edi+SERVICE_DESCRIPTOR_BASE]
211 mov ebx, [edi+eax*4]
212
213 /* Allocate space on our stack */
214 sub esp, ecx
215
216 /* Set the size of the arguments and the destination */
217 shr ecx, 2
218 mov edi, esp
219
220 /* Make sure we're within the User Probe Address */
221 cmp esi, _MmUserProbeAddress
222 jnb AccessViolation
223
224 CopyParams:
225 /* Copy the parameters */
226 rep movsd
227
228 #ifdef DBG
229 /*
230 * The following lines are for the benefit of GDB. It will see the return
231 * address of the "call ebx" below, find the last label before it and
232 * thinks that that's the start of the function. It will then check to see
233 * if it starts with a standard function prolog (push ebp, mov ebp,esp1).
234 * When that standard function prolog is not found, it will stop the
235 * stack backtrace. Since we do want to backtrace into usermode, let's
236 * make GDB happy and create a standard prolog.
237 */
238 KiSystemService:
239 push ebp
240 mov ebp,esp
241 pop ebp
242 #endif
243
244 /* Do the System Call */
245 call ebx
246
247 AfterSysCall:
248 #ifdef DBG
249 /* Make sure the user-mode call didn't return at elevated IRQL */
250 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
251 jz SkipCheck
252 mov esi, eax /* We need to save the syscall's return val */
253 call _KeGetCurrentIrql@0
254 or al, al
255 jnz InvalidIrql
256 mov eax, esi /* Restore it */
257
258 /* Get our temporary current thread pointer for sanity check */
259 mov ecx, fs:[KPCR_CURRENT_THREAD]
260
261 /* Make sure that we are not attached and that APCs are not disabled */
262 mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
263 or dl, dl
264 jnz InvalidIndex
265 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
266 or edx, edx
267 jnz InvalidIndex
268 #endif
269
270 SkipCheck:
271
272 /* Deallocate the kernel stack frame */
273 mov esp, ebp
274
275 KeReturnFromSystemCall:
276
277 /* Get the Current Thread */
278 mov ecx, [fs:KPCR_CURRENT_THREAD]
279
280 /* Restore the old trap frame pointer */
281 mov edx, [ebp+KTRAP_FRAME_EDX]
282 mov [ecx+KTHREAD_TRAP_FRAME], edx
283 .endfunc
284
285 .func KiServiceExit
286 _KiServiceExit:
287 /* Disable interrupts */
288 cli
289
290 /* Check for, and deliver, User-Mode APCs if needed */
291 CHECK_FOR_APC_DELIVER 1
292
293 /* Exit and cleanup */
294 TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything
295 .endfunc
296
297 KiBBTUnexpectedRange:
298
299 /* If this isn't a Win32K call, fail */
300 cmp ecx, SERVICE_TABLE_TEST
301 jne InvalidCall
302
303 /* Set up Win32K Table */
304 push edx
305 push ebx
306 call _PsConvertToGuiThread@0
307
308 /* Check return code */
309 or eax, eax
310
311 /* Restore registers */
312 pop eax
313 pop edx
314
315 /* Reset trap frame address */
316 mov ebp, esp
317 mov [esi+KTHREAD_TRAP_FRAME], ebp
318
319 /* Try the Call again, if we suceeded */
320 jz SharedCode
321
322 /*
323 * The Shadow Table should have a special byte table which tells us
324 * whether we should return FALSE, -1 or STATUS_INVALID_SYSTEM_SERVICE.
325 */
326
327 /* Get the table limit and base */
328 lea edx, _KeServiceDescriptorTableShadow + SERVICE_TABLE_TEST
329 mov ecx, [edx+SERVICE_DESCRIPTOR_LIMIT]
330 mov edx, [edx+SERVICE_DESCRIPTOR_BASE]
331
332 /* Get the table address and add our index into the array */
333 lea edx, [edx+ecx*4]
334 and eax, SERVICE_NUMBER_MASK
335 add edx, eax
336
337 /* Find out what we should return */
338 movsx eax, byte ptr [edx]
339 or eax, eax
340
341 /* Return either 0 or -1, we've set it in EAX */
342 jle KeReturnFromSystemCall
343
344 /* Set STATUS_INVALID_SYSTEM_SERVICE */
345 mov eax, STATUS_INVALID_SYSTEM_SERVICE
346 jmp KeReturnFromSystemCall
347
348 InvalidCall:
349
350 /* Invalid System Call */
351 mov eax, STATUS_INVALID_SYSTEM_SERVICE
352 jmp KeReturnFromSystemCall
353
354 AccessViolation:
355
356 /* Check if this came from kernel-mode */
357 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
358
359 /* It's fine, go ahead with it */
360 jz CopyParams
361
362 /* Caller sent invalid parameters, fail here */
363 mov eax, STATUS_ACCESS_VIOLATION
364 jmp AfterSysCall
365
366 BadStack:
367
368 /* Restore ESP0 stack */
369 mov ecx, [fs:KPCR_TSS]
370 mov esp, ss:[ecx+KTSS_ESP0]
371
372 /* Generate V86M Stack for Trap 6 */
373 push 0
374 push 0
375 push 0
376 push 0
377
378 /* Generate interrupt stack for Trap 6 */
379 push KGDT_R3_DATA + RPL_MASK
380 push 0
381 push 0x20202
382 push KGDT_R3_CODE + RPL_MASK
383 push 0
384 jmp _KiTrap6
385
386 #ifdef DBG
387 InvalidIrql:
388 /* Save current IRQL */
389 push fs:[KPCR_IRQL]
390
391 /* Set us at passive */
392 mov dword ptr fs:[KPCR_IRQL], 0
393 cli
394
395 /* Bugcheck */
396 push 0
397 push 0
398 push eax
399 push ebx
400 push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
401 call _KeBugCheckEx@20
402
403 InvalidIndex:
404
405 /* Get the index and APC state */
406 movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX]
407 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
408
409 /* Bugcheck */
410 push 0
411 push edx
412 push eax
413 push ebx
414 push APC_INDEX_MISMATCH
415 call _KeBugCheckEx@20
416 ret
417 #endif
418
419 .func KiServiceExit2
420 _KiServiceExit2:
421
422 /* Disable interrupts */
423 cli
424
425 /* Check for, and deliver, User-Mode APCs if needed */
426 CHECK_FOR_APC_DELIVER 0
427
428 /* Exit and cleanup */
429 TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
430 .endfunc
431
432 .func Kei386EoiHelper@0
433 _Kei386EoiHelper@0:
434
435 /* Disable interrupts */
436 cli
437
438 /* Check for, and deliver, User-Mode APCs if needed */
439 CHECK_FOR_APC_DELIVER 0
440
441 /* Exit and cleanup */
442 _Kei386EoiHelper2ndEntry:
443 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
444 .endfunc
445
446 V86_Exit:
447 /* Move to EDX position */
448 add esp, KTRAP_FRAME_EDX
449
450 /* Restore volatiles */
451 pop edx
452 pop ecx
453 pop eax
454
455 /* Move to non-volatiles */
456 lea esp, [ebp+KTRAP_FRAME_EDI]
457 pop edi
458 pop esi
459 pop ebx
460 pop ebp
461
462 /* Skip error code and return */
463 add esp, 4
464 iret
465
466 AbiosExit:
467 /* FIXME: TODO */
468 UNHANDLED_PATH
469
470 .func KiDebugService
471 Dr_kids: DR_TRAP_FIXUP
472 V86_kids: V86_TRAP_FIXUP
473 _KiDebugService:
474
475 /* Push error code */
476 push 0
477
478 /* Enter trap */
479 TRAP_PROLOG kids
480
481 /* Increase EIP so we skip the INT3 */
482 //inc dword ptr [ebp+KTRAP_FRAME_EIP]
483
484 /* Call debug service dispatcher */
485 mov eax, [ebp+KTRAP_FRAME_EAX]
486 mov ecx, [ebp+KTRAP_FRAME_ECX]
487 mov edx, [ebp+KTRAP_FRAME_EAX]
488
489 /* Check for V86 mode */
490 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
491 jnz NotUserMode
492
493 /* Check if this is kernel or user-mode */
494 test byte ptr [ebp+KTRAP_FRAME_CS], 1
495 jz CallDispatch
496 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
497 jnz NotUserMode
498
499 /* Re-enable interrupts */
500 VdmProc:
501 sti
502
503 /* Call the debug routine */
504 CallDispatch:
505 mov esi, ecx
506 mov edi, edx
507 mov edx, eax
508 mov ecx, 3
509 push edi
510 push esi
511 push edx
512 call _KdpServiceDispatcher@12
513
514 NotUserMode:
515
516 /* Get the current process */
517 mov ebx, [fs:KPCR_CURRENT_THREAD]
518 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
519
520 /* Check if this is a VDM Process */
521 //cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
522 //jz VdmProc
523
524 /* Exit through common routine */
525 jmp _Kei386EoiHelper@0
526 .endfunc
527
528 .func NtRaiseException@12
529 _NtRaiseException@12:
530
531 /* NOTE: We -must- be called by Zw* to have the right frame! */
532 /* Push the stack frame */
533 push ebp
534
535 /* Get the current thread and restore its trap frame */
536 mov ebx, [fs:KPCR_CURRENT_THREAD]
537 mov edx, [ebp+KTRAP_FRAME_EDX]
538 mov [ebx+KTHREAD_TRAP_FRAME], edx
539
540 /* Set up stack frame */
541 mov ebp, esp
542
543 /* Get the Trap Frame in EBX */
544 mov ebx, [ebp+0]
545
546 /* Get the exception list and restore */
547 mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
548 mov [fs:KPCR_EXCEPTION_LIST], eax
549
550 /* Get the parameters */
551 mov edx, [ebp+16] /* Search frames */
552 mov ecx, [ebp+12] /* Context */
553 mov eax, [ebp+8] /* Exception Record */
554
555 /* Raise the exception */
556 push edx
557 push ebx
558 push 0
559 push ecx
560 push eax
561 call _KiRaiseException@20
562
563 /* Restore trap frame in EBP */
564 pop ebp
565 mov esp, ebp
566
567 /* Check the result */
568 or eax, eax
569 jz _KiServiceExit2
570
571 /* Restore debug registers too */
572 jmp _KiServiceExit
573 .endfunc
574
575 .func NtContinue@8
576 _NtContinue@8:
577
578 /* NOTE: We -must- be called by Zw* to have the right frame! */
579 /* Push the stack frame */
580 push ebp
581
582 /* Get the current thread and restore its trap frame */
583 mov ebx, [fs:KPCR_CURRENT_THREAD]
584 mov edx, [ebp+KTRAP_FRAME_EDX]
585 mov [ebx+KTHREAD_TRAP_FRAME], edx
586
587 /* Set up stack frame */
588 mov ebp, esp
589
590 /* Save the parameters */
591 mov eax, [ebp+0]
592 mov ecx, [ebp+8]
593
594 /* Call KiContinue */
595 push eax
596 push 0
597 push ecx
598 call _KiContinue@12
599
600 /* Check if we failed (bad context record) */
601 or eax, eax
602 jnz Error
603
604 /* Check if test alert was requested */
605 cmp dword ptr [ebp+12], 0
606 je DontTest
607
608 /* Test alert for the thread */
609 mov al, [ebx+KTHREAD_PREVIOUS_MODE]
610 push eax
611 call _KeTestAlertThread@4
612
613 DontTest:
614 /* Return to previous context */
615 pop ebp
616 mov esp, ebp
617 jmp _KiServiceExit2
618
619 Error:
620 pop ebp
621 mov esp, ebp
622 jmp _KiServiceExit
623 .endfunc
624
625 /* EXCEPTION DISPATCHERS *****************************************************/
626
627 .func CommonDispatchException
628 _CommonDispatchException:
629
630 /* Make space for an exception record */
631 sub esp, EXCEPTION_RECORD_LENGTH
632
633 /* Set it up */
634 mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
635 xor eax, eax
636 mov [esp+EXCEPTION_RECORD_EXCEPTION_FLAGS], eax
637 mov [esp+EXCEPTION_RECORD_EXCEPTION_RECORD], eax
638 mov [esp+EXCEPTION_RECORD_EXCEPTION_ADDRESS], ebx
639 mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
640
641 /* Check parameter count */
642 cmp eax, 0
643 jz NoParams
644
645 /* Get information */
646 lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
647 mov [ebx], edx
648 mov [ebx+4], esi
649 mov [ebx+8], edi
650
651 NoParams:
652
653 /* Set the record in ECX and check if this was V86 */
654 mov ecx, esp
655 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
656 jz SetPreviousMode
657
658 /* Set V86 mode */
659 mov eax, 0xFFFF
660 jmp MaskMode
661
662 SetPreviousMode:
663
664 /* Calculate the previous mode */
665 mov eax, [ebp+KTRAP_FRAME_CS]
666 MaskMode:
667 and eax, MODE_MASK
668
669 /* Dispatch the exception */
670 push 1
671 push eax
672 push ebp
673 push 0
674 push ecx
675 call _KiDispatchException@20
676
677 /* End the trap */
678 mov esp, ebp
679 jmp _Kei386EoiHelper@0
680 .endfunc
681
682 .func DispatchNoParam
683 _DispatchNoParam:
684 /* Call the common dispatcher */
685 xor ecx, ecx
686 call _CommonDispatchException
687 .endfunc
688
689 .func DispatchOneParam
690 _DispatchOneParam:
691 /* Call the common dispatcher */
692 xor edx, edx
693 mov ecx, 1
694 call _CommonDispatchException
695 .endfunc
696
697 .func DispatchTwoParam
698 _DispatchTwoParam:
699 /* Call the common dispatcher */
700 xor edx, edx
701 mov ecx, 2
702 call _CommonDispatchException
703 .endfunc
704
705 /* HARDWARE TRAP HANDLERS ****************************************************/
706
707 .func KiFixupFrame
708 _KiFixupFrame:
709
710 /* TODO: Routine to fixup a KTRAP_FRAME when faulting from a syscall. */
711 UNHANDLED_PATH
712 .endfunc
713
714 .func KiTrap0
715 Dr_kit0: DR_TRAP_FIXUP
716 V86_kit0: V86_TRAP_FIXUP
717 _KiTrap0:
718 /* Push error code */
719 push 0
720
721 /* Enter trap */
722 TRAP_PROLOG kit0
723
724 /* Check for V86 */
725 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
726 jnz V86Int0
727
728 /* Check if the frame was from kernelmode */
729 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
730 jz SendException
731
732 /* Check the old mode */
733 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
734 jne VdmCheck
735
736 SendException:
737 /* Re-enable interrupts for user-mode and send the exception */
738 sti
739 mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
740 mov ebx, [ebp+KTRAP_FRAME_EIP]
741 jmp _DispatchNoParam
742
743 VdmCheck:
744 /* Check if this is a VDM process */
745 mov ebx, [fs:KPCR_CURRENT_THREAD]
746 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
747 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
748 jz SendException
749
750 /* We don't support this yet! */
751 V86Int0:
752 /* FIXME: TODO */
753 UNHANDLED_PATH
754 .endfunc
755
756 .func KiTrap1
757 Dr_kit1: DR_TRAP_FIXUP
758 V86_kit1: V86_TRAP_FIXUP
759 _KiTrap1:
760 /* Push error code */
761 push 0
762
763 /* Enter trap */
764 TRAP_PROLOG kit1
765
766 /* Check for V86 */
767 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
768 jnz V86Int1
769
770 /* Check if the frame was from kernelmode */
771 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
772 jz PrepInt1
773
774 /* Check the old mode */
775 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
776 jne V86Int1
777
778 EnableInterrupts:
779 /* Enable interrupts for user-mode */
780 sti
781
782 PrepInt1:
783 /* Prepare the exception */
784 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAGS_TF
785 mov ebx, [ebp+KTRAP_FRAME_EIP]
786 mov eax, STATUS_SINGLE_STEP
787 jmp _DispatchNoParam
788
789 V86Int1:
790 /* Check if this is a VDM process */
791 mov ebx, [fs:KPCR_CURRENT_THREAD]
792 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
793 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
794 jz EnableInterrupts
795
796 /* We don't support VDM! */
797 UNHANDLED_PATH
798 .endfunc
799
800 .globl _KiTrap2
801 .func KiTrap2
802 _KiTrap2:
803
804 /* FIXME: This is an NMI, nothing like a normal exception */
805 mov eax, 2
806 jmp _KiSystemFatalException
807 .endfunc
808
809 .func KiTrap3
810 Dr_kit3: DR_TRAP_FIXUP
811 V86_kit3: V86_TRAP_FIXUP
812 _KiTrap3:
813 /* Push error code */
814 push 0
815
816 /* Enter trap */
817 TRAP_PROLOG kit3
818
819 /* Check for V86 */
820 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
821 jnz V86Int3
822
823 /* Check if the frame was from kernelmode */
824 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
825 jz PrepInt3
826
827 /* Check the old mode */
828 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
829 jne V86Int3
830
831 EnableInterrupts3:
832 /* Enable interrupts for user-mode */
833 sti
834
835 PrepInt3:
836 /* Prepare the exception */
837 mov esi, ecx
838 mov edi, edx
839 mov edx, eax
840
841 /* Setup EIP, NTSTATUS and parameter count, then dispatch */
842 mov ebx, [ebp+KTRAP_FRAME_EIP]
843 dec ebx
844 mov eax, STATUS_BREAKPOINT
845 mov ecx, 3
846 call _CommonDispatchException
847
848 V86Int3:
849 /* Check if this is a VDM process */
850 mov ebx, [fs:KPCR_CURRENT_THREAD]
851 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
852 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
853 jz EnableInterrupts3
854
855 /* We don't support VDM! */
856 UNHANDLED_PATH
857 .endfunc
858
859 .func KiTrap4
860 Dr_kit4: DR_TRAP_FIXUP
861 V86_kit4: V86_TRAP_FIXUP
862 _KiTrap4:
863 /* Push error code */
864 push 0
865
866 /* Enter trap */
867 TRAP_PROLOG kit4
868
869 /* Check for V86 */
870 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
871 jnz V86Int4
872
873 /* Check if the frame was from kernelmode */
874 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
875 jz SendException4
876
877 /* Check the old mode */
878 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
879 jne VdmCheck4
880
881 SendException4:
882 /* Re-enable interrupts for user-mode and send the exception */
883 sti
884 mov eax, STATUS_INTEGER_OVERFLOW
885 mov ebx, [ebp+KTRAP_FRAME_EIP]
886 dec ebx
887 jmp _DispatchNoParam
888
889 VdmCheck4:
890 /* Check if this is a VDM process */
891 mov ebx, [fs:KPCR_CURRENT_THREAD]
892 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
893 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
894 jz SendException4
895
896 /* We don't support this yet! */
897 V86Int4:
898 UNHANDLED_PATH
899 .endfunc
900
901 .func KiTrap5
902 Dr_kit5: DR_TRAP_FIXUP
903 V86_kit5: V86_TRAP_FIXUP
904 _KiTrap5:
905 /* Push error code */
906 push 0
907
908 /* Enter trap */
909 TRAP_PROLOG kit5
910
911 /* Check for V86 */
912 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
913 jnz V86Int5
914
915 /* Check if the frame was from kernelmode */
916 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
917 jnz CheckMode
918
919 /* It did, and this should never happen */
920 mov eax, 5
921 jmp _KiSystemFatalException
922
923 /* Check the old mode */
924 CheckMode:
925 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
926 jne VdmCheck5
927
928 /* Re-enable interrupts for user-mode and send the exception */
929 SendException5:
930 sti
931 mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
932 mov ebx, [ebp+KTRAP_FRAME_EIP]
933 jmp _DispatchNoParam
934
935 VdmCheck5:
936 /* Check if this is a VDM process */
937 mov ebx, [fs:KPCR_CURRENT_THREAD]
938 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
939 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
940 jz SendException5
941
942 /* We don't support this yet! */
943 V86Int5:
944 UNHANDLED_PATH
945 .endfunc
946
947 .func KiTrap6
948 Dr_kit6: DR_TRAP_FIXUP
949 V86_kit6: V86_TRAP_FIXUP
950 _KiTrap6:
951
952 /* It this a V86 GPF? */
953 test dword ptr [esp+8], EFLAGS_V86_MASK
954 jz NotV86UD
955
956 /* Enter V86 Trap */
957 V86_TRAP_PROLOG kit6
958
959 /* Not yet supported (Invalid OPCODE from V86) */
960 UNHANDLED_PATH
961
962 NotV86UD:
963 /* Push error code */
964 push 0
965
966 /* Enter trap */
967 TRAP_PROLOG kit6
968
969 /* Check if this happened in kernel mode */
970 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
971 jz KmodeOpcode
972
973 /* Check for VDM */
974 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
975 jz UmodeOpcode
976
977 /* Check if the process is vDM */
978 mov ebx, fs:[KPCR_CURRENT_THREAD]
979 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
980 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
981 jnz IsVdmOpcode
982
983 UmodeOpcode:
984 /* Get EIP and enable interrupts at this point */
985 mov esi, [ebp+KTRAP_FRAME_EIP]
986 sti
987
988 /* Set intruction prefix length */
989 mov ecx, 4
990
991 /* Setup a SEH frame */
992 push ebp
993 push OpcodeSEH
994 push fs:[KPCR_EXCEPTION_LIST]
995 mov fs:[KPCR_EXCEPTION_LIST], esp
996
997 OpcodeLoop:
998 /* Get the instruction and check if it's LOCK */
999 mov al, [esi]
1000 cmp al, 0xF0
1001 jz LockCrash
1002
1003 /* Keep moving */
1004 add esi, 1
1005 loop OpcodeLoop
1006
1007 /* Undo SEH frame */
1008 pop fs:[KPCR_EXCEPTION_LIST]
1009 add esp, 8
1010
1011 KmodeOpcode:
1012
1013 /* Re-enable interrupts */
1014 sti
1015
1016 /* Setup illegal instruction exception and dispatch it */
1017 mov ebx, [ebp+KTRAP_FRAME_EIP]
1018 mov eax, STATUS_ILLEGAL_INSTRUCTION
1019 jmp _DispatchNoParam
1020
1021 LockCrash:
1022
1023 /* Undo SEH Frame */
1024 pop fs:[KPCR_EXCEPTION_LIST]
1025 add esp, 8
1026
1027 /* Setup invalid lock exception and dispatch it */
1028 mov ebx, [ebp+KTRAP_FRAME_EIP]
1029 mov eax, STATUS_INVALID_LOCK_SEQUENCE
1030 jmp _DispatchNoParam
1031
1032 IsVdmOpcode:
1033
1034 /* Unhandled yet */
1035 UNHANDLED_PATH
1036
1037 /* Return to caller */
1038 jmp _Kei386EoiHelper@0
1039
1040 OpcodeSEH:
1041
1042 /* Get SEH frame */
1043 mov esp, [esp+8]
1044 pop fs:[KPCR_EXCEPTION_LIST]
1045 add esp, 4
1046 pop ebp
1047
1048 /* Check if this was user mode */
1049 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1050 jnz KmodeOpcode
1051
1052 /* Do a bugcheck */
1053 push ebp
1054 push 0
1055 push 0
1056 push 0
1057 push 0
1058 push KMODE_EXCEPTION_NOT_HANDLED
1059 call _KeBugCheckWithTf@24
1060 .endfunc
1061
1062 .func KiTrap7
1063 Dr_kit7: DR_TRAP_FIXUP
1064 V86_kit7: V86_TRAP_FIXUP
1065 _KiTrap7:
1066 /* Push error code */
1067 push 0
1068
1069 /* Enter trap */
1070 TRAP_PROLOG kit7
1071
1072 /* Get the current thread and stack */
1073 StartTrapHandle:
1074 mov eax, [fs:KPCR_CURRENT_THREAD]
1075 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1076 sub ecx, NPX_FRAME_LENGTH
1077
1078 /* Check if emulation is enabled */
1079 test dword ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
1080 jnz EmulationEnabled
1081
1082 CheckState:
1083 /* Check if the NPX state is loaded */
1084 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1085 mov ebx, cr0
1086 jz IsLoaded
1087
1088 /* Remove flags */
1089 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
1090 mov cr0, ebx
1091
1092 /* Check the NPX thread */
1093 mov edx, [fs:KPCR_NPX_THREAD]
1094 or edx, edx
1095 jz NoNpxThread
1096
1097 /* Get the NPX Stack */
1098 mov esi, [edx+KTHREAD_INITIAL_STACK]
1099 sub esi, NPX_FRAME_LENGTH
1100
1101 /* Check if we have FXSR and check which operand to use */
1102 test byte ptr _KeI386FxsrPresent, 1
1103 jz FnSave
1104 fxsave [esi]
1105 jmp AfterSave
1106
1107 FnSave:
1108 fnsave [esi]
1109
1110 AfterSave:
1111 /* Set the thread's state to dirty */
1112 mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1113
1114 NoNpxThread:
1115 /* Check if we have FXSR and choose which operand to use */
1116 test byte ptr _KeI386FxsrPresent, 1
1117 jz FrRestore
1118 fxrstor [ecx]
1119 jmp AfterRestore
1120
1121 FrRestore:
1122 frstor [esi]
1123
1124 AfterRestore:
1125 /* Set state loaded */
1126 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1127 mov [fs:KPCR_NPX_THREAD], eax
1128
1129 /* Enable interrupts to happen now */
1130 sti
1131 nop
1132
1133 /* Check if CR0 needs to be reloaded due to a context switch */
1134 cmp dword ptr [ecx+FN_CR0_NPX_STATE], 0
1135 jz _Kei386EoiHelper@0
1136
1137 /* We have to reload CR0... disable interrupts */
1138 cli
1139
1140 /* Get CR0 and update it */
1141 mov ebx, cr0
1142 or ebx, [ecx+FN_CR0_NPX_STATE]
1143 mov cr0, ebx
1144
1145 /* Restore interrupts and check if TS is back on */
1146 sti
1147 test bl, CR0_TS
1148 jz _Kei386EoiHelper@0
1149
1150 /* Clear TS, and loop handling again */
1151 clts
1152 cli
1153 jmp StartTrapHandle
1154
1155 KernelNpx:
1156
1157 /* Set delayed error */
1158 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
1159
1160 /* Check if this happened during restore */
1161 cmp dword ptr [ebp+KTRAP_FRAME_EIP], offset FrRestore
1162 jnz UserNpx
1163
1164 /* Skip instruction and dispatch the exception */
1165 add dword ptr [ebp+KTRAP_FRAME_EIP], 3
1166 jmp _Kei386EoiHelper@0
1167
1168 IsLoaded:
1169 /* Check if TS is set */
1170 test bl, CR0_TS
1171 jnz TsSetOnLoadedState
1172
1173 HandleNpxFault:
1174 /* Check if the trap came from V86 mode */
1175 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1176 jnz V86Npx
1177
1178 /* Check if it came from kernel mode */
1179 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1180 jz KernelNpx
1181
1182 /* Check if it came from a VDM */
1183 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1184 jne V86Npx
1185
1186 UserNpx:
1187 /* Get the current thread */
1188 mov eax, fs:[KPCR_CURRENT_THREAD]
1189
1190 /* Check NPX state */
1191 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1192
1193 /* Get the NPX save area */
1194 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1195 lea ecx, [ecx-NPX_FRAME_LENGTH]
1196 jz NoSaveRestore
1197
1198 HandleUserNpx:
1199
1200 /* Set new CR0 */
1201 mov ebx, cr0
1202 and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
1203 mov cr0, ebx
1204
1205 /* Check if we have FX support */
1206 test byte ptr _KeI386FxsrPresent, 1
1207 jz FnSave2
1208
1209 /* Save the state */
1210 fxsave [ecx]
1211 jmp MakeCr0Dirty
1212 FnSave2:
1213 fnsave [ecx]
1214 wait
1215
1216 MakeCr0Dirty:
1217 /* Make CR0 state not loaded */
1218 or ebx, NPX_STATE_NOT_LOADED
1219 or ebx, [ecx+FN_CR0_NPX_STATE]
1220 mov cr0, ebx
1221
1222 /* Update NPX state */
1223 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1224 mov dword ptr fs:[KPCR_NPX_THREAD], 0
1225
1226 NoSaveRestore:
1227 /* Clear the TS bit and re-enable interrupts */
1228 and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
1229 sti
1230
1231 /* Check if we have FX support */
1232 test byte ptr _KeI386FxsrPresent, 1
1233 jz FnError
1234
1235 /* Get error offset, control and status words */
1236 mov ebx, [ecx+FX_ERROR_OFFSET]
1237 movzx eax, word ptr [ecx+FX_CONTROL_WORD]
1238 movzx edx, word ptr [ecx+FX_STATUS_WORD]
1239
1240 /* Get the faulting opcode */
1241 mov esi, [ecx+FX_DATA_OFFSET]
1242 jmp CheckError
1243
1244 FnError:
1245 /* Get error offset, control and status words */
1246 mov ebx, [ecx+FP_ERROR_OFFSET]
1247 movzx eax, word ptr [ecx+FP_CONTROL_WORD]
1248 movzx edx, word ptr [ecx+FP_STATUS_WORD]
1249
1250 /* Get the faulting opcode */
1251 mov esi, [ecx+FP_DATA_OFFSET]
1252
1253 CheckError:
1254 /* Mask exceptions */
1255 and eax, 0x3F
1256 not eax
1257 and eax, edx
1258
1259 /* Check if what's left is invalid */
1260 test al, 1
1261 jz ValidNpxOpcode
1262
1263 /* Check if it was a stack fault */
1264 test al, 64
1265 jnz InvalidStack
1266
1267 /* Raise exception */
1268 mov eax, STATUS_FLOAT_INVALID_OPERATION
1269 jmp _DispatchOneParam
1270
1271 InvalidStack:
1272
1273 /* Raise exception */
1274 mov eax, STATUS_FLOAT_STACK_CHECK
1275 jmp _DispatchTwoParam
1276
1277 ValidNpxOpcode:
1278
1279 /* Check for divide by 0 */
1280 test al, 4
1281 jz 1f
1282
1283 /* Raise exception */
1284 mov eax, STATUS_FLOAT_DIVIDE_BY_ZERO
1285 jmp _DispatchOneParam
1286
1287 1:
1288 /* Check for denormal */
1289 test al, 2
1290 jz 1f
1291
1292 /* Raise exception */
1293 mov eax, STATUS_FLOAT_INVALID_OPERATION
1294 jmp _DispatchOneParam
1295
1296 1:
1297 /* Check for overflow */
1298 test al, 8
1299 jz 1f
1300
1301 /* Raise exception */
1302 mov eax, STATUS_FLOAT_OVERFLOW
1303 jmp _DispatchOneParam
1304
1305 1:
1306 /* Check for underflow */
1307 test al, 16
1308 jz 1f
1309
1310 /* Raise exception */
1311 mov eax, STATUS_FLOAT_UNDERFLOW
1312 jmp _DispatchOneParam
1313
1314 1:
1315 /* Check for precision fault */
1316 test al, 32
1317 jz UnexpectedNpx
1318
1319 /* Raise exception */
1320 mov eax, STATUS_FLOAT_INEXACT_RESULT
1321 jmp _DispatchOneParam
1322
1323 UnexpectedNpx:
1324
1325 /* Strange result, bugcheck the OS */
1326 sti
1327 push ebp
1328 push 0
1329 push 0
1330 push eax
1331 push 1
1332 push TRAP_CAUSE_UNKNOWN
1333 call _KeBugCheckWithTf@24
1334
1335 V86Npx:
1336 /* Check if this is a VDM */
1337 mov eax, fs:[KPCR_CURRENT_THREAD]
1338 mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
1339 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1340 jz HandleUserNpx
1341
1342 /* V86 NPX not handled */
1343 UNHANDLED_PATH
1344
1345 EmulationEnabled:
1346 /* Did this come from kernel-mode? */
1347 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1348 jz CheckState
1349
1350 /* It came from user-mode, so this would only be valid inside a VDM */
1351 /* Since we don't actually have VDMs in ROS, bugcheck. */
1352 jmp UnexpectedNpx
1353
1354 TsSetOnLoadedState:
1355 /* TS shouldn't be set, unless this we don't have a Math Processor */
1356 test bl, CR0_MP
1357 jnz BogusTrap
1358
1359 /* Strange that we got a trap at all, but ignore and continue */
1360 clts
1361 jmp _Kei386EoiHelper@0
1362
1363 BogusTrap:
1364 /* Cause a bugcheck */
1365 push 0
1366 push 0
1367 push ebx
1368 push 2
1369 push TRAP_CAUSE_UNKNOWN
1370 call _KeBugCheckEx@20
1371 .endfunc
1372
1373 .globl _KiTrap8
1374 .func KiTrap8
1375 _KiTrap8:
1376
1377 /* Can't really do too much */
1378 mov eax, 8
1379 jmp _KiSystemFatalException
1380 .endfunc
1381
1382 .func KiTrap9
1383 Dr_kit9: DR_TRAP_FIXUP
1384 V86_kit9: V86_TRAP_FIXUP
1385 _KiTrap9:
1386 /* Push error code */
1387 push 0
1388
1389 /* Enter trap */
1390 TRAP_PROLOG kit9
1391
1392 /* Enable interrupts and bugcheck */
1393 sti
1394 mov eax, 9
1395 jmp _KiSystemFatalException
1396 .endfunc
1397
1398 .func KiTrap10
1399 Dr_kit10: DR_TRAP_FIXUP
1400 V86_kit10: V86_TRAP_FIXUP
1401 _KiTrap10:
1402 /* Enter trap */
1403 TRAP_PROLOG kit10
1404
1405 /* Check for V86 */
1406 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1407 jnz V86IntA
1408
1409 /* Check if the frame was from kernelmode */
1410 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1411 jz Fatal
1412
1413 V86IntA:
1414 /* Check if OF was set during iretd */
1415 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
1416 sti
1417 jz Fatal
1418
1419 /* It was, just mask it out */
1420 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
1421 jmp _Kei386EoiHelper@0
1422
1423 Fatal:
1424 /* TSS failure for some other reason: crash */
1425 mov eax, 10
1426 jmp _KiSystemFatalException
1427 .endfunc
1428
1429 .func KiTrap11
1430 Dr_kit11: DR_TRAP_FIXUP
1431 V86_kit11: V86_TRAP_FIXUP
1432 _KiTrap11:
1433 /* Enter trap */
1434 TRAP_PROLOG kit11
1435
1436 /* FIXME: ROS Doesn't handle segment faults yet */
1437 mov eax, 11
1438 jmp _KiSystemFatalException
1439 .endfunc
1440
1441 .func KiTrap12
1442 Dr_kit12: DR_TRAP_FIXUP
1443 V86_kit12: V86_TRAP_FIXUP
1444 _KiTrap12:
1445 /* Enter trap */
1446 TRAP_PROLOG kit12
1447
1448 /* FIXME: ROS Doesn't handle stack faults yet */
1449 mov eax, 12
1450 jmp _KiSystemFatalException
1451 .endfunc
1452
1453 .func KiTrapExceptHandler
1454 _KiTrapExceptHandler:
1455
1456 /* Setup SEH handler frame */
1457 mov esp, [esp+8]
1458 pop fs:[KPCR_EXCEPTION_LIST]
1459 add esp, 4
1460 pop ebp
1461
1462 /* Check if the fault came from user mode */
1463 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1464 jnz SetException
1465
1466 /* Kernel fault, bugcheck */
1467 push ebp
1468 push 0
1469 push 0
1470 push 0
1471 push 0
1472 push KMODE_EXCEPTION_NOT_HANDLED
1473 call _KeBugCheckWithTf@24
1474 .endfunc
1475
1476 .func KiTrap13
1477 Dr_kitd: DR_TRAP_FIXUP
1478 V86_kitd: V86_TRAP_FIXUP
1479 _KiTrap13:
1480
1481 /* It this a V86 GPF? */
1482 test dword ptr [esp+12], EFLAGS_V86_MASK
1483 jz NotV86
1484
1485 /* Enter V86 Trap */
1486 V86_TRAP_PROLOG kitd
1487
1488 /* Make sure that this is a V86 process */
1489 mov ecx, [fs:KPCR_CURRENT_THREAD]
1490 mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
1491 cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
1492 jnz RaiseIrql
1493
1494 /* Otherwise, something is very wrong, raise an exception */
1495 sti
1496 mov ebx, [ebp+KTRAP_FRAME_EIP]
1497 mov esi, -1
1498 mov eax, STATUS_ACCESS_VIOLATION
1499 jmp _DispatchTwoParam
1500
1501 RaiseIrql:
1502
1503 /* Go to APC level */
1504 mov ecx, APC_LEVEL
1505 call @KfRaiseIrql@4
1506
1507 /* Save old IRQL and enable interrupts */
1508 push eax
1509 sti
1510
1511 /* Handle the opcode */
1512 call _Ki386HandleOpcodeV86@0
1513
1514 /* Check if this was VDM */
1515 test al, 0xFF
1516 jnz NoReflect
1517
1518 /* FIXME: TODO */
1519 UNHANDLED_PATH
1520
1521 NoReflect:
1522
1523 /* Lower IRQL and disable interrupts */
1524 pop ecx
1525 call @KfLowerIrql@4
1526 cli
1527
1528 /* Check if this was a V86 trap */
1529 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1530 jz NotV86Trap
1531
1532 /* Exit the V86 Trap */
1533 V86_TRAP_EPILOG
1534
1535 NotV86Trap:
1536
1537 /* Either this wasn't V86, or it was, but an APC interrupted us */
1538 jmp _Kei386EoiHelper@0
1539
1540 NotV86:
1541 /* Enter trap */
1542 TRAP_PROLOG kitd
1543
1544 /* Check if this was from kernel-mode */
1545 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1546 jnz UserModeGpf
1547
1548 /* Check if we have a VDM alert */
1549 cmp dword ptr fs:[KPCR_VDM_ALERT], 0
1550 jnz VdmAlertGpf
1551
1552 /* Check for GPF during GPF */
1553 mov eax, [ebp+KTRAP_FRAME_EIP]
1554 cmp eax, offset CheckPrivilegedInstruction
1555 jbe KmodeGpf
1556 cmp eax, offset CheckPrivilegedInstruction2
1557
1558 /* FIXME: TODO */
1559 UNHANDLED_PATH
1560
1561 /* Get the opcode and trap frame */
1562 KmodeGpf:
1563 mov eax, [ebp+KTRAP_FRAME_EIP]
1564 mov eax, [eax]
1565 mov edx, [ebp+KTRAP_FRAME_EBP]
1566
1567 /* We want to check if this was POP [DS/ES/FS/GS] */
1568 add edx, KTRAP_FRAME_DS
1569 cmp al, 0x1F
1570 jz SegPopGpf
1571 add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
1572 cmp al, 7
1573 jz SegPopGpf
1574 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1575 cmp ax, 0xA10F
1576 jz SegPopGpf
1577 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1578 cmp ax, 0xA90F
1579 jz SegPopGpf
1580
1581 /* It isn't, was it IRETD? */
1582 cmp al, 0xCF
1583 jne NotIretGpf
1584
1585 /* Get error code */
1586 lea edx, [ebp+KTRAP_FRAME_ESP]
1587 mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
1588 and ax, ~RPL_MASK
1589
1590 /* Get CS */
1591 mov cx, word ptr [edx+4]
1592 and cx, ~RPL_MASK
1593 cmp cx, ax
1594 jnz NotCsGpf
1595
1596 /* This should be a Ki386CallBios return */
1597 mov eax, offset _Ki386BiosCallReturnAddress
1598 cmp eax, [edx]
1599 jne NotBiosGpf
1600 mov eax, [edx+4]
1601 cmp ax, KGDT_R0_CODE + RPL_MASK
1602 jne NotBiosGpf
1603
1604 /* Jump to return address */
1605 jmp _Ki386BiosCallReturnAddress
1606
1607 NotBiosGpf:
1608 /* Check if the thread was in kernel mode */
1609 mov ebx, [fs:KPCR_CURRENT_THREAD]
1610 test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
1611 jz UserModeGpf
1612
1613 /* Set RPL_MASK for check below */
1614 or word ptr [edx+4], RPL_MASK
1615
1616 NotCsGpf:
1617 /* Check if the IRET goes to user-mode */
1618 test dword ptr [edx+4], RPL_MASK
1619 jz UserModeGpf
1620
1621 /* Setup trap frame to copy */
1622 mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
1623 lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
1624
1625 TrapCopy:
1626
1627 /* Copy each field */
1628 mov eax, [edx]
1629 mov [edx+12], eax
1630 sub edx, 4
1631 loop TrapCopy
1632
1633 /* Enable interrupts and adjust stack */
1634 sti
1635 add esp, 12
1636 add ebp, 12
1637
1638 /* Setup exception record */
1639 mov ebx, [ebp+KTRAP_FRAME_EIP]
1640 mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
1641 and esi, 0xFFFF
1642 mov eax, STATUS_ACCESS_VIOLATION
1643 jmp _DispatchTwoParam
1644
1645 MsrCheck:
1646
1647 /* FIXME: Handle RDMSR/WRMSR */
1648 UNHANDLED_PATH
1649
1650 NotIretGpf:
1651
1652 /* Check if this was an MSR opcode */
1653 cmp al, 0xF
1654 jz MsrCheck
1655
1656 /* Check if DS is Ring 3 */
1657 cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1658 jz CheckEs
1659
1660 /* Otherwise, fix it up */
1661 mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1662 jmp ExitGpfTrap
1663
1664 CheckEs:
1665
1666 /* Check if ES is Ring 3 */
1667 cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1668 jz UserModeGpf
1669
1670 /* Otherwise, fix it up */
1671 mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1672 jmp ExitGpfTrap
1673
1674 SegPopGpf:
1675
1676 /* Sanity check */
1677 lea eax, [ebp+KTRAP_FRAME_ESP]
1678 cmp edx, eax
1679 jz HandleSegPop
1680 int 3
1681
1682 /* Handle segment POP fault by setting it to 0 */
1683 HandleSegPop:
1684 xor eax, eax
1685 mov dword ptr [edx], eax
1686
1687 ExitGpfTrap:
1688
1689 /* Do a trap exit */
1690 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
1691
1692 UserModeGpf:
1693
1694 /* If the previous mode was kernel, raise a fatal exception */
1695 mov eax, 13
1696 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1697 jz _KiSystemFatalException
1698
1699 /* Get the process and check which CS this came from */
1700 mov ebx, fs:[KPCR_CURRENT_THREAD]
1701 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
1702 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1703 jz CheckVdmGpf
1704
1705 /* Check if this is a VDM */
1706 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1707 jnz DispatchV86Gpf
1708
1709 /* Enable interrupts and check if we have an error code */
1710 sti
1711 cmp word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0
1712 jnz SetException
1713 jmp CheckPrivilegedInstruction
1714
1715 HandleSegPop2:
1716 /* Update EIP (will be updated below again) */
1717 add dword ptr [ebp+KTRAP_FRAME_EIP], 1
1718
1719 HandleEsPop:
1720 /* Clear the segment, update EIP and ESP */
1721 mov dword ptr [edx], 0
1722 add dword ptr [ebp+KTRAP_FRAME_EIP], 1
1723 add dword ptr [ebp+KTRAP_FRAME_ESP], 4
1724 jmp _Kei386EoiHelper@0
1725
1726 CheckVdmGpf:
1727 /* Check if this is a VDM */
1728 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1729 jz CheckPrivilegedInstruction
1730
1731 /* Bring interrupts back */
1732 sti
1733
1734 /* Check what kind of instruction this is */
1735 mov eax, [ebp+KTRAP_FRAME_EIP]
1736 mov eax, [eax]
1737
1738 /* FIXME: Check for BOP4 */
1739
1740 /* Check if this is POP ES */
1741 mov edx, ebp
1742 add edx, KTRAP_FRAME_ES
1743 cmp al, 0x07
1744 jz HandleEsPop
1745
1746 /* Check if this is POP FS */
1747 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1748 cmp ax, 0xA10F
1749 jz HandleSegPop2
1750
1751 /* Check if this is POP GS */
1752 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1753 cmp ax, 0xA90F
1754 jz HandleSegPop2
1755
1756 CheckPrivilegedInstruction:
1757 /* Bring interrupts back */
1758 sti
1759
1760 /* Setup a SEH handler */
1761 push ebp
1762 push offset _KiTrapExceptHandler
1763 push fs:[KPCR_EXCEPTION_LIST]
1764 mov fs:[KPCR_EXCEPTION_LIST], esp
1765
1766 /* Get EIP */
1767 mov esi, [ebp+KTRAP_FRAME_EIP]
1768
1769 /* Setup loop count */
1770 mov ecx, 15
1771
1772 InstLoop:
1773 /* Save loop count */
1774 push ecx
1775
1776 /* Get the instruction */
1777 lods byte ptr [esi]
1778
1779 /* Now lookup in the prefix table */
1780 mov ecx, 11
1781 mov edi, offset _KiTrapPrefixTable
1782 repnz scasb
1783
1784 /* Restore loop count */
1785 pop ecx
1786
1787 /* If it's not a prefix byte, check other instructions */
1788 jnz NotPrefixByte
1789
1790 /* FIXME */
1791 UNHANDLED_PATH
1792
1793 NotPrefixByte:
1794 /* FIXME: Check if it's a HLT */
1795
1796 /* Check if the instruction has two bytes */
1797 cmp al, 0xF
1798 jne CheckRing3Io
1799
1800 /* FIXME */
1801 UNHANDLED_PATH
1802
1803 CheckRing3Io:
1804 /* Get EFLAGS and IOPL */
1805 mov ebx, [ebp+KTRAP_FRAME_EFLAGS]
1806 and ebx, 0x3000
1807 shr ebx, 12
1808
1809 /* Check the CS's RPL mask */
1810 mov ecx, [ebp+KTRAP_FRAME_CS]
1811 and ecx, RPL_MASK
1812 cmp ebx, ecx
1813 jge NotIoViolation
1814
1815 CheckPrivilegedInstruction2:
1816 /* Check if this is a CLI or STI */
1817 cmp al, 0xFA
1818 je IsPrivInstruction
1819 cmp al, 0xFB
1820 je IsPrivInstruction
1821
1822 /* Setup I/O table lookup */
1823 mov ecx, 13
1824 mov edi, offset _KiTrapIoTable
1825
1826 /* Loopup in the table */
1827 repnz scasb
1828 jnz NotIoViolation
1829
1830 /* FIXME: Check IOPM!!! */
1831
1832 IsPrivInstruction:
1833 /* Cleanup the SEH frame */
1834 pop fs:[KPCR_EXCEPTION_LIST]
1835 add esp, 8
1836
1837 /* Setup the exception */
1838 mov ebx, [ebp+KTRAP_FRAME_EIP]
1839 mov eax, STATUS_PRIVILEGED_INSTRUCTION
1840 jmp _DispatchNoParam
1841
1842 NotIoViolation:
1843 /* Cleanup the SEH frame */
1844 pop fs:[KPCR_EXCEPTION_LIST]
1845 add esp, 8
1846
1847 SetException:
1848 /* Setup the exception */
1849 mov ebx, [ebp+KTRAP_FRAME_EIP]
1850 mov esi, -1
1851 mov eax, STATUS_ACCESS_VIOLATION
1852 jmp _DispatchTwoParam
1853
1854 DispatchV86Gpf:
1855 /* FIXME */
1856 UNHANDLED_PATH
1857 .endfunc
1858
1859 .func KiTrap14
1860 Dr_kit14: DR_TRAP_FIXUP
1861 V86_kit14: V86_TRAP_FIXUP
1862 _KiTrap14:
1863
1864 /* Enter trap */
1865 TRAP_PROLOG kit14
1866
1867 /* Check if we have a VDM alert */
1868 cmp dword ptr fs:[KPCR_VDM_ALERT], 0
1869 jnz VdmAlertGpf
1870
1871 /* Get the current thread */
1872 mov edi, fs:[KPCR_CURRENT_THREAD]
1873
1874 /* Get the stack address of the frame */
1875 lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH]
1876 sub eax, [edi+KTHREAD_INITIAL_STACK]
1877 jz NoFixUp
1878
1879 /* This isn't the base frame, check if it's the second */
1880 cmp eax, -KTRAP_FRAME_EFLAGS
1881 jb NoFixUp
1882
1883 /* Check if we have a TEB */
1884 mov eax, fs:[KPCR_TEB]
1885 or eax, eax
1886 jle NoFixUp
1887
1888 /* Fixup the frame */
1889 call _KiFixupFrame
1890
1891 /* Save CR2 */
1892 NoFixUp:
1893 mov edi, cr2
1894
1895 /* ROS HACK: Sometimes we get called with INTS DISABLED! WTF? */
1896 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
1897 je HandlePf
1898
1899 /* Enable interrupts and check if we got here with interrupts disabled */
1900 sti
1901 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
1902 jz IllegalState
1903
1904 HandlePf:
1905 /* Send trap frame and check if this is kernel-mode or usermode */
1906 push ebp
1907 mov eax, [ebp+KTRAP_FRAME_CS]
1908 and eax, MODE_MASK
1909 push eax
1910
1911 /* Send faulting address and check if this is read or write */
1912 push edi
1913 mov eax, [ebp+KTRAP_FRAME_ERROR_CODE]
1914 and eax, 1
1915 push eax
1916
1917 /* Call the access fault handler */
1918 call _MmAccessFault@16
1919 test eax, eax
1920 jl AccessFail
1921
1922 /* Access fault handled, return to caller */
1923 jmp _Kei386EoiHelper@0
1924
1925 AccessFail:
1926 /* First check if this is a fault in the S-LIST functions */
1927 mov ecx, offset _ExpInterlockedPopEntrySListFault@0
1928 cmp [ebp+KTRAP_FRAME_EIP], ecx
1929 jz SlistFault
1930
1931 /* Check if this is a fault in the syscall handler */
1932 mov ecx, offset CopyParams
1933 cmp [ebp+KTRAP_FRAME_EIP], ecx
1934 jz SysCallCopyFault
1935 mov ecx, offset ReadBatch
1936 cmp [ebp+KTRAP_FRAME_EIP], ecx
1937 jnz CheckVdmPf
1938
1939 /* FIXME: TODO */
1940 UNHANDLED_PATH
1941 jmp _Kei386EoiHelper@0
1942
1943 SysCallCopyFault:
1944 /* FIXME: TODO */
1945 UNHANDLED_PATH
1946 jmp _Kei386EoiHelper@0
1947
1948 /* Check if the fault occured in a V86 mode */
1949 CheckVdmPf:
1950 mov ecx, [ebp+KTRAP_FRAME_ERROR_CODE]
1951 and ecx, 1
1952 shr ecx, 1
1953 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1954 jnz VdmPF
1955
1956 /* Check if the fault occured in a VDM */
1957 mov esi, fs:[KPCR_CURRENT_THREAD]
1958 mov esi, [esi+KTHREAD_APCSTATE_PROCESS]
1959 cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0
1960 jz CheckStatus
1961
1962 /* Check if we this was in kernel-mode */
1963 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1964 jz CheckStatus
1965 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1966 jz CheckStatus
1967
1968 VdmPF:
1969 /* FIXME: TODO */
1970 UNHANDLED_PATH
1971
1972 /* Save EIP and check what kind of status failure we got */
1973 CheckStatus:
1974 mov esi, [ebp+KTRAP_FRAME_EIP]
1975 cmp eax, STATUS_ACCESS_VIOLATION
1976 je AccessViol
1977 cmp eax, STATUS_GUARD_PAGE_VIOLATION
1978 je SpecialCode
1979 cmp eax, STATUS_STACK_OVERFLOW
1980 je SpecialCode
1981
1982 /* Setup an in-page exception to dispatch */
1983 mov edx, ecx
1984 mov ebx, esi
1985 mov esi, edi
1986 mov ecx, 3
1987 mov edi, eax
1988 mov eax, STATUS_IN_PAGE_ERROR
1989 call _CommonDispatchException
1990
1991 AccessViol:
1992 /* Use more proper status code */
1993 mov eax, KI_EXCEPTION_ACCESS_VIOLATION
1994
1995 SpecialCode:
1996 /* Setup a normal page fault exception */
1997 mov ebx, esi
1998 mov edx, ecx
1999 mov esi, edi
2000 jmp _DispatchTwoParam
2001
2002 SlistFault:
2003 /* FIXME: TODO */
2004 UNHANDLED_PATH
2005
2006 IllegalState:
2007
2008 /* This is completely illegal, bugcheck the system */
2009 push ebp
2010 push esi
2011 push ecx
2012 push eax
2013 push edi
2014 push IRQL_NOT_LESS_OR_EQUAL
2015 call _KeBugCheckWithTf@24
2016
2017 VdmAlertGpf:
2018
2019 /* FIXME: NOT SUPPORTED */
2020 UNHANDLED_PATH
2021 .endfunc
2022
2023 .func KiTrap0F
2024 Dr_kit15: DR_TRAP_FIXUP
2025 V86_kit15: V86_TRAP_FIXUP
2026 _KiTrap0F:
2027 /* Push error code */
2028 push 0
2029
2030 /* Enter trap */
2031 TRAP_PROLOG kit15
2032 sti
2033
2034 /* Raise a fatal exception */
2035 mov eax, 15
2036 jmp _KiSystemFatalException
2037 .endfunc
2038
2039 .func KiTrap16
2040 Dr_kit16: DR_TRAP_FIXUP
2041 V86_kit16: V86_TRAP_FIXUP
2042 _KiTrap16:
2043 /* Push error code */
2044 push 0
2045
2046 /* Enter trap */
2047 TRAP_PROLOG kit16
2048
2049 /* Check if this is the NPX Thread */
2050 mov eax, fs:[KPCR_CURRENT_THREAD]
2051 cmp eax, fs:[KPCR_NPX_THREAD]
2052
2053 /* Get the initial stack and NPX frame */
2054 mov ecx, [eax+KTHREAD_INITIAL_STACK]
2055 lea ecx, [ecx-NPX_FRAME_LENGTH]
2056
2057 /* If this is a valid fault, handle it */
2058 jz HandleNpxFault
2059
2060 /* Otherwise, re-enable interrupts and set delayed error */
2061 sti
2062 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
2063 jmp _Kei386EoiHelper@0
2064 .endfunc
2065
2066 .func KiTrap17
2067 Dr_kit17: DR_TRAP_FIXUP
2068 V86_kit17: V86_TRAP_FIXUP
2069 _KiTrap17:
2070 /* Push error code */
2071 push 0
2072
2073 /* Enter trap */
2074 TRAP_PROLOG kit17
2075
2076 /* FIXME: ROS Doesn't handle alignment faults yet */
2077 mov eax, 17
2078 jmp _KiSystemFatalException
2079 .endfunc
2080
2081 .func KiSystemFatalException
2082 _KiSystemFatalException:
2083
2084 /* Push the trap frame */
2085 push ebp
2086
2087 /* Push empty parameters */
2088 push 0
2089 push 0
2090 push 0
2091
2092 /* Push trap number and bugcheck code */
2093 push eax
2094 push UNEXPECTED_KERNEL_MODE_TRAP
2095 call _KeBugCheckWithTf@24
2096 ret
2097 .endfunc
2098
2099 .func KiCoprocessorError@0
2100 _KiCoprocessorError@0:
2101
2102 /* Get the NPX Thread's Initial stack */
2103 mov eax, [fs:KPCR_NPX_THREAD]
2104 mov eax, [eax+KTHREAD_INITIAL_STACK]
2105
2106 /* Make space for the FPU Save area */
2107 sub eax, SIZEOF_FX_SAVE_AREA
2108
2109 /* Set the CR0 State */
2110 mov dword ptr [eax+FN_CR0_NPX_STATE], 8
2111
2112 /* Update it */
2113 mov eax, cr0
2114 or eax, 8
2115 mov cr0, eax
2116
2117 /* Return to caller */
2118 ret
2119 .endfunc
2120
2121 .func Ki16BitStackException
2122 _Ki16BitStackException:
2123
2124 /* Save stack */
2125 push ss
2126 push esp
2127
2128 /* Go to kernel mode thread stack */
2129 mov eax, fs:[KPCR_CURRENT_THREAD]
2130 add esp, [eax+KTHREAD_INITIAL_STACK]
2131
2132 /* Switch to good stack segment */
2133 UNHANDLED_PATH
2134 .endfunc
2135
2136 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
2137
2138 .globl _KiStartUnexpectedRange@0
2139 _KiStartUnexpectedRange@0:
2140
2141 GENERATE_INT_HANDLERS
2142
2143 .globl _KiEndUnexpectedRange@0
2144 _KiEndUnexpectedRange@0:
2145 jmp _KiUnexpectedInterruptTail
2146
2147 .func KiUnexpectedInterruptTail
2148 V86_kui: V86_TRAP_FIXUP
2149 Dr_kui: DR_TRAP_FIXUP
2150 _KiUnexpectedInterruptTail:
2151
2152 /* Enter interrupt trap */
2153 INT_PROLOG kui, DoNotPushFakeErrorCode
2154
2155 /* Increase interrupt count */
2156 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
2157
2158 /* Put vector in EBX and make space for KIRQL */
2159 mov ebx, [esp]
2160 sub esp, 4
2161
2162 /* Begin interrupt */
2163 push esp
2164 push ebx
2165 push HIGH_LEVEL
2166 call _HalBeginSystemInterrupt@12
2167
2168 /* Check if it was spurious or not */
2169 or al, al
2170 jnz Handled
2171
2172 /* Spurious, ignore it */
2173 add esp, 8
2174 jmp _Kei386EoiHelper2ndEntry
2175
2176 Handled:
2177 /* Unexpected interrupt, print a message on debug builds */
2178 #if DBG
2179 push [esp+4]
2180 push offset _UnexpectedMsg
2181 call _DbgPrint
2182 add esp, 8
2183 #endif
2184
2185 /* Exit the interrupt */
2186 mov esi, $
2187 cli
2188 call _HalEndSystemInterrupt@8
2189 jmp _Kei386EoiHelper@0
2190 .endfunc
2191
2192 .globl _KiUnexpectedInterrupt
2193 _KiUnexpectedInterrupt:
2194
2195 /* Bugcheck with invalid interrupt code */
2196 push TRAP_CAUSE_UNKNOWN
2197 call _KeBugCheck@4
2198
2199 /* INTERRUPT HANDLERS ********************************************************/
2200
2201 .func KiDispatchInterrupt@0
2202 _KiDispatchInterrupt@0:
2203
2204 /* Get the PCR and disable interrupts */
2205 mov ebx, [fs:KPCR_SELF]
2206 cli
2207
2208 /* Check if we have to deliver DPCs, timers, or deferred threads */
2209 mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
2210 or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
2211 or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
2212 jz CheckQuantum
2213
2214 /* Save stack pointer and exception list, then clear it */
2215 push ebp
2216 push dword ptr [ebx+KPCR_EXCEPTION_LIST]
2217 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
2218
2219 /* Save the stack and switch to the DPC Stack */
2220 mov edx, esp
2221 //mov esp, [ebx+KPCR_PRCB_DPC_STACK]
2222 push edx
2223
2224 /* Deliver DPCs */
2225 mov ecx, [ebx+KPCR_PRCB]
2226 call @KiRetireDpcList@4
2227
2228 /* Restore stack and exception list */
2229 pop esp
2230 pop dword ptr [ebx]
2231 pop ebp
2232
2233 CheckQuantum:
2234
2235 /* Re-enable interrupts */
2236 sti
2237
2238 /* Check if we have quantum end */
2239 cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
2240 jnz QuantumEnd
2241
2242 /* Check if we have a thread to swap to */
2243 cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
2244 jz Return
2245
2246 /* FIXME: Schedule new thread */
2247 UNHANDLED_PATH
2248
2249 Return:
2250 /* All done */
2251 ret
2252
2253 QuantumEnd:
2254 /* Disable quantum end and process it */
2255 mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
2256 call _KiQuantumEnd@0
2257 ret
2258 .endfunc
2259
2260 .func KiInterruptTemplate
2261 V86_kit: V86_TRAP_FIXUP
2262 Dr_kit: DR_TRAP_FIXUP
2263 _KiInterruptTemplate:
2264
2265 /* Enter interrupt trap */
2266 INT_PROLOG kit, DoPushFakeErrorCode
2267 .endfunc
2268
2269 _KiInterruptTemplate2ndDispatch:
2270 /* Dummy code, will be replaced by the address of the KINTERRUPT */
2271 mov edi, 0
2272
2273 _KiInterruptTemplateObject:
2274 /* Dummy jump, will be replaced by the actual jump */
2275 jmp _KeSynchronizeExecution@12
2276
2277 _KiInterruptTemplateDispatch:
2278 /* Marks the end of the template so that the jump above can be edited */
2279
2280 .func KiChainedDispatch2ndLvl@0
2281 _KiChainedDispatch2ndLvl@0:
2282
2283 /* Not yet supported */
2284 UNHANDLED_PATH
2285 .endfunc
2286
2287 .func KiChainedDispatch@0
2288 _KiChainedDispatch@0:
2289
2290 /* Increase interrupt count */
2291 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
2292
2293 /* Save trap frame */
2294 mov ebp, esp
2295
2296 /* Save vector and IRQL */
2297 mov eax, [edi+KINTERRUPT_VECTOR]
2298 mov ecx, [edi+KINTERRUPT_IRQL]
2299
2300 /* Save old irql */
2301 push eax
2302 sub esp, 4
2303
2304 /* Begin interrupt */
2305 push esp
2306 push eax
2307 push ecx
2308 call _HalBeginSystemInterrupt@12
2309
2310 /* Check if it was handled */
2311 or al, al
2312 jz SpuriousInt
2313
2314 /* Call the 2nd-level handler */
2315 call _KiChainedDispatch2ndLvl@0
2316
2317 /* Exit the interrupt */
2318 mov esi, $
2319 cli
2320 call _HalEndSystemInterrupt@8
2321 jmp _Kei386EoiHelper@0
2322 .endfunc
2323
2324 .func KiInterruptDispatch@0
2325 _KiInterruptDispatch@0:
2326
2327 /* Increase interrupt count */
2328 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
2329
2330 /* Save trap frame */
2331 mov ebp, esp
2332
2333 /* Save vector and IRQL */
2334 mov eax, [edi+KINTERRUPT_VECTOR]
2335 mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
2336
2337 /* Save old irql */
2338 push eax
2339 sub esp, 4
2340
2341 /* Begin interrupt */
2342 push esp
2343 push eax
2344 push ecx
2345 call _HalBeginSystemInterrupt@12
2346
2347 /* Check if it was handled */
2348 or al, al
2349 jz SpuriousInt
2350
2351 /* Acquire the lock */
2352 GetIntLock:
2353 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
2354 ACQUIRE_SPINLOCK(esi, IntSpin)
2355
2356 /* Call the ISR */
2357 mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
2358 push eax
2359 push edi
2360 call [edi+KINTERRUPT_SERVICE_ROUTINE]
2361
2362 /* Release the lock */
2363 RELEASE_SPINLOCK(esi)
2364
2365 /* Exit the interrupt */
2366 cli
2367 call _HalEndSystemInterrupt@8
2368 jmp _Kei386EoiHelper@0
2369
2370 SpuriousInt:
2371 /* Exit the interrupt */
2372 add esp, 8
2373 jmp _Kei386EoiHelper@0
2374
2375 #ifdef CONFIG_SMP
2376 IntSpin:
2377 SPIN_ON_LOCK esi, GetIntLock
2378 #endif
2379 .endfunc