Source code of Windows XP (NT5)
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.

479 lines
13 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. vdmentry.c
  5. Abstract:
  6. This function dispatches to the vdm services
  7. Author:
  8. Dave Hastings (daveh) 6-Apr-1992
  9. Notes:
  10. This module will be fleshed out when the great vdm code consolidation
  11. occurs, sometime soon after the functionality is done.
  12. Revision History:
  13. 24-Sep-1993 Jonle: reoptimize dispatcher to suit the number of services
  14. add QueueInterrupt service
  15. --*/
  16. #include "vdmp.h"
  17. #include <ntvdmp.h>
  18. ULONG VdmpMaxPMCliTime;
  19. #if DISABLE_CLI
  20. ULONG VdmpPMCliCount;
  21. #endif
  22. BOOLEAN
  23. VdmpIsVdmProcess(
  24. VOID
  25. );
  26. VOID
  27. VdmpEnableOPL2 (
  28. ULONG BasePort
  29. );
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text(PAGE, VdmpIsVdmProcess)
  32. #pragma alloc_text(PAGE, NtVdmControl)
  33. #pragma alloc_text(PAGE, VdmpEnableOPL2)
  34. #endif
  35. #if DBG
  36. ULONG VdmInjectFailures;
  37. #endif
  38. BOOLEAN
  39. VdmpIsVdmProcess(
  40. VOID
  41. )
  42. /*++
  43. Routine Description:
  44. This function verifies the caller is a VDM process.
  45. Arguments:
  46. None.
  47. Return Value:
  48. True if the caller is a VDM process.
  49. False if not
  50. --*/
  51. {
  52. PEPROCESS Process;
  53. PVDM_TIB VdmTib;
  54. NTSTATUS Status;
  55. PAGED_CODE();
  56. Process = PsGetCurrentProcess();
  57. if (Process->VdmObjects == NULL) {
  58. return FALSE;
  59. }
  60. //
  61. // Make sure the current thread has valid vdmtib.
  62. //
  63. Status = VdmpGetVdmTib(&VdmTib);
  64. if (!NT_SUCCESS(Status)) {
  65. return(FALSE);
  66. }
  67. //
  68. // More checking here ...
  69. //
  70. return TRUE;
  71. }
  72. NTSTATUS
  73. NtVdmControl(
  74. IN VDMSERVICECLASS Service,
  75. IN OUT PVOID ServiceData
  76. )
  77. /*++
  78. Routine Description:
  79. 386 specific routine which dispatches to the appropriate function
  80. based on service number.
  81. Arguments:
  82. Service -- Specifies what service is to be performed
  83. ServiceData -- Supplies a pointer to service specific data
  84. Return Value:
  85. if invalid service number: STATUS_INVALID_PARAMETER_1
  86. else see individual services.
  87. --*/
  88. {
  89. NTSTATUS Status;
  90. PVDM_PROCESS_OBJECTS pVdmObjects;
  91. VDM_INITIALIZE_DATA CapturedVdmInitializeData;
  92. PAGED_CODE();
  93. //
  94. // Make sure the caller is ntvdm. Except ...
  95. // VdmStartExecution - video driver uses it to support int 10
  96. // VdmInitialize - the vdm state is not fully initialized to
  97. // perform the check
  98. //
  99. if ((Service != VdmInitialize) &&
  100. (Service != VdmStartExecution) &&
  101. (PsGetCurrentProcess()->VdmObjects == NULL)) {
  102. return STATUS_ACCESS_DENIED;
  103. }
  104. try {
  105. //
  106. // Dispatch in descending order of frequency
  107. //
  108. if (Service == VdmStartExecution) {
  109. Status = VdmpStartExecution();
  110. } else if (Service == VdmQueueInterrupt) {
  111. Status = VdmpQueueInterrupt(ServiceData);
  112. } else if (Service == VdmDelayInterrupt) {
  113. Status = VdmpDelayInterrupt(ServiceData);
  114. } else if (Service == VdmQueryDir) {
  115. Status = VdmQueryDirectoryFile(ServiceData);
  116. } else if (Service == VdmInitialize) {
  117. VdmpMaxPMCliTime = 1;
  118. ProbeForRead(ServiceData, sizeof(VDM_INITIALIZE_DATA), 1);
  119. RtlCopyMemory (&CapturedVdmInitializeData, ServiceData, sizeof (VDM_INITIALIZE_DATA));
  120. Status = VdmpInitialize(&CapturedVdmInitializeData);
  121. } else if (Service == VdmFeatures) {
  122. //
  123. // Verify that we were passed a valid user address
  124. //
  125. ProbeForWriteBoolean((PBOOLEAN)ServiceData);
  126. //
  127. // Return the appropriate feature bits to notify
  128. // ntvdm which modes (if any) fast IF emulation is
  129. // available for
  130. //
  131. if (KeI386VdmIoplAllowed) {
  132. *((PULONG)ServiceData) = V86_VIRTUAL_INT_EXTENSIONS;
  133. } else {
  134. // remove this if pm extensions to be used
  135. *((PULONG)ServiceData) = KeI386VirtualIntExtensions &
  136. ~PM_VIRTUAL_INT_EXTENSIONS;
  137. }
  138. Status = STATUS_SUCCESS;
  139. } else if (Service == VdmSetInt21Handler) {
  140. ProbeForRead(ServiceData, sizeof(VDMSET_INT21_HANDLER_DATA), 1);
  141. Status = Ke386SetVdmInterruptHandler(
  142. KeGetCurrentThread()->ApcState.Process,
  143. 0x21L,
  144. (USHORT)(((PVDMSET_INT21_HANDLER_DATA)ServiceData)->Selector),
  145. ((PVDMSET_INT21_HANDLER_DATA)ServiceData)->Offset,
  146. ((PVDMSET_INT21_HANDLER_DATA)ServiceData)->Gate32
  147. );
  148. } else if (Service == VdmPrinterDirectIoOpen) {
  149. Status = VdmpPrinterDirectIoOpen(ServiceData);
  150. } else if (Service == VdmPrinterDirectIoClose) {
  151. Status = VdmpPrinterDirectIoClose(ServiceData);
  152. } else if (Service == VdmPrinterInitialize) {
  153. Status = VdmpPrinterInitialize(ServiceData);
  154. } else if (Service == VdmSetLdtEntries && VdmpIsVdmProcess()) {
  155. ProbeForRead(ServiceData, sizeof(VDMSET_LDT_ENTRIES_DATA), 1);
  156. Status = VdmpSetLdtEntries(
  157. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Selector0,
  158. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Entry0Low,
  159. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Entry0Hi,
  160. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Selector1,
  161. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Entry1Low,
  162. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Entry1Hi
  163. );
  164. } else if (Service == VdmSetProcessLdtInfo && VdmpIsVdmProcess()) {
  165. PPROCESS_LDT_INFORMATION ldtInfo;
  166. ULONG length;
  167. ProbeForRead(ServiceData, sizeof(VDMSET_PROCESS_LDT_INFO_DATA), 1);
  168. ldtInfo = ((PVDMSET_PROCESS_LDT_INFO_DATA)ServiceData)->LdtInformation;
  169. length = ((PVDMSET_PROCESS_LDT_INFO_DATA)ServiceData)->LdtInformationLength;
  170. ProbeForRead(ldtInfo, length, 1);
  171. Status = VdmpSetProcessLdtInfo(ldtInfo, length);
  172. } else if (Service == VdmAdlibEmulation && VdmpIsVdmProcess()) {
  173. //
  174. // Ntvdm calls here to do adlib emulation under the following conditions:
  175. // ADLIB_DIRECT_IO - only If a FM synth device is opened for exclusive access.
  176. // ADLIB_KERNEL_EMULATION - otherwise.
  177. // Note ADLIB_USER_EMULATION is defaulted. It is basically used by external
  178. // ADLIB/SB vdds.
  179. //
  180. ProbeForRead(ServiceData, sizeof(VDM_ADLIB_DATA), 1);
  181. pVdmObjects = PsGetCurrentProcess()->VdmObjects;
  182. pVdmObjects->AdlibAction = ((PVDM_ADLIB_DATA)ServiceData)->Action;
  183. pVdmObjects->AdlibPhysPortStart = ((PVDM_ADLIB_DATA)ServiceData)->PhysicalPortStart;
  184. pVdmObjects->AdlibPhysPortEnd = ((PVDM_ADLIB_DATA)ServiceData)->PhysicalPortEnd;
  185. pVdmObjects->AdlibVirtPortStart = ((PVDM_ADLIB_DATA)ServiceData)->VirtualPortStart;
  186. pVdmObjects->AdlibVirtPortEnd = ((PVDM_ADLIB_DATA)ServiceData)->VirtualPortEnd;
  187. pVdmObjects->AdlibIndexRegister = 0;
  188. pVdmObjects->AdlibStatus = 0x6; // OPL2 emulation
  189. if (pVdmObjects->AdlibAction == ADLIB_DIRECT_IO) {
  190. VdmpEnableOPL2(pVdmObjects->AdlibPhysPortStart);
  191. }
  192. Status = STATUS_SUCCESS;
  193. } else if (Service == VdmPMCliControl) {
  194. pVdmObjects = PsGetCurrentProcess()->VdmObjects;
  195. ProbeForRead(ServiceData, sizeof(VDM_PM_CLI_DATA), 1);
  196. Status = STATUS_SUCCESS;
  197. switch (((PVDM_PM_CLI_DATA)ServiceData)->Control) {
  198. case PM_CLI_CONTROL_DISABLE:
  199. pVdmObjects->VdmControl &= ~PM_CLI_CONTROL;
  200. break;
  201. case PM_CLI_CONTROL_ENABLE:
  202. pVdmObjects->VdmControl |= PM_CLI_CONTROL;
  203. #if DISABLE_CLI
  204. VdmpPMCliCount = 0;
  205. #endif
  206. if ((*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_VIRTUAL_INTERRUPTS) == 0) {
  207. VdmSetPMCliTimeStamp(TRUE);
  208. }
  209. break;
  210. case PM_CLI_CONTROL_CHECK:
  211. VdmCheckPMCliTimeStamp();
  212. break;
  213. case PM_CLI_CONTROL_SET:
  214. VdmSetPMCliTimeStamp(FALSE);
  215. break;
  216. case PM_CLI_CONTROL_CLEAR:
  217. VdmClearPMCliTimeStamp();
  218. break;
  219. default:
  220. Status = STATUS_INVALID_PARAMETER_1;
  221. }
  222. } else {
  223. Status = STATUS_INVALID_PARAMETER_1;
  224. }
  225. } except (EXCEPTION_EXECUTE_HANDLER) {
  226. Status = GetExceptionCode();
  227. }
  228. #if DBG
  229. if (PsGetCurrentProcess()->VdmObjects != NULL) {
  230. if (VdmInjectFailures != 0) {
  231. PS_SET_BITS (&PsGetCurrentProcess()->Flags,
  232. PS_PROCESS_INJECT_INPAGE_ERRORS);
  233. }
  234. }
  235. #endif
  236. ASSERT(KeGetCurrentIrql () == PASSIVE_LEVEL);
  237. return Status;
  238. }
  239. VOID
  240. VdmpEnableOPL2 (
  241. ULONG BasePort
  242. )
  243. /*++
  244. Routine Description:
  245. This routine checks if OPL3 is present. If yes, it will set it OPL2
  246. mode.
  247. Note, According to OPL3 programming guide, we don't need to worry about
  248. the delay between ins and outs (back to back IOs). In fact, I found out
  249. it needs a little bit delay. When I code this routine in assembly,
  250. it does not work. So, we may need to add a little more delay here if
  251. OPL2 stops working on some audio cards.
  252. Arguments:
  253. BasePort - adlib base port
  254. Return Value:
  255. None.
  256. --*/
  257. {
  258. UCHAR ch;
  259. PUCHAR SecondaryPort;
  260. ch = READ_PORT_UCHAR((PUCHAR)BasePort);
  261. if (ch == 0) { // if OPL3
  262. SecondaryPort = (PUCHAR)(BasePort + 2); // move to secondary ports
  263. WRITE_PORT_UCHAR(SecondaryPort, 5); // Select index register 5
  264. ch = READ_PORT_UCHAR((PUCHAR)BasePort); // a little bit delay
  265. WRITE_PORT_UCHAR(SecondaryPort + 1, 0); // Select index register 5
  266. }
  267. }
  268. VOID
  269. VdmCheckPMCliTimeStamp (
  270. VOID
  271. )
  272. /*++
  273. Routine Description:
  274. This routine checks if interrupts are disabled for too long by protected
  275. mode apps. If ints are disabled for over predefined limit, they will be
  276. reenabled such that ntvdm will be able to dispatch pending interrupts.
  277. Note, V86 mode should NOT call this function.
  278. Arguments:
  279. None.
  280. Return Value:
  281. None.
  282. --*/
  283. {
  284. PVDM_PROCESS_OBJECTS pVdmObjects;
  285. PKPROCESS process = (PKPROCESS)PsGetCurrentProcess();
  286. NTSTATUS status;
  287. PVDM_TIB vdmTib;
  288. pVdmObjects = ((PEPROCESS)process)->VdmObjects;
  289. if (pVdmObjects->VdmControl & PM_CLI_CONTROL &&
  290. pVdmObjects->PMCliTimeStamp != 0) {
  291. if (((process->UserTime + 1)- pVdmObjects->PMCliTimeStamp) >= VdmpMaxPMCliTime) {
  292. pVdmObjects->PMCliTimeStamp = 0;
  293. #if DISABLE_CLI
  294. VdmpPMCliCount++;
  295. #endif
  296. try {
  297. *FIXED_NTVDMSTATE_LINEAR_PC_AT |= VDM_VIRTUAL_INTERRUPTS;
  298. status = VdmpGetVdmTib(&vdmTib);
  299. if (NT_SUCCESS(status)) {
  300. vdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
  301. }
  302. } except(ExSystemExceptionFilter()) {
  303. status = GetExceptionCode();
  304. }
  305. }
  306. }
  307. }
  308. VOID
  309. VdmSetPMCliTimeStamp (
  310. BOOLEAN Reset
  311. )
  312. /*++
  313. Routine Description:
  314. This routine checks if interrupts are disabled for too long by protected
  315. mode apps. If ints are disabled for over predefined limit, they will be
  316. reenabled such that ntvdm will be able to dispatch pending interrupts.
  317. Note, V86 mode should NOT call this function.
  318. Arguments:
  319. Reset - a Bool value to indicate should we re-set the count if it is not zero
  320. Return Value:
  321. None.
  322. --*/
  323. {
  324. PVDM_PROCESS_OBJECTS pVdmObjects;
  325. PKPROCESS process = (PKPROCESS)PsGetCurrentProcess();
  326. #if DISABLE_CLI
  327. if (VdmpPMCliCount > 0x20) {
  328. try {
  329. *FIXED_NTVDMSTATE_LINEAR_PC_AT |= VDM_VIRTUAL_INTERRUPTS;
  330. }
  331. except (EXCEPTION_EXECUTE_HANDLER) {
  332. NOTHING;
  333. }
  334. return;
  335. }
  336. #endif
  337. pVdmObjects = ((PEPROCESS)process)->VdmObjects;
  338. if (pVdmObjects->VdmControl & PM_CLI_CONTROL) {
  339. if (Reset || pVdmObjects->PMCliTimeStamp == 0) {
  340. pVdmObjects->PMCliTimeStamp = process->UserTime + 1;
  341. }
  342. }
  343. }
  344. VOID
  345. VdmClearPMCliTimeStamp (
  346. VOID
  347. )
  348. /*++
  349. Routine Description:
  350. This routine checks if interrupts are disabled for too long by protected
  351. mode apps. If ints are disabled for over predefined limit, they will be
  352. reenabled such that ntvdm will be able to dispatch pending interrupts.
  353. Note, V86 mode should NOT call this function.
  354. Arguments:
  355. None.
  356. Return Value:
  357. None.
  358. --*/
  359. {
  360. PVDM_PROCESS_OBJECTS pVdmObjects;
  361. pVdmObjects = PsGetCurrentProcess()->VdmObjects;
  362. if (pVdmObjects->VdmControl & PM_CLI_CONTROL) {
  363. pVdmObjects->PMCliTimeStamp = 0;
  364. }
  365. }