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