- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[reactos.git] / reactos / ntoskrnl / ke / i386 / trap.s
index 8288c2c..abb36b7 100644 (file)
@@ -12,6 +12,9 @@
 #include <internal/i386/asmmacro.S>
 .intel_syntax noprefix
 
+#define Running 2
+#define WrDispatchInt 0x1F
+
 /* GLOBALS *******************************************************************/
 
 .data
@@ -87,13 +90,44 @@ _KiUnexpectedEntrySize:
 _UnexpectedMsg:
     .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
 
+_UnhandledMsg:
+    .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
+
+_KiTrapPrefixTable:
+    .byte 0xF2                      /* REP                                  */
+    .byte 0xF3                      /* REP INS/OUTS                         */
+    .byte 0x67                      /* ADDR                                 */
+    .byte 0xF0                      /* LOCK                                 */
+    .byte 0x66                      /* OP                                   */
+    .byte 0x2E                      /* SEG                                  */
+    .byte 0x3E                      /* DS                                   */
+    .byte 0x26                      /* ES                                   */
+    .byte 0x64                      /* FS                                   */
+    .byte 0x65                      /* GS                                   */
+    .byte 0x36                      /* SS                                   */
+
+_KiTrapIoTable:
+    .byte 0xE4                      /* IN                                   */
+    .byte 0xE5                      /* IN                                   */
+    .byte 0xEC                      /* IN                                   */
+    .byte 0xED                      /* IN                                   */
+    .byte 0x6C                      /* INS                                  */
+    .byte 0x6D                      /* INS                                  */
+    .byte 0xE6                      /* OUT                                  */
+    .byte 0xE7                      /* OUT                                  */
+    .byte 0xEE                      /* OUT                                  */
+    .byte 0xEF                      /* OUT                                  */
+    .byte 0x6E                      /* OUTS                                 */
+    .byte 0x6F                      /* OUTS                                 */
+
 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
 .text
 
 _KiGetTickCount:
 _KiCallbackReturn:
 _KiRaiseAssertion:
-    int 3
+    /* FIXME: TODO */
+    UNHANDLED_PATH
 
 .func KiSystemService
 Dr_kss: DR_TRAP_FIXUP
@@ -144,6 +178,7 @@ SharedCode:
 
     /* Check if we should flush the User Batch */
     xor ebx, ebx
+ReadBatch:
     or ebx, [ecx+TEB_GDI_BATCH_COUNT]
     jz NotWin32K
 
@@ -432,8 +467,8 @@ V86_Exit:
     iret
 
 AbiosExit:
-    /* Not yet supported */
-    int 3
+    /* FIXME: TODO */
+    UNHANDLED_PATH
 
 .func KiDebugService
 Dr_kids:    DR_TRAP_FIXUP
@@ -452,7 +487,7 @@ _KiDebugService:
     /* Call debug service dispatcher */
     mov eax, [ebp+KTRAP_FRAME_EAX]
     mov ecx, [ebp+KTRAP_FRAME_ECX]
-    mov edx, [ebp+KTRAP_FRAME_EAX]
+    mov edx, [ebp+KTRAP_FRAME_EDX]
 
     /* Check for V86 mode */
     test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
@@ -607,7 +642,7 @@ _CommonDispatchException:
     mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
 
     /* Check parameter count */
-    cmp eax, 0
+    cmp ecx, 0
     jz NoParams
 
     /* Get information */
@@ -629,9 +664,11 @@ NoParams:
 
 SetPreviousMode:
 
-    /* Calculate the previous mode */
+    /* Get the caller's CS */
     mov eax, [ebp+KTRAP_FRAME_CS]
+
 MaskMode:
+    /* Check if it was user-mode or kernel-mode */
     and eax, MODE_MASK
 
     /* Dispatch the exception */
@@ -672,6 +709,13 @@ _DispatchTwoParam:
 
 /* HARDWARE TRAP HANDLERS ****************************************************/
 
+.func KiFixupFrame
+_KiFixupFrame:
+
+    /* TODO: Routine to fixup a KTRAP_FRAME when faulting from a syscall. */
+    UNHANDLED_PATH
+.endfunc
+
 .func KiTrap0
 Dr_kit0:    DR_TRAP_FIXUP
 V86_kit0:   V86_TRAP_FIXUP
@@ -710,7 +754,8 @@ VdmCheck:
 
     /* We don't support this yet! */
 V86Int0:
