Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

vdmints.c File Reference

#include <ntos.h>
#include <zwapi.h>
#include "vdmp.h"

Go to the source code of this file.

Defines

#define VDM_HWINT_INCREMENT   EVENT_INCREMENT

Functions

VOID VdmpQueueIntApcRoutine (IN PKAPC Apc, IN PKNORMAL_ROUTINE *NormalRoutine, IN PVOID *NormalContext, IN PVOID *SystemArgument1, IN PVOID *SystemArgument2)
VOID VdmpQueueIntNormalRoutine (IN PVOID NormalContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
VOID VdmpDelayIntDpcRoutine (IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
VOID VdmpDelayIntApcRoutine (IN PKAPC Apc, IN PKNORMAL_ROUTINE *NormalRoutine, IN PVOID *NormalContext, IN PVOID *SystemArgument1, IN PVOID *SystemArgument2)
int RestartDelayedInterrupts (PVDMICAUSERDATA pIcaUserData)
int IcaScan (PVDMICAUSERDATA pIcaUserData, PVDMVIRTUALICA pIcaAdapter)
int IcaAccept (PVDMICAUSERDATA pIcaUserData, PVDMVIRTUALICA pIcaAdapter)
ULONG GetIretHookAddress (PKTRAP_FRAME TrapFrame, PVDMICAUSERDATA pIcaUserData, int IrqNum)
VOID PushRmInterrupt (PKTRAP_FRAME TrapFrame, ULONG IretHookAddress, PVDM_TIB VdmTib, ULONG InterruptNumber)
NTSTATUS PushPmInterrupt (PKTRAP_FRAME TrapFrame, ULONG IretHookAddress, PVDM_TIB VdmTib, ULONG InterruptNumber)
VOID VdmpNullRundownRoutine (IN PKAPC Apc)
int VdmpExceptionHandler (IN PEXCEPTION_POINTERS ExceptionInfo)
NTSTATUS VdmpQueueInterrupt (IN HANDLE ThreadHandle)
NTSTATUS VdmDispatchInterrupts (PKTRAP_FRAME TrapFrame, PVDM_TIB VdmTib)
NTSTATUS VdmpDelayInterrupt (PVDMDELAYINTSDATA pdsd)
BOOLEAN VdmpDispatchableIntPending (ULONG EFlags)
NTSTATUS VdmpIsThreadTerminating (HANDLE ThreadId)

Variables

POBJECT_TYPE ExSemaphoreObjectType
POBJECT_TYPE ExEventObjectType


Define Documentation

#define VDM_HWINT_INCREMENT   EVENT_INCREMENT
 

Definition at line 31 of file vdmints.c.

Referenced by VdmDispatchInterrupts(), VdmpDelayIntDpcRoutine(), and VdmpQueueIntApcRoutine().


Function Documentation

ULONG GetIretHookAddress PKTRAP_FRAME  TrapFrame,
PVDMICAUSERDATA  pIcaUserData,
int  IrqNum
 

Definition at line 897 of file vdmints.c.

References PAGED_CODE.

Referenced by VdmDispatchInterrupts().

00904 : 00905 00906 Retrieves the IretHookAddress from the real mode\protect mode 00907 iret hook bop table. This function is equivalent to 00908 softpc\base\system\ica.c - ica_iret_hook_needed() 00909 00910 Arguments: 00911 00912 TrapFrame - address of current trapframe 00913 pIcaUserData - addr of ica data 00914 IrqNum - IrqLineNum 00915 00916 Return Value: 00917 00918 ULONG IretHookAddress. seg:offset or sel:offset Iret Hook, 00919 0 if none 00920 --*/ 00921 { 00922 ULONG IrqMask; 00923 ULONG AddrBopTable; 00924 int IretBopSize; 00925 00926 PAGED_CODE(); 00927 00928 IrqMask = 1 << IrqNum; 00929 if (!(IrqMask & *pIcaUserData->pIretHooked) || 00930 !*pIcaUserData->pAddrIretBopTable ) 00931 { 00932 return 0; 00933 } 00934 00935 if (TrapFrame->EFlags & EFLAGS_V86_MASK) { 00936 AddrBopTable = *pIcaUserData->pAddrIretBopTable; 00937 IretBopSize = VDM_RM_IRETBOPSIZE; 00938 } 00939 else { 00940 AddrBopTable = (VDM_PM_IRETBOPSEG << 16) | VDM_PM_IRETBOPOFF; 00941 IretBopSize = VDM_PM_IRETBOPSIZE; 00942 } 00943 00944 *pIcaUserData->pDelayIret |= IrqMask; 00945 00946 return AddrBopTable + IretBopSize * IrqNum; 00947 }

int IcaAccept PVDMICAUSERDATA  pIcaUserData,
PVDMVIRTUALICA  pIcaAdapter
 

Definition at line 831 of file vdmints.c.

References FALSE, IcaScan(), and PAGED_CODE.

Referenced by VdmDispatchInterrupts().

00837 : 00838 00839 Does the equivalent of a cpu IntAck cycle retrieving the Irql Line Num 00840 for interrupt dispatch, and setting the ica state to reflect that 00841 the interrupt is in service. 00842 00843 Similar to softpc\base\system\ica.c - ica_accept() scan_irr(), 00844 except that this code rejects interrupt dispatching if the ica 00845 is in Auto-EOI as this may involve a new interrupt cycle, and 00846 eoi hooks to be activated. 00847 00848 Arguments: 00849 PVDMICAUSERDATA pIcaUserData - addr of ica userdata 00850 PVDMVIRTUALICA pIcaAdapter - addr of ica adapter 00851 00852 00853 Return Value: 00854 00855 ULONG IrqLineNum for the specific adapter (0 to 7) 00856 returns -1 if there are no interrupts to generate (spurious ints 00857 are normally done on line 7 00858 00859 --*/ 00860 { 00861 int line; 00862 UCHAR bit; 00863 00864 PAGED_CODE(); 00865 00866 00867 // 00868 // Drop the INT line, and scan the ica 00869 // 00870 pIcaAdapter->ica_cpu_int = FALSE; 00871 00872 line = IcaScan(pIcaUserData, pIcaAdapter); 00873 00874 if (line < 0) { 00875 return -1; 00876 } 00877 00878 bit = (1 << line); 00879 pIcaAdapter->ica_isr |= bit; 00880 00881 // 00882 // decrement the count and clear the IRR bit 00883 // ensure the count doesn't wrap past zero. 00884 // 00885 if (--(pIcaAdapter->ica_count[line]) <= 0) { 00886 pIcaAdapter->ica_irr &= ~bit; 00887 pIcaAdapter->ica_count[line] = 0; 00888 } 00889 00890 00891 return(line); 00892 }

int IcaScan PVDMICAUSERDATA  pIcaUserData,
PVDMVIRTUALICA  pIcaAdapter
 

Definition at line 750 of file vdmints.c.

References PAGED_CODE.

Referenced by IcaAccept(), and RestartDelayedInterrupts().

00756 : 00757 00758 Similar to softpc\base\system\ica.c - scan_irr(), 00759 00760 Check the IRR, the IMR and the ISR to determine which interrupt 00761 should be delivered. 00762 00763 A bit set in the IRR will generate an interrupt if: 00764 IMR bit, DelayIret bit, DelayIrq bit AND ISR higher priority bits 00765 are clear (unless Special Mask Mode, in which case ISR is ignored) 00766 00767 If there is no bit set, then return -1 00768 00769 00770 Arguments: 00771 PVDMICAUSERDATA pIcaUserData - addr of ica userdata 00772 PVDMVIRTUALICA pIcaAdapter - addr of ica adapter 00773 00774 00775 Return Value: 00776 00777 int IrqLineNum for the specific adapter (0 to 7) 00778 -1 for none 00779 00780 --*/ 00781 { 00782 int i,line; 00783 UCHAR bit; 00784 ULONG IrrImrDelay; 00785 ULONG ActiveIsr; 00786 00787 PAGED_CODE(); 00788 00789 IrrImrDelay = *pIcaUserData->pDelayIrq | *pIcaUserData->pDelayIret; 00790 if (pIcaAdapter == pIcaUserData->pIcaSlave) { 00791 IrrImrDelay >>= 8; 00792 } 00793 00794 IrrImrDelay = pIcaAdapter->ica_irr & ~(pIcaAdapter->ica_imr | (UCHAR)IrrImrDelay); 00795 00796 if (IrrImrDelay) { 00797 00798 /* 00799 * Does the current mode require the ica to prevent 00800 * interrupts if that line is still active (ie in the isr)? 00801 * 00802 * Normal Case: Used by DOS and Win3.1/S the isr prevents interrupts. 00803 * Special Mask Mode, Special Fully Nested Mode do not block 00804 * interrupts using bits in the isr. SMM is the mode used 00805 * by Windows95 and Win3.1/E. 00806 * 00807 */ 00808 ActiveIsr = (pIcaAdapter->ica_mode & (ICA_SMM|ICA_SFNM)) 00809 ? 0 : pIcaAdapter->ica_isr; 00810 00811 for(i = 0; i < 8; i++) { 00812 line = (pIcaAdapter->ica_hipri + i) & 7; 00813 bit = 1 << line; 00814 if (ActiveIsr & bit) { 00815 break; /* No nested interrupt possible */ 00816 } 00817 00818 if (IrrImrDelay & bit) { 00819 return line; 00820 } 00821 } 00822 } 00823 00824 return -1; 00825 }

NTSTATUS PushPmInterrupt PKTRAP_FRAME  TrapFrame,
ULONG  IretHookAddress,
PVDM_TIB  VdmTib,
ULONG  InterruptNumber
 

Definition at line 1045 of file vdmints.c.

References _Vdm_InterruptHandler::CsSelector, _Vdm_InterruptHandler::Eip, _Vdm_Tib::Flags, Ki386GetSelectorParameters(), PAGED_CODE, PUSHORT, SEL_TYPE_2GIG, SEL_TYPE_BIG, SEL_TYPE_ED, USHORT, and _Vdm_Tib::VdmInterruptHandlers.

Referenced by VdmDispatchInterrupts().

01053 : 01054 01055 Pushes ProtectMode interrupt frame onto the UserMode stack in the TrapFrame 01056 Raises an exception if an invalid stack is found 01057 01058 Arguments: 01059 01060 TrapFrame - address of current trapframe 01061 IretHookAddress - address of Iret Hook, 0 if none 01062 VdmTib - address of current vdm tib 01063 InterruptNumber - interrupt number to reflect 01064 01065 Return Value: 01066 01067 None. 01068 01069 --*/ 01070 { 01071 ULONG Flags,Base,Limit; 01072 ULONG VdmSp, VdmSpOrg; 01073 PUSHORT VdmStackPointer; 01074 ULONG StackOffset; 01075 BOOLEAN Frame32 = (BOOLEAN) VdmTib->DpmiInfo.Flags; 01076 01077 PAGED_CODE(); 01078 01079 // 01080 // Switch to "locked" dpmi stack if lock count is zero 01081 // This emulates the win3.1 Begin_Use_Locked_PM_Stack function. 01082 // 01083 01084 if (!VdmTib->DpmiInfo.LockCount++) { 01085 VdmTib->DpmiInfo.SaveEsp = TrapFrame->HardwareEsp; 01086 VdmTib->DpmiInfo.SaveEip = TrapFrame->Eip; 01087 VdmTib->DpmiInfo.SaveSsSelector = (USHORT) TrapFrame->HardwareSegSs; 01088 TrapFrame->HardwareEsp = 0x1000; 01089 TrapFrame->HardwareSegSs = (ULONG) VdmTib->DpmiInfo.SsSelector | 0x7; 01090 } 01091 01092 // 01093 // Use Sp or Esp ? 01094 // 01095 if (!Ki386GetSelectorParameters((USHORT)TrapFrame->HardwareSegSs, 01096 &Flags, &Base, &Limit)) 01097 { 01098 return STATUS_ACCESS_VIOLATION; 01099 } 01100 01101 // 01102 // Adjust the limit for page granularity 01103 // 01104 Limit++; 01105 if (Flags & SEL_TYPE_2GIG) { 01106 Limit = (Limit << 12) | 0xfff; 01107 } 01108 01109 VdmSp = (Flags & SEL_TYPE_BIG) ? TrapFrame->HardwareEsp 01110 : (USHORT)TrapFrame->HardwareEsp; 01111 01112 // 01113 // Get pointer to current stack 01114 // 01115 VdmStackPointer = (PUSHORT)(Base + VdmSp); 01116 01117 01118 // 01119 // Create enough room for iret hook frame 01120 // 01121 VdmSpOrg = VdmSp; 01122 if (IretHookAddress) { 01123 if (Frame32) { 01124 VdmSp -= 3*sizeof(ULONG); 01125 } else { 01126 VdmSp -= 3*sizeof(USHORT); 01127 } 01128 } 01129 01130 // 01131 // Create enough room for 2 iret frames 01132 // 01133 01134 if (Frame32) { 01135 VdmSp -= 6*sizeof(ULONG); 01136 } else { 01137 VdmSp -= 6*sizeof(USHORT); 01138 } 01139 01140 // 01141 // Set Final Value of Sp\Esp, do this before checking stack 01142 // limits so that invalid esp is visible to debuggers 01143 // 01144 if (Flags & SEL_TYPE_BIG) { 01145 TrapFrame->HardwareEsp = VdmSp; 01146 } 01147 else { 01148 (USHORT)TrapFrame->HardwareEsp = (USHORT)VdmSp; 01149 } 01150 01151 01152 // 01153 // Check stack limits 01154 // If any of the following conditions are TRUE 01155 // - New stack pointer wraps (not enuf space) 01156 // - If normal stack and Sp not below limit 01157 // - If Expand Down stack and Sp not above limit 01158 // 01159 // Then raise a Stack Fault 01160 // 01161 if ( VdmSp >= VdmSpOrg || 01162 !(Flags & SEL_TYPE_ED) && VdmSpOrg > Limit || 01163 (Flags & SEL_TYPE_ED) && VdmSp < Limit ) 01164 { 01165 return STATUS_ACCESS_VIOLATION; 01166 } 01167 01168 // 01169 // Build the Hw Int iret frame 01170 // 01171 01172 if (Frame32) { 01173 01174 *(--(PULONG)VdmStackPointer) = TrapFrame->EFlags; 01175 *(PUSHORT)(--(PULONG)VdmStackPointer) = (USHORT)TrapFrame->SegCs; 01176 *(--(PULONG)VdmStackPointer) = TrapFrame->Eip; 01177 *(--(PULONG)VdmStackPointer) = TrapFrame->EFlags & ~EFLAGS_TF_MASK; 01178 *(--(PULONG)VdmStackPointer) = VdmTib->DpmiInfo.DosxIntIretD >> 16; 01179 *(--(PULONG)VdmStackPointer) = VdmTib->DpmiInfo.DosxIntIretD & 0xffff; 01180 01181 } else { 01182 01183 *(--(PUSHORT)VdmStackPointer) = (USHORT)TrapFrame->EFlags; 01184 *(--(PUSHORT)VdmStackPointer) = (USHORT)TrapFrame->SegCs; 01185 *(--(PUSHORT)VdmStackPointer) = (USHORT)TrapFrame->Eip; 01186 *(--(PUSHORT)VdmStackPointer) = (USHORT)(TrapFrame->EFlags & ~EFLAGS_TF_MASK); 01187 *(--(PULONG)VdmStackPointer) = VdmTib->DpmiInfo.DosxIntIret; 01188 01189 } 01190 01191 // 01192 // Point cs and ip at interrupt handler 01193 // 01194 TrapFrame->SegCs = VdmTib->VdmInterruptHandlers[InterruptNumber].CsSelector | 0x7; 01195 TrapFrame->Eip = VdmTib->VdmInterruptHandlers[InterruptNumber].Eip; 01196 01197 // 01198 // Turn off trace bit so we don't trace the iret hook 01199 // 01200 TrapFrame->EFlags &= ~EFLAGS_TF_MASK; 01201 01202 // 01203 // Build the Irethook Iret frame, if one exists 01204 // 01205 if (IretHookAddress) { 01206 ULONG SegCs, Eip; 01207 01208 // 01209 // Point cs and eip at the iret hook, so when we build 01210 // the frame below, the correct contents are set 01211 // 01212 SegCs = IretHookAddress >> 16; 01213 Eip = IretHookAddress & 0xFFFF; 01214 01215 if (Frame32) { 01216 01217 *(--(PULONG)VdmStackPointer) = TrapFrame->EFlags; 01218 *(PUSHORT)(--(PULONG)VdmStackPointer) = (USHORT)SegCs; 01219 *(--(PULONG)VdmStackPointer) = Eip; 01220 01221 } else { 01222 01223 *(--(PUSHORT)VdmStackPointer) = (USHORT)TrapFrame->EFlags; 01224 *(--(PUSHORT)VdmStackPointer) = (USHORT)SegCs; 01225 *(--(PUSHORT)VdmStackPointer) = (USHORT)Eip; 01226 01227 } 01228 } 01229 return STATUS_SUCCESS; 01230 }

VOID PushRmInterrupt PKTRAP_FRAME  TrapFrame,
ULONG  IretHookAddress,
PVDM_TIB  VdmTib,
ULONG  InterruptNumber
 

Definition at line 953 of file vdmints.c.

References PAGED_CODE, PUSHORT, USHORT, and _Vdm_Tib::VdmInterruptHandlers.

Referenced by VdmDispatchInterrupts().

00961 : 00962 00963 Pushes RealMode interrupt frame onto the UserMode stack in the TrapFrame 00964 00965 Arguments: 00966 00967 TrapFrame - address of current trapframe 00968 IretHookAddress - address of Iret Hook, 0 if none 00969 VdmTib - address of current vdm tib 00970 InterruptNumber - interrupt number to reflect 00971 00972 00973 Return Value: 00974 00975 None. 00976 00977 --*/ 00978 { 00979 ULONG UserSS; 00980 USHORT UserSP; 00981 USHORT NewCS; 00982 USHORT NewIP; 00983 00984 PAGED_CODE(); 00985 00986 00987 // 00988 // Get pointers to current stack 00989 // 00990 UserSS = TrapFrame->HardwareSegSs << 4; 00991 UserSP = (USHORT) TrapFrame->HardwareEsp; 00992 00993 // 00994 // load interrupt stack frame, pushing flags, Cs and ip 00995 // 00996 UserSP -= 2; 00997 *(PUSHORT)(UserSS + UserSP) = (USHORT)TrapFrame->EFlags; 00998 UserSP -= 2; 00999 *(PUSHORT)(UserSS + UserSP) = (USHORT)TrapFrame->SegCs; 01000 UserSP -= 2; 01001 *(PUSHORT)(UserSS + UserSP) = (USHORT)TrapFrame->Eip; 01002 01003 01004 // 01005 // load IretHook stack frame if one exists 01006 // 01007 if (IretHookAddress) { 01008 UserSP -= 2; 01009 *(PUSHORT)(UserSS + UserSP) = (USHORT)(TrapFrame->EFlags & ~EFLAGS_TF_MASK); 01010 UserSP -= 2; 01011 *(PUSHORT)(UserSS + UserSP) = (USHORT)(IretHookAddress >> 16); 01012 UserSP -= 2; 01013 *(PUSHORT)(UserSS + UserSP) = (USHORT)IretHookAddress; 01014 } 01015 01016 // 01017 // Set new sp, ip, and cs. 01018 // 01019 01020 if (VdmTib->VdmInterruptHandlers[InterruptNumber].Flags & VDM_INT_HOOKED) { 01021 NewCS = (USHORT) (VdmTib->DpmiInfo.DosxRmReflector >> 16); 01022 NewIP = (USHORT) VdmTib->DpmiInfo.DosxRmReflector; 01023 // 01024 // now encode the interrupt number into CS 01025 // 01026 NewCS -= (USHORT) InterruptNumber; 01027 NewIP += (USHORT) (InterruptNumber*16); 01028 01029 } else { 01030 PUSHORT pIvtEntry = (PUSHORT) (InterruptNumber * 4); 01031 01032 NewIP = *pIvtEntry++; 01033 NewCS = *pIvtEntry; 01034 } 01035 01036 TrapFrame->HardwareEsp = UserSP; 01037 TrapFrame->Eip = NewIP; 01038 TrapFrame->SegCs = NewCS; 01039 }

int RestartDelayedInterrupts PVDMICAUSERDATA  pIcaUserData  ) 
 

Definition at line 715 of file vdmints.c.

References IcaScan(), PAGED_CODE, and TRUE.

Referenced by VdmDispatchInterrupts().

00718 { 00719 int line; 00720 00721 00722 PAGED_CODE(); 00723 00724 *pIcaUserData->pUndelayIrq = 0; 00725 00726 line = IcaScan(pIcaUserData, pIcaUserData->pIcaSlave); 00727 if (line != -1) { 00728 // set the slave 00729 pIcaUserData->pIcaSlave->ica_int_line = line; 00730 pIcaUserData->pIcaSlave->ica_cpu_int = TRUE; 00731 00732 // set the master cascade 00733 line = pIcaUserData->pIcaSlave->ica_ssr; 00734 pIcaUserData->pIcaMaster->ica_irr |= 1 << line; 00735 pIcaUserData->pIcaMaster->ica_count[line]++; 00736 } 00737 00738 line = IcaScan(pIcaUserData, pIcaUserData->pIcaMaster); 00739 if (line != -1) { 00740 pIcaUserData->pIcaMaster->ica_cpu_int = TRUE; 00741 pIcaUserData->pIcaMaster->ica_int_line = TRUE; 00742 } 00743 00744 return line; 00745 }

NTSTATUS VdmDispatchInterrupts PKTRAP_FRAME  TrapFrame,
PVDM_TIB  VdmTib
 

Definition at line 477 of file vdmints.c.

References _VdmEventInfo::Event, _Vdm_Tib::EventInfo, ExRaiseStatus(), GetIretHookAddress(), IcaAccept(), _VdmEventInfo::InstructionSize, KeBoostPriorityThread(), KeGetCurrentThread, KeI386VdmIoplAllowed, KeI386VirtualIntExtensions, NT_SUCCESS, NTSTATUS(), PAGED_CODE, ProbeForWrite(), PsGetCurrentProcess, PushPmInterrupt(), PushRmInterrupt(), RestartDelayedInterrupts(), Status, USHORT, VDM_HWINT_INCREMENT, VDM_VIRTUAL_INTERRUPTS, VdmEndExecution(), VDMEVENTCLASS, VdmIntAck, VdmpEnterIcaLock(), VdmpExceptionHandler(), VdmpLeaveIcaLock(), and VdmTraceEvent().

Referenced by VdmpQueueIntApcRoutine(), and VdmpStartExecution().

00483 : 00484 00485 This routine dispatches interrupts to the vdm. 00486 Assumes that we are in application mode and NOT MONITOR context. 00487 This routine may switch from application context back to monitor 00488 context, if it cannot handle the interrupt (Ica in AEOI, or timer 00489 int pending). 00490 00491 Arguments: 00492 00493 TrapFrame address of current trapframe 00494 VdmTib address of current vdm tib 00495 00496 Return Value: 00497 00498 None. 00499 00500 --*/ 00501 { 00502 NTSTATUS Status; 00503 ULONG IretHookAddress; 00504 ULONG InterruptNumber; 00505 int IrqLineNum; 00506 USHORT IcaRotate = 0; 00507 PVDMICAUSERDATA pIcaUserData; 00508 PVDMVIRTUALICA pIcaAdapter; 00509 VDMEVENTCLASS VdmEvent = VdmMaxEvent; 00510 00511 PAGED_CODE(); 00512 00513 try { 00514 00515 // 00516 // Probe pointers in IcaUserData which will be touched 00517 // 00518 pIcaUserData = ((PVDM_PROCESS_OBJECTS)PsGetCurrentProcess()->VdmObjects) 00519 ->pIcaUserData; 00520 00521 00522 ProbeForWrite(pIcaUserData->pAddrIretBopTable, 00523 (TrapFrame->EFlags & EFLAGS_V86_MASK) 00524 ? VDM_RM_IRETBOPSIZE*16 : VDM_PM_IRETBOPSIZE*16, 00525 sizeof(ULONG) 00526 ); 00527 00528 // 00529 // Take the Ica Lock, if this fails raise status as we can't 00530 // safely recover the critical section state 00531 // 00532 Status = VdmpEnterIcaLock(pIcaUserData->pIcaLock); 00533 if (!NT_SUCCESS(Status)) { 00534 ExRaiseStatus(Status); 00535 } 00536 00537 00538 if (*pIcaUserData->pUndelayIrq) 00539 RestartDelayedInterrupts(pIcaUserData); 00540 VDIretry: 00541 00542 00543 // 00544 // Clear the VIP bit 00545 // 00546 if (((KeI386VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) && 00547 (TrapFrame->EFlags & EFLAGS_V86_MASK)) || 00548 ((KeI386VirtualIntExtensions & PM_VIRTUAL_INT_EXTENSIONS) && 00549 !(TrapFrame->EFlags & EFLAGS_V86_MASK)) ) 00550 { 00551 TrapFrame->EFlags &= ~EFLAGS_VIP; 00552 } 00553 00554 00555 // 00556 // Mark the vdm state as hw int dispatched. Must use the lock as 00557 // kernel mode DelayedIntApcRoutine changes the bit as well 00558 // 00559 _asm { 00560 mov eax,FIXED_NTVDMSTATE_LINEAR 00561 lock and dword ptr [eax], ~VDM_INT_HARDWARE 00562 } 00563 00564 pIcaAdapter = pIcaUserData->pIcaMaster; 00565 IrqLineNum = IcaAccept(pIcaUserData, pIcaAdapter); 00566 if (IrqLineNum >= 0) { 00567 UCHAR bit = 1 << IrqLineNum; 00568 00569 if (pIcaUserData->pIcaMaster->ica_ssr & bit) { 00570 pIcaAdapter = pIcaUserData->pIcaSlave; 00571 IrqLineNum = IcaAccept(pIcaUserData, pIcaAdapter); 00572 if (IrqLineNum < 0) { 00573 pIcaUserData->pIcaMaster->ica_isr &= ~bit; 00574 } 00575 } 00576 } 00577 00578 // 00579 // Skip spurious ints 00580 // 00581 if (IrqLineNum < 0) { 00582 // 00583 // Check for delayed interrupts which need to be restarted 00584 // 00585 if (*pIcaUserData->pUndelayIrq && 00586 RestartDelayedInterrupts(pIcaUserData) != -1) 00587 { 00588 goto VDIretry; 00589 } 00590 00591 Status = VdmpLeaveIcaLock(pIcaUserData->pIcaLock); 00592 if (!NT_SUCCESS(Status)) { 00593 ExRaiseStatus(Status); 00594 } 00595 00596 return Status; 00597 } 00598 00599 00600 // 00601 // Capture the AutoEoi mode case for special handling 00602 // 00603 if (pIcaAdapter->ica_mode & ICA_AEOI) { 00604 VdmEvent = VdmIntAck; 00605 VdmTib->EventInfo.IntAckInfo = (ULONG)IcaRotate | VDMINTACK_AEOI; 00606 if (pIcaAdapter == pIcaUserData->pIcaSlave) { 00607 VdmTib->EventInfo.IntAckInfo |= VDMINTACK_SLAVE; 00608 } 00609 } 00610 00611 00612 InterruptNumber = IrqLineNum + pIcaAdapter->ica_base; 00613 00614 // 00615 // Get the IretHookAddress ... if any 00616 // 00617 if (pIcaAdapter == pIcaUserData->pIcaSlave) { 00618 IrqLineNum += 8; 00619 } 00620 00621 00622 IretHookAddress = GetIretHookAddress( TrapFrame, 00623 pIcaUserData, 00624 IrqLineNum 00625 ); 00626 00627 if (*pNtVDMState & VDM_TRACE_HISTORY) { 00628 VdmTraceEvent(VDMTR_KERNEL_HW_INT, 00629 (USHORT)InterruptNumber, 00630 0, 00631 TrapFrame); 00632 } 00633 00634 // 00635 // Push the interrupt frames 00636 // 00637 if (TrapFrame->EFlags & EFLAGS_V86_MASK) { 00638 PushRmInterrupt(TrapFrame, 00639 IretHookAddress, 00640 VdmTib, 00641 InterruptNumber 00642 ); 00643 } 00644 else { 00645 Status = PushPmInterrupt( 00646 TrapFrame, 00647 IretHookAddress, 00648 VdmTib, 00649 InterruptNumber 00650 ); 00651 00652 if (!NT_SUCCESS(Status)) { 00653 VdmpLeaveIcaLock(pIcaUserData->pIcaLock); 00654 ExRaiseStatus(Status); 00655 } 00656 } 00657 00658 // 00659 // Disable interrupts and the trap flag 00660 // 00661 00662 00663 if (((KeI386VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) && 00664 (TrapFrame->EFlags & EFLAGS_V86_MASK)) || 00665 ((KeI386VirtualIntExtensions & PM_VIRTUAL_INT_EXTENSIONS) && 00666 !(TrapFrame->EFlags & EFLAGS_V86_MASK)) ) 00667 { 00668 TrapFrame->EFlags &= ~EFLAGS_VIF; 00669 } 00670 else if (!KeI386VdmIoplAllowed || 00671 !(TrapFrame->EFlags & EFLAGS_V86_MASK)) 00672 { 00673 *pNtVDMState &= ~VDM_VIRTUAL_INTERRUPTS; 00674 } 00675 else { 00676 TrapFrame->EFlags &= ~EFLAGS_INTERRUPT_MASK; 00677 } 00678 00679 TrapFrame->EFlags &= ~(EFLAGS_NT_MASK | EFLAGS_TF_MASK); 00680 00681 KeBoostPriorityThread(KeGetCurrentThread(), VDM_HWINT_INCREMENT); 00682 00683 00684 // 00685 // Release the ica lock 00686 // 00687 Status = VdmpLeaveIcaLock(pIcaUserData->pIcaLock); 00688 if (!NT_SUCCESS(Status)) { 00689 ExRaiseStatus(Status); 00690 } 00691 00692 // 00693 // check to see if we are supposed to switch back to monitor context 00694 // 00695 if (VdmEvent != VdmMaxEvent) { 00696 VdmTib->EventInfo.Event = VdmIntAck; 00697 VdmTib->EventInfo.InstructionSize = 0; 00698 VdmEndExecution(TrapFrame, VdmTib); 00699 } 00700 } 00701 except(VdmpExceptionHandler(GetExceptionInformation())) { 00702 Status = GetExceptionCode(); 00703 VdmDispatchException(TrapFrame, 00704 Status, 00705 (PVOID)TrapFrame->Eip, 00706 0,0,0,0 // no parameters 00707 ); 00708 } 00709 00710 return Status; 00711 }

VOID VdmpDelayIntApcRoutine IN PKAPC  Apc,
IN PKNORMAL_ROUTINE NormalRoutine,
IN PVOID *  NormalContext,
IN PVOID *  SystemArgument1,
IN PVOID *  SystemArgument2
 

Definition at line 1709 of file vdmints.c.

References FALSE, Ke386VdmClearApcObject(), KeAcquireSpinLock, KeReleaseSpinLock(), KernelMode, KPROCESSOR_MODE, NULL, PsGetCurrentProcess, TRUE, VdmpExceptionHandler(), and VdmpQueueIntApcRoutine().

Referenced by VdmpDelayIntDpcRoutine(), and VdmpNullRundownRoutine().

01719 : 01720 01721 This function is the special APC routine that is called to 01722 dispatch a delayed interupt. This routines clears the IrqLine 01723 bit. VdmpQueueIntApcRoutine will restart interrupts. 01724 01725 Arguments: 01726 01727 Apc - Supplies a pointer to the APC object used to invoke this routine. 01728 01729 NormalRoutine - Supplies a pointer to a pointer to an optional 01730 normal routine, which is executed when wow is blocked. 01731 01732 NormalContext - Supplies a pointer to a pointer to an arbitrary data 01733 structure that was specified when the APC was initialized and is 01734 NOT USED. 01735 01736 SystemArgument1, SystemArgument2 - Supplies a set of two pointers to 01737 two arguments that contain untyped data that are 01738 NOT USED. 01739 01740 Return Value: 01741 01742 None. 01743 01744 --*/ 01745 01746 { 01747 KIRQL OldIrql; 01748 PLIST_ENTRY Next; 01749 PDELAYINTIRQ pDelayIntIrq; 01750 PVDM_PROCESS_OBJECTS pVdmObjects; 01751 KPROCESSOR_MODE ProcessorMode; 01752 PULONG pDelayIrq; 01753 PULONG pUndelayIrq; 01754 PULONG pDelayIret; 01755 ULONG IrqLine; 01756 BOOLEAN FreeIrqLine; 01757 01758 01759 // 01760 // Get a pointer to pVdmObjects 01761 // 01762 pVdmObjects = PsGetCurrentProcess()->VdmObjects; 01763 ExAcquireFastMutex(&pVdmObjects->DelayIntFastMutex); 01764 KeAcquireSpinLock(&pVdmObjects->DelayIntSpinLock, &OldIrql); 01765 01766 Ke386VdmClearApcObject(Apc); 01767 01768 FreeIrqLine = FALSE; 01769 01770 try { 01771 01772 // 01773 // Search the DelayedIntList for the pDelayIntIrq. 01774 // 01775 Next = pVdmObjects->DelayIntListHead.Flink; 01776 while (Next != &pVdmObjects->DelayIntListHead) { 01777 pDelayIntIrq = CONTAINING_RECORD(Next,DELAYINTIRQ,DelayIntListEntry); 01778 if (&pDelayIntIrq->Apc == Apc) { 01779 break; 01780 } 01781 Next = Next->Flink; 01782 } 01783 01784 if (Next == &pVdmObjects->DelayIntListHead) { 01785 pDelayIntIrq = NULL; 01786 } 01787 01788 // 01789 // If we found the IrqLine in the DelayedIntList, 01790 // restart interrupts. 01791 // 01792 if (pDelayIntIrq && pDelayIntIrq->InUse) { 01793 pDelayIntIrq->InUse = VDMDELAY_NOTINUSE; 01794 IrqLine = pDelayIntIrq->IrqLine; 01795 FreeIrqLine = TRUE; 01796 } 01797 01798 } 01799 except(VdmpExceptionHandler(GetExceptionInformation())) { 01800 ; // fall thru 01801 } 01802 01803 01804 KeReleaseSpinLock(&pVdmObjects->DelayIntSpinLock, OldIrql); 01805 01806 01807 try { 01808 01809 if (!FreeIrqLine) { 01810 leave; 01811 } 01812 01813 pDelayIrq = pVdmObjects->pIcaUserData->pDelayIrq; 01814 pUndelayIrq = pVdmObjects->pIcaUserData->pUndelayIrq; 01815 pDelayIret = pVdmObjects->pIcaUserData->pDelayIret; 01816 01817 // 01818 // These variables are being modified without holding the 01819 // ICA lock. This should be OK because none of the ntvdm 01820 // devices (timer, mouse etc. should ever do a delayed int 01821 // while a previous delayed interrupt is still pending. 01822 // 01823 01824 *pDelayIrq &= ~IrqLine; 01825 _asm { 01826 mov eax, pUndelayIrq 01827 mov ebx, IrqLine 01828 lock or [eax], ebx 01829 } 01830 01831 // 01832 // If we are waiting for an iret hook we have nothing left to do 01833 // since the iret hook will restart interrupts. 01834 // 01835 if (!(IrqLine & *pDelayIret)) { 01836 01837 // 01838 // set hardware int pending 01839 // 01840 _asm { 01841 mov eax,FIXED_NTVDMSTATE_LINEAR 01842 lock or dword ptr [eax], VDM_INT_HARDWARE 01843 } 01844 01845 // 01846 // Queue a UserModeApc to dispatch interrupts 01847 // 01848 if (NormalRoutine) { 01849 ProcessorMode = KernelMode; 01850 VdmpQueueIntApcRoutine(Apc, 01851 NormalRoutine, 01852 (PVOID *)&ProcessorMode, 01853 SystemArgument1, 01854 SystemArgument2 01855 ); 01856 } 01857 } 01858 } 01859 except(VdmpExceptionHandler(GetExceptionInformation())) { 01860 ; // fall thru 01861 } 01862 01863 ExReleaseFastMutex(&pVdmObjects->DelayIntFastMutex); 01864 01865 return; 01866 }

VOID VdmpDelayIntDpcRoutine IN PKDPC  Dpc,
IN PVOID  DeferredContext,
IN PVOID  SystemArgument1,
IN PVOID  SystemArgument2
 

Definition at line 1583 of file vdmints.c.

References Ke386VdmInsertQueueApc(), KeAcquireSpinLock, KeReleaseSpinLock(), KernelMode, NULL, ObDereferenceObject, _ETHREAD::Tcb, VDM_HWINT_INCREMENT, _EPROCESS::VdmObjects, VdmpDelayIntApcRoutine(), VdmpNullRundownRoutine(), and VdmpQueueIntNormalRoutine().

Referenced by VdmpDelayInterrupt().

01592 : 01593 01594 This function is the DPC routine that is called when a DelayedInterrupt 01595 timer expires. Its function is to insert the associated APC into the 01596 target thread's APC queue. 01597 01598 Arguments: 01599 01600 Dpc - Supplies a pointer to a control object of type DPC. 01601 01602 DeferredContext - Supplies a pointer to the Target EProcess 01603 01604 SystemArgument1, SystemArgument2 - Supplies a set of two pointers to 01605 two arguments that contain untyped data that are 01606 NOT USED. 01607 01608 01609 Return Value: 01610 01611 None. 01612 01613 --*/ 01614 01615 { 01616 01617 PVDM_PROCESS_OBJECTS pVdmObjects; 01618 PEPROCESS Process; 01619 PETHREAD Thread, MainThread; 01620 PLIST_ENTRY Next; 01621 PDELAYINTIRQ pDelayIntIrq; 01622 KIRQL OldIrql; 01623 01624 // 01625 // Get address of Process VdmObjects 01626 // 01627 Process = (PEPROCESS)DeferredContext; 01628 pVdmObjects = (PVDM_PROCESS_OBJECTS)Process->VdmObjects; 01629 01630 01631 KeAcquireSpinLock(&pVdmObjects->DelayIntSpinLock, &OldIrql); 01632 01633 01634 // 01635 // Search the DelayedIntList for the matching Dpc. 01636 // 01637 Next = pVdmObjects->DelayIntListHead.Flink; 01638 while (Next != &pVdmObjects->DelayIntListHead) { 01639 pDelayIntIrq = CONTAINING_RECORD(Next,DELAYINTIRQ,DelayIntListEntry); 01640 if (&pDelayIntIrq->Dpc == Dpc) { 01641 break; 01642 } 01643 Next = Next->Flink; 01644 } 01645 01646 if (Next == &pVdmObjects->DelayIntListHead) { 01647 pDelayIntIrq = NULL; 01648 MainThread = Thread = NULL; 01649 } 01650 else { 01651 Thread = pDelayIntIrq->Thread; 01652 pDelayIntIrq->Thread = NULL; 01653 MainThread = pDelayIntIrq->MainThread; 01654 pDelayIntIrq->MainThread = NULL; 01655 } 01656 01657 01658 if (pDelayIntIrq && pDelayIntIrq->InUse) { 01659 if ((Thread && 01660 Ke386VdmInsertQueueApc(&pDelayIntIrq->Apc, 01661 &Thread->Tcb, 01662 KernelMode, 01663 VdmpDelayIntApcRoutine, 01664 VdmpNullRundownRoutine, // rundown 01665 VdmpQueueIntNormalRoutine, // normal routine 01666 NULL, // NormalContext 01667 VDM_HWINT_INCREMENT 01668 )) 01669 || 01670 (MainThread && 01671 Ke386VdmInsertQueueApc(&pDelayIntIrq->Apc, 01672 &MainThread->Tcb, 01673 KernelMode, 01674 VdmpDelayIntApcRoutine, 01675 VdmpNullRundownRoutine, // rundown 01676 VdmpQueueIntNormalRoutine, // normal routine 01677 NULL, // NormalContext 01678 VDM_HWINT_INCREMENT 01679 ))) 01680 { 01681 pDelayIntIrq->InUse = VDMDELAY_KAPC; 01682 } 01683 else { 01684 // This hwinterrupt line is blocked forever. 01685 pDelayIntIrq->InUse = VDMDELAY_NOTINUSE; 01686 } 01687 } 01688 01689 01690 KeReleaseSpinLock(&pVdmObjects->DelayIntSpinLock, OldIrql); 01691 01692 if (Thread) { 01693 ObDereferenceObject(Thread); 01694 } 01695 01696 if (MainThread) { 01697 ObDereferenceObject(MainThread); 01698 } 01699 01700 ObDereferenceObject(Process); 01701 01702 01703 return; 01704 }

NTSTATUS VdmpDelayInterrupt PVDMDELAYINTSDATA  pdsd  ) 
 

Definition at line 1235 of file vdmints.c.

References Delay, ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, ExFreePool(), FALSE, KeAcquireSpinLock, KeInitializeDpc(), KeInitializeTimer(), KeMaximumIncrement, KeMinimumIncrement, KeReleaseSpinLock(), KernelMode, KeSetTimer(), KeTimeIncrement, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, ObReferenceObjectByHandle(), ObReferenceObjectByPointer(), _EPROCESS::Pcb, ProbeForRead, ProbeForWriteUlong, PsChargePoolQuota(), PsGetCurrentProcess, PsThreadType, Status, TRUE, _EPROCESS::VdmObjects, and VdmpDelayIntDpcRoutine().

Referenced by NtVdmControl().

01241 : 01242 01243 Sets a timer to dispatch the delayed interrupt through KeSetTimer. 01244 When the timer fires a user mode APC is queued to queue the interrupt. 01245 01246 This function uses lazy allocation routines to allocate internal 01247 data structures (nonpaged pool) on a per Irq basis, and needs to 01248 be notified when specific Irq Lines no longer need Delayed 01249 Interrupt services. 01250 01251 The caller must own the IcaLock to synchronize access to the 01252 Irq lists. 01253 01254 WARNING: - Until the Delayed interrupt fires or is cancelled, 01255 the specific Irq line will not generate any interrupts. 01256 01257 - The APC routine, does not take the HostIca lock, when 01258 unblocking the IrqLine. Devices which use delayed Interrupts 01259 should not queue ANY additional interrupts for the same IRQ 01260 line until the delayed interrupt has fired or been cancelled. 01261 01262 Arguments: 01263 01264 pdsd.Delay Delay Interval in usecs 01265 if Delay is 0xFFFFFFFF then per Irq Line nonpaged 01266 data structures are freed. No Timers are set. 01267 else the Delay is used as the timer delay. 01268 01269 pdsd.DelayIrqLine IrqLine Number 01270 01271 pdsd.hThread Thread Handle of CurrentMonitorTeb 01272 01273 01274 Return Value: 01275 01276 NTSTATUS. 01277 01278 --*/ 01279 01280 { 01281 PVDM_PROCESS_OBJECTS pVdmObjects; 01282 PLIST_ENTRY Next; 01283 PEPROCESS Process; 01284 PDELAYINTIRQ pDelayIntIrq; 01285 PETHREAD Thread, MainThread; 01286 NTSTATUS Status; 01287 KIRQL OldIrql; 01288 ULONG IrqLine; 01289 ULONG Delay; 01290 PULONG pDelayIrq; 01291 PULONG pUndelayIrq; 01292 LARGE_INTEGER liDelay; 01293 BOOLEAN FreeIrqLine, AlreadyInUse; 01294 01295 01296 01297 // 01298 // Get a pointer to pVdmObjects 01299 // 01300 Process = PsGetCurrentProcess(); 01301 pVdmObjects = Process->VdmObjects; 01302 if (Process->Pcb.VdmFlag != TRUE || !pVdmObjects) { 01303 return STATUS_INVALID_PARAMETER_1; 01304 } 01305 01306 ExAcquireFastMutex(&pVdmObjects->DelayIntFastMutex); 01307 01308 Status = STATUS_SUCCESS; 01309 Thread = MainThread = NULL; 01310 FreeIrqLine = TRUE; 01311 AlreadyInUse = FALSE; 01312 01313 try { 01314 01315 // 01316 // Probe the parameters 01317 // 01318 ProbeForRead(pdsd, sizeof(VDMDELAYINTSDATA), sizeof(ULONG)); 01319 01320 // 01321 // Form a BitMask for the IrqLine Number 01322 // 01323 IrqLine = 1 << pdsd->DelayIrqLine; 01324 if (!IrqLine) { 01325 Status = STATUS_INVALID_PARAMETER_2; 01326 goto VidEarlyExit; 01327 } 01328 01329 pDelayIrq = pVdmObjects->pIcaUserData->pDelayIrq; 01330 ProbeForWriteUlong(pDelayIrq); 01331 pUndelayIrq = pVdmObjects->pIcaUserData->pUndelayIrq; 01332 ProbeForWriteUlong(pUndelayIrq); 01333 01334 01335 // 01336 // Copy out the Delay parameter, and convert hundreths nanosecs 01337 // 01338 Delay = pdsd->Delay; 01339 01340 // 01341 // Check to see if we need to reset the timer resolution 01342 // 01343 if (Delay == 0xFFFFFFFF) { 01344 ZwSetTimerResolution(KeMaximumIncrement, FALSE, &Delay); 01345 goto VidEarlyExit; 01346 } 01347 01348 01349 FreeIrqLine = FALSE; 01350 01351 // convert delay to hundreths of nanosecs 01352 // and ensure min delay of 1 msec 01353 // 01354 Delay = Delay < 1000 ? 10000 : Delay * 10; 01355 01356 // 01357 // If the delay time is close to the system's clock rate 01358 // then adjust the system's clock rate and if needed 01359 // the delay time so that the timer will fire before the 01360 // the due time. 01361 // 01362 if (Delay < 150000) { 01363 ULONG ul = Delay >> 1; 01364 01365 if (ul < KeTimeIncrement && KeTimeIncrement > KeMinimumIncrement) { 01366 ZwSetTimerResolution(ul, TRUE, (PULONG)&liDelay.LowPart); 01367 } 01368 01369 if (Delay < KeTimeIncrement) { 01370 // can't set system clock rate low enuf, so use half delay 01371 Delay >>= 1; 01372 } 01373 else if (Delay < (KeTimeIncrement << 1)) { 01374 // Real close to the system clock rate, lower delay 01375 // proportionally, to avoid missing clock cycles. 01376 Delay -= KeTimeIncrement >> 1; 01377 } 01378 } 01379 01380 // 01381 // Reference the Target Thread 01382 // 01383 Status = ObReferenceObjectByHandle( 01384 pdsd->hThread, 01385 THREAD_QUERY_INFORMATION, 01386 PsThreadType, 01387 KeGetPreviousMode(), 01388 &Thread, 01389 NULL 01390 ); 01391 if (!NT_SUCCESS(Status)) { 01392 Thread = NULL; 01393 goto VidEarlyExit; 01394 } 01395 01396 01397 Status = ObReferenceObjectByPointer( 01398 pVdmObjects->MainThread, 01399 THREAD_QUERY_INFORMATION, 01400 PsThreadType, 01401 KernelMode 01402 ); 01403 if (NT_SUCCESS(Status)) { 01404 MainThread = pVdmObjects->MainThread; 01405 } 01406 else { 01407 goto VidEarlyExit; 01408 } 01409 01410 VidEarlyExit:; 01411 } 01412 except(EXCEPTION_EXECUTE_HANDLER) { 01413 Status = GetExceptionCode(); 01414 } 01415 01416 if (!NT_SUCCESS(Status)) { 01417 ExReleaseFastMutex(&pVdmObjects->DelayIntFastMutex); 01418 if (Thread) { 01419 ObDereferenceObject(Thread); 01420 } 01421 01422 if (MainThread) { 01423 ObDereferenceObject(MainThread); 01424 } 01425 01426 return Status; 01427 } 01428 01429 01430 01431 KeAcquireSpinLock(&pVdmObjects->DelayIntSpinLock, &OldIrql); 01432 01433 try { 01434 01435 // 01436 // Search the DelayedIntList for a matching Irq Line. 01437 // 01438 Next = pVdmObjects->DelayIntListHead.Flink; 01439 while (Next != &pVdmObjects->DelayIntListHead) { 01440 pDelayIntIrq = CONTAINING_RECORD(Next, DELAYINTIRQ, DelayIntListEntry); 01441 if (pDelayIntIrq->IrqLine == IrqLine) { 01442 break; 01443 } 01444 Next = Next->Flink; 01445 } 01446 01447 if (Next == &pVdmObjects->DelayIntListHead) { 01448 pDelayIntIrq = NULL; 01449 } 01450 01451 01452 if (!pDelayIntIrq) { 01453 if (FreeIrqLine) { 01454 goto VidExit; 01455 } 01456 01457 // 01458 // If a DelayIntIrq does not exist for this irql, allocate from nonpaged 01459 // pool and initialize it 01460 // 01461 01462 pDelayIntIrq = ExAllocatePoolWithTag(NonPagedPool, 01463 sizeof(DELAYINTIRQ), 01464 ' MDV'); 01465 01466 if (!pDelayIntIrq) { 01467 Status = STATUS_NO_MEMORY; 01468 goto VidExit; 01469 } 01470 01471 01472 try { 01473 PsChargePoolQuota(Process, NonPagedPool, sizeof(DELAYINTIRQ)); 01474 } 01475 except(EXCEPTION_EXECUTE_HANDLER) { 01476 Status = GetExceptionCode(); 01477 ExFreePool(pDelayIntIrq); 01478 goto VidExit; 01479 } 01480 RtlZeroMemory(pDelayIntIrq, sizeof(DELAYINTIRQ)); 01481 pDelayIntIrq->IrqLine = IrqLine; 01482 01483 KeInitializeTimer(&pDelayIntIrq->Timer); 01484 01485 KeInitializeDpc(&pDelayIntIrq->Dpc, 01486 VdmpDelayIntDpcRoutine, 01487 Process 01488 ); 01489 01490 InsertTailList(&pVdmObjects->DelayIntListHead, 01491 &pDelayIntIrq->DelayIntListEntry 01492 ); 01493 } 01494 01495 01496 if (Delay == 0xFFFFFFFF) { 01497 if (pDelayIntIrq->InUse == VDMDELAY_KTIMER) { 01498 pDelayIntIrq->InUse = VDMDELAY_NOTINUSE; 01499 pDelayIntIrq = NULL; 01500 } 01501 } 01502 else if (pDelayIntIrq->InUse == VDMDELAY_NOTINUSE) { 01503 liDelay = RtlEnlargedIntegerMultiply(Delay, -1); 01504 KeSetTimer(&pDelayIntIrq->Timer, liDelay, &pDelayIntIrq->Dpc); 01505 ObReferenceObject(Process); 01506 } 01507 01508 VidExit:; 01509 } 01510 except(EXCEPTION_EXECUTE_HANDLER) { 01511 Status = GetExceptionCode(); 01512 } 01513 01514 if (pDelayIntIrq && !pDelayIntIrq->InUse) { 01515 01516 if (NT_SUCCESS(Status)) { 01517 // 01518 // Save PETHREAD of Target thread for the dpc routine 01519 // the DPC routine will deref the threads. 01520 // 01521 pDelayIntIrq->InUse = VDMDELAY_KTIMER; 01522 pDelayIntIrq->Thread = Thread; 01523 Thread = NULL; 01524 pDelayIntIrq->MainThread = MainThread; 01525 MainThread = NULL; 01526 } 01527 else { 01528 pDelayIntIrq->InUse = VDMDELAY_NOTINUSE; 01529 pDelayIntIrq->Thread = NULL; 01530 FreeIrqLine = TRUE; 01531 } 01532 } 01533 else { 01534 AlreadyInUse = TRUE; 01535 } 01536 01537 01538 01539 KeReleaseSpinLock(&pVdmObjects->DelayIntSpinLock, OldIrql); 01540 01541 try { 01542 if (FreeIrqLine) { 01543 *pDelayIrq &= ~IrqLine; 01544 _asm { 01545 mov eax, pUndelayIrq 01546 mov ebx, IrqLine 01547 lock or [eax], ebx 01548 } 01549 } 01550 else if (!AlreadyInUse) { // TakeIrqLine 01551 *pDelayIrq |= IrqLine; 01552 _asm { 01553 mov eax, pUndelayIrq 01554 mov ebx, IrqLine 01555 not ebx 01556 lock and [eax], ebx 01557 } 01558 } 01559 } 01560 except(EXCEPTION_EXECUTE_HANDLER) { 01561 Status = GetExceptionCode(); 01562 } 01563 01564 ExReleaseFastMutex(&pVdmObjects->DelayIntFastMutex); 01565 01566 if (Thread) { 01567 ObDereferenceObject(Thread); 01568 } 01569 01570 if (MainThread) { 01571 ObDereferenceObject(MainThread); 01572 } 01573 01574 return Status; 01575 01576 }

BOOLEAN VdmpDispatchableIntPending ULONG  EFlags  ) 
 

Definition at line 1870 of file vdmints.c.

References ASSERT, KeI386VdmIoplAllowed, KeI386VirtualIntExtensions, PAGED_CODE, and VDM_VIRTUAL_INTERRUPTS.

01875 : 01876 01877 This routine determines whether or not there is a dispatchable 01878 virtual interrupt to dispatch. 01879 01880 Arguments: 01881 01882 EFlags -- supplies a pointer to the EFlags to be checked 01883 01884 Return Value: 01885 01886 True -- a virtual interrupt should be dispatched 01887 False -- no virtual interrupt should be dispatched 01888 01889 --*/ 01890 { 01891 PAGED_CODE(); 01892 // 01893 // Insure that we are not trying to run with IOPL and pentium extensions 01894 // 01895 ASSERT((!(KeI386VdmIoplAllowed && 01896 (KeI386VirtualIntExtensions & (V86_VIRTUAL_INT_EXTENSIONS | 01897 PM_VIRTUAL_INT_EXTENSIONS))))); 01898 01899 if (EFlags & EFLAGS_V86_MASK) { 01900 if (KeI386VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) { 01901 return(0 != (EFlags & EFLAGS_VIF)); 01902 } else if (KeI386VdmIoplAllowed) { 01903 return (0 != (EFlags & EFLAGS_INTERRUPT_MASK)); 01904 } else { 01905 return (0 != (*pNtVDMState & VDM_VIRTUAL_INTERRUPTS)); 01906 } 01907 } else { 01908 if (KeI386VirtualIntExtensions & PM_VIRTUAL_INT_EXTENSIONS) { 01909 return(0 != (EFlags & EFLAGS_VIF)); 01910 } else { 01911 return (0 != (*pNtVDMState & VDM_VIRTUAL_INTERRUPTS)); 01912 } 01913 } 01914 }

int VdmpExceptionHandler IN PEXCEPTION_POINTERS  ExceptionInfo  ) 
 

Definition at line 1996 of file vdmints.c.

References DbgPrint, EXCEPTION_EXECUTE_HANDLER, and PAGED_CODE.

Referenced by VdmDispatchInterrupts(), VdmpDelayIntApcRoutine(), VdmpQueueIntApcRoutine(), and VdmpQueueIntNormalRoutine().

01999 { 02000 #if DBG 02001 PEXCEPTION_RECORD ExceptionRecord; 02002 PCONTEXT ContextRecord; 02003 ULONG NumberParameters; 02004 PULONG ExceptionInformation; 02005 #endif 02006 02007 PAGED_CODE(); 02008 02009 #if DBG 02010 02011 ExceptionRecord = ExceptionInfo->ExceptionRecord; 02012 DbgPrint("VdmExRecord ExCode %x Flags %x Address %x\n", 02013 ExceptionRecord->ExceptionCode, 02014 ExceptionRecord->ExceptionFlags, 02015 ExceptionRecord->ExceptionAddress 02016 ); 02017 02018 NumberParameters = ExceptionRecord->NumberParameters; 02019 if (NumberParameters) { 02020 DbgPrint("VdmExRecord Parameters:\n"); 02021 02022 ExceptionInformation = ExceptionRecord->ExceptionInformation; 02023 while (NumberParameters--) { 02024 DbgPrint("\t%x\n", *ExceptionInformation); 02025 } 02026 } 02027 02028 #endif 02029 02030 return EXCEPTION_EXECUTE_HANDLER; 02031 }

NTSTATUS VdmpIsThreadTerminating HANDLE  ThreadId  ) 
 

Definition at line 1922 of file vdmints.c.

References NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, PAGED_CODE, PsIsThreadTerminating, PsLookupProcessThreadByCid(), and Status.

01927 : 01928 01929 This routine determines if the specified thread is terminating or not. 01930 01931 Arguments: 01932 01933 Return Value: 01934 01935 True -- 01936 False - 01937 01938 --*/ 01939 { 01940 CLIENT_ID Cid; 01941 PETHREAD Thread; 01942 NTSTATUS Status; 01943 01944 PAGED_CODE(); 01945 01946 // 01947 // If the owning thread juest exited the IcaLock the 01948 // OwningThread Tid may be NULL, return success, since 01949 // we don't know what the owning threads state was. 01950 // 01951 if (!ThreadId) { 01952 return STATUS_SUCCESS; 01953 } 01954 01955 Cid.UniqueProcess = NtCurrentTeb()->ClientId.UniqueProcess; 01956 Cid.UniqueThread = ThreadId; 01957 01958 Status = PsLookupProcessThreadByCid(&Cid, NULL, &Thread); 01959 if (NT_SUCCESS(Status)) { 01960 Status = PsIsThreadTerminating(Thread) ? STATUS_THREAD_IS_TERMINATING 01961 : STATUS_SUCCESS; 01962 ObDereferenceObject(Thread); 01963 } 01964 01965 return Status; 01966 }

VOID VdmpNullRundownRoutine IN PKAPC  Apc  ) 
 

Definition at line 1969 of file vdmints.c.

References NULL, and VdmpDelayIntApcRoutine().

Referenced by VdmpDelayIntDpcRoutine(), VdmpQueueIntApcRoutine(), and VdmpQueueInterrupt().

01974 : 01975 01976 This routine is used as a rundown routine for our APC. 01977 Attempts to clear the delayed int state 01978 01979 Arguments: 01980 01981 Apc - Supplies a pointer to the Apc to run down. 01982 01983 Return Value: 01984 01985 None. 01986 01987 --*/ 01988 { 01989 VdmpDelayIntApcRoutine( Apc, NULL, NULL, NULL, NULL); 01990 }

VOID VdmpQueueIntApcRoutine IN PKAPC  Apc,
IN PKNORMAL_ROUTINE NormalRoutine,
IN PVOID *  NormalContext,
IN PVOID *  SystemArgument1,
IN PVOID *  SystemArgument2
 

Definition at line 232 of file vdmints.c.

References ASSERT, _VdmEventInfo::Event, _Vdm_Tib::EventInfo, _VdmEventInfo::InstructionSize, Ke386VdmClearApcObject(), Ke386VdmInsertQueueApc(), KeI386VirtualIntExtensions, KernelMode, KPROCESSOR_MODE, NT_SUCCESS, NTSTATUS(), NULL, PAGED_CODE, PsGetCurrentProcess, PsGetCurrentThread, PsIsThreadTerminating, Status, _ETHREAD::Tcb, UserMode, VDM_HWINT_INCREMENT, VDM_INTERRUPT_PENDING, VdmDispatchInterrupts(), VdmEndExecution(), VdmIntAck, VdmpDispatchableIntPending(), VdmpExceptionHandler(), VdmpGetVdmTib(), VdmpNullRundownRoutine(), VdmpQueueIntApcRoutine(), and VDMTIB_KPROBE.

Referenced by VdmpDelayIntApcRoutine(), VdmpQueueIntApcRoutine(), and VdmpQueueInterrupt().

00242 : 00243 00244 Kernel and User mode Special Apc routine to dispatchvirtual 00245 interrupts to the vdm. 00246 00247 For KernelMode routine: 00248 if vdm is running in application mode 00249 queue a UserModeApc to the same thread 00250 else do nothing 00251 00252 For UserMode routine 00253 if vdm is running in application mode dispatch virtual interrupts 00254 else do nothing 00255 00256 Arguments: 00257 00258 Apc - 00259 Supplies a pointer to the APC object used to invoke this routine. 00260 00261 NormalRoutine - 00262 Supplies a pointer to a pointer to the normal routine 00263 function that was specified when the APC was initialized. 00264 00265 NormalContext - Supplies a pointer to the processor mode 00266 specifying that this is a Kernel Mode or UserMode apc 00267 00268 SystemArgument1 - 00269 00270 SystemArgument2 - NOT USED 00271 Supplies a set of two pointers to two arguments that contain 00272 untyped data. 00273 00274 Return Value: 00275 00276 None. 00277 00278 --*/ 00279 00280 { 00281 PVDM_PROCESS_OBJECTS pVdmObjects; 00282 NTSTATUS Status; 00283 PETHREAD Thread; 00284 PKTRAP_FRAME TrapFrame; 00285 PVDM_TIB VdmTib; 00286 00287 PAGED_CODE(); 00288 00289 Ke386VdmClearApcObject(Apc); 00290 00291 00292 try { 00293 00294 // 00295 // Get the trap frame for the current thread 00296 // 00297 Thread = PsGetCurrentThread(); 00298 00299 // 00300 // If the thread is dying, bail out 00301 // 00302 if (PsIsThreadTerminating(Thread)) 00303 return; 00304 00305 // 00306 // if no pending interrupts, ignore this APC. 00307 // 00308 if (!(*pNtVDMState & VDM_INTERRUPT_PENDING)) { 00309 return; 00310 } 00311 00312 TrapFrame = VdmGetTrapFrame(&Thread->Tcb); 00313 00314 if (VdmpDispatchableIntPending(TrapFrame->EFlags)) 00315 { 00316 pVdmObjects = PsGetCurrentProcess()->VdmObjects; 00317 // 00318 // if we are in v86 mode or segmented protected mode 00319 // then queue the UserMode Apc, which will dispatch 00320 // the hardware interrupt 00321 // 00322 if ((TrapFrame->EFlags & EFLAGS_V86_MASK) || 00323 TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)) 00324 { 00325 if ((KPROCESSOR_MODE)*NormalContext == KernelMode) { 00326 00327 Ke386VdmInsertQueueApc( 00328 &pVdmObjects->QueuedIntUserApc, 00329 &Thread->Tcb, 00330 UserMode, 00331 VdmpQueueIntApcRoutine, 00332 VdmpNullRundownRoutine,// rundown 00333 NULL, // normal routine 00334 (PVOID)UserMode, // NormalContext 00335 (*pNtVDMState & VDM_INT_HARDWARE) // PrBoost 00336 ? VDM_HWINT_INCREMENT : 0 00337 ); 00338 00339 } 00340 else { 00341 ASSERT(*NormalContext == (PVOID)UserMode); 00342 00343 Status = VdmpGetVdmTib(&VdmTib, VDMTIB_KPROBE); 00344 if (!NT_SUCCESS(Status)) { 00345 return; 00346 } 00347 00348 00349 //VdmTib = (PsGetCurrentProcess()->VdmObjects)->VdmTib; 00350 // VdmTib = 00351 // ((PVDM_PROCESS_OBJECTS)(PsGetCurrentProcess()->VdmObjects))->VdmTib; 00352 00353 // 00354 // If there are no hardware ints, dispatch timer ints 00355 // else dispatch hw interrupts 00356 // 00357 if (*pNtVDMState & VDM_INT_TIMER && 00358 !(*pNtVDMState & VDM_INT_HARDWARE)) 00359 { 00360 VdmTib->EventInfo.Event = VdmIntAck; 00361 VdmTib->EventInfo.InstructionSize = 0; 00362 VdmTib->EventInfo.IntAckInfo = 0; 00363 VdmEndExecution(TrapFrame, VdmTib); 00364 } 00365 else { 00366 VdmDispatchInterrupts(TrapFrame, VdmTib); 00367 } 00368 } 00369 } 00370 00371 // 00372 // If we are not in application mode and wow is all blocked 00373 // then Wake up WowExec by setting the wow idle event 00374 // 00375 else if (*NormalRoutine && 00376 !(*pNtVDMState & VDM_WOWBLOCKED)) 00377 { 00378 *NormalRoutine = NULL; 00379 } 00380 00381 } 00382 // WARNING this may set VIP for flat if VPI is ever set in CR4 00383 else if (((KeI386VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) && 00384 (TrapFrame->EFlags & EFLAGS_V86_MASK)) || 00385 ((KeI386VirtualIntExtensions & PM_VIRTUAL_INT_EXTENSIONS) && 00386 !(TrapFrame->EFlags & EFLAGS_V86_MASK)) ) 00387 { 00388 // The CPU traps EVERY instruction if VIF and VIP are both ON. 00389 // Make sure that you set VIP ON only when there are pending 00390 // interrupts, i.e. (*pNtVDMState & VDM_INTERRUPT_PENDING) != 0. 00391 ASSERT(*pNtVDMState & VDM_INTERRUPT_PENDING); 00392 00393 TrapFrame->EFlags |= EFLAGS_VIP; 00394 } 00395 } 00396 except(VdmpExceptionHandler(GetExceptionInformation())) { 00397 VdmDispatchException(TrapFrame, 00398 GetExceptionCode(), 00399 (PVOID)TrapFrame->Eip, 00400 0,0,0,0 // no parameters 00401 ); 00402 return; 00403 } 00404 }

NTSTATUS VdmpQueueInterrupt IN HANDLE  ThreadHandle  ) 
 

Definition at line 146 of file vdmints.c.

References Ke386VdmInsertQueueApc(), KernelMode, KPROCESSOR_MODE, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PAGED_CODE, _EPROCESS::Pcb, PsGetCurrentProcess, PsThreadType, Status, _ETHREAD::Tcb, ThreadHandle, _ETHREAD::ThreadsProcess, TRUE, _EPROCESS::VdmObjects, VdmpNullRundownRoutine(), VdmpQueueIntApcRoutine(), and VdmpQueueIntNormalRoutine().

Referenced by NtVdmControl().

00152 : 00153 00154 Queues a user mode APC to the specifed application thread 00155 which will dispatch an interrupt. 00156 00157 if APC is already queued to specified thread 00158 does nothing 00159 00160 if APC is queued to the wrong thread 00161 dequeue it 00162 00163 Reset the user APC for the specifed thread 00164 00165 Insert the APC in the queue for the specifed thread 00166 00167 Arguments: 00168 00169 ThreadHandle - handle of thread to insert QueueIntApcRoutine 00170 00171 Return Value: 00172 00173 NTSTATUS. 00174 00175 --*/ 00176 00177 { 00178 00179 PEPROCESS Process; 00180 PETHREAD Thread; 00181 NTSTATUS Status; 00182 KPROCESSOR_MODE PrevMode; 00183 PVDM_PROCESS_OBJECTS pVdmObjects; 00184 00185 PAGED_CODE(); 00186 00187 00188 PrevMode = KeGetPreviousMode(); 00189 00190 Status = ObReferenceObjectByHandle(ThreadHandle, 00191 THREAD_QUERY_INFORMATION, 00192 PsThreadType, 00193 PrevMode, 00194 &Thread, 00195 NULL 00196 ); 00197 if (!NT_SUCCESS(Status)) { 00198 return Status; 00199 } 00200 00201 Process = PsGetCurrentProcess(); 00202 if (Process != Thread->ThreadsProcess || Process->Pcb.VdmFlag != TRUE) 00203 { 00204 Status = STATUS_INVALID_PARAMETER_1; 00205 } 00206 else { 00207 pVdmObjects = Process->VdmObjects; 00208 00209 if (!Ke386VdmInsertQueueApc(&pVdmObjects->QueuedIntApc, 00210 &Thread->Tcb, 00211 KernelMode, 00212 VdmpQueueIntApcRoutine, 00213 VdmpNullRundownRoutine, // rundown 00214 VdmpQueueIntNormalRoutine, // normal routine 00215 (PVOID)KernelMode, // NormalContext 00216 0 00217 )) 00218 { 00219 Status = STATUS_UNSUCCESSFUL; 00220 } 00221 else { 00222 Status = STATUS_SUCCESS; 00223 } 00224 } 00225 00226 ObDereferenceObject(Thread); 00227 return Status; 00228 }

VOID VdmpQueueIntNormalRoutine IN PVOID  NormalContext,
IN PVOID  SystemArgument1,
IN PVOID  SystemArgument2
 

Definition at line 408 of file vdmints.c.

References Event(), EVENT_INCREMENT, ExEventObjectType, FALSE, KeSetEvent(), NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PsGetCurrentProcess, PsGetCurrentThread, Status, _ETHREAD::Tcb, UserMode, and VdmpExceptionHandler().

Referenced by VdmpDelayIntDpcRoutine(), and VdmpQueueInterrupt().

00415 : 00416 00417 00418 00419 Arguments: 00420 00421 00422 Return Value: 00423 00424 None. 00425 00426 --*/ 00427 { 00428 PETHREAD Thread; 00429 PKEVENT Event; 00430 NTSTATUS Status; 00431 PKTRAP_FRAME TrapFrame; 00432 PVDM_PROCESS_OBJECTS pVdmObjects; 00433 00434 00435 try { 00436 00437 // 00438 // Wake up WowExec by setting the wow idle event 00439 // 00440 00441 pVdmObjects = PsGetCurrentProcess()->VdmObjects; 00442 00443 Status = ObReferenceObjectByHandle( 00444 *pVdmObjects->pIcaUserData->phWowIdleEvent, 00445 EVENT_MODIFY_STATE, 00446 ExEventObjectType, 00447 UserMode, 00448 &Event, 00449 NULL 00450 ); 00451 00452 if (NT_SUCCESS(Status)) { 00453 KeSetEvent(Event, EVENT_INCREMENT, FALSE); 00454 ObDereferenceObject(Event); 00455 } 00456 00457 } 00458 except(VdmpExceptionHandler(GetExceptionInformation())) { 00459 Thread = PsGetCurrentThread(); 00460 TrapFrame = VdmGetTrapFrame(&Thread->Tcb); 00461 VdmDispatchException(TrapFrame, 00462 GetExceptionCode(), 00463 (PVOID)TrapFrame->Eip, 00464 0,0,0,0 // no parameters 00465 ); 00466 return; 00467 } 00468 }


Variable Documentation

POBJECT_TYPE ExEventObjectType
 

Definition at line 143 of file vdmints.c.

POBJECT_TYPE ExSemaphoreObjectType
 

Definition at line 142 of file vdmints.c.

Referenced by ExpSemaphoreInitialization(), NtCreateSemaphore(), NtOpenSemaphore(), NtQuerySemaphore(), NtReleaseSemaphore(), and NtSignalAndWaitForSingleObject().


Generated on Sat May 15 19:46:07 2004 for test by doxygen 1.3.7