summaryrefslogtreecommitdiffstats
path: root/private/mvdm/v86/monitor/i386/int.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/v86/monitor/i386/int.c')
-rw-r--r--private/mvdm/v86/monitor/i386/int.c454
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.
+ */
+}