-    int 3
+    /* FIXME: TODO */
+    UNHANDLED_PATH
 .endfunc
 
 .func KiTrap1
@@ -754,7 +799,7 @@ V86Int1:
     jz EnableInterrupts
 
     /* We don't support VDM! */
-    int 3
+    UNHANDLED_PATH
 .endfunc
 
 .globl _KiTrap2
@@ -801,8 +846,8 @@ PrepInt3:
     /* Setup EIP, NTSTATUS and parameter count, then dispatch */
     mov ebx, [ebp+KTRAP_FRAME_EIP]
     dec ebx
-    mov eax, STATUS_BREAKPOINT
     mov ecx, 3
+    mov eax, STATUS_BREAKPOINT
     call _CommonDispatchException
 
 V86Int3:
@@ -813,7 +858,7 @@ V86Int3:
     jz EnableInterrupts3
 
     /* We don't support VDM! */
-    int 3
+    UNHANDLED_PATH
 .endfunc
 
 .func KiTrap4
@@ -855,7 +900,7 @@ VdmCheck4:
 
     /* We don't support this yet! */
 V86Int4:
-    int 3
+    UNHANDLED_PATH
 .endfunc
 
 .func KiTrap5
@@ -901,7 +946,7 @@ VdmCheck5:
 
     /* We don't support this yet! */
 V86Int5:
-    int 3
+    UNHANDLED_PATH
 .endfunc
 
 .func KiTrap6
@@ -917,8 +962,7 @@ _KiTrap6:
     V86_TRAP_PROLOG kit6
 
     /* Not yet supported (Invalid OPCODE from V86) */
-    int 3
-    jmp $
+    UNHANDLED_PATH
 
 NotV86UD:
     /* Push error code */
@@ -993,8 +1037,7 @@ LockCrash:
 IsVdmOpcode:
 
     /* Unhandled yet */
-    int 3
-    jmp $
+    UNHANDLED_PATH
 
     /* Return to caller */
     jmp _Kei386EoiHelper@0
@@ -1302,8 +1345,7 @@ V86Npx:
     jz HandleUserNpx
 
     /* V86 NPX not handled */
-    int 3
-    jmp $
+    UNHANDLED_PATH
 
 EmulationEnabled:
     /* Did this come from kernel-mode? */
@@ -1413,6 +1455,29 @@ _KiTrap12:
     jmp _KiSystemFatalException
 .endfunc
 
+.func KiTrapExceptHandler
+_KiTrapExceptHandler:
+
+    /* Setup SEH handler frame */
+    mov esp, [esp+8]
+    pop fs:[KPCR_EXCEPTION_LIST]
+    add esp, 4
+    pop ebp
+
+    /* Check if the fault came from user mode */
+    test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
+    jnz SetException
+
+    /* Kernel fault, bugcheck */
+    push ebp
+    push 0
+    push 0
+    push 0
+    push 0
+    push KMODE_EXCEPTION_NOT_HANDLED
+    call _KeBugCheckWithTf@24
+.endfunc
+
 .func KiTrap13
 Dr_kitd:    DR_TRAP_FIXUP
 V86_kitd:   V86_TRAP_FIXUP
@@ -1456,7 +1521,7 @@ RaiseIrql:
     jnz NoReflect
 
     /* FIXME: TODO */
-    int 3
+    UNHANDLED_PATH
 
 NoReflect:
 
@@ -1485,9 +1550,21 @@ NotV86:
     test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
     jnz UserModeGpf
 
-    /* FIXME: Check for GPF during GPF */
+    /* Check if we have a VDM alert */
+    cmp dword ptr fs:[KPCR_VDM_ALERT], 0
+    jnz VdmAlertGpf
+
+    /* Check for GPF during GPF */
+    mov eax, [ebp+KTRAP_FRAME_EIP]
+    cmp eax, offset CheckPrivilegedInstruction
+    jbe KmodeGpf
+    cmp eax, offset CheckPrivilegedInstruction2
+
+    /* FIXME: TODO */
+    UNHANDLED_PATH
 
     /* Get the opcode and trap frame */
+KmodeGpf:
     mov eax, [ebp+KTRAP_FRAME_EIP]
     mov eax, [eax]
     mov edx, [ebp+KTRAP_FRAME_EBP]
