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.

1026 lines
28 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. psldt.c
  5. Abstract:
  6. This module contains code for the io port handler support
  7. Author:
  8. Dave Hastings (daveh) 26 Jan 1991
  9. Revision History:
  10. --*/
  11. #include "psp.h"
  12. #if DBG
  13. #define ASSERTEQUAL(value1, value2, string) \
  14. if ((ULONG)value1 != (ULONG)value2) { \
  15. DbgPrint string ; \
  16. }
  17. #define ASSERTEQUALBREAK(value1, value2, string)\
  18. if ((ULONG)value1 != (ULONG)value2) { \
  19. DbgPrint string ; \
  20. DbgBreakPoint(); \
  21. }
  22. #else
  23. #define ASSERTEQUAL(value1, value2, string)
  24. #define ASSERTEQUALBREAK(value1, value2, string)
  25. #endif
  26. //
  27. // Internal functions
  28. //
  29. NTSTATUS
  30. Psp386InstallIoHandler(
  31. IN PEPROCESS Process,
  32. IN PEMULATOR_ACCESS_ENTRY EmulatorAccessEntry,
  33. IN ULONG PortNumber,
  34. IN ULONG Context
  35. );
  36. NTSTATUS
  37. Psp386RemoveIoHandler(
  38. IN PEPROCESS Process,
  39. IN PEMULATOR_ACCESS_ENTRY EmulatorAccessEntry,
  40. IN ULONG PortNumber
  41. );
  42. NTSTATUS
  43. Psp386InsertVdmIoHandlerBlock(
  44. IN PEPROCESS Process,
  45. IN PVDM_IO_HANDLER VdmIoHandler
  46. );
  47. PVDM_IO_HANDLER
  48. Psp386GetVdmIoHandler(
  49. IN PEPROCESS Process,
  50. IN ULONG PortNumber
  51. );
  52. NTSTATUS
  53. Psp386CreateVdmIoListHead(
  54. IN PEPROCESS Process
  55. );
  56. #ifdef ALLOC_PRAGMA
  57. #pragma alloc_text(INIT,PspVdmInitialize)
  58. #pragma alloc_text(PAGE,PspSetProcessIoHandlers)
  59. #pragma alloc_text(PAGE,Ps386GetVdmIoHandler)
  60. #pragma alloc_text(PAGE,Psp386RemoveIoHandler)
  61. #pragma alloc_text(PAGE,Psp386InstallIoHandler)
  62. #pragma alloc_text(PAGE,Psp386CreateVdmIoListHead)
  63. #pragma alloc_text(PAGE,Psp386InsertVdmIoHandlerBlock)
  64. #pragma alloc_text(PAGE,Psp386GetVdmIoHandler)
  65. #pragma alloc_text(PAGE,PspDeleteVdmObjects)
  66. #endif
  67. //
  68. // Resource to synchronize access to IoHandler list
  69. //
  70. ERESOURCE VdmIoListCreationResource;
  71. NTSTATUS
  72. PspSetProcessIoHandlers(
  73. IN PEPROCESS Process,
  74. IN PVOID IoHandlerInformation,
  75. IN ULONG IoHandlerLength
  76. )
  77. /*++
  78. Routine Description:
  79. This routine installs a device driver IO handling routine for the
  80. specified process. If an io operation is detected in a vdm on a port
  81. that has a device driver IO handling routine, that routine will be called.
  82. Arguments:
  83. Process -- Supplies a pointer to the process for which Io port handlers
  84. are to be installed
  85. IoHandlerInformation -- Supplies a pointer to the information about the
  86. io port handlers
  87. IoHandlerLength -- Supplies the length of the IoHandlerInformation
  88. structure.
  89. Return Value:
  90. --*/
  91. {
  92. PPROCESS_IO_PORT_HANDLER_INFORMATION IoHandlerInfo;
  93. NTSTATUS Status;
  94. PEMULATOR_ACCESS_ENTRY EmulatorAccess;
  95. ULONG EmulatorEntryNumber, NumberPorts;
  96. ULONG PortSize;
  97. PAGED_CODE();
  98. //
  99. // Insure that this call was made from KernelMode
  100. //
  101. if (KeGetPreviousMode() != KernelMode) {
  102. return STATUS_INVALID_PARAMETER; // this info type invalid in usermode
  103. }
  104. //
  105. // Insure that the data passed is long enough
  106. //
  107. if (IoHandlerLength < (ULONG)sizeof( PROCESS_IO_PORT_HANDLER_INFORMATION)) {
  108. return STATUS_INFO_LENGTH_MISMATCH;
  109. }
  110. IoHandlerInfo = IoHandlerInformation;
  111. //
  112. // For each of the entries in the array that describes the handlers,
  113. // determine what size of port the specified handler is being installed
  114. // for, and then iterate over each individual port.
  115. //
  116. for (EmulatorEntryNumber = 0, EmulatorAccess =
  117. IoHandlerInfo->EmulatorAccessEntries;
  118. EmulatorEntryNumber < IoHandlerInfo->NumEntries;
  119. EmulatorEntryNumber++, EmulatorAccess++) {
  120. switch (EmulatorAccess->AccessType) {
  121. case Uchar:
  122. PortSize = 1;
  123. break;
  124. case Ushort:
  125. PortSize = 2;
  126. break;
  127. case Ulong:
  128. default:
  129. PortSize = 4;
  130. }
  131. for (NumberPorts = 0;
  132. NumberPorts < EmulatorAccess->NumConsecutivePorts;
  133. NumberPorts++) {
  134. if (IoHandlerInfo->Install) {
  135. Status = Psp386InstallIoHandler(
  136. Process,
  137. EmulatorAccess,
  138. EmulatorAccess->BasePort + NumberPorts * PortSize,
  139. IoHandlerInfo->Context
  140. );
  141. if (NT_SUCCESS(Status)) {
  142. }
  143. } else {
  144. Status = Psp386RemoveIoHandler(
  145. Process,
  146. EmulatorAccess,
  147. EmulatorAccess->BasePort + NumberPorts * PortSize
  148. );
  149. }
  150. if (!NT_SUCCESS(Status)) {
  151. goto exitloop;
  152. }
  153. }
  154. }
  155. Status = STATUS_SUCCESS;
  156. exitloop:
  157. return Status;
  158. }
  159. VOID
  160. PspDeleteVdmObjects(
  161. IN PEPROCESS Process
  162. )
  163. /*++
  164. Routine Description:
  165. Frees the VdmObjects structure and the Frees the IoHandler list
  166. Arguments:
  167. Process -- Supplies a pointer to the process
  168. Return Value:
  169. None
  170. --*/
  171. {
  172. SIZE_T PoolQuota;
  173. PVDM_PROCESS_OBJECTS pVdmObjects;
  174. PVDM_IO_HANDLER p1, p2;
  175. PVDM_IO_LISTHEAD p3;
  176. PLIST_ENTRY Next;
  177. PDELAYINTIRQ pDelayIntIrq;
  178. pVdmObjects = Process->VdmObjects;
  179. if (pVdmObjects == NULL) {
  180. return;
  181. }
  182. //
  183. // First Free any port handler entries for this process,
  184. //
  185. p1 = NULL;
  186. p3 = pVdmObjects->VdmIoListHead;
  187. if (p3) {
  188. p2 = p3->VdmIoHandlerList;
  189. while (p2) {
  190. p1 = p2;
  191. p2 = p1->Next;
  192. ExFreePool( p1 );
  193. }
  194. ExDeleteResourceLite(&p3->VdmIoResource);
  195. ExFreePool( p3 );
  196. pVdmObjects->VdmIoListHead = NULL;
  197. }
  198. if (pVdmObjects->pIcaUserData) {
  199. PsReturnProcessPagedPoolQuota (Process,
  200. sizeof(VDMICAUSERDATA));
  201. ExFreePool(pVdmObjects->pIcaUserData);
  202. }
  203. //
  204. // Free up the DelayedIntList, spinlock protection is not needed because
  205. // object referencing on the process is being used instead. Meaning there
  206. // can be no outstanding timers because the process object reference
  207. // count would have to be nonzero.
  208. //
  209. PoolQuota = 0;
  210. Next = pVdmObjects->DelayIntListHead.Flink;
  211. while (Next != &pVdmObjects->DelayIntListHead) {
  212. pDelayIntIrq = CONTAINING_RECORD(Next, DELAYINTIRQ, DelayIntListEntry);
  213. Next = Next->Flink;
  214. RemoveEntryList (&pDelayIntIrq->DelayIntListEntry);
  215. ExFreePool (pDelayIntIrq);
  216. PoolQuota += sizeof(DELAYINTIRQ);
  217. }
  218. if (PoolQuota != 0) {
  219. PsReturnProcessNonPagedPoolQuota(Process, PoolQuota);
  220. }
  221. PsReturnProcessNonPagedPoolQuota (Process, sizeof(VDM_PROCESS_OBJECTS));
  222. ExFreePool (pVdmObjects);
  223. Process->VdmObjects = NULL;
  224. }
  225. NTSTATUS
  226. Psp386RemoveIoHandler(
  227. IN PEPROCESS Process,
  228. IN PEMULATOR_ACCESS_ENTRY EmulatorAccessEntry,
  229. IN ULONG PortNumber
  230. )
  231. /*++
  232. Routine Description:
  233. This routine remove a handler for a port. On debug version, it will
  234. print a message if there is no handler.
  235. Arguments:
  236. Process -- Supplies a pointer to the process
  237. EmulatorAccess -- Supplies a pointer to the information about the
  238. io port handler
  239. PortNumber -- Supplies the port number to remove the handler from.
  240. Return Value:
  241. --*/
  242. {
  243. PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects;
  244. PVDM_IO_HANDLER VdmIoHandler;
  245. KIRQL OldIrql;
  246. PAGED_CODE();
  247. //
  248. // Ensure we have a vdm process which is initialized
  249. // correctly for VdmIoHandlers
  250. //
  251. if (!pVdmObjects) {
  252. #if DBG
  253. DbgPrint("Psp386RemoveIoHandler: uninitialized VdmObjects\n");
  254. #endif
  255. return STATUS_UNSUCCESSFUL;
  256. }
  257. //
  258. // If the list does not have a head, then there are no handlers to
  259. // remove.
  260. //
  261. if (!pVdmObjects->VdmIoListHead) {
  262. #if DBG
  263. DbgPrint("Psp386RemoveIoHandler : attempt to remove non-existent hdlr\n");
  264. #endif
  265. return STATUS_SUCCESS;
  266. }
  267. //
  268. // Lock the list, so we can insure a correct update.
  269. //
  270. KeRaiseIrql(APC_LEVEL, &OldIrql);
  271. ExAcquireResourceExclusiveLite(&pVdmObjects->VdmIoListHead->VdmIoResource,TRUE);
  272. VdmIoHandler = Psp386GetVdmIoHandler(
  273. Process,
  274. PortNumber & ~0x3
  275. );
  276. if (!VdmIoHandler) {
  277. #if DBG
  278. DbgPrint("Psp386RemoveIoHandler : attempt to remove non-existent hdlr\n");
  279. #endif
  280. ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource);
  281. KeLowerIrql(OldIrql);
  282. return STATUS_SUCCESS;
  283. }
  284. ASSERTEQUALBREAK(
  285. VdmIoHandler->PortNumber,
  286. (PortNumber & ~0x3),
  287. ("Psp386RemoveIoHandler : Bad pointer returned from GetVdmIoHandler\n")
  288. );
  289. if (EmulatorAccessEntry->AccessMode & EMULATOR_READ_ACCESS) {
  290. switch (EmulatorAccessEntry->AccessType) {
  291. case Uchar:
  292. if (EmulatorAccessEntry->StringSupport) {
  293. ASSERTEQUAL(
  294. EmulatorAccessEntry->Routine,
  295. VdmIoHandler->IoFunctions[0].UcharStringIo[PortNumber % 4],
  296. ("Psp386RemoveIoHandler : UcharString fns don't match\n")
  297. );
  298. VdmIoHandler->IoFunctions[0].UcharStringIo[PortNumber % 4] = NULL;
  299. } else {
  300. ASSERTEQUAL(
  301. EmulatorAccessEntry->Routine,
  302. VdmIoHandler->IoFunctions[0].UcharIo[PortNumber % 4],
  303. ("Psp386RemoveIoHandler : Uchar fns don't match\n")
  304. );
  305. VdmIoHandler->IoFunctions[0].UcharIo[PortNumber % 4] = NULL;
  306. }
  307. break;
  308. case Ushort:
  309. if (EmulatorAccessEntry->StringSupport) {
  310. ASSERTEQUAL(
  311. EmulatorAccessEntry->Routine,
  312. VdmIoHandler->IoFunctions[0].UshortStringIo[(PortNumber & 2) >> 1],
  313. ("Psp386RemoveIoHandler : UshortString fns don't match\n")
  314. );
  315. VdmIoHandler->IoFunctions[0].UshortStringIo[(PortNumber & 2) >> 1] = NULL;
  316. } else {
  317. ASSERTEQUAL(
  318. EmulatorAccessEntry->Routine,
  319. VdmIoHandler->IoFunctions[0].UshortIo[(PortNumber & 2) >> 1],
  320. ("Psp386RemoveIoHandler : Ushort fns don't match\n")
  321. );
  322. VdmIoHandler->IoFunctions[0].UshortIo[(PortNumber & 2) >> 1] = NULL;
  323. }
  324. break;
  325. case Ulong:
  326. if (EmulatorAccessEntry->StringSupport) {
  327. ASSERTEQUAL(
  328. EmulatorAccessEntry->Routine,
  329. VdmIoHandler->IoFunctions[0].UlongStringIo,
  330. ("Psp386RemoveIoHandler : UlongString fns don't match\n")
  331. );
  332. VdmIoHandler->IoFunctions[0].UlongStringIo = NULL;
  333. } else {
  334. ASSERTEQUAL(
  335. EmulatorAccessEntry->Routine,
  336. VdmIoHandler->IoFunctions[0].UlongIo,
  337. ("Psp386RemoveIoHandler : Ulong fns don't match\n")
  338. );
  339. VdmIoHandler->IoFunctions[0].UlongIo = NULL;
  340. }
  341. break;
  342. }
  343. }
  344. if (EmulatorAccessEntry->AccessMode & EMULATOR_WRITE_ACCESS) {
  345. switch (EmulatorAccessEntry->AccessType) {
  346. case Uchar:
  347. if (EmulatorAccessEntry->StringSupport) {
  348. ASSERTEQUAL(
  349. EmulatorAccessEntry->Routine,
  350. VdmIoHandler->IoFunctions[1].UcharStringIo[PortNumber % 4],
  351. ("Psp386RemoveIoHandler : UcharString fns don't match\n")
  352. );
  353. VdmIoHandler->IoFunctions[1].UcharStringIo[PortNumber % 4] = NULL;
  354. } else {
  355. ASSERTEQUAL(
  356. EmulatorAccessEntry->Routine,
  357. VdmIoHandler->IoFunctions[1].UcharIo[PortNumber % 4],
  358. ("Psp386RemoveIoHandler : Uchar fns don't match\n")
  359. );
  360. VdmIoHandler->IoFunctions[1].UcharIo[PortNumber % 4] = NULL;
  361. }
  362. break;
  363. case Ushort:
  364. if (EmulatorAccessEntry->StringSupport) {
  365. ASSERTEQUAL(
  366. EmulatorAccessEntry->Routine,
  367. VdmIoHandler->IoFunctions[1].UshortStringIo[(PortNumber & 2) >> 1],
  368. ("Psp386RemoveIoHandler : UshortString fns don't match\n")
  369. );
  370. VdmIoHandler->IoFunctions[1].UshortStringIo[(PortNumber & 2) >> 1] = NULL;
  371. } else {
  372. ASSERTEQUAL(
  373. EmulatorAccessEntry->Routine,
  374. VdmIoHandler->IoFunctions[1].UshortIo[(PortNumber & 2) >> 1],
  375. ("Psp386RemoveIoHandler : Ushort fns don't match\n")
  376. );
  377. VdmIoHandler->IoFunctions[1].UshortIo[(PortNumber & 2) >> 1] = NULL;
  378. }
  379. break;
  380. case Ulong:
  381. if (EmulatorAccessEntry->StringSupport) {
  382. ASSERTEQUAL(
  383. EmulatorAccessEntry->Routine,
  384. VdmIoHandler->IoFunctions[1].UlongStringIo,
  385. ("Psp386RemoveIoHandler : UlongString fns don't match\n")
  386. );
  387. VdmIoHandler->IoFunctions[1].UlongStringIo = NULL;
  388. } else {
  389. ASSERTEQUAL(
  390. EmulatorAccessEntry->Routine,
  391. VdmIoHandler->IoFunctions[1].UlongIo,
  392. ("Psp386RemoveIoHandler : Ulong fns don't match\n")
  393. );
  394. VdmIoHandler->IoFunctions[1].UlongIo = NULL;
  395. }
  396. break;
  397. }
  398. }
  399. ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource);
  400. KeLowerIrql(OldIrql);
  401. return STATUS_SUCCESS;
  402. }
  403. NTSTATUS
  404. Psp386InstallIoHandler(
  405. IN PEPROCESS Process,
  406. IN PEMULATOR_ACCESS_ENTRY EmulatorAccessEntry,
  407. IN ULONG PortNumber,
  408. IN ULONG Context
  409. )
  410. /*++
  411. Routine Description:
  412. This routine install a handler for a port. On debug version, it will
  413. print a message if there is already a handler.
  414. Arguments:
  415. Process -- Supplies a pointer to the process
  416. EmulatorAccess -- Supplies a pointer to the information about the
  417. io port handler
  418. PortNumber -- Supplies the port number to install the handler for.
  419. Return Value:
  420. --*/
  421. {
  422. PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects;
  423. PVDM_IO_HANDLER VdmIoHandler;
  424. NTSTATUS Status;
  425. KIRQL OldIrql;
  426. PAGED_CODE();
  427. //
  428. // Ensure we have a vdm process which is initialized
  429. // correctly for VdmIoHandlers
  430. //
  431. if (!pVdmObjects) {
  432. #if DBG
  433. DbgPrint("Psp386InstallIoHandler: uninitialized VdmObjects\n");
  434. #endif
  435. return STATUS_UNSUCCESSFUL;
  436. }
  437. Status = STATUS_SUCCESS;
  438. //
  439. // If this is the first handler to be installed, create the list head,
  440. // and initialize the resource lock.
  441. //
  442. if (!pVdmObjects->VdmIoListHead) {
  443. Status = Psp386CreateVdmIoListHead(
  444. Process
  445. );
  446. if (!NT_SUCCESS(Status)) {
  447. return Status;
  448. }
  449. }
  450. //
  451. // Lock the list to insure correct update.
  452. //
  453. KeRaiseIrql(APC_LEVEL, &OldIrql);
  454. ExAcquireResourceExclusiveLite(&pVdmObjects->VdmIoListHead->VdmIoResource,TRUE);
  455. //
  456. // Update Context
  457. //
  458. pVdmObjects->VdmIoListHead->Context = Context;
  459. VdmIoHandler = Psp386GetVdmIoHandler(
  460. Process,
  461. PortNumber & ~0x3
  462. );
  463. // If there isn't already a node for this block of ports,
  464. // attempt to allocate a new one.
  465. //
  466. if (!VdmIoHandler) {
  467. try {
  468. VdmIoHandler = ExAllocatePoolWithQuota(
  469. PagedPool,
  470. sizeof(VDM_IO_HANDLER)
  471. );
  472. } except(EXCEPTION_EXECUTE_HANDLER) {
  473. Status = GetExceptionCode();
  474. if (VdmIoHandler) {
  475. ExFreePool(VdmIoHandler);
  476. }
  477. }
  478. if (!NT_SUCCESS(Status)) {
  479. ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource);
  480. KeLowerIrql(OldIrql);
  481. return Status;
  482. }
  483. RtlZeroMemory(VdmIoHandler, sizeof(VDM_IO_HANDLER));
  484. VdmIoHandler->PortNumber = PortNumber & ~0x3;
  485. Status = Psp386InsertVdmIoHandlerBlock(
  486. Process,
  487. VdmIoHandler
  488. );
  489. if (!NT_SUCCESS(Status)) {
  490. ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource);
  491. KeLowerIrql(OldIrql);
  492. return Status;
  493. }
  494. }
  495. ASSERTEQUALBREAK(
  496. VdmIoHandler->PortNumber,
  497. (PortNumber & ~0x3),
  498. ("Psp386InstallIoHandler : Bad pointer returned from GetVdmIoHandler\n")
  499. );
  500. if (EmulatorAccessEntry->AccessMode & EMULATOR_READ_ACCESS) {
  501. switch (EmulatorAccessEntry->AccessType) {
  502. case Uchar:
  503. if (EmulatorAccessEntry->StringSupport) {
  504. ASSERTEQUALBREAK(
  505. NULL,
  506. VdmIoHandler->IoFunctions[0].UcharStringIo[PortNumber % 4],
  507. ("Psp386InstallIoHandler : UcharString fns don't match\n")
  508. );
  509. VdmIoHandler->IoFunctions[0].UcharStringIo[PortNumber % 4] =
  510. (PDRIVER_IO_PORT_UCHAR_STRING)EmulatorAccessEntry->Routine;
  511. } else {
  512. ASSERTEQUALBREAK(
  513. NULL,
  514. VdmIoHandler->IoFunctions[0].UcharIo[PortNumber % 4],
  515. ("Psp386InstallIoHandler : Uchar fns don't match\n")
  516. );
  517. VdmIoHandler->IoFunctions[0].UcharIo[PortNumber % 4] =
  518. (PDRIVER_IO_PORT_UCHAR)EmulatorAccessEntry->Routine;
  519. }
  520. break;
  521. case Ushort:
  522. if (EmulatorAccessEntry->StringSupport) {
  523. ASSERTEQUALBREAK(
  524. NULL,
  525. VdmIoHandler->IoFunctions[0].UshortStringIo[(PortNumber & 2) >> 1],
  526. ("Psp386InstallIoHandler : UshortString fns don't match\n")
  527. );
  528. VdmIoHandler->IoFunctions[0].UshortStringIo[(PortNumber & 2) >> 1] =
  529. (PDRIVER_IO_PORT_USHORT_STRING)EmulatorAccessEntry->Routine;
  530. } else {
  531. ASSERTEQUALBREAK(
  532. NULL,
  533. VdmIoHandler->IoFunctions[0].UshortIo[(PortNumber & 2) >> 1],
  534. ("Psp386InstallIoHandler : Ushort fns don't match\n")
  535. );
  536. VdmIoHandler->IoFunctions[0].UshortIo[(PortNumber & 2) >> 1] =
  537. (PDRIVER_IO_PORT_USHORT)EmulatorAccessEntry->Routine;
  538. }
  539. break;
  540. case Ulong:
  541. if (EmulatorAccessEntry->StringSupport) {
  542. ASSERTEQUALBREAK(
  543. NULL,
  544. VdmIoHandler->IoFunctions[0].UlongStringIo,
  545. ("Psp386InstallIoHandler : UlongString fns don't match\n")
  546. );
  547. VdmIoHandler->IoFunctions[0].UlongStringIo =
  548. (PDRIVER_IO_PORT_ULONG_STRING)EmulatorAccessEntry->Routine;
  549. } else {
  550. ASSERTEQUALBREAK(
  551. NULL,
  552. VdmIoHandler->IoFunctions[0].UlongIo,
  553. ("Psp386InstallIoHandler : Ulong fns don't match\n")
  554. );
  555. VdmIoHandler->IoFunctions[0].UlongIo =
  556. (PDRIVER_IO_PORT_ULONG)EmulatorAccessEntry->Routine;
  557. }
  558. break;
  559. }
  560. }
  561. if (EmulatorAccessEntry->AccessMode & EMULATOR_WRITE_ACCESS) {
  562. switch (EmulatorAccessEntry->AccessType) {
  563. case Uchar:
  564. if (EmulatorAccessEntry->StringSupport) {
  565. ASSERTEQUALBREAK(
  566. NULL,
  567. VdmIoHandler->IoFunctions[1].UcharStringIo[PortNumber % 4],
  568. ("Psp386InstallIoHandler : UcharString fns don't match\n")
  569. );
  570. VdmIoHandler->IoFunctions[1].UcharStringIo[PortNumber % 4] =
  571. (PDRIVER_IO_PORT_UCHAR_STRING)EmulatorAccessEntry->Routine;
  572. } else {
  573. ASSERTEQUALBREAK(
  574. NULL,
  575. VdmIoHandler->IoFunctions[1].UcharIo[PortNumber % 4],
  576. ("Psp386InstallIoHandler : Uchar fns don't match\n")
  577. );
  578. VdmIoHandler->IoFunctions[1].UcharIo[PortNumber % 4] =
  579. (PDRIVER_IO_PORT_UCHAR)EmulatorAccessEntry->Routine;
  580. }
  581. break;
  582. case Ushort:
  583. if (EmulatorAccessEntry->StringSupport) {
  584. ASSERTEQUALBREAK(
  585. NULL,
  586. VdmIoHandler->IoFunctions[1].UshortStringIo[(PortNumber & 2) >> 1],
  587. ("Psp386InstallIoHandler : UshortString fns don't match\n")
  588. );
  589. VdmIoHandler->IoFunctions[1].UshortStringIo[(PortNumber & 2) >> 1] =
  590. (PDRIVER_IO_PORT_USHORT_STRING)EmulatorAccessEntry->Routine;
  591. } else {
  592. ASSERTEQUALBREAK(
  593. NULL,
  594. VdmIoHandler->IoFunctions[1].UshortIo[(PortNumber & 2) >> 1],
  595. ("Psp386InstallIoHandler : Ushort fns don't match\n")
  596. );
  597. VdmIoHandler->IoFunctions[1].UshortIo[(PortNumber & 2) >> 1] =
  598. (PDRIVER_IO_PORT_USHORT)EmulatorAccessEntry->Routine;
  599. }
  600. break;
  601. case Ulong:
  602. if (EmulatorAccessEntry->StringSupport) {
  603. ASSERTEQUALBREAK(
  604. NULL,
  605. VdmIoHandler->IoFunctions[1].UlongStringIo,
  606. ("Psp386InstallIoHandler : UlongString fns don't match\n")
  607. );
  608. VdmIoHandler->IoFunctions[1].UlongStringIo =
  609. (PDRIVER_IO_PORT_ULONG_STRING)EmulatorAccessEntry->Routine;
  610. } else {
  611. ASSERTEQUALBREAK(
  612. NULL,
  613. VdmIoHandler->IoFunctions[1].UlongIo,
  614. ("Psp386InstallIoHandler : Ulong fns don't match\n")
  615. );
  616. VdmIoHandler->IoFunctions[1].UlongIo =
  617. (PDRIVER_IO_PORT_ULONG)EmulatorAccessEntry->Routine;
  618. }
  619. }
  620. }
  621. ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource);
  622. KeLowerIrql(OldIrql);
  623. return STATUS_SUCCESS;
  624. }
  625. NTSTATUS
  626. Psp386CreateVdmIoListHead(
  627. IN PEPROCESS Process
  628. )
  629. /*++
  630. Routine Description:
  631. This routine creates the head node of the Io handler list. This node
  632. contains the spin lock that protects the list. This routine also
  633. initializes the spin lock.
  634. Arguments:
  635. Process -- Supplies a pointer to the process
  636. Return Value:
  637. Notes:
  638. --*/
  639. {
  640. PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects;
  641. NTSTATUS Status;
  642. PVDM_IO_LISTHEAD HandlerListHead=NULL;
  643. KIRQL OldIrql;
  644. PAGED_CODE();
  645. Status = STATUS_SUCCESS;
  646. // if there isn't yet a head, grab the resource lock and create one
  647. if (pVdmObjects->VdmIoListHead == NULL) {
  648. KeRaiseIrql(APC_LEVEL, &OldIrql);
  649. ExAcquireResourceExclusiveLite(&VdmIoListCreationResource, TRUE);
  650. // if no head was created while we grabbed the spin lock
  651. if (pVdmObjects->VdmIoListHead == NULL) {
  652. try {
  653. // allocate space for the list head
  654. // and charge the quota for it
  655. HandlerListHead = ExAllocatePoolWithQuota(
  656. NonPagedPool,
  657. sizeof(VDM_IO_LISTHEAD)
  658. );
  659. } except(EXCEPTION_EXECUTE_HANDLER) {
  660. Status = GetExceptionCode();
  661. if (HandlerListHead) {
  662. ExFreePool(HandlerListHead);
  663. }
  664. }
  665. if ((!NT_SUCCESS(Status) || !HandlerListHead)) {
  666. ExReleaseResourceLite(&VdmIoListCreationResource);
  667. KeLowerIrql(OldIrql);
  668. return (Status == STATUS_SUCCESS ?
  669. STATUS_INSUFFICIENT_RESOURCES :
  670. Status);
  671. }
  672. ExInitializeResourceLite(&HandlerListHead->VdmIoResource);
  673. HandlerListHead->VdmIoHandlerList = NULL;
  674. //
  675. // Attach the list head to the process
  676. // and attach the handler to the list.
  677. // Since this was a new list
  678. pVdmObjects->VdmIoListHead = HandlerListHead;
  679. ExReleaseResourceLite(&VdmIoListCreationResource);
  680. KeLowerIrql(OldIrql);
  681. }
  682. }
  683. return STATUS_SUCCESS;
  684. }
  685. NTSTATUS
  686. Psp386InsertVdmIoHandlerBlock(
  687. IN PEPROCESS Process,
  688. IN PVDM_IO_HANDLER VdmIoHandler
  689. )
  690. /*++
  691. Routine Description:
  692. This routine inserts a new VdmIoHandler block into the process's io
  693. handler list.
  694. Arguments:
  695. Process -- Supplies a pointer to the process
  696. VdmIoHandler -- Supplies a pointer to the block to insert.
  697. Return Value:
  698. --*/
  699. {
  700. PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects;
  701. PVDM_IO_HANDLER HandlerList, p;
  702. PVDM_IO_LISTHEAD HandlerListHead;
  703. PAGED_CODE();
  704. HandlerListHead = pVdmObjects->VdmIoListHead;
  705. HandlerList = HandlerListHead->VdmIoHandlerList;
  706. p = NULL;
  707. while ((HandlerList != NULL) &&
  708. (HandlerList->PortNumber < VdmIoHandler->PortNumber)) {
  709. #if DBG
  710. if (HandlerList->PortNumber == VdmIoHandler->PortNumber) {
  711. DbgPrint("Ps386InsertVdmIoHandlerBlock : handler list corrupt\n");
  712. }
  713. #endif
  714. p = HandlerList;
  715. HandlerList = HandlerList->Next;
  716. }
  717. if (p == NULL) { // Beginning of list
  718. VdmIoHandler->Next = HandlerListHead->VdmIoHandlerList;
  719. HandlerListHead->VdmIoHandlerList = VdmIoHandler;
  720. } else if (HandlerList == NULL) { // End of list
  721. p->Next = VdmIoHandler;
  722. VdmIoHandler->Next = NULL;
  723. } else { // Middle of list
  724. VdmIoHandler->Next = HandlerList;
  725. p->Next = VdmIoHandler;
  726. }
  727. return STATUS_SUCCESS;
  728. }
  729. BOOLEAN
  730. Ps386GetVdmIoHandler(
  731. IN PEPROCESS Process,
  732. IN ULONG PortNumber,
  733. OUT PVDM_IO_HANDLER VdmIoHandler,
  734. OUT PULONG Context
  735. )
  736. /*++
  737. Routine Description:
  738. This routine finds the VdmIoHandler block for the specified port.
  739. Arguments:
  740. Process -- Supplies a pointer to the process
  741. PortNumber -- Supplies the port number
  742. VdmIoHandler -- Supplies a pointer to the destination for the lookup
  743. Returns:
  744. True -- A handler structure was found and copied
  745. False -- A handler structure was not found
  746. --*/
  747. {
  748. PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects;
  749. PVDM_IO_HANDLER p;
  750. BOOLEAN Success;
  751. KIRQL OldIrql;
  752. PAGED_CODE();
  753. if (pVdmObjects == NULL) {
  754. return FALSE;
  755. }
  756. if (PortNumber % 4) {
  757. #if DBG
  758. DbgPrint(
  759. "Ps386GetVdmIoHandler : Invalid Port Number %lx\n",
  760. PortNumber
  761. );
  762. #endif
  763. return FALSE;
  764. }
  765. if (!pVdmObjects->VdmIoListHead) {
  766. return FALSE;
  767. }
  768. KeRaiseIrql(APC_LEVEL, &OldIrql);
  769. ExAcquireResourceExclusiveLite(&pVdmObjects->VdmIoListHead->VdmIoResource,TRUE);
  770. p = Psp386GetVdmIoHandler(
  771. Process,
  772. PortNumber
  773. );
  774. if (p) {
  775. *VdmIoHandler = *p;
  776. *Context = pVdmObjects->VdmIoListHead->Context;
  777. Success = TRUE;
  778. } else {
  779. Success = FALSE;
  780. }
  781. ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource);
  782. KeLowerIrql(OldIrql);
  783. return Success;
  784. }
  785. PVDM_IO_HANDLER
  786. Psp386GetVdmIoHandler(
  787. IN PEPROCESS Process,
  788. IN ULONG PortNumber
  789. )
  790. /*++
  791. Routine Description:
  792. This routine finds the VdmIoHandler block for the specified port.
  793. Arguments:
  794. Process -- Supplies a pointer to the process
  795. PortNumber -- Supplies the port number
  796. Returns:
  797. NULL if no handler found
  798. non-NULL if handler found
  799. --*/
  800. {
  801. PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects;
  802. PVDM_IO_HANDLER p;
  803. PAGED_CODE();
  804. if (PortNumber % 4) {
  805. #if DBG
  806. DbgPrint(
  807. "Ps386GetVdmIoHandler : Invalid Port Number %lx\n",
  808. PortNumber
  809. );
  810. #endif
  811. return NULL;
  812. }
  813. p = pVdmObjects->VdmIoListHead->VdmIoHandlerList;
  814. while ((p) && (p->PortNumber != PortNumber)) {
  815. p = p->Next;
  816. }
  817. return p;
  818. }
  819. NTSTATUS
  820. PspVdmInitialize(
  821. )
  822. /*++
  823. Routine Description:
  824. This routine initializes the process based Vdm support for x86.
  825. Arguments:
  826. None
  827. Return Value:
  828. TBS
  829. --*/
  830. {
  831. return ExInitializeResourceLite(&VdmIoListCreationResource);
  832. }
  833.