diff options
Diffstat (limited to 'private/mvdm/v86/monitor/i386/int.c')
-rw-r--r-- | private/mvdm/v86/monitor/i386/int.c | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/private/mvdm/v86/monitor/i386/int.c b/private/mvdm/v86/monitor/i386/int.c new file mode 100644 index 000000000..7912809da --- /dev/null +++ b/private/mvdm/v86/monitor/i386/int.c @@ -0,0 +1,454 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + int.c + +Abstract: + + This file contains interrupt support routines for the monitor + +Author: + + Dave Hastings (daveh) 18-Apr-1992 + +Notes: + + The code in this file split out from monitor.c (18-Apr-1992) + +Revision History: + +--*/ + +#include <monitorp.h> + +BOOL +DpmiHwIntHandler( + ULONG IntNumber + ); + +VOID +IRQ13_Eoi( + int IrqLine, + int CallCount + ); + +BOOLEAN IRQ13BeingHandled; // true until IRQ13 eoi'ed + + +VOID +InterruptInit( + VOID +) +/*++ + +Routine Description: + + This routine initializes the interrupt code for the monitor. + +Arguments: + + +Return Value: + + None. + +--*/ +{ + BOOL Bool; + + + + Bool = RegisterEOIHook( 13, IRQ13_Eoi); + if (!Bool) { +#if DBG + DbgPrint("NtVdm : Could not register IRQ 13 Eoi handler\n"); + DbgBreakPoint(); +#endif + TerminateVDM(); + } +} + +VOID +InterruptTerminate( + VOID + ) +/*++ + +Routine Description: + + This routine frees the resoures allocated by InterruptInit + +Arguments: + + +Return Value: + + None. + +--*/ +{ +} + + +VOID +cpu_interrupt( + IN int Type, + IN int Number + ) +/*++ + +Routine Description: + + This routine causes an interrupt of the specified type to be raised + at the appropriate time. + +Arguments: + + Type -- indicates the type of the interrupt. One of HARDWARE, TIMER, YODA, + or RESET + + YODA and RESET are ignored + +Return Value: + + None. + +Notes: + +--*/ +{ + NTSTATUS Status; + HANDLE MonitorThread; + + host_ica_lock(); + + if (Type == CPU_TIMER_TICK) { + + // + // Set the VDM State for timer tick int pending + // + _asm { + mov eax, FIXED_NTVDMSTATE_LINEAR + lock or dword ptr [eax], VDM_INT_TIMER + } + } else if (Type == CPU_HW_INT) { + + if (*pNtVDMState & VDM_INT_HARDWARE) { + goto EarlyExit; + } + + // + // Set the VDM State for Hardware Int pending + // + _asm { + mov eax, FIXED_NTVDMSTATE_LINEAR + lock or dword ptr [eax], VDM_INT_HARDWARE + } + } else { +#if DBG + DbgPrint("Monitor: Invalid Interrupt Type=%ld\n",Type); +#endif + goto EarlyExit; + } + + if (CurrentMonitorTeb != NtCurrentTeb()) { + + /* + * Look up the ThreadHandle and Queue and InterruptApc + * If no ThreadHandle found do nothing + * + * The CurrentMonitorTeb may not be in the ThreadHandle\Teb list + * because upon task termination the the CurrentMonitorTeb variable + * cannot be updated until a new task is activated by the + * non-preemptive scheduler. + */ + MonitorThread = ThreadLookUp(CurrentMonitorTeb); + if (MonitorThread) { + Status = NtVdmControl(VdmQueueInterrupt, (PVOID)MonitorThread); + // nothing much we can do if this fails +#if DBG + if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL) { + DbgPrint("NtVdmControl.VdmQueueInterrupt Status=%lx\n",Status); + } +#endif + } + + } + +EarlyExit: + + host_ica_unlock(); +} + + + + +VOID +DispatchInterrupts( + ) +/*++ + +Routine Description: + + This routine dispatches interrupts to their appropriate handler routine + in priority order. The order is YODA, RESET, TIMER, HARDWARE. however + the YODA and RESET interrupts do nothing. Hardware interrupts are not + simulated unless the virtual interrupt enable flag is set. Flags + indicating which interrupts are pending appear in the pNtVDMState. + + +Arguments: + + None. + +Return Value: + + None. + +Notes: + +--*/ +{ + + host_ica_lock(); + + // If any delayed interrupts have expired + // call the ica to restart interrupts + if (UndelayIrqLine) { + ica_RestartInterrupts(UndelayIrqLine); + } + + + if (*pNtVDMState & VDM_INT_TIMER) { + *pNtVDMState &= ~VDM_INT_TIMER; + host_ica_unlock(); // maybe don't need to unlock ? Jonle + host_timer_event(); + host_ica_lock(); + } + + if ( getIF() && getMSW() & MSW_PE && *pNtVDMState & VDM_INT_HARDWARE) { + // + // Mark the vdm state as hw int dispatched. Must use the lock as + // kernel mode DelayedIntApcRoutine changes the bit as well + // + _asm { + mov eax,FIXED_NTVDMSTATE_LINEAR + lock and dword ptr [eax], NOT VDM_INT_HARDWARE + } + DispatchHwInterrupt(); + } + + host_ica_unlock(); +} + + + + +VOID +DispatchHwInterrupt( + ) +/*++ + +Routine Description: + + This routine dispatches hardware interrupts to the vdm in Protect Mode. + It calls the ICA to get the vector number and sets up the VDM stack + appropriately. Real Mode interrupt dispatching has been moved to the + kernel. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + int InterruptNumber; + ULONG IretHookAddress = 0L; + + InterruptNumber = ica_intack(&IretHookAddress); + if (InterruptNumber == -1) { // skip spurious ints + return; + } + + DpmiHwIntHandler(InterruptNumber); + + if (IretHookAddress) { + BOOL Frame32 = (BOOL) VdmTib.PmStackInfo.Flags; + BOOL Stack32; + USHORT SegSs, VdmCs; + ULONG VdmSp, VdmEip; + PUCHAR VdmStackPointer; + ULONG StackOffset; + + SegSs = getSS(); + VdmStackPointer = Sim32GetVDMPointer(((ULONG)SegSs) << 16, 1, TRUE); + + // + // Figure out how many bits of sp to use + // + + if (Ldt[(SegSs & ~0x7)/sizeof(LDT_ENTRY)].HighWord.Bits.Default_Big) { + VdmSp = getESP(); + StackOffset = 12; + } else { + VdmSp = getSP(); + StackOffset = 6; + } + + (PCHAR)VdmStackPointer += VdmSp; + + // + // BUGBUG need to add stack limit checking 15-Nov-1993 Jonle + // + setESP(VdmSp - StackOffset); + + // + // Push info for Iret hook handler + // + VdmCs = (USHORT) ((IretHookAddress & 0xFFFF0000) >> 16); + VdmEip = (IretHookAddress & 0xFFFF); + + if (Frame32) { + *(PULONG)(VdmStackPointer - 4) = VdmTib.VdmContext.EFlags; + *(PULONG)(VdmStackPointer - 8) = (ULONG) VdmCs; + *(PULONG)(VdmStackPointer - 12) = VdmEip; + } else { + *(PUSHORT)(VdmStackPointer - 2) = (USHORT) VdmTib.VdmContext.EFlags; + *(PUSHORT)(VdmStackPointer - 4) = VdmCs; + *(PUSHORT)(VdmStackPointer - 6) = (USHORT) VdmEip; + } + } + +} + + +VOID +IRQ13_Eoi( + int IrqLine, + int CallCount + ) +{ + UNREFERENCED_PARAMETER(IrqLine); + UNREFERENCED_PARAMETER(CallCount); + + // + // if CallCount is less than Zero, then the interrupt request + // is being canceled. + // + if (CallCount < 0) { + return; + } + + IRQ13BeingHandled = FALSE; +} + + + + + + +VOID +MonitorEndIretHook( + VOID + ) +/*++ + +Routine Description: + + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + + PVOID VdmStackPointer; + + if (IntelMSW & MSW_PE) { + BOOL Frame32 = (BOOL) VdmTib.PmStackInfo.Flags; + ULONG FrameSize; + + if (Frame32) { + FrameSize = 12; + } else { + FrameSize = 6; + } + + VdmStackPointer = Sim32GetVDMPointer(((ULONG)getSS() << 16),2,TRUE); + + if (Ldt[(getSS() & ~0x7)/sizeof(LDT_ENTRY)].HighWord.Bits.Default_Big) { + (PCHAR)VdmStackPointer += getESP(); + setESP(getESP() + FrameSize); + } else { + (PCHAR)VdmStackPointer += getSP(); + setSP((USHORT) (getSP() + FrameSize)); + } + + if (Frame32) { + + VdmTib.VdmContext.EFlags = *(PULONG)((PCHAR)VdmStackPointer + 8); + setCS(*(PUSHORT)((PCHAR)VdmStackPointer + 4)); + VdmTib.VdmContext.Eip = *((PULONG)VdmStackPointer); + + } else { + + VdmTib.VdmContext.EFlags = (VdmTib.VdmContext.EFlags & 0xFFFF0000) | + ((ULONG) *(PUSHORT)((PCHAR)VdmStackPointer + 4)); + setCS(*(PUSHORT)((PCHAR)VdmStackPointer + 2)); + VdmTib.VdmContext.Eip = (VdmTib.VdmContext.Eip & 0xFFFF0000) | + ((ULONG) *(PUSHORT)((PCHAR)VdmStackPointer)); + + } + + } else { + + VdmStackPointer = Sim32GetVDMPointer(((ULONG)getSS() << 16) | getSP(),2,FALSE); + + setSP((USHORT) (getSP() + 6)); + + (USHORT)(VdmTib.VdmContext.EFlags) = *((PUSHORT)((PCHAR)VdmStackPointer + 4)); + setCS(*((PUSHORT)((PCHAR)VdmStackPointer + 2))); + setIP(*((PUSHORT)VdmStackPointer)); + + } + + +} + +VOID +host_clear_hw_int() +/*++ + +Routine Description: + + This routine "forgets" a previously requested hardware interrupt. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + /* + * We do nothing here to save a kernel call, because the + * interrupt if it hasn't been intacked yet or dispatched, + * will produce a harmless spurious int, which is dropped + * in the i386 interrupt dispatching code anyhow. + */ +} |