@@ -1573,8 +1650,7 @@ TrapCopy:
 MsrCheck:
 
     /* FIXME: Handle RDMSR/WRMSR */
-    int 3
-    jmp $
+    UNHANDLED_PATH
 
 NotIretGpf:
 
@@ -1620,26 +1696,333 @@ ExitGpfTrap:
 
 UserModeGpf:
 
-    /* FIXME: Unhandled */
-    int 3
-    jmp $
+    /* If the previous mode was kernel, raise a fatal exception */
+    mov eax, 13
+    test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
+    jz _KiSystemFatalException
+
+    /* Get the process and check which CS this came from */
+    mov ebx, fs:[KPCR_CURRENT_THREAD]
+    mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
+    cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
+    jz CheckVdmGpf
+
+    /* Check if this is a VDM */
+    cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
+    jnz DispatchV86Gpf
+
+    /* Enable interrupts and check if we have an error code */
+    sti
+    cmp word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0
+    jnz SetException
+    jmp CheckPrivilegedInstruction
+
+HandleSegPop2:
+    /* Update EIP (will be updated below again) */
+    add dword ptr [ebp+KTRAP_FRAME_EIP], 1
+
+HandleEsPop:
+    /* Clear the segment, update EIP and ESP */
+    mov dword ptr [edx], 0
+    add dword ptr [ebp+KTRAP_FRAME_EIP], 1
+    add dword ptr [ebp+KTRAP_FRAME_ESP], 4
+    jmp _Kei386EoiHelper@0
+
+CheckVdmGpf:
+    /* Check if this is a VDM */
+    cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
+    jz CheckPrivilegedInstruction
+
+    /* Bring interrupts back */
+    sti
+
+    /* Check what kind of instruction this is */
+    mov eax, [ebp+KTRAP_FRAME_EIP]
+    mov eax, [eax]
+
+    /* FIXME: Check for BOP4 */
+
+    /* Check if this is POP ES */
+    mov edx, ebp
+    add edx, KTRAP_FRAME_ES
+    cmp al, 0x07
+    jz HandleEsPop
+
+    /* Check if this is POP FS */
+    add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
+    cmp ax, 0xA10F
+    jz HandleSegPop2
+
+    /* Check if this is POP GS */
+    add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
+    cmp ax, 0xA90F
+    jz HandleSegPop2
+
+CheckPrivilegedInstruction:
+    /* Bring interrupts back */
+    sti
+
+    /* Setup a SEH handler */
+    push ebp
+    push offset _KiTrapExceptHandler
+    push fs:[KPCR_EXCEPTION_LIST]
+    mov fs:[KPCR_EXCEPTION_LIST], esp
+
+    /* Get EIP */
+    mov esi, [ebp+KTRAP_FRAME_EIP]
+
+    /* Setup loop count */
+    mov ecx, 15
+
+InstLoop:
+    /* Save loop count */
+    push ecx
+
+    /* Get the instruction */
+    lods byte ptr [esi]
+
+    /* Now lookup in the prefix table */
+    mov ecx, 11
+    mov edi, offset _KiTrapPrefixTable
+    repnz scasb
+
+    /* Restore loop count */
+    pop ecx
+
+    /* If it's not a prefix byte, check other instructions */
+    jnz NotPrefixByte
+
+    /* FIXME */
+    UNHANDLED_PATH
+
+NotPrefixByte:
+    /* FIXME: Check if it's a HLT */
+
+    /* Check if the instruction has two bytes */
+    cmp al, 0xF
+    jne CheckRing3Io
+
+    /* FIXME */
+    UNHANDLED_PATH
+
+CheckRing3Io:
+    /* Get EFLAGS and IOPL */
+    mov ebx, [ebp+KTRAP_FRAME_EFLAGS]
+    and ebx, 0x3000
+    shr ebx, 12
+
+    /* Check the CS's RPL mask */
+    mov ecx, [ebp+KTRAP_FRAME_CS]
+    and ecx, RPL_MASK
+    cmp ebx, ecx
+    jge NotIoViolation
+
+CheckPrivilegedInstruction2:
+    /* Check if this is a CLI or STI */
+    cmp al, 0xFA
+    je IsPrivInstruction
+    cmp al, 0xFB
+    je IsPrivInstruction
+
+    /* Setup I/O table lookup */
+    mov ecx, 13
+    mov edi, offset _KiTrapIoTable
+
+    /* Loopup in the table */
+    repnz scasb
+    jnz NotIoViolation
+
+    /* FIXME: Check IOPM!!! */
+
+IsPrivInstruction:
+    /* Cleanup the SEH frame */
+    pop fs:[KPCR_EXCEPTION_LIST]
+    add esp, 8
+
+    /* Setup the exception */
+    mov ebx, [ebp+KTRAP_FRAME_EIP]
+    mov eax, STATUS_PRIVILEGED_INSTRUCTION
+    jmp _DispatchNoParam
+
+NotIoViolation:
+    /* Cleanup the SEH frame */
+    pop fs:[KPCR_EXCEPTION_LIST]
+    add esp, 8
+
+SetException:
+    /* Setup the exception */
+    mov ebx, [ebp+KTRAP_FRAME_EIP]
+    mov esi, -1
+    mov eax, STATUS_ACCESS_VIOLATION
+    jmp _DispatchTwoParam
+
+DispatchV86Gpf:
+    /* FIXME */
+    UNHANDLED_PATH
 .endfunc
 
 .func KiTrap14
 Dr_kit14:   DR_TRAP_FIXUP
 V86_kit14:  V86_TRAP_FIXUP
 _KiTrap14:
+
     /* Enter trap */
     TRAP_PROLOG kit14
 
-    /* Call the C exception handler */
-    push 14
+    /* Check if we have a VDM alert */
+    cmp dword ptr fs:[KPCR_VDM_ALERT], 0
+    jnz VdmAlertGpf
+
+    /* Get the current thread */
+    mov edi, fs:[KPCR_CURRENT_THREAD]
+
+    /* Get the stack address of the frame */
+    lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH]
+    sub eax, [edi+KTHREAD_INITIAL_STACK]
+    jz NoFixUp
+
+    /* This isn't the base frame, check if it's the second */
+    cmp eax, -KTRAP_FRAME_EFLAGS
+    jb NoFixUp
+
+    /* Check if we have a TEB */
+    mov eax, fs:[KPCR_TEB]
+    or eax, eax
+    jle NoFixUp
+
+    /* Fixup the frame */
+    call _KiFixupFrame
+
+    /* Save CR2 */
+NoFixUp:
+    mov edi, cr2
+
+    /* ROS HACK: Sometimes we get called with INTS DISABLED! WTF? */
+    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
+    je HandlePf
+
+    /* Enable interrupts and check if we got here with interrupts disabled */
+    sti
+    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
+    jz IllegalState
+
+HandlePf:
+    /* Send trap frame and check if this is kernel-mode or usermode */
     push ebp
-    call _KiPageFaultHandler
-    add esp, 8
+    mov eax, [ebp+KTRAP_FRAME_CS]
+    and eax, MODE_MASK
+    push eax
 
-    /* Return to caller */
+    /* Send faulting address and check if this is read or write */
+    push edi
+    mov eax, [ebp+KTRAP_FRAME_ERROR_CODE]
+    and eax, 1
+    push eax
+
+    /* Call the access fault handler */
+    call _MmAccessFault@16
+    test eax, eax
+    jl AccessFail
+
+    /* Access fault handled, return to caller */
+    jmp _Kei386EoiHelper@0
+
+AccessFail:
+    /* First check if this is a fault in the S-LIST functions */
+    mov ecx, offset _ExpInterlockedPopEntrySListFault@0
+    cmp [ebp+KTRAP_FRAME_EIP], ecx
+    jz SlistFault
+
+    /* Check if this is a fault in the syscall handler */
+    mov ecx, offset CopyParams
+    cmp [ebp+KTRAP_FRAME_EIP], ecx
+    jz SysCallCopyFault
+    mov ecx, offset ReadBatch
+    cmp [ebp+KTRAP_FRAME_EIP], ecx
+    jnz CheckVdmPf
+
+    /* FIXME: TODO */
+    UNHANDLED_PATH
+    jmp _Kei386EoiHelper@0
+
+SysCallCopyFault:
+    /* FIXME: TODO */
+    UNHANDLED_PATH
     jmp _Kei386EoiHelper@0
