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

vdmints.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1991 Microsoft Corporation 00004 00005 Module Name: 00006 00007 vdmints.c 00008 00009 Abstract: 00010 00011 Vdm kernel Virtual interrupt support 00012 00013 Author: 00014 00015 13-Oct-1993 Jonathan Lew (Jonle) 00016 00017 Notes: 00018 00019 00020 Revision History: 00021 00022 00023 --*/ 00024 00025 00026 #include <ntos.h> 00027 #include <zwapi.h> 00028 #include "vdmp.h" 00029 00030 // thread priority boost for vdm hardware interrupt. 00031 #define VDM_HWINT_INCREMENT EVENT_INCREMENT 00032 00033 // 00034 // internal function prototypes 00035 // 00036 00037 00038 VOID 00039 VdmpQueueIntApcRoutine ( 00040 IN PKAPC Apc, 00041 IN PKNORMAL_ROUTINE *NormalRoutine, 00042 IN PVOID *NormalContext, 00043 IN PVOID *SystemArgument1, 00044 IN PVOID *SystemArgument2 00045 ); 00046 00047 VOID 00048 VdmpQueueIntNormalRoutine ( 00049 IN PVOID NormalContext, 00050 IN PVOID SystemArgument1, 00051 IN PVOID SystemArgument2 00052 ); 00053 00054 00055 VOID 00056 VdmpDelayIntDpcRoutine ( 00057 IN PKDPC Dpc, 00058 IN PVOID DeferredContext, 00059 IN PVOID SystemArgument1, 00060 IN PVOID SystemArgument2 00061 ); 00062 00063 00064 VOID 00065 VdmpDelayIntApcRoutine ( 00066 IN PKAPC Apc, 00067 IN PKNORMAL_ROUTINE *NormalRoutine, 00068 IN PVOID *NormalContext, 00069 IN PVOID *SystemArgument1, 00070 IN PVOID *SystemArgument2 00071 ); 00072 00073 int 00074 RestartDelayedInterrupts( 00075 PVDMICAUSERDATA pIcaUserData 00076 ); 00077 00078 int 00079 IcaScan( 00080 PVDMICAUSERDATA pIcaUserData, 00081 PVDMVIRTUALICA pIcaAdapter 00082 ); 00083 00084 int 00085 IcaAccept( 00086 PVDMICAUSERDATA pIcaUserData, 00087 PVDMVIRTUALICA pIcaAdapter 00088 ); 00089 00090 ULONG 00091 GetIretHookAddress( 00092 PKTRAP_FRAME TrapFrame, 00093 PVDMICAUSERDATA pIcaUserData, 00094 int IrqNum 00095 ); 00096 00097 VOID 00098 PushRmInterrupt( 00099 PKTRAP_FRAME TrapFrame, 00100 ULONG IretHookAddress, 00101 PVDM_TIB VdmTib, 00102 ULONG InterruptNumber 00103 ); 00104 00105 NTSTATUS 00106 PushPmInterrupt( 00107 PKTRAP_FRAME TrapFrame, 00108 ULONG IretHookAddress, 00109 PVDM_TIB VdmTib, 00110 ULONG InterruptNumber 00111 ); 00112 00113 VOID 00114 VdmpNullRundownRoutine( 00115 IN PKAPC Apc 00116 ); 00117 00118 00119 int 00120 VdmpExceptionHandler( 00121 IN PEXCEPTION_POINTERS ExceptionInfo 00122 ); 00123 00124 00125 #ifdef ALLOC_PRAGMA 00126 #pragma alloc_text(PAGE, VdmpQueueInterrupt) 00127 #pragma alloc_text(PAGE, VdmpQueueIntApcRoutine) 00128 #pragma alloc_text(PAGE, VdmpQueueIntNormalRoutine) 00129 #pragma alloc_text(PAGE, VdmDispatchInterrupts) 00130 #pragma alloc_text(PAGE, RestartDelayedInterrupts) 00131 #pragma alloc_text(PAGE, IcaScan) 00132 #pragma alloc_text(PAGE, IcaAccept) 00133 #pragma alloc_text(PAGE, GetIretHookAddress) 00134 #pragma alloc_text(PAGE, PushRmInterrupt) 00135 #pragma alloc_text(PAGE, PushPmInterrupt) 00136 #pragma alloc_text(PAGE, VdmpDispatchableIntPending) 00137 #pragma alloc_text(PAGE, VdmpIsThreadTerminating) 00138 #pragma alloc_text(PAGE, VdmpNullRundownRoutine) 00139 #pragma alloc_text(PAGE, VdmpExceptionHandler) 00140 #endif 00141 00142 extern POBJECT_TYPE ExSemaphoreObjectType; 00143 extern POBJECT_TYPE ExEventObjectType; 00144 00145 NTSTATUS 00146 VdmpQueueInterrupt( 00147 IN HANDLE ThreadHandle 00148 ) 00149 00150 /*++ 00151 00152 Routine Description: 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 } 00229 00230 00231 VOID 00232 VdmpQueueIntApcRoutine ( 00233 IN PKAPC Apc, 00234 IN PKNORMAL_ROUTINE *NormalRoutine, 00235 IN PVOID *NormalContext, 00236 IN PVOID *SystemArgument1, 00237 IN PVOID *SystemArgument2 00238 ) 00239 00240 /*++ 00241 00242 Routine Description: 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 } 00405 00406 00407 VOID 00408 VdmpQueueIntNormalRoutine ( 00409 IN PVOID NormalContext, 00410 IN PVOID SystemArgument1, 00411 IN PVOID SystemArgument2 00412 ) 00413 /*++ 00414 00415 Routine Description: 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 } 00469 00470 00471 00472 00473 00474 00475 00476 NTSTATUS 00477 VdmDispatchInterrupts( 00478 PKTRAP_FRAME TrapFrame, 00479 PVDM_TIB VdmTib 00480 ) 00481 /*++ 00482 00483 Routine Description: 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 } 00712 00713 00714 int 00715 RestartDelayedInterrupts( 00716 PVDMICAUSERDATA pIcaUserData 00717 ) 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 } 00746 00747 00748 00749 int 00750 IcaScan( 00751 PVDMICAUSERDATA pIcaUserData, 00752 PVDMVIRTUALICA pIcaAdapter 00753 ) 00754 /*++ 00755 00756 Routine Description: 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 } 00826 00827 00828 00829 00830 int 00831 IcaAccept( 00832 PVDMICAUSERDATA pIcaUserData, 00833 PVDMVIRTUALICA pIcaAdapter 00834 ) 00835 /*++ 00836 00837 Routine Description: 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 } 00893 00894 00895 00896 ULONG 00897 GetIretHookAddress( 00898 PKTRAP_FRAME TrapFrame, 00899 PVDMICAUSERDATA pIcaUserData, 00900 int IrqNum 00901 ) 00902 /*++ 00903 00904 Routine Description: 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 } 00948 00949 00950 00951 00952 VOID 00953 PushRmInterrupt( 00954 PKTRAP_FRAME TrapFrame, 00955 ULONG IretHookAddress, 00956 PVDM_TIB VdmTib, 00957 ULONG InterruptNumber 00958 ) 00959 /*++ 00960 00961 Routine Description: 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 } 01040 01041 01042 01043 01044 NTSTATUS 01045 PushPmInterrupt( 01046 PKTRAP_FRAME TrapFrame, 01047 ULONG IretHookAddress, 01048 PVDM_TIB VdmTib, 01049 ULONG InterruptNumber 01050 ) 01051 /*++ 01052 01053 Routine Description: 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 } 01231 01232 01233 01234 NTSTATUS 01235 VdmpDelayInterrupt( 01236 PVDMDELAYINTSDATA pdsd 01237 ) 01238 01239 /*++ 01240 01241 Routine Description: 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 } 01577 01578 01579 01580 01581 01582 VOID 01583 VdmpDelayIntDpcRoutine ( 01584 IN PKDPC Dpc, 01585 IN PVOID DeferredContext, 01586 IN PVOID SystemArgument1, 01587 IN PVOID SystemArgument2 01588 ) 01589 01590 /*++ 01591 01592 Routine Description: 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 } 01705 01706 01707 01708 VOID 01709 VdmpDelayIntApcRoutine ( 01710 IN PKAPC Apc, 01711 IN PKNORMAL_ROUTINE *NormalRoutine, 01712 IN PVOID *NormalContext, 01713 IN PVOID *SystemArgument1, 01714 IN PVOID *SystemArgument2 01715 ) 01716 01717 /*++ 01718 01719 Routine Description: 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 } 01867 01868 01869 BOOLEAN 01870 VdmpDispatchableIntPending( 01871 ULONG EFlags 01872 ) 01873 /*++ 01874 01875 Routine Description: 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 } 01915 01916 01917 01918 01919 01920 01921 NTSTATUS 01922 VdmpIsThreadTerminating( 01923 HANDLE ThreadId 01924 ) 01925 /*++ 01926 01927 Routine Description: 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 } 01967 01968 VOID 01969 VdmpNullRundownRoutine( 01970 IN PKAPC Apc 01971 ) 01972 /*++ 01973 01974 Routine Description: 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 } 01991 01992 01993 01994 01995 int 01996 VdmpExceptionHandler( 01997 IN PEXCEPTION_POINTERS ExceptionInfo 01998 ) 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 }

Generated on Sat May 15 19:42:22 2004 for test by doxygen 1.3.7