/*++ Copyright (c) 1990 Microsoft Corporation Module Name: Monitor.c Abstract: This module is the user mode portion of the x86 monitor Author: Dave Hastings (daveh) 16 Mar 1991 Environment: User mode only Revision History: Sudeep Bharati (sudeepb) 31-Dec-1991 Converted all register manipulation interfaces to functions from macros. This is to make ntvdm an exe as well as a dll, and these register oriented routines are exported from ntvdm for WOW32 and other installable VDDs. Dave Hastings (daveh) 18-Apr-1992 Split into multiple files. Track current monitor thread by Teb pointer. Register initial thread. Sudeep Bharati (sudeepb) 22-Sep-1992 Added Page Fault Handling For installable VDD support --*/ #include "monitorp.h" #include "dbgsvc.h" // // Internal functions // VOID EventVdmIo( VOID ); VOID EventVdmStringIo( VOID ); VOID EventVdmMemAccess( VOID ); VOID EventVdmIntAck( VOID ); VOID EventVdmBop( VOID ); VOID EventVdmError( VOID ); VOID EventVdmIrq13( VOID ); VOID EventVdmHandShakeAck( VOID ); VOID CreateProfile( VOID ); VOID StartProfile( VOID ); VOID StopProfile( VOID ); VOID AnalyzeProfile( VOID ); VOID CheckScreenSwitchRequest( HANDLE handle ); // [LATER] how do you prevent a struct from straddling a page boundary? ULONG IntelBase; // base memory address ULONG VdmSize; // Size of memory in VDM ULONG VdmDebugLevel; // used to control debugging PVOID CurrentMonitorTeb; // thread that is currently executing instructions. ULONG InitialBreakpoint = FALSE; // if set, breakpoint at end of cpu_init ULONG InitialVdmTibFlags = INITIAL_VDM_TIB_FLAGS; // VdmTib flags picked up from here CONTEXT InitialContext; // Initial context for all threads BOOLEAN DebugContextActive = FALSE; ULONG VdmFeatureBits = 0; // bit to indicate special features BOOLEAN MainThreadInMonitor = TRUE; extern PVOID NTVDMpLockPrefixTable; extern BOOL HandshakeInProgress; extern HANDLE hSuspend; extern HANDLE hResume; extern HANDLE hMainThreadSuspended; extern PVOID __safe_se_handler_table[]; /* base of safe handler entry table */ extern BYTE __safe_se_handler_count; /* absolute symbol whose address is the count of table entries */ IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used = { sizeof(_load_config_used), // Reserved 0, // Reserved 0, // Reserved 0, // Reserved 0, // GlobalFlagsClear 0, // GlobalFlagsSet 0, // CriticalSectionTimeout (milliseconds) 0, // DeCommitFreeBlockThreshold 0, // DeCommitTotalFreeThreshold (ULONG)&NTVDMpLockPrefixTable, // LockPrefixTable, defined in FASTPM.ASM 0, 0, 0, 0, 0, 0, 0, // Reserved 0, // & security_cookie (ULONG)__safe_se_handler_table, (ULONG)&__safe_se_handler_count }; // Bop dispatch table extern void (*BIOS[])(); // // Event Dispatch table // VOID (*EventDispatch[VdmMaxEvent])(VOID) = { EventVdmIo, EventVdmStringIo, EventVdmMemAccess, EventVdmIntAck, EventVdmBop, EventVdmError, EventVdmIrq13, EventVdmHandShakeAck }; #if DBG BOOLEAN fBreakInDebugger = FALSE; #endif EXPORT VOID cpu_init( ) /*++ Routine Description: This routine is used to prepare the IEU for instruction simulation. It will set the Intel registers to thier initial value, and perform any implementation specific initialization necessary. Arguments: Return Value: None. --*/ { NTSTATUS Status; InitialVdmTibFlags |= RM_BIT_MASK; // // Find out if we are running with IOPL. We call the kernel // rather than checking the registry ourselves, so that we can // insure that both the kernel and ntvdm.exe agree. If they didn't, // it would result in unnecssary trapping instructions. Whether or // not Vdms run with IOPL only changes on reboot // Status = NtVdmControl(VdmFeatures, &VdmFeatureBits); #if DBG if (!NT_SUCCESS(Status)) { DbgPrint( "NTVDM: Could not find out whether to use IOPL, %lx\n", Status ); } #endif // // If we have fast v86 mode IF emulation set the bit that tells // the 16 bit IF macros they know. // if (VdmFeatureBits & V86_VIRTUAL_INT_EXTENSIONS) { InitialVdmTibFlags |= RI_BIT_MASK; } *pNtVDMState = InitialVdmTibFlags; // Switch the npx back to 80 bit mode. Win32 apps start with // 64-bit precision for compatibility across platforms, but // DOS and Win16 apps expect 80 bit precision. // _asm fninit; // // We setup the InitialContext structure with the correct floating // point and debug register configuration, and cpu_createthread // uses this context to configure each 16-bit thread's floating // point and debug registers. // InitialContext.ContextFlags = CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS; Status = NtGetContextThread( NtCurrentThread(), &InitialContext ); if (!NT_SUCCESS(Status)) { #if DBG DbgPrint("NtVdm terminating : Could not get float/debug context for\n" " initial thread, status %lx\n", Status); DbgBreakPoint(); #endif TerminateVDM(); } // // // Turn OFF em bit so that dos apps will work correctly. // // On machines without 387's the floating point flag will have been // cleared. // InitialContext.ContextFlags = CONTEXT_FLOATING_POINT; InitialContext.FloatSave.Cr0NpxState &= ~0x6; // CR0_EM | CR0_MP // // Do the rest of thread initialization // cpu_createthread( NtCurrentThread(), NULL ); InterruptInit(); if (InitialBreakpoint) { DbgBreakPoint(); } } EXPORT VOID cpu_terminate( ) /*++ Routine Description: Arguments: Return Value: --*/ { InterruptTerminate(); } EXPORT VOID cpu_simulate( ) /*++ Routine Description: This routine causes the simulation of intel instructions to start. Arguments: Return Value: None. --*/ { NTSTATUS Status; PVDM_TIB VdmTib; ULONG oldIntState = VDM_VIRTUAL_INTERRUPTS; DBGTRACE(VDMTR_TYPE_MONITOR | MONITOR_CPU_SIMULATE, 0, 0); CurrentMonitorTeb = NtCurrentTeb(); VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->ContinueExecution = TRUE; VdmTib->VdmContext.ContextFlags = CONTEXT_FULL; while (VdmTib->ContinueExecution) { //ASSERT(CurrentMonitorTeb == NtCurrentTeb()); ASSERT(InterlockedIncrement(&VdmTib->NumTasks) == 0); if (*pNtVDMState & VDM_INTERRUPT_PENDING) { DispatchInterrupts(); } // translate MSW bits into EFLAGS if ( getMSW() & MSW_PE ) { if (!VDMForWOW && !getIF() && oldIntState == VDM_VIRTUAL_INTERRUPTS) { // // For PM apps, we need to set Cli time stamp if interrupts // are disabled and the time stamp was not set already. // This is because apps may use int31 to change interrupt // state instead of using cli. // VDM_PM_CLI_DATA cliData; cliData.Control = PM_CLI_CONTROL_SET; NtVdmControl(VdmPMCliControl, &cliData); } VdmTib->VdmContext.EFlags &= ~EFLAGS_V86_MASK; if (HandshakeInProgress) { CheckScreenSwitchRequest(hMainThreadSuspended); } MainThreadInMonitor = FALSE; Status = FastEnterPm(); } else { VdmTib->VdmContext.EFlags |= EFLAGS_V86_MASK; if (HandshakeInProgress) { CheckScreenSwitchRequest(hMainThreadSuspended); } MainThreadInMonitor = FALSE; Status = NtVdmControl(VdmStartExecution,NULL); } MainThreadInMonitor = TRUE; if (HandshakeInProgress) { CheckScreenSwitchRequest(hMainThreadSuspended); } if (!NT_SUCCESS(Status)) { #if DBG DbgPrint("NTVDM: Could not start execution\n"); #endif return; } // // Refresh VdmTib for the fact that wow32 thread never enters cpu_simulate // but returns here to handle BOP // Note, I think this needs only in FREE build. // CurrentMonitorTeb = NtCurrentTeb(); VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; if (!VDMForWOW) { oldIntState = getIF() ? VDM_VIRTUAL_INTERRUPTS : 0; } ASSERT(InterlockedDecrement(&VdmTib->NumTasks) < 0); #if DBG if (fBreakInDebugger) { fBreakInDebugger = 0; DbgBreakPoint(); } #endif // Translate Eflags value ASSERT ((!((VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK) && (getMSW() & MSW_PE)))); if ( VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK ) { VdmTib->VdmContext.EFlags &= ~EFLAGS_V86_MASK; } // bugbug does cs:eip wrap cause some kind of fault? VdmTib->VdmContext.Eip += VdmTib->EventInfo.InstructionSize; if (VdmTib->EventInfo.Event >= VdmMaxEvent) { #if DBG DbgPrint("NTVDM: Unknown event type\n"); DbgBreakPoint(); #endif VdmTib->ContinueExecution = FALSE; continue; } (*EventDispatch[VdmTib->EventInfo.Event])(); } // set this back to true incase we are nested VdmTib->ContinueExecution = TRUE; // // Restore the old Vdm tib info. This is necessary for the for the // case where the application thread is suspended, and a host simulate is // performed from another thread // DBGTRACE(VDMTR_TYPE_MONITOR | MONITOR_CPU_UNSIMULATE, 0, 0); } VOID host_unsimulate( ) /*++ Routine Description: This routine causes execution of instructions in a VDM to stop. Arguments: Return Value: None. --*/ { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->ContinueExecution = FALSE; } VOID EventVdmIo( VOID ) /*++ Routine Description: This function calls the appropriate io simulation routine. Arguments: Return Value: None. --*/ { PVDM_TIB VdmTib; EnableScreenSwitch(TRUE, hMainThreadSuspended); // only in FULLSCREEN VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; if (VdmTib->EventInfo.IoInfo.Size == 1) { if (VdmTib->EventInfo.IoInfo.Read) { inb(VdmTib->EventInfo.IoInfo.PortNumber,(half_word *)&(VdmTib->VdmContext.Eax)); } else { outb(VdmTib->EventInfo.IoInfo.PortNumber,getAL()); } } else if (VdmTib->EventInfo.IoInfo.Size == 2) { if (VdmTib->EventInfo.IoInfo.Read) { inw(VdmTib->EventInfo.IoInfo.PortNumber,(word *)&(VdmTib->VdmContext.Eax)); } else { outw(VdmTib->EventInfo.IoInfo.PortNumber,getAX()); } } #if DBG else { DbgPrint( "NtVdm: Unimplemented IO size %d\n", VdmTib->EventInfo.IoInfo.Size ); DbgBreakPoint(); } #endif DisableScreenSwitch(hMainThreadSuspended); } VOID EventVdmStringIo( VOID ) /*++ Routine Description: This function calls the appropriate io simulation routine. Arguments: Return Value: None. --*/ { PVDMSTRINGIOINFO pvsio; PUSHORT pIndexRegister; USHORT Index; PVDM_TIB VdmTib; EnableScreenSwitch(TRUE, hMainThreadSuspended); VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; // WARNING no 32 bit address support pvsio = &VdmTib->EventInfo.StringIoInfo; if (pvsio->Size == 1) { if (pvsio->Read) { insb((io_addr)pvsio->PortNumber, (half_word *)Sim32GetVDMPointer(pvsio->Address, 1, ISPESET), (word)pvsio->Count ); pIndexRegister = (PUSHORT)&VdmTib->VdmContext.Edi; } else { outsb((io_addr)pvsio->PortNumber, (half_word *)Sim32GetVDMPointer(pvsio->Address,1,ISPESET), (word)pvsio->Count ); pIndexRegister = (PUSHORT)&VdmTib->VdmContext.Esi; } } else if (pvsio->Size == 2) { if (pvsio->Read) { insw((io_addr)pvsio->PortNumber, (word *)Sim32GetVDMPointer(pvsio->Address,1,ISPESET), (word)pvsio->Count ); pIndexRegister = (PUSHORT)&VdmTib->VdmContext.Edi; } else { outsw((io_addr)pvsio->PortNumber, (word *)Sim32GetVDMPointer(pvsio->Address,1,ISPESET), (word)pvsio->Count ); pIndexRegister = (PUSHORT)&VdmTib->VdmContext.Esi; } } else { #if DBG DbgPrint( "NtVdm: Unimplemented IO size %d\n", VdmTib->EventInfo.IoInfo.Size ); DbgBreakPoint(); #endif DisableScreenSwitch(hMainThreadSuspended); return; } if (getDF()) { Index = *pIndexRegister - (USHORT)(pvsio->Count * pvsio->Size); } else { Index = *pIndexRegister + (USHORT)(pvsio->Count * pvsio->Size); } *pIndexRegister = Index; if (pvsio->Rep) { (USHORT)VdmTib->VdmContext.Ecx = 0; } DisableScreenSwitch(hMainThreadSuspended); } VOID EventVdmIntAck( VOID ) /*++ Routine Description: This routine is called each time we have returned to monitor context to dispatch interrupts. Its function is to check for AutoEoi and call the ica to do a nonspecific eoi, when the ica adapter is in AEOI mode. Arguments: Return Value: None. --*/ { int line; int adapter; PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; if (VdmTib->EventInfo.IntAckInfo) { if (VdmTib->EventInfo.IntAckInfo & VDMINTACK_SLAVE) adapter = 1; else adapter = 0; line = -1; host_ica_lock(); ica_eoi(adapter, &line, (int)(VdmTib->EventInfo.IntAckInfo & VDMINTACK_RAEOIMASK) ); host_ica_unlock(); } } VOID EventVdmBop( VOID ) /*++ Routine Description: This routine dispatches to the appropriate bop handler Arguments: Return Value: None. --*/ { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; if (VdmTib->EventInfo.BopNumber > MAX_BOP) { #if DBG DbgPrint( "NtVdm: Invalid BOP %lx\n", VdmTib->EventInfo.BopNumber ); #endif VdmTib->ContinueExecution = FALSE; } else { DBGTRACE(VDMTR_TYPE_MONITOR | MONITOR_EVENT_BOP, (USHORT)VdmTib->EventInfo.BopNumber, (ULONG)(*((UCHAR *)Sim32GetVDMPointer( (VdmTib->VdmContext.SegCs << 16) | VdmTib->VdmContext.Eip, 1, ISPESET))) ); (*BIOS[VdmTib->EventInfo.BopNumber])(); CurrentMonitorTeb = NtCurrentTeb(); } } VOID EventVdmError( VOID ) /*++ Routine Description: This routine prints a message(debug only), and exits the vdm Arguments: Return Value: None. --*/ { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; #if DBG DbgPrint( "NtVdm: Error code %lx\n", VdmTib->EventInfo.ErrorStatus ); DbgBreakPoint(); #endif TerminateVDM(); VdmTib->ContinueExecution = FALSE; } VOID EventVdmIrq13( VOID ) /*++ Routine Description: This routine simulates an IRQ 13 to the vdm Arguments: Return Value: None. --*/ { if (!IRQ13BeingHandled) { IRQ13BeingHandled = TRUE; ica_hw_interrupt( ICA_SLAVE, 5, 1 ); } } VOID EventVdmHandShakeAck( VOID ) /*++ Routine Description: This routine does nothing. Arguments: Return Value: None. --*/ { } VOID EventVdmMemAccess( VOID ) /*++ Routine Description: This routine will call the page fault handler routine which is common to both x86 and mips. Arguments: Return Value: None. --*/ { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; // RWMode is 0 if read fault or 1 if write fault. DispatchPageFault( VdmTib->EventInfo.FaultInfo.FaultAddr, VdmTib->EventInfo.FaultInfo.RWMode ); CurrentMonitorTeb = NtCurrentTeb(); } // Get and Set routines for intel registers. ULONG getEAX (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (VdmTib->VdmContext.Eax); } USHORT getAX (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)(VdmTib->VdmContext.Eax)); } UCHAR getAL (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((BYTE)(VdmTib->VdmContext.Eax)); } UCHAR getAH (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((BYTE)(VdmTib->VdmContext.Eax >> 8)); } ULONG getEBX (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (VdmTib->VdmContext.Ebx); } USHORT getBX (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)(VdmTib->VdmContext.Ebx)); } UCHAR getBL (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((BYTE)(VdmTib->VdmContext.Ebx)); } UCHAR getBH (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((BYTE)(VdmTib->VdmContext.Ebx >> 8)); } ULONG getECX (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (VdmTib->VdmContext.Ecx); } USHORT getCX (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)(VdmTib->VdmContext.Ecx)); } UCHAR getCL (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((BYTE)(VdmTib->VdmContext.Ecx)); } UCHAR getCH (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((BYTE)(VdmTib->VdmContext.Ecx >> 8)); } ULONG getEDX (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (VdmTib->VdmContext.Edx); } USHORT getDX (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)(VdmTib->VdmContext.Edx)); } UCHAR getDL (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((BYTE)(VdmTib->VdmContext.Edx)); } UCHAR getDH (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((BYTE)(VdmTib->VdmContext.Edx >> 8)); } ULONG getESP (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (VdmTib->VdmContext.Esp); } USHORT getSP (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.Esp); } ULONG getEBP (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (VdmTib->VdmContext.Ebp); } USHORT getBP (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.Ebp); } ULONG getESI (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (VdmTib->VdmContext.Esi); } USHORT getSI (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.Esi); } ULONG getEDI (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (VdmTib->VdmContext.Edi); } USHORT getDI (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.Edi); } ULONG getEIP (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (VdmTib->VdmContext.Eip); } USHORT getIP (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.Eip); } USHORT getCS (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.SegCs); } USHORT getSS (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.SegSs); } USHORT getDS (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.SegDs); } USHORT getES (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.SegEs); } USHORT getFS (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.SegFs); } USHORT getGS (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->VdmContext.SegGs); } ULONG getCF (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((VdmTib->VdmContext.EFlags & FLG_CARRY) ? 1 : 0); } ULONG getPF (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((VdmTib->VdmContext.EFlags & FLG_PARITY) ? 1 : 0); } ULONG getAF (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((VdmTib->VdmContext.EFlags & FLG_AUXILIARY) ? 1 : 0); } ULONG getZF (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((VdmTib->VdmContext.EFlags & FLG_ZERO) ? 1 : 0); } ULONG getSF (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((VdmTib->VdmContext.EFlags & FLG_SIGN) ? 1 : 0); } ULONG getTF (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((VdmTib->VdmContext.EFlags & FLG_TRAP) ? 1 : 0); } ULONG getIF (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((VdmTib->VdmContext.EFlags & FLG_INTERRUPT) ? 1 : 0); } ULONG getDF (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((VdmTib->VdmContext.EFlags & FLG_DIRECTION) ? 1 : 0); } ULONG getOF (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((VdmTib->VdmContext.EFlags & FLG_OVERFLOW) ? 1 : 0); } USHORT getMSW (VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return ((USHORT)VdmTib->IntelMSW); } USHORT getSTATUS(VOID){ PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (USHORT)VdmTib->VdmContext.EFlags; } ULONG getEFLAGS(VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return VdmTib->VdmContext.EFlags; } USHORT getFLAGS(VOID) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return (USHORT)VdmTib->VdmContext.EFlags; } VOID setEAX (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Eax = val; } VOID setAX (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Eax = (VdmTib->VdmContext.Eax & 0xFFFF0000) | ((ULONG)val & 0x0000FFFF); } VOID setAH (UCHAR val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Eax = (VdmTib->VdmContext.Eax & 0xFFFF00FF) | ((ULONG)(val << 8) & 0x0000FF00); } VOID setAL (UCHAR val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Eax = (VdmTib->VdmContext.Eax & 0xFFFFFF00) | ((ULONG)val & 0x000000FF); } VOID setEBX (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Ebx = val ; } VOID setBX (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Ebx = (VdmTib->VdmContext.Ebx & 0xFFFF0000) | ((ULONG)val & 0x0000FFFF); } VOID setBH (UCHAR val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Ebx = (VdmTib->VdmContext.Ebx & 0xFFFF00FF) | ((ULONG)(val << 8) & 0x0000FF00); } VOID setBL (UCHAR val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Ebx = (VdmTib->VdmContext.Ebx & 0xFFFFFF00) | ((ULONG)val & 0x000000FF); } VOID setECX (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Ecx = val ; } VOID setCX (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Ecx = (VdmTib->VdmContext.Ecx & 0xFFFF0000) | ((ULONG)val & 0x0000FFFF); } VOID setCH (UCHAR val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Ecx = (VdmTib->VdmContext.Ecx & 0xFFFF00FF) | ((ULONG)(val << 8) & 0x0000FF00); } VOID setCL (UCHAR val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Ecx = (VdmTib->VdmContext.Ecx & 0xFFFFFF00) | ((ULONG)val & 0x000000FF); } VOID setEDX (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Edx = val ; } VOID setDX (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Edx = (VdmTib->VdmContext.Edx & 0xFFFF0000) | ((ULONG)val & 0x0000FFFF); } VOID setDH (UCHAR val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Edx = (VdmTib->VdmContext.Edx & 0xFFFF00FF) | ((ULONG)(val << 8) & 0x0000FF00); } VOID setDL (UCHAR val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Edx = (VdmTib->VdmContext.Edx & 0xFFFFFF00) | ((ULONG)val & 0x000000FF); } VOID setESP (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Esp = val ; } VOID setSP (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Esp = (VdmTib->VdmContext.Esp & 0xFFFF0000) | ((ULONG)val & 0x0000FFFF); } VOID setEBP (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Ebp = val; } VOID setBP (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Ebp = (VdmTib->VdmContext.Ebp & 0xFFFF0000) | ((ULONG)val & 0x0000FFFF); } VOID setESI (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Esi = val ; } VOID setSI (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Esi = (VdmTib->VdmContext.Esi & 0xFFFF0000) | ((ULONG)val & 0x0000FFFF); } VOID setEDI (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Edi = val ; } VOID setDI (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Edi = (VdmTib->VdmContext.Edi & 0xFFFF0000) | ((ULONG)val & 0x0000FFFF); } VOID setEIP (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Eip = val ; } VOID setIP (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.Eip = (VdmTib->VdmContext.Eip & 0xFFFF0000) | ((ULONG)val & 0x0000FFFF); } VOID setCS (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.SegCs = (ULONG) val & 0x0000FFFF ; } VOID setSS (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.SegSs = (ULONG) val & 0x0000FFFF ; } VOID setDS (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.SegDs = (ULONG) val & 0x0000FFFF ; } VOID setES (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.SegEs = (ULONG) val & 0x0000FFFF ; } VOID setFS (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.SegFs = (ULONG) val & 0x0000FFFF ; } VOID setGS (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.SegGs = (ULONG) val & 0x0000FFFF ; } VOID setCF (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~FLG_CARRY) | (((ULONG)val << FLG_CARRY_BIT) & FLG_CARRY); } VOID setPF (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~FLG_PARITY) | (((ULONG)val << FLG_PARITY_BIT) & FLG_PARITY); } VOID setAF (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~FLG_AUXILIARY) | (((ULONG)val << FLG_AUXILIARY_BIT) & FLG_AUXILIARY); } VOID setZF (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~FLG_ZERO) | (((ULONG)val << FLG_ZERO_BIT) & FLG_ZERO); } VOID setSF (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~FLG_SIGN) | (((ULONG)val << FLG_SIGN_BIT) & FLG_SIGN); } VOID setIF (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~FLG_INTERRUPT) | (((ULONG)val << FLG_INTERRUPT_BIT) & FLG_INTERRUPT); } VOID setDF (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~FLG_DIRECTION) | (((ULONG)val << FLG_DIRECTION_BIT) & FLG_DIRECTION); } VOID setOF (ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~FLG_OVERFLOW) | (((ULONG)val << FLG_OVERFLOW_BIT) & FLG_OVERFLOW); } VOID setMSW (USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->IntelMSW = val ; } VOID setSTATUS(USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & 0xFFFF0000) | val; } VOID setEFLAGS(ULONG val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = val; } VOID setFLAGS(USHORT val) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & 0xFFFF0000) | val; } // // The following is a private register function // ULONG getPE(){ PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return((VdmTib->IntelMSW & MSW_PE) ? 1 : 0); } PX86CONTEXT getIntelRegistersPointer( VOID ) /*++ Routine Description: Return Address on Intel Registers for WOW Fast Access Arguments: None Return Value: Pointer to Intel Registers x86 Context Record --*/ { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; return &(VdmTib->VdmContext); } BOOLEAN MonitorInitializePrinterInfo( WORD Ports, PWORD PortTable, PUCHAR State, PUCHAR Control, PUCHAR Status, PUCHAR HostState) { UCHAR adapter; PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; ASSERT (Ports == 3); ASSERT (Status != NULL); // only do this if the structure has not been initialized -- meaning // the pointers can be set once. if (NULL == VdmTib->PrinterInfo.prt_Status) { VdmTib->PrinterInfo.prt_PortAddr[0] = PortTable[0]; VdmTib->PrinterInfo.prt_PortAddr[1] = PortTable[1]; VdmTib->PrinterInfo.prt_PortAddr[2] = PortTable[2]; VdmTib->PrinterInfo.prt_Handle[0] = VdmTib->PrinterInfo.prt_Handle[1] = VdmTib->PrinterInfo.prt_Handle[2] = NULL; // default mode is kernel simulating status port read // mode will be changed if // (1). A vdd is hooking printer ports. // (2). Dongle mode is detected VdmTib->PrinterInfo.prt_Mode[0] = VdmTib->PrinterInfo.prt_Mode[1] = VdmTib->PrinterInfo.prt_Mode[2] = PRT_MODE_SIMULATE_STATUS_PORT; // primarily for dongle VdmTib->PrinterInfo.prt_BytesInBuffer[0] = VdmTib->PrinterInfo.prt_BytesInBuffer[1] = VdmTib->PrinterInfo.prt_BytesInBuffer[2] = 0; // primarily for simulating printer status read in kernel VdmTib->PrinterInfo.prt_State = State; VdmTib->PrinterInfo.prt_Control = Control; VdmTib->PrinterInfo.prt_Status = Status; VdmTib->PrinterInfo.prt_HostState = HostState; // // Give the kernel printer emulation an opportunity to cache the // pointers // if (!NT_SUCCESS(NtVdmControl(VdmPrinterInitialize,NULL))) { return FALSE; } return TRUE; } else { return FALSE; } } BOOLEAN MonitorEnablePrinterDirectAccess(WORD adapter, HANDLE handle, BOOLEAN Enable) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; ASSERT(VDM_NUMBER_OF_LPT > adapter); if (Enable) { // if the adapter has been allocated by a third party VDD, // can't do direct io. if (PRT_MODE_VDD_CONNECTED != VdmTib->PrinterInfo.prt_Mode[adapter]) { VdmTib->PrinterInfo.prt_Mode[adapter] = PRT_MODE_DIRECT_IO; VdmTib->PrinterInfo.prt_Handle[adapter] = handle; // NtVdmControl(VdmPrinterDirectIoOpen, &adapter); return TRUE; } else return FALSE; } else { // disabling direct i/o. reset it back to status port simulation if (VdmTib->PrinterInfo.prt_Handle[adapter] == handle) { NtVdmControl(VdmPrinterDirectIoClose, &adapter); VdmTib->PrinterInfo.prt_Mode[adapter] = PRT_MODE_SIMULATE_STATUS_PORT; VdmTib->PrinterInfo.prt_Handle[adapter] = NULL; VdmTib->PrinterInfo.prt_BytesInBuffer[adapter] = 0; return TRUE; } else return FALSE; } } BOOLEAN MonitorVddConnectPrinter(WORD Adapter, HANDLE hVdd, BOOLEAN Connect) { PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; if (VDM_NUMBER_OF_LPT <= Adapter) return FALSE; if (Connect) { VdmTib->PrinterInfo.prt_Mode[Adapter] = PRT_MODE_VDD_CONNECTED; VdmTib->PrinterInfo.prt_Handle[Adapter] = hVdd; return TRUE; } else { if (hVdd == VdmTib->PrinterInfo.prt_Handle[Adapter]) { VdmTib->PrinterInfo.prt_Mode[Adapter] = PRT_MODE_SIMULATE_STATUS_PORT; VdmTib->PrinterInfo.prt_Handle[Adapter] = NULL; return TRUE; } else return FALSE; } } BOOLEAN MonitorPrinterWriteData(WORD Adapter, BYTE Value) { USHORT BytesInBuffer; PVDM_TIB VdmTib; VdmTib = (PVDM_TIB)NtCurrentTeb()->Vdm; ASSERT(VDM_NUMBER_OF_LPT > Adapter); BytesInBuffer = VdmTib->PrinterInfo.prt_BytesInBuffer[Adapter]; VdmTib->PrinterInfo.prt_Buffer[Adapter][BytesInBuffer] = Value; VdmTib->PrinterInfo.prt_BytesInBuffer[Adapter]++; return TRUE; } /* CheckScreenSwitchRequest - * * This function checks if timer thread has asked us to stop such that it * can handle the fullscreen and windowed switch. * If yes, we will signal that we are stopped and wait for resume event. * */ VOID CheckScreenSwitchRequest(HANDLE handle) { DWORD status; // // Check if Suspen is requested. If yes, we will signal that we are going to // the wait state and wait for the resume event // Since 'handle' event is a manual event, it is important that // we check-and-wait in a loop such that timer thread will not pick up the // 'handle' event between the wait-for-resume and the ResetEvent(handle). // while (TRUE) { status = WaitForSingleObject(hSuspend, 0); if (status == 0) { SetEvent(handle); WaitForSingleObject(hResume, INFINITE); ResetEvent(handle); } else { // // Make sure event is reset before leaving this function // ResetEvent(handle); return; } } }