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