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