BOOLEAN FORCEINLINE KiVdmTrap(IN PKTRAP_FRAME TrapFrame) { /* Either the V8086 flag is on, or this is user-mode with a VDM */ return ((TrapFrame->EFlags & EFLAGS_V86_MASK) || ((KiUserTrap(TrapFrame)) && (PsGetCurrentProcess()->VdmObjects))); }
VOID DECLSPEC_NORETURN FASTCALL HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) { KPROCESSOR_MODE ProcessorMode; KIRQL OldIrql; ASSERT(ApicGetProcessorIrql() == APC_LEVEL); /* Enter trap */ KiEnterInterruptTrap(TrapFrame); #ifdef APIC_LAZY_IRQL if (!HalBeginSystemInterrupt(APC_LEVEL, APC_VECTOR, &OldIrql)) { /* "Spurious" interrupt, exit the interrupt */ KiEoiHelper(TrapFrame); } #else /* Save the old IRQL */ OldIrql = ApicGetCurrentIrql(); ASSERT(OldIrql < APC_LEVEL); #endif /* Raise to APC_LEVEL */ ApicRaiseIrql(APC_LEVEL); /* End the interrupt */ ApicSendEOI(); /* Kernel or user APC? */ if (KiUserTrap(TrapFrame)) ProcessorMode = UserMode; else if (TrapFrame->EFlags & EFLAGS_V86_MASK) ProcessorMode = UserMode; else ProcessorMode = KernelMode; /* Enable interrupts and call the kernel's APC interrupt handler */ _enable(); KiDeliverApc(ProcessorMode, NULL, TrapFrame); /* Disable interrupts */ _disable(); /* Restore the old IRQL */ ApicLowerIrql(OldIrql); /* Exit the interrupt */ KiEoiHelper(TrapFrame); }
DECLSPEC_NORETURN VOID FASTCALL KiTrap01Handler(IN PKTRAP_FRAME TrapFrame) { /* Save trap frame */ KiEnterTrap(TrapFrame); /* Check for VDM trap */ ASSERT((KiVdmTrap(TrapFrame)) == FALSE); /* Enable interrupts if the trap came from user-mode */ if (KiUserTrap(TrapFrame)) _enable(); /* Mask out trap flag and dispatch the exception */ TrapFrame->EFlags &= ~EFLAGS_TF; KiDispatchException0Args(STATUS_SINGLE_STEP, TrapFrame->Eip, TrapFrame); }
DECLSPEC_NORETURN VOID FASTCALL KiTrap05Handler(IN PKTRAP_FRAME TrapFrame) { /* Save trap frame */ KiEnterTrap(TrapFrame); /* Check for VDM trap */ ASSERT((KiVdmTrap(TrapFrame)) == FALSE); /* Check for kernel-mode fault */ if (!KiUserTrap(TrapFrame)) KiSystemFatalException(EXCEPTION_BOUND_CHECK, TrapFrame); /* Enable interrupts */ _enable(); /* Dispatch the exception */ KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED, TrapFrame->Eip, TrapFrame); }
DECLSPEC_NORETURN VOID FASTCALL KiDebugHandler(IN PKTRAP_FRAME TrapFrame, IN ULONG Parameter1, IN ULONG Parameter2, IN ULONG Parameter3) { /* Check for VDM trap */ ASSERT((KiVdmTrap(TrapFrame)) == FALSE); /* Enable interrupts if the trap came from user-mode */ if (KiUserTrap(TrapFrame)) _enable(); /* Dispatch the exception */ KiDispatchExceptionFromTrapFrame(STATUS_BREAKPOINT, TrapFrame->Eip - 1, 3, Parameter1, Parameter2, Parameter3, TrapFrame); }
DECLSPEC_NORETURN VOID FASTCALL KiTrap06Handler(IN PKTRAP_FRAME TrapFrame) { PUCHAR Instruction; ULONG i; KIRQL OldIrql; /* Check for V86 GPF */ if (__builtin_expect(KiV86Trap(TrapFrame), 1)) { /* Enter V86 trap */ KiEnterV86Trap(TrapFrame); /* Must be a VDM process */ if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0)) { /* Enable interrupts */ _enable(); /* Setup illegal instruction fault */ KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, TrapFrame->Eip, TrapFrame); } /* Go to APC level */ OldIrql = KfRaiseIrql(APC_LEVEL); _enable(); /* Check for BOP */ if (!VdmDispatchBop(TrapFrame)) { /* Should only happen in VDM mode */ UNIMPLEMENTED; while (TRUE); } /* Bring IRQL back */ KfLowerIrql(OldIrql); _disable(); /* Do a quick V86 exit if possible */ KiExitV86Trap(TrapFrame); } /* Save trap frame */ KiEnterTrap(TrapFrame); /* Enable interrupts */ Instruction = (PUCHAR)TrapFrame->Eip; _enable(); /* Check for user trap */ if (KiUserTrap(TrapFrame)) { /* FIXME: Use SEH */ /* Scan next 4 opcodes */ for (i = 0; i < 4; i++) { /* Check for LOCK instruction */ if (Instruction[i] == 0xF0) { /* Send invalid lock sequence exception */ KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE, TrapFrame->Eip, TrapFrame); } } /* FIXME: SEH ends here */ } /* Kernel-mode or user-mode fault (but not LOCK) */ KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, TrapFrame->Eip, TrapFrame); }
DECLSPEC_NORETURN VOID FASTCALL KiNpxHandler(IN PKTRAP_FRAME TrapFrame, IN PKTHREAD Thread, IN PFX_SAVE_AREA SaveArea) { ULONG Cr0, Mask, Error, ErrorOffset, DataOffset; /* Check for VDM trap */ ASSERT((KiVdmTrap(TrapFrame)) == FALSE); /* Check for kernel trap */ if (!KiUserTrap(TrapFrame)) { /* Kernel might've tripped a delayed error */ SaveArea->Cr0NpxState |= CR0_TS; /* Only valid if it happened during a restore */ //if ((PVOID)TrapFrame->Eip == FrRestore) { /* It did, so just skip the instruction */ //TrapFrame->Eip += 3; /* sizeof(FRSTOR) */ //KiEoiHelper(TrapFrame); } } /* User or kernel trap -- get ready to issue an exception */ //if (Thread->NpxState == NPX_STATE_NOT_LOADED) { /* Update CR0 */ Cr0 = __readcr0(); Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS); __writecr0(Cr0); /* Save FPU state */ Ke386SaveFpuState(SaveArea); /* Mark CR0 state dirty */ Cr0 |= NPX_STATE_NOT_LOADED; Cr0 |= SaveArea->Cr0NpxState; __writecr0(Cr0); /* Update NPX state */ Thread->NpxState = NPX_STATE_NOT_LOADED; KeGetCurrentPrcb()->NpxThread = NULL; } /* Clear the TS bit and re-enable interrupts */ SaveArea->Cr0NpxState &= ~CR0_TS; _enable(); /* Check if we should get the FN or FX error */ if (KeI386FxsrPresent) { /* Get it from FX */ Mask = SaveArea->U.FxArea.ControlWord; Error = SaveArea->U.FxArea.StatusWord; /* Get the FPU exception address too */ ErrorOffset = SaveArea->U.FxArea.ErrorOffset; DataOffset = SaveArea->U.FxArea.DataOffset; } else { /* Get it from FN */ Mask = SaveArea->U.FnArea.ControlWord; Error = SaveArea->U.FnArea.StatusWord; /* Get the FPU exception address too */ ErrorOffset = SaveArea->U.FnArea.ErrorOffset; DataOffset = SaveArea->U.FnArea.DataOffset; } /* Get legal exceptions that software should handle */ Error &= (FSW_INVALID_OPERATION | FSW_DENORMAL | FSW_ZERO_DIVIDE | FSW_OVERFLOW | FSW_UNDERFLOW | FSW_PRECISION); Error &= ~Mask; if (Error & FSW_STACK_FAULT) { /* Issue stack check fault */ KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK, ErrorOffset, 0, DataOffset, TrapFrame); } /* Check for invalid operation */ if (Error & FSW_INVALID_OPERATION) { /* Issue fault */ KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION, ErrorOffset, 0, TrapFrame); } /* Check for divide by zero */ if (Error & FSW_ZERO_DIVIDE) { /* Issue fault */ KiDispatchException1Args(STATUS_FLOAT_DIVIDE_BY_ZERO, ErrorOffset, 0, TrapFrame); } /* Check for denormal */ if (Error & FSW_DENORMAL) { /* Issue fault */ KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION, ErrorOffset, 0, TrapFrame); } /* Check for overflow */ if (Error & FSW_OVERFLOW) { /* Issue fault */ KiDispatchException1Args(STATUS_FLOAT_OVERFLOW, ErrorOffset, 0, TrapFrame); } /* Check for underflow */ if (Error & FSW_UNDERFLOW) { /* Issue fault */ KiDispatchException1Args(STATUS_FLOAT_UNDERFLOW, ErrorOffset, 0, TrapFrame); } /* Check for precision fault */ if (Error & FSW_PRECISION) { /* Issue fault */ KiDispatchException1Args(STATUS_FLOAT_INEXACT_RESULT, ErrorOffset, 0, TrapFrame); } /* Unknown FPU fault */ KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 1, Error, 0, 0, TrapFrame); }
VOID NTAPI KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame, IN KIRQL Irql) { PKTHREAD Thread = KeGetCurrentThread(); PKPRCB Prcb = KeGetCurrentPrcb(); /* Check if this tick is being skipped */ if (Prcb->SkipTick) { /* Handle it next time */ Prcb->SkipTick = FALSE; return; } /* Increase interrupt count */ Prcb->InterruptCount++; /* Check if we came from user mode */ #ifndef _M_ARM if (KiUserTrap(TrapFrame) || (TrapFrame->EFlags & EFLAGS_V86_MASK)) #else if (TrapFrame->PreviousMode == UserMode) #endif { /* Increase thread user time */ Prcb->UserTime++; Thread->UserTime++; } else { /* See if we were in an ISR */ Prcb->KernelTime++; if (Irql > DISPATCH_LEVEL) { /* Handle that */ Prcb->InterruptTime++; } else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive)) { /* Handle being in kernel mode */ Thread->KernelTime++; } else { /* Handle being in a DPC */ Prcb->DpcTime++; #if DBG /* Update the DPC time */ Prcb->DebugDpcTime++; /* Check if we have timed out */ if (Prcb->DebugDpcTime == KiDPCTimeout) { /* We did! */ DbgPrint("*** DPC routine > 1 sec --- This is not a break in KeUpdateSystemTime\n"); /* Break if debugger is enabled */ if (KdDebuggerEnabled) DbgBreakPoint(); /* Clear state */ Prcb->DebugDpcTime = 0; } #endif } } /* Update DPC rates */ Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) + Prcb->DpcRequestRate) >> 1; Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount; /* Check if the queue is large enough */ if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive)) { /* Request a DPC */ Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; HalRequestSoftwareInterrupt(DISPATCH_LEVEL); /* Fix the maximum queue depth */ if ((Prcb->DpcRequestRate < KiIdealDpcRate) && (Prcb->MaximumDpcQueueDepth > 1)) { /* Make it smaller */ Prcb->MaximumDpcQueueDepth--; } } else { /* Check if we've reached the adjustment limit */ if (!(--Prcb->AdjustDpcThreshold)) { /* Reset it, and check the queue maximum */ Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth) { /* Increase it */ Prcb->MaximumDpcQueueDepth++; } } } /* Decrement the thread quantum */ Thread->Quantum -= CLOCK_QUANTUM_DECREMENT; /* Check if the time expired */ if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread)) { /* Schedule a quantum end */ Prcb->QuantumEnd = 1; HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } }