123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- /*++
- Copyright (c) 2012 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- dispatch.c
- Abstract:
- This module implements interrupt dispatch functionality for x86 processors.
- Author:
- Evan Green 27-Aug-2012
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include <minoca/kernel/kdebug.h>
- #include <minoca/kernel/x86.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID
- KeDispatchSingleStepTrap (
- PTRAP_FRAME TrapFrame
- )
- /*++
- Routine Description:
- This routine dispatches a single step trap.
- Arguments:
- TrapFrame - Supplies a pointer to the machine state immediately before the
- trap.
- Return Value:
- None.
- --*/
- {
- CYCLE_ACCOUNT PreviousPeriod;
- PKTHREAD Thread;
- ASSERT(ArAreInterruptsEnabled() == FALSE);
- if (IS_TRAP_FRAME_FROM_PRIVILEGED_MODE(TrapFrame) == FALSE) {
- PreviousPeriod = KeBeginCycleAccounting(CycleAccountKernel);
- ArEnableInterrupts();
- Thread = KeGetCurrentThread();
- PsSignalThread(Thread, SIGNAL_TRAP, NULL, FALSE);
- PsCheckRuntimeTimers(Thread);
- PsDispatchPendingSignals(Thread, TrapFrame);
- ArDisableInterrupts();
- //
- // If there is no handler or debugger yet, go into the kernel debugger.
- //
- if ((Thread->OwningProcess->SignalHandlerRoutine == NULL) &&
- (Thread->OwningProcess->DebugData == NULL)) {
- KdDebugExceptionHandler(EXCEPTION_SINGLE_STEP, NULL, TrapFrame);
- }
- KeBeginCycleAccounting(PreviousPeriod);
- } else {
- //
- // Here's something interesting. The sysenter instruction doesn't clear
- // the trap flag, so if usermode sets TF and executes sysenter, it
- // produces a single step exception in kernel mode. Move to the slow
- // system call path (so that eflags gets restored), and move Eip to a
- // version that sets TF in the trap frame.
- //
- if (TrapFrame->Eip == (UINTN)ArSysenterHandlerAsm) {
- TrapFrame->Eflags &= ~IA32_EFLAG_TF;
- TrapFrame->Eip = (UINTN)ArTrapSystemCallHandlerAsm;
- return;
- }
- KdDebugExceptionHandler(EXCEPTION_SINGLE_STEP, NULL, TrapFrame);
- }
- return;
- }
- VOID
- KeDispatchNmiTrap (
- VOID
- )
- /*++
- Routine Description:
- This routine dispatches an NMI interrupt. NMIs are task switches (to avoid
- a race with the sysret instruction), so the previous context is saved in a
- task structure.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- PTSS KernelTask;
- CYCLE_ACCOUNT PreviousPeriod;
- PPROCESSOR_BLOCK Processor;
- TRAP_FRAME TrapFrame;
- ASSERT(ArAreInterruptsEnabled() == FALSE);
- //
- // Do a little detection of nested NMIs, which are currently not supported.
- //
- Processor = KeGetCurrentProcessorBlock();
- Processor->NmiCount += 1;
- if (Processor->NmiCount == 2) {
- RtlDebugBreak();
- }
- PreviousPeriod = CycleAccountInvalid;
- ArGetKernelTssTrapFrame(&TrapFrame);
- if (IS_TRAP_FRAME_FROM_PRIVILEGED_MODE(&TrapFrame) == FALSE) {
- PreviousPeriod = KeBeginCycleAccounting(CycleAccountKernel);
- }
- //
- // Switch to the kernel task's CR3 in order to allow peeking at user mode
- // addresses if this NMI is for a debugger freeze.
- //
- KernelTask = Processor->Tss;
- if (KernelTask != NULL) {
- ArSetCurrentPageDirectory(KernelTask->Cr3);
- }
- KdNmiHandler(&TrapFrame);
- ArSetKernelTssTrapFrame(&TrapFrame);
- if (PreviousPeriod != CycleAccountInvalid) {
- KeBeginCycleAccounting(PreviousPeriod);
- }
- Processor->NmiCount -= 1;
- return;
- }
- VOID
- KeDispatchDebugServiceTrap (
- PTRAP_FRAME TrapFrame
- )
- /*++
- Routine Description:
- This routine dispatches a debug service trap.
- Arguments:
- TrapFrame - Supplies a pointer to the machine state immediately before the
- trap.
- Return Value:
- None.
- --*/
- {
- CYCLE_ACCOUNT PreviousPeriod;
- PKTHREAD Thread;
- ASSERT(ArAreInterruptsEnabled() == FALSE);
- if (IS_TRAP_FRAME_FROM_PRIVILEGED_MODE(TrapFrame) == FALSE) {
- PreviousPeriod = KeBeginCycleAccounting(CycleAccountKernel);
- ArEnableInterrupts();
- Thread = KeGetCurrentThread();
- PsSignalThread(Thread, SIGNAL_TRAP, NULL, FALSE);
- PsCheckRuntimeTimers(Thread);
- PsDispatchPendingSignals(Thread, TrapFrame);
- ArDisableInterrupts();
- KeBeginCycleAccounting(PreviousPeriod);
- } else {
- KdDebugExceptionHandler(TrapFrame->Eax,
- (PVOID)(TrapFrame->Ecx),
- TrapFrame);
- }
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
|