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