Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

513 lines
10 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. int.c
  5. Abstract:
  6. This file contains interrupt support routines for the monitor
  7. Author:
  8. Dave Hastings (daveh) 18-Apr-1992
  9. Notes:
  10. The code in this file split out from monitor.c (18-Apr-1992)
  11. Revision History:
  12. --*/
  13. #include <monitorp.h>
  14. #if defined(NEC_98)
  15. VOID WaitVsync();
  16. #endif // NEC_98
  17. BOOL
  18. DpmiHwIntHandler(
  19. ULONG IntNumber
  20. );
  21. VOID
  22. IRQ13_Eoi(
  23. int IrqLine,
  24. int CallCount
  25. );
  26. #if defined(NEC_98)
  27. VOID
  28. IRQ13_Eoi_real(
  29. int IrqLine,
  30. int CallCount
  31. );
  32. #endif // NEC_98
  33. BOOLEAN IRQ13BeingHandled; // true until IRQ13 eoi'ed
  34. VOID
  35. InterruptInit(
  36. VOID
  37. )
  38. /*++
  39. Routine Description:
  40. This routine initializes the interrupt code for the monitor.
  41. Arguments:
  42. Return Value:
  43. None.
  44. --*/
  45. {
  46. BOOL Bool;
  47. #if defined(NEC_98)
  48. Bool = RegisterEOIHook( 8, IRQ13_Eoi);
  49. Bool = RegisterEOIHook( 14, IRQ13_Eoi_real);
  50. #else // !NEC_98
  51. Bool = RegisterEOIHook( 13, IRQ13_Eoi);
  52. #endif // !NEC_98
  53. if (!Bool) {
  54. #if DBG
  55. DbgPrint("NtVdm : Could not register IRQ 13 Eoi handler\n");
  56. DbgBreakPoint();
  57. #endif
  58. TerminateVDM();
  59. }
  60. }
  61. VOID
  62. InterruptTerminate(
  63. VOID
  64. )
  65. /*++
  66. Routine Description:
  67. This routine frees the resoures allocated by InterruptInit
  68. Arguments:
  69. Return Value:
  70. None.
  71. --*/
  72. {
  73. }
  74. VOID
  75. cpu_interrupt(
  76. IN int Type,
  77. IN int Number
  78. )
  79. /*++
  80. Routine Description:
  81. This routine causes an interrupt of the specified type to be raised
  82. at the appropriate time.
  83. Arguments:
  84. Type -- indicates the type of the interrupt. One of HARDWARE, TIMER, YODA,
  85. or RESET
  86. YODA and RESET are ignored
  87. Return Value:
  88. None.
  89. Notes:
  90. --*/
  91. {
  92. NTSTATUS Status;
  93. HANDLE MonitorThread;
  94. host_ica_lock();
  95. if (CurrentMonitorTeb == NtCurrentTeb() && !getIF() && (getMSW() & MSW_PE)) {
  96. VDM_PM_CLI_DATA cliData;
  97. cliData.Control = PM_CLI_CONTROL_CHECK;
  98. NtVdmControl(VdmPMCliControl, &cliData);
  99. }
  100. if (Type == CPU_TIMER_TICK) {
  101. //
  102. // Set the VDM State for timer tick int pending
  103. //
  104. _asm {
  105. mov eax, FIXED_NTVDMSTATE_LINEAR
  106. lock or dword ptr [eax], VDM_INT_TIMER
  107. }
  108. } else if (Type == CPU_HW_INT) {
  109. if (*pNtVDMState & VDM_INT_HARDWARE) {
  110. goto EarlyExit;
  111. }
  112. //
  113. // Set the VDM State for Hardware Int pending
  114. //
  115. _asm {
  116. mov eax, FIXED_NTVDMSTATE_LINEAR
  117. lock or dword ptr [eax], VDM_INT_HARDWARE
  118. }
  119. } else {
  120. #if DBG
  121. DbgPrint("Monitor: Invalid Interrupt Type=%ld\n",Type);
  122. #endif
  123. goto EarlyExit;
  124. }
  125. if (CurrentMonitorTeb != NtCurrentTeb()) {
  126. /*
  127. * Look up the ThreadHandle and Queue and InterruptApc
  128. * If no ThreadHandle found do nothing
  129. *
  130. * The CurrentMonitorTeb may not be in the ThreadHandle\Teb list
  131. * because upon task termination the the CurrentMonitorTeb variable
  132. * cannot be updated until a new task is activated by the
  133. * non-preemptive scheduler.
  134. */
  135. MonitorThread = ThreadLookUp(CurrentMonitorTeb);
  136. if (MonitorThread) {
  137. Status = NtVdmControl(VdmQueueInterrupt, (PVOID)MonitorThread);
  138. // nothing much we can do if this fails
  139. #if DBG
  140. if (!NT_SUCCESS(Status) && Status != STATUS_UNSUCCESSFUL) {
  141. DbgPrint("NtVdmControl.VdmQueueInterrupt Status=%lx\n",Status);
  142. }
  143. #endif
  144. }
  145. }
  146. EarlyExit:
  147. host_ica_unlock();
  148. }
  149. VOID
  150. DispatchInterrupts(
  151. )
  152. /*++
  153. Routine Description:
  154. This routine dispatches interrupts to their appropriate handler routine
  155. in priority order. The order is YODA, RESET, TIMER, HARDWARE. however
  156. the YODA and RESET interrupts do nothing. Hardware interrupts are not
  157. simulated unless the virtual interrupt enable flag is set. Flags
  158. indicating which interrupts are pending appear in the pNtVDMState.
  159. Arguments:
  160. None.
  161. Return Value:
  162. None.
  163. Notes:
  164. --*/
  165. {
  166. host_ica_lock();
  167. // If any delayed interrupts have expired
  168. // call the ica to restart interrupts
  169. if (UndelayIrqLine) {
  170. ica_RestartInterrupts(UndelayIrqLine);
  171. }
  172. if (*pNtVDMState & VDM_INT_TIMER) {
  173. *pNtVDMState &= ~VDM_INT_TIMER;
  174. host_ica_unlock(); // maybe don't need to unlock ? Jonle
  175. host_timer_event();
  176. host_ica_lock();
  177. }
  178. if ( getIF() && getMSW() & MSW_PE && *pNtVDMState & VDM_INT_HARDWARE) {
  179. //
  180. // Mark the vdm state as hw int dispatched. Must use the lock as
  181. // kernel mode DelayedIntApcRoutine changes the bit as well
  182. //
  183. _asm {
  184. mov eax,FIXED_NTVDMSTATE_LINEAR
  185. lock and dword ptr [eax], NOT VDM_INT_HARDWARE
  186. }
  187. DispatchHwInterrupt();
  188. }
  189. host_ica_unlock();
  190. }
  191. VOID
  192. DispatchHwInterrupt(
  193. )
  194. /*++
  195. Routine Description:
  196. This routine dispatches hardware interrupts to the vdm in Protect Mode.
  197. It calls the ICA to get the vector number and sets up the VDM stack
  198. appropriately. Real Mode interrupt dispatching has been moved to the
  199. kernel.
  200. Arguments:
  201. None.
  202. Return Value:
  203. None.
  204. --*/
  205. {
  206. int InterruptNumber;
  207. ULONG IretHookAddress = 0L;
  208. PVDM_TIB VdmTib;
  209. InterruptNumber = ica_intack(&IretHookAddress);
  210. if (InterruptNumber == -1) { // skip spurious ints
  211. return;
  212. }
  213. DpmiHwIntHandler(InterruptNumber);
  214. VdmTib = (PVDM_TIB)(NtCurrentTeb()->Vdm);
  215. if (IretHookAddress) {
  216. BOOL Frame32 = (BOOL) VdmTib->DpmiInfo.Flags;
  217. BOOL Stack32;
  218. USHORT SegSs, VdmCs;
  219. ULONG VdmSp, VdmEip;
  220. PUCHAR VdmStackPointer;
  221. ULONG StackOffset;
  222. SegSs = getSS();
  223. VdmStackPointer = Sim32GetVDMPointer(((ULONG)SegSs) << 16, 1, TRUE);
  224. //
  225. // Figure out how many bits of sp to use
  226. //
  227. if (Ldt[(SegSs & ~0x7)/sizeof(LDT_ENTRY)].HighWord.Bits.Default_Big) {
  228. VdmSp = getESP();
  229. StackOffset = 12;
  230. } else {
  231. VdmSp = getSP();
  232. StackOffset = 6;
  233. }
  234. (PCHAR)VdmStackPointer += VdmSp;
  235. //
  236. // BUGBUG need to add stack limit checking 15-Nov-1993 Jonle
  237. //
  238. setESP(VdmSp - StackOffset);
  239. //
  240. // Push info for Iret hook handler
  241. //
  242. VdmCs = (USHORT) ((IretHookAddress & 0xFFFF0000) >> 16);
  243. VdmEip = (IretHookAddress & 0xFFFF);
  244. if (Frame32) {
  245. *(PULONG)(VdmStackPointer - 4) = VdmTib->VdmContext.EFlags;
  246. *(PULONG)(VdmStackPointer - 8) = (ULONG) VdmCs;
  247. *(PULONG)(VdmStackPointer - 12) = VdmEip;
  248. } else {
  249. *(PUSHORT)(VdmStackPointer - 2) = (USHORT) VdmTib->VdmContext.EFlags;
  250. *(PUSHORT)(VdmStackPointer - 4) = VdmCs;
  251. *(PUSHORT)(VdmStackPointer - 6) = (USHORT) VdmEip;
  252. }
  253. }
  254. #if defined(NEC_98)
  255. if(InterruptNumber == 0xA) {
  256. WaitVsync();
  257. }
  258. #endif // NEC_98
  259. }
  260. VOID
  261. IRQ13_Eoi(
  262. int IrqLine,
  263. int CallCount
  264. )
  265. {
  266. UNREFERENCED_PARAMETER(IrqLine);
  267. UNREFERENCED_PARAMETER(CallCount);
  268. //
  269. // if CallCount is less than Zero, then the interrupt request
  270. // is being canceled.
  271. //
  272. #if defined(NEC_98)
  273. if( getMSW() & MSW_PE ){
  274. #endif // NEC_98
  275. if (CallCount < 0) {
  276. return;
  277. }
  278. IRQ13BeingHandled = FALSE;
  279. #if defined(NEC_98)
  280. }
  281. #endif // NEC_98
  282. }
  283. #if defined(NEC_98)
  284. VOID
  285. IRQ13_Eoi_real(
  286. int IrqLine,
  287. int CallCount
  288. )
  289. {
  290. UNREFERENCED_PARAMETER(IrqLine);
  291. UNREFERENCED_PARAMETER(CallCount);
  292. if( !(getMSW() & MSW_PE) ){
  293. if (CallCount < 0) {
  294. return;
  295. }
  296. IRQ13BeingHandled = FALSE;
  297. }
  298. }
  299. #endif // NEC_98
  300. VOID
  301. MonitorEndIretHook(
  302. VOID
  303. )
  304. /*++
  305. Routine Description:
  306. Arguments:
  307. None.
  308. Return Value:
  309. None.
  310. --*/
  311. {
  312. PVOID VdmStackPointer;
  313. PVDM_TIB VdmTib;
  314. VdmTib = (PVDM_TIB)(NtCurrentTeb()->Vdm);
  315. if (VdmTib->IntelMSW & MSW_PE) {
  316. BOOL Frame32 = (BOOL) VdmTib->DpmiInfo.Flags;
  317. ULONG FrameSize;
  318. if (Frame32) {
  319. FrameSize = 12;
  320. } else {
  321. FrameSize = 6;
  322. }
  323. VdmStackPointer = Sim32GetVDMPointer(((ULONG)getSS() << 16),2,TRUE);
  324. if (Ldt[(getSS() & ~0x7)/sizeof(LDT_ENTRY)].HighWord.Bits.Default_Big) {
  325. (PCHAR)VdmStackPointer += getESP();
  326. setESP(getESP() + FrameSize);
  327. } else {
  328. (PCHAR)VdmStackPointer += getSP();
  329. setSP((USHORT) (getSP() + FrameSize));
  330. }
  331. if (Frame32) {
  332. VdmTib->VdmContext.EFlags = *(PULONG)((PCHAR)VdmStackPointer + 8);
  333. setCS(*(PUSHORT)((PCHAR)VdmStackPointer + 4));
  334. VdmTib->VdmContext.Eip = *((PULONG)VdmStackPointer);
  335. } else {
  336. VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & 0xFFFF0000) |
  337. ((ULONG) *(PUSHORT)((PCHAR)VdmStackPointer + 4));
  338. setCS(*(PUSHORT)((PCHAR)VdmStackPointer + 2));
  339. VdmTib->VdmContext.Eip = (VdmTib->VdmContext.Eip & 0xFFFF0000) |
  340. ((ULONG) *(PUSHORT)((PCHAR)VdmStackPointer));
  341. }
  342. } else {
  343. VdmStackPointer = Sim32GetVDMPointer(((ULONG)getSS() << 16) | getSP(),2,FALSE);
  344. setSP((USHORT) (getSP() + 6));
  345. (USHORT)(VdmTib->VdmContext.EFlags) = *((PUSHORT)((PCHAR)VdmStackPointer + 4));
  346. setCS(*((PUSHORT)((PCHAR)VdmStackPointer + 2)));
  347. setIP(*((PUSHORT)VdmStackPointer));
  348. }
  349. }
  350. VOID
  351. host_clear_hw_int()
  352. /*++
  353. Routine Description:
  354. This routine "forgets" a previously requested hardware interrupt.
  355. Arguments:
  356. None.
  357. Return Value:
  358. None.
  359. --*/
  360. {
  361. /*
  362. * We do nothing here to save a kernel call, because the
  363. * interrupt if it hasn't been intacked yet or dispatched,
  364. * will produce a harmless spurious int, which is dropped
  365. * in the i386 interrupt dispatching code anyhow.
  366. */
  367. }