+
+    /* Check if the fault occured in a V86 mode */
+CheckVdmPf:
+    mov ecx, [ebp+KTRAP_FRAME_ERROR_CODE]
+    and ecx, 1
+    shr ecx, 1
+    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
+    jnz VdmPF
+
+    /* Check if the fault occured in a VDM */
+    mov esi, fs:[KPCR_CURRENT_THREAD]
+    mov esi, [esi+KTHREAD_APCSTATE_PROCESS]
+    cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0
+    jz CheckStatus
+
+    /* Check if we this was in kernel-mode */
+    test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
+    jz CheckStatus
+    cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
+    jz CheckStatus
+
+VdmPF:
+    /* FIXME: TODO */
+    UNHANDLED_PATH
+
+    /* Save EIP and check what kind of status failure we got */
+CheckStatus:
+    mov esi, [ebp+KTRAP_FRAME_EIP]
+    cmp eax, STATUS_ACCESS_VIOLATION
+    je AccessViol
+    cmp eax, STATUS_GUARD_PAGE_VIOLATION
+    je SpecialCode
+    cmp eax, STATUS_STACK_OVERFLOW
+    je SpecialCode
+
+    /* Setup an in-page exception to dispatch */
+    mov edx, ecx
+    mov ebx, esi
+    mov esi, edi
+    mov ecx, 3
+    mov edi, eax
+    mov eax, STATUS_IN_PAGE_ERROR
+    call _CommonDispatchException
+
+AccessViol:
+    /* Use more proper status code */
+    mov eax, KI_EXCEPTION_ACCESS_VIOLATION
+
+SpecialCode:
+    /* Setup a normal page fault exception */
+    mov ebx, esi
+    mov edx, ecx
+    mov esi, edi
+    jmp _DispatchTwoParam
+
+SlistFault:
+    /* FIXME: TODO */
+    UNHANDLED_PATH
+
+IllegalState:
+
+    /* This is completely illegal, bugcheck the system */
+    push ebp
+    push esi
+    push ecx
+    push eax
+    push edi
+    push IRQL_NOT_LESS_OR_EQUAL
+    call _KeBugCheckWithTf@24
+
+VdmAlertGpf:
+
+    /* FIXME: NOT SUPPORTED */
+    UNHANDLED_PATH
 .endfunc
 
 .func KiTrap0F
@@ -1752,8 +2135,7 @@ _Ki16BitStackException:
     add esp, [eax+KTHREAD_INITIAL_STACK]
 
     /* Switch to good stack segment */
-    /* TODO */
-    int 3
+    UNHANDLED_PATH
 .endfunc
 
 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
@@ -1850,7 +2232,7 @@ _KiDispatchInterrupt@0:
 
     /* Restore stack and exception list */
     pop esp
-    pop dword ptr [ebx]
+    pop dword ptr [ebx+KPCR_EXCEPTION_LIST]
     pop ebp
 
 CheckQuantum:
@@ -1864,10 +2246,44 @@ CheckQuantum:
 
     /* Check if we have a thread to swap to */
     cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
-    jz Return
+    je Return
 
-    /* FIXME: Schedule new thread */
-    int 3
+    /* Make space on the stack to save registers */
+    sub esp, 3 * 4
+    mov [esp+8], esi
+    mov [esp+4], edi
+    mov [esp+0], ebp
+
+    /* Get the current thread */
+    mov edi, [ebx+KPCR_CURRENT_THREAD]
+
+#ifdef CONFIG_SMP
+    #error SMP Interrupt not handled!
+#endif
+
+    /* Get the next thread and clear it */
+    mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
+    and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
+
+    /* Set us as the current running thread */
+    mov [ebx+KPCR_CURRENT_THREAD], esi
+    mov byte ptr [esi+KTHREAD_STATE], Running
+    mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt
+
+    /* Put thread in ECX and get the PRCB in EDX */
+    mov ecx, edi
+    lea edx, [ebx+KPCR_PRCB_DATA]
+    call @KiQueueReadyThread@8
+
+    /* Set APC_LEVEL and do the swap */
+    mov cl, APC_LEVEL
+    call @KiSwapContextInternal@0
+
+    /* Restore registers */
+    mov ebp, [esp+0]
+    mov edi, [esp+4]
+    mov esi, [esp+8]
+    add esp, 3*4
 
 Return:
     /* All done */
@@ -1904,7 +2320,7 @@ _KiInterruptTemplateDispatch:
 _KiChainedDispatch2ndLvl@0:
 
     /* Not yet supported */
-    int 3
+    UNHANDLED_PATH
 .endfunc
 
 .func KiChainedDispatch@0