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.

521 lines
14 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. #define VDM_DEFAULT_PM_CLI_TIMEOUT 0xf
  19. ULONG VdmpMaxPMCliTime;
  20. BOOLEAN
  21. VdmpIsVdmProcess(
  22. VOID
  23. );
  24. NTSTATUS
  25. VdmpQueryVdmProcess (
  26. PVDM_QUERY_VDM_PROCESS_DATA VdmProcessData
  27. );
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text(PAGE, VdmpIsVdmProcess)
  30. #pragma alloc_text(PAGE, VdmpQueryVdmProcess)
  31. #pragma alloc_text(PAGE, NtVdmControl)
  32. #endif
  33. #if DBG
  34. ULONG VdmInjectFailures;
  35. #endif
  36. BOOLEAN
  37. VdmpIsVdmProcess(
  38. VOID
  39. )
  40. /*++
  41. Routine Description:
  42. This function verifies the caller is a VDM process.
  43. Arguments:
  44. None.
  45. Return Value:
  46. True if the caller is a VDM process.
  47. False if not
  48. --*/
  49. {
  50. PEPROCESS Process;
  51. PVDM_TIB VdmTib;
  52. NTSTATUS Status;
  53. PAGED_CODE();
  54. Process = PsGetCurrentProcess();
  55. if (Process->VdmObjects == NULL) {
  56. return FALSE;
  57. }
  58. //
  59. // Make sure the current thread has valid vdmtib.
  60. //
  61. Status = VdmpGetVdmTib(&VdmTib);
  62. if (!NT_SUCCESS(Status)) {
  63. return(FALSE);
  64. }
  65. //
  66. // More checking here ...
  67. //
  68. return TRUE;
  69. }
  70. NTSTATUS
  71. NtVdmControl(
  72. IN VDMSERVICECLASS Service,
  73. IN OUT PVOID ServiceData
  74. )
  75. /*++
  76. Routine Description:
  77. 386 specific routine which dispatches to the appropriate function
  78. based on service number.
  79. Arguments:
  80. Service -- Specifies what service is to be performed
  81. ServiceData -- Supplies a pointer to service specific data
  82. Return Value:
  83. if invalid service number: STATUS_INVALID_PARAMETER_1
  84. else see individual services.
  85. --*/
  86. {
  87. NTSTATUS Status;
  88. PVDM_PROCESS_OBJECTS pVdmObjects;
  89. VDM_INITIALIZE_DATA CapturedVdmInitializeData;
  90. PVDM_TIB VdmTib;
  91. PAGED_CODE();
  92. //
  93. // Allow any process to call this API to check if a process handle specifies
  94. // and NTVDM process.
  95. //
  96. if (Service == VdmQueryVdmProcess) {
  97. return VdmpQueryVdmProcess((PVDM_QUERY_VDM_PROCESS_DATA)ServiceData);
  98. }
  99. //
  100. // Make sure current process is VDMAllowed
  101. //
  102. if (!(PsGetCurrentProcess()->Flags & PS_PROCESS_FLAGS_VDM_ALLOWED)) {
  103. return STATUS_ACCESS_DENIED;
  104. }
  105. //
  106. // Make sure the caller is ntvdm. Except ...
  107. // VdmInitialize - the vdm state is not fully initialized to
  108. // perform the check
  109. //
  110. if ((Service != VdmInitialize) &&
  111. (PsGetCurrentProcess()->VdmObjects == NULL)) {
  112. return STATUS_ACCESS_DENIED;
  113. }
  114. //
  115. // Some services required a valid VdmTib
  116. //
  117. Status = VdmpGetVdmTib(&VdmTib);
  118. if (!NT_SUCCESS(Status)) {
  119. VdmTib = NULL;
  120. }
  121. try {
  122. //
  123. // Dispatch in descending order of frequency
  124. //
  125. if (Service == VdmStartExecution && VdmTib) {
  126. Status = VdmpStartExecution();
  127. } else if (Service == VdmQueueInterrupt) {
  128. Status = VdmpQueueInterrupt(ServiceData);
  129. } else if (Service == VdmDelayInterrupt) {
  130. Status = VdmpDelayInterrupt(ServiceData);
  131. } else if (Service == VdmQueryDir && VdmTib) {
  132. Status = VdmQueryDirectoryFile(ServiceData);
  133. } else if (Service == VdmInitialize) {
  134. VdmpMaxPMCliTime = VDM_DEFAULT_PM_CLI_TIMEOUT;
  135. ProbeForRead(ServiceData, sizeof(VDM_INITIALIZE_DATA), 1);
  136. RtlCopyMemory (&CapturedVdmInitializeData, ServiceData, sizeof (VDM_INITIALIZE_DATA));
  137. Status = VdmpInitialize(&CapturedVdmInitializeData);
  138. } else if (Service == VdmFeatures) {
  139. //
  140. // Verify that we were passed a valid user address
  141. //
  142. ProbeForWriteBoolean((PBOOLEAN)ServiceData);
  143. //
  144. // Return the appropriate feature bits to notify
  145. // ntvdm which modes (if any) fast IF emulation is
  146. // available for
  147. //
  148. *((PULONG)ServiceData) = KeI386VirtualIntExtensions &
  149. ~PM_VIRTUAL_INT_EXTENSIONS;
  150. Status = STATUS_SUCCESS;
  151. } else if (Service == VdmSetInt21Handler && VdmTib) {
  152. ProbeForRead(ServiceData, sizeof(VDMSET_INT21_HANDLER_DATA), 1);
  153. Status = Ke386SetVdmInterruptHandler(
  154. KeGetCurrentThread()->ApcState.Process,
  155. 0x21L,
  156. (USHORT)(((PVDMSET_INT21_HANDLER_DATA)ServiceData)->Selector),
  157. ((PVDMSET_INT21_HANDLER_DATA)ServiceData)->Offset,
  158. ((PVDMSET_INT21_HANDLER_DATA)ServiceData)->Gate32
  159. );
  160. } else if (Service == VdmPrinterDirectIoOpen && VdmTib) {
  161. Status = VdmpPrinterDirectIoOpen(ServiceData);
  162. } else if (Service == VdmPrinterDirectIoClose && VdmTib) {
  163. Status = VdmpPrinterDirectIoClose(ServiceData);
  164. } else if (Service == VdmPrinterInitialize && VdmTib) {
  165. Status = VdmpPrinterInitialize(ServiceData);
  166. } else if (Service == VdmSetLdtEntries && VdmTib) {
  167. ProbeForRead(ServiceData, sizeof(VDMSET_LDT_ENTRIES_DATA), 1);
  168. Status = PsSetLdtEntries(
  169. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Selector0,
  170. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Entry0Low,
  171. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Entry0Hi,
  172. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Selector1,
  173. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Entry1Low,
  174. ((PVDMSET_LDT_ENTRIES_DATA)ServiceData)->Entry1Hi
  175. );
  176. } else if (Service == VdmSetProcessLdtInfo && VdmTib) {
  177. PPROCESS_LDT_INFORMATION ldtInfo;
  178. ULONG length;
  179. ProbeForRead(ServiceData, sizeof(VDMSET_PROCESS_LDT_INFO_DATA), 1);
  180. ldtInfo = ((PVDMSET_PROCESS_LDT_INFO_DATA)ServiceData)->LdtInformation;
  181. length = ((PVDMSET_PROCESS_LDT_INFO_DATA)ServiceData)->LdtInformationLength;
  182. ProbeForRead(ldtInfo, length, 1);
  183. Status = PsSetProcessLdtInfo(ldtInfo, length);
  184. } else if (Service == VdmAdlibEmulation && VdmTib) {
  185. //
  186. // Ntvdm calls here to do adlib emulation under the following conditions:
  187. // ADLIB_DIRECT_IO - only If a FM synth device is opened for exclusive access.
  188. // ADLIB_KERNEL_EMULATION - otherwise.
  189. // Note ADLIB_USER_EMULATION is defaulted. It is basically used by external
  190. // ADLIB/SB vdds.
  191. //
  192. ProbeForRead(ServiceData, sizeof(VDM_ADLIB_DATA), 1);
  193. pVdmObjects = PsGetCurrentProcess()->VdmObjects;
  194. if (((PVDM_ADLIB_DATA)ServiceData)->Action == ADLIB_DIRECT_IO) {
  195. Status = STATUS_ACCESS_DENIED;
  196. } else {
  197. pVdmObjects->AdlibAction = ((PVDM_ADLIB_DATA)ServiceData)->Action;
  198. pVdmObjects->AdlibPhysPortStart = ((PVDM_ADLIB_DATA)ServiceData)->PhysicalPortStart;
  199. pVdmObjects->AdlibPhysPortEnd = ((PVDM_ADLIB_DATA)ServiceData)->PhysicalPortEnd;
  200. pVdmObjects->AdlibVirtPortStart = ((PVDM_ADLIB_DATA)ServiceData)->VirtualPortStart;
  201. pVdmObjects->AdlibVirtPortEnd = ((PVDM_ADLIB_DATA)ServiceData)->VirtualPortEnd;
  202. pVdmObjects->AdlibIndexRegister = 0;
  203. pVdmObjects->AdlibStatus = 0x6; // OPL2 emulation
  204. Status = STATUS_SUCCESS;
  205. }
  206. } else if (Service == VdmPMCliControl) {
  207. pVdmObjects = PsGetCurrentProcess()->VdmObjects;
  208. ProbeForRead(ServiceData, sizeof(VDM_PM_CLI_DATA), 1);
  209. Status = STATUS_SUCCESS;
  210. switch (((PVDM_PM_CLI_DATA)ServiceData)->Control) {
  211. case PM_CLI_CONTROL_DISABLE:
  212. pVdmObjects->VdmControl &= ~PM_CLI_CONTROL;
  213. break;
  214. case PM_CLI_CONTROL_ENABLE:
  215. pVdmObjects->VdmControl |= PM_CLI_CONTROL;
  216. if ((*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_VIRTUAL_INTERRUPTS) == 0) {
  217. VdmSetPMCliTimeStamp(TRUE);
  218. }
  219. break;
  220. case PM_CLI_CONTROL_CHECK:
  221. VdmCheckPMCliTimeStamp();
  222. break;
  223. case PM_CLI_CONTROL_SET:
  224. VdmSetPMCliTimeStamp(FALSE);
  225. break;
  226. case PM_CLI_CONTROL_CLEAR:
  227. VdmClearPMCliTimeStamp();
  228. break;
  229. default:
  230. Status = STATUS_INVALID_PARAMETER_1;
  231. }
  232. } else {
  233. Status = STATUS_INVALID_PARAMETER_1;
  234. }
  235. } except (EXCEPTION_EXECUTE_HANDLER) {
  236. Status = GetExceptionCode();
  237. }
  238. #if DBG
  239. if (PsGetCurrentProcess()->VdmObjects != NULL) {
  240. if (VdmInjectFailures != 0) {
  241. PS_SET_BITS (&PsGetCurrentProcess()->Flags,
  242. PS_PROCESS_INJECT_INPAGE_ERRORS);
  243. }
  244. }
  245. #endif
  246. ASSERT(KeGetCurrentIrql () == PASSIVE_LEVEL);
  247. return Status;
  248. }
  249. VOID
  250. VdmCheckPMCliTimeStamp (
  251. VOID
  252. )
  253. /*++
  254. Routine Description:
  255. This routine checks if interrupts are disabled for too long by protected
  256. mode apps. If ints are disabled for over predefined limit, they will be
  257. reenabled such that ntvdm will be able to dispatch pending interrupts.
  258. Note, V86 mode should NOT call this function.
  259. Arguments:
  260. None.
  261. Return Value:
  262. None.
  263. --*/
  264. {
  265. PVDM_PROCESS_OBJECTS pVdmObjects;
  266. PKPROCESS process = (PKPROCESS)PsGetCurrentProcess();
  267. NTSTATUS status;
  268. PVDM_TIB vdmTib;
  269. pVdmObjects = ((PEPROCESS)process)->VdmObjects;
  270. if (pVdmObjects->VdmControl & PM_CLI_CONTROL &&
  271. pVdmObjects->PMCliTimeStamp != 0) {
  272. if (((process->UserTime + 1)- pVdmObjects->PMCliTimeStamp) >= VdmpMaxPMCliTime) {
  273. pVdmObjects->PMCliTimeStamp = 0;
  274. try {
  275. *FIXED_NTVDMSTATE_LINEAR_PC_AT |= VDM_VIRTUAL_INTERRUPTS;
  276. status = VdmpGetVdmTib(&vdmTib);
  277. if (NT_SUCCESS(status)) {
  278. vdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
  279. }
  280. } except(EXCEPTION_EXECUTE_HANDLER) {
  281. status = GetExceptionCode();
  282. }
  283. }
  284. }
  285. }
  286. VOID
  287. VdmSetPMCliTimeStamp (
  288. BOOLEAN Reset
  289. )
  290. /*++
  291. Routine Description:
  292. This routine checks if interrupts are disabled for too long by protected
  293. mode apps. If ints are disabled for over predefined limit, they will be
  294. reenabled such that ntvdm will be able to dispatch pending interrupts.
  295. Note, V86 mode should NOT call this function.
  296. Arguments:
  297. Reset - a Bool value to indicate should we re-set the count if it is not zero
  298. Return Value:
  299. None.
  300. --*/
  301. {
  302. PVDM_PROCESS_OBJECTS pVdmObjects;
  303. PKPROCESS process = (PKPROCESS)PsGetCurrentProcess();
  304. pVdmObjects = ((PEPROCESS)process)->VdmObjects;
  305. if (pVdmObjects->VdmControl & PM_CLI_CONTROL) {
  306. if (Reset || pVdmObjects->PMCliTimeStamp == 0) {
  307. pVdmObjects->PMCliTimeStamp = process->UserTime + 1;
  308. }
  309. }
  310. }
  311. VOID
  312. VdmClearPMCliTimeStamp (
  313. VOID
  314. )
  315. /*++
  316. Routine Description:
  317. This routine checks if interrupts are disabled for too long by protected
  318. mode apps. If ints are disabled for over predefined limit, they will be
  319. reenabled such that ntvdm will be able to dispatch pending interrupts.
  320. Note, V86 mode should NOT call this function.
  321. Arguments:
  322. None.
  323. Return Value:
  324. None.
  325. --*/
  326. {
  327. PVDM_PROCESS_OBJECTS pVdmObjects;
  328. pVdmObjects = PsGetCurrentProcess()->VdmObjects;
  329. if (pVdmObjects->VdmControl & PM_CLI_CONTROL) {
  330. pVdmObjects->PMCliTimeStamp = 0;
  331. }
  332. }
  333. NTSTATUS
  334. VdmpQueryVdmProcess (
  335. PVDM_QUERY_VDM_PROCESS_DATA QueryVdmProcessData
  336. )
  337. /*++
  338. Routine Description:
  339. This routine checks if the process handle specifies a ntvdm process.
  340. If the specified process has VDM_ALLOW bit set and it has VdmObject kernel
  341. mode structure allocated, then it is a VDM process.
  342. Arguments:
  343. QueryVdmProcessData - supplies a pointer to a user mode VDM_QUERY_VDM_PROCESS_DATA
  344. Return Value:
  345. NTSTATUS
  346. The QueryVdmProcessData is filled in only when return status is STATUS_SUCCESS
  347. --*/
  348. {
  349. NTSTATUS st = STATUS_SUCCESS;
  350. HANDLE processHandle;
  351. PEPROCESS process;
  352. BOOLEAN flag;
  353. KPROCESSOR_MODE PreviousMode;
  354. PreviousMode = KeGetPreviousMode();
  355. if (PreviousMode != KernelMode) {
  356. try {
  357. //
  358. // Verify that we were passed a valid user address
  359. //
  360. ProbeForRead(&(QueryVdmProcessData->ProcessHandle), sizeof(HANDLE), sizeof(UCHAR));
  361. processHandle = QueryVdmProcessData->ProcessHandle;
  362. } except (EXCEPTION_EXECUTE_HANDLER) {
  363. return GetExceptionCode();
  364. }
  365. } else {
  366. processHandle = QueryVdmProcessData->ProcessHandle;
  367. }
  368. st = ObReferenceObjectByHandle(
  369. processHandle,
  370. PROCESS_QUERY_INFORMATION,
  371. PsProcessType,
  372. KeGetPreviousMode(),
  373. (PVOID *)&process,
  374. NULL
  375. );
  376. if ( !NT_SUCCESS(st) ) {
  377. return st;
  378. }
  379. if (process->Flags & PS_PROCESS_FLAGS_VDM_ALLOWED && process->VdmObjects) {
  380. flag = TRUE;
  381. } else {
  382. flag = FALSE;
  383. }
  384. ObDereferenceObject(process);
  385. try {
  386. //
  387. // Verify the user address is writable.
  388. //
  389. ProbeForWrite(&(QueryVdmProcessData->IsVdmProcess), sizeof(BOOLEAN), sizeof(UCHAR));
  390. QueryVdmProcessData->IsVdmProcess = flag;
  391. } except (EXCEPTION_EXECUTE_HANDLER) {
  392. st = GetExceptionCode();
  393. }
  394. return st;
  395. }