/*++ Copyright (c) 1990 Microsoft Corporation Module Name: psldt.c Abstract: This module contains code for the io port handler support Author: Dave Hastings (daveh) 26 Jan 1991 Revision History: --*/ #include "psp.h" #if DBG #define ASSERTEQUAL(value1, value2, string) \ if ((ULONG)value1 != (ULONG)value2) { \ DbgPrint string ; \ } #define ASSERTEQUALBREAK(value1, value2, string)\ if ((ULONG)value1 != (ULONG)value2) { \ DbgPrint string ; \ DbgBreakPoint(); \ } #else #define ASSERTEQUAL(value1, value2, string) #define ASSERTEQUALBREAK(value1, value2, string) #endif // // Internal functions // NTSTATUS Psp386InstallIoHandler( IN PEPROCESS Process, IN PEMULATOR_ACCESS_ENTRY EmulatorAccessEntry, IN ULONG PortNumber, IN ULONG Context ); NTSTATUS Psp386RemoveIoHandler( IN PEPROCESS Process, IN PEMULATOR_ACCESS_ENTRY EmulatorAccessEntry, IN ULONG PortNumber ); NTSTATUS Psp386InsertVdmIoHandlerBlock( IN PEPROCESS Process, IN PVDM_IO_HANDLER VdmIoHandler ); PVDM_IO_HANDLER Psp386GetVdmIoHandler( IN PEPROCESS Process, IN ULONG PortNumber ); NTSTATUS Psp386CreateVdmIoListHead( IN PEPROCESS Process ); #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,PspVdmInitialize) #pragma alloc_text(PAGE,PspSetProcessIoHandlers) #pragma alloc_text(PAGE,Ps386GetVdmIoHandler) #pragma alloc_text(PAGE,Psp386RemoveIoHandler) #pragma alloc_text(PAGE,Psp386InstallIoHandler) #pragma alloc_text(PAGE,Psp386CreateVdmIoListHead) #pragma alloc_text(PAGE,Psp386InsertVdmIoHandlerBlock) #pragma alloc_text(PAGE,Psp386GetVdmIoHandler) #pragma alloc_text(PAGE,PspDeleteVdmObjects) #endif // // Resource to synchronize access to IoHandler list // ERESOURCE VdmIoListCreationResource; NTSTATUS PspSetProcessIoHandlers( IN PEPROCESS Process, IN PVOID IoHandlerInformation, IN ULONG IoHandlerLength ) /*++ Routine Description: This routine installs a device driver IO handling routine for the specified process. If an io operation is detected in a vdm on a port that has a device driver IO handling routine, that routine will be called. Arguments: Process -- Supplies a pointer to the process for which Io port handlers are to be installed IoHandlerInformation -- Supplies a pointer to the information about the io port handlers IoHandlerLength -- Supplies the length of the IoHandlerInformation structure. Return Value: --*/ { PPROCESS_IO_PORT_HANDLER_INFORMATION IoHandlerInfo; NTSTATUS Status; PEMULATOR_ACCESS_ENTRY EmulatorAccess; ULONG EmulatorEntryNumber, NumberPorts; ULONG PortSize; PAGED_CODE(); // // Insure that this call was made from KernelMode // if (KeGetPreviousMode() != KernelMode) { return STATUS_INVALID_PARAMETER; // this info type invalid in usermode } // // Insure that the data passed is long enough // if (IoHandlerLength < (ULONG)sizeof( PROCESS_IO_PORT_HANDLER_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; } IoHandlerInfo = IoHandlerInformation; // // For each of the entries in the array that describes the handlers, // determine what size of port the specified handler is being installed // for, and then iterate over each individual port. // for (EmulatorEntryNumber = 0, EmulatorAccess = IoHandlerInfo->EmulatorAccessEntries; EmulatorEntryNumber < IoHandlerInfo->NumEntries; EmulatorEntryNumber++, EmulatorAccess++) { switch (EmulatorAccess->AccessType) { case Uchar: PortSize = 1; break; case Ushort: PortSize = 2; break; case Ulong: default: PortSize = 4; } for (NumberPorts = 0; NumberPorts < EmulatorAccess->NumConsecutivePorts; NumberPorts++) { if (IoHandlerInfo->Install) { Status = Psp386InstallIoHandler( Process, EmulatorAccess, EmulatorAccess->BasePort + NumberPorts * PortSize, IoHandlerInfo->Context ); if (NT_SUCCESS(Status)) { } } else { Status = Psp386RemoveIoHandler( Process, EmulatorAccess, EmulatorAccess->BasePort + NumberPorts * PortSize ); } if (!NT_SUCCESS(Status)) { goto exitloop; } } } Status = STATUS_SUCCESS; exitloop: return Status; } VOID PspDeleteVdmObjects( IN PEPROCESS Process ) /*++ Routine Description: Frees the VdmObjects structure and the Frees the IoHandler list Arguments: Process -- Supplies a pointer to the process Return Value: None --*/ { SIZE_T PoolQuota; PVDM_PROCESS_OBJECTS pVdmObjects; PVDM_IO_HANDLER p1, p2; PVDM_IO_LISTHEAD p3; PLIST_ENTRY Next; PDELAYINTIRQ pDelayIntIrq; pVdmObjects = Process->VdmObjects; if (pVdmObjects == NULL) { return; } // // First Free any port handler entries for this process, // p1 = NULL; p3 = pVdmObjects->VdmIoListHead; if (p3) { p2 = p3->VdmIoHandlerList; while (p2) { p1 = p2; p2 = p1->Next; ExFreePool( p1 ); } ExDeleteResourceLite(&p3->VdmIoResource); ExFreePool( p3 ); pVdmObjects->VdmIoListHead = NULL; } if (pVdmObjects->pIcaUserData) { PsReturnProcessPagedPoolQuota (Process, sizeof(VDMICAUSERDATA)); ExFreePool(pVdmObjects->pIcaUserData); } // // Free up the DelayedIntList, spinlock protection is not needed because // object referencing on the process is being used instead. Meaning there // can be no outstanding timers because the process object reference // count would have to be nonzero. // PoolQuota = 0; Next = pVdmObjects->DelayIntListHead.Flink; while (Next != &pVdmObjects->DelayIntListHead) { pDelayIntIrq = CONTAINING_RECORD(Next, DELAYINTIRQ, DelayIntListEntry); Next = Next->Flink; RemoveEntryList (&pDelayIntIrq->DelayIntListEntry); ExFreePool (pDelayIntIrq); PoolQuota += sizeof(DELAYINTIRQ); } if (PoolQuota != 0) { PsReturnProcessNonPagedPoolQuota(Process, PoolQuota); } PsReturnProcessNonPagedPoolQuota (Process, sizeof(VDM_PROCESS_OBJECTS)); ExFreePool (pVdmObjects); Process->VdmObjects = NULL; } NTSTATUS Psp386RemoveIoHandler( IN PEPROCESS Process, IN PEMULATOR_ACCESS_ENTRY EmulatorAccessEntry, IN ULONG PortNumber ) /*++ Routine Description: This routine remove a handler for a port. On debug version, it will print a message if there is no handler. Arguments: Process -- Supplies a pointer to the process EmulatorAccess -- Supplies a pointer to the information about the io port handler PortNumber -- Supplies the port number to remove the handler from. Return Value: --*/ { PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects; PVDM_IO_HANDLER VdmIoHandler; KIRQL OldIrql; PAGED_CODE(); // // Ensure we have a vdm process which is initialized // correctly for VdmIoHandlers // if (!pVdmObjects) { #if DBG DbgPrint("Psp386RemoveIoHandler: uninitialized VdmObjects\n"); #endif return STATUS_UNSUCCESSFUL; } // // If the list does not have a head, then there are no handlers to // remove. // if (!pVdmObjects->VdmIoListHead) { #if DBG DbgPrint("Psp386RemoveIoHandler : attempt to remove non-existent hdlr\n"); #endif return STATUS_SUCCESS; } // // Lock the list, so we can insure a correct update. // KeRaiseIrql(APC_LEVEL, &OldIrql); ExAcquireResourceExclusiveLite(&pVdmObjects->VdmIoListHead->VdmIoResource,TRUE); VdmIoHandler = Psp386GetVdmIoHandler( Process, PortNumber & ~0x3 ); if (!VdmIoHandler) { #if DBG DbgPrint("Psp386RemoveIoHandler : attempt to remove non-existent hdlr\n"); #endif ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource); KeLowerIrql(OldIrql); return STATUS_SUCCESS; } ASSERTEQUALBREAK( VdmIoHandler->PortNumber, (PortNumber & ~0x3), ("Psp386RemoveIoHandler : Bad pointer returned from GetVdmIoHandler\n") ); if (EmulatorAccessEntry->AccessMode & EMULATOR_READ_ACCESS) { switch (EmulatorAccessEntry->AccessType) { case Uchar: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[0].UcharStringIo[PortNumber % 4], ("Psp386RemoveIoHandler : UcharString fns don't match\n") ); VdmIoHandler->IoFunctions[0].UcharStringIo[PortNumber % 4] = NULL; } else { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[0].UcharIo[PortNumber % 4], ("Psp386RemoveIoHandler : Uchar fns don't match\n") ); VdmIoHandler->IoFunctions[0].UcharIo[PortNumber % 4] = NULL; } break; case Ushort: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[0].UshortStringIo[(PortNumber & 2) >> 1], ("Psp386RemoveIoHandler : UshortString fns don't match\n") ); VdmIoHandler->IoFunctions[0].UshortStringIo[(PortNumber & 2) >> 1] = NULL; } else { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[0].UshortIo[(PortNumber & 2) >> 1], ("Psp386RemoveIoHandler : Ushort fns don't match\n") ); VdmIoHandler->IoFunctions[0].UshortIo[(PortNumber & 2) >> 1] = NULL; } break; case Ulong: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[0].UlongStringIo, ("Psp386RemoveIoHandler : UlongString fns don't match\n") ); VdmIoHandler->IoFunctions[0].UlongStringIo = NULL; } else { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[0].UlongIo, ("Psp386RemoveIoHandler : Ulong fns don't match\n") ); VdmIoHandler->IoFunctions[0].UlongIo = NULL; } break; } } if (EmulatorAccessEntry->AccessMode & EMULATOR_WRITE_ACCESS) { switch (EmulatorAccessEntry->AccessType) { case Uchar: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[1].UcharStringIo[PortNumber % 4], ("Psp386RemoveIoHandler : UcharString fns don't match\n") ); VdmIoHandler->IoFunctions[1].UcharStringIo[PortNumber % 4] = NULL; } else { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[1].UcharIo[PortNumber % 4], ("Psp386RemoveIoHandler : Uchar fns don't match\n") ); VdmIoHandler->IoFunctions[1].UcharIo[PortNumber % 4] = NULL; } break; case Ushort: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[1].UshortStringIo[(PortNumber & 2) >> 1], ("Psp386RemoveIoHandler : UshortString fns don't match\n") ); VdmIoHandler->IoFunctions[1].UshortStringIo[(PortNumber & 2) >> 1] = NULL; } else { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[1].UshortIo[(PortNumber & 2) >> 1], ("Psp386RemoveIoHandler : Ushort fns don't match\n") ); VdmIoHandler->IoFunctions[1].UshortIo[(PortNumber & 2) >> 1] = NULL; } break; case Ulong: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[1].UlongStringIo, ("Psp386RemoveIoHandler : UlongString fns don't match\n") ); VdmIoHandler->IoFunctions[1].UlongStringIo = NULL; } else { ASSERTEQUAL( EmulatorAccessEntry->Routine, VdmIoHandler->IoFunctions[1].UlongIo, ("Psp386RemoveIoHandler : Ulong fns don't match\n") ); VdmIoHandler->IoFunctions[1].UlongIo = NULL; } break; } } ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource); KeLowerIrql(OldIrql); return STATUS_SUCCESS; } NTSTATUS Psp386InstallIoHandler( IN PEPROCESS Process, IN PEMULATOR_ACCESS_ENTRY EmulatorAccessEntry, IN ULONG PortNumber, IN ULONG Context ) /*++ Routine Description: This routine install a handler for a port. On debug version, it will print a message if there is already a handler. Arguments: Process -- Supplies a pointer to the process EmulatorAccess -- Supplies a pointer to the information about the io port handler PortNumber -- Supplies the port number to install the handler for. Return Value: --*/ { PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects; PVDM_IO_HANDLER VdmIoHandler; NTSTATUS Status; KIRQL OldIrql; PAGED_CODE(); // // Ensure we have a vdm process which is initialized // correctly for VdmIoHandlers // if (!pVdmObjects) { #if DBG DbgPrint("Psp386InstallIoHandler: uninitialized VdmObjects\n"); #endif return STATUS_UNSUCCESSFUL; } Status = STATUS_SUCCESS; // // If this is the first handler to be installed, create the list head, // and initialize the resource lock. // if (!pVdmObjects->VdmIoListHead) { Status = Psp386CreateVdmIoListHead( Process ); if (!NT_SUCCESS(Status)) { return Status; } } // // Lock the list to insure correct update. // KeRaiseIrql(APC_LEVEL, &OldIrql); ExAcquireResourceExclusiveLite(&pVdmObjects->VdmIoListHead->VdmIoResource,TRUE); // // Update Context // pVdmObjects->VdmIoListHead->Context = Context; VdmIoHandler = Psp386GetVdmIoHandler( Process, PortNumber & ~0x3 ); // If there isn't already a node for this block of ports, // attempt to allocate a new one. // if (!VdmIoHandler) { try { VdmIoHandler = ExAllocatePoolWithQuota( PagedPool, sizeof(VDM_IO_HANDLER) ); } except(EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); if (VdmIoHandler) { ExFreePool(VdmIoHandler); } } if (!NT_SUCCESS(Status)) { ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource); KeLowerIrql(OldIrql); return Status; } RtlZeroMemory(VdmIoHandler, sizeof(VDM_IO_HANDLER)); VdmIoHandler->PortNumber = PortNumber & ~0x3; Status = Psp386InsertVdmIoHandlerBlock( Process, VdmIoHandler ); if (!NT_SUCCESS(Status)) { ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource); KeLowerIrql(OldIrql); return Status; } } ASSERTEQUALBREAK( VdmIoHandler->PortNumber, (PortNumber & ~0x3), ("Psp386InstallIoHandler : Bad pointer returned from GetVdmIoHandler\n") ); if (EmulatorAccessEntry->AccessMode & EMULATOR_READ_ACCESS) { switch (EmulatorAccessEntry->AccessType) { case Uchar: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[0].UcharStringIo[PortNumber % 4], ("Psp386InstallIoHandler : UcharString fns don't match\n") ); VdmIoHandler->IoFunctions[0].UcharStringIo[PortNumber % 4] = (PDRIVER_IO_PORT_UCHAR_STRING)EmulatorAccessEntry->Routine; } else { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[0].UcharIo[PortNumber % 4], ("Psp386InstallIoHandler : Uchar fns don't match\n") ); VdmIoHandler->IoFunctions[0].UcharIo[PortNumber % 4] = (PDRIVER_IO_PORT_UCHAR)EmulatorAccessEntry->Routine; } break; case Ushort: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[0].UshortStringIo[(PortNumber & 2) >> 1], ("Psp386InstallIoHandler : UshortString fns don't match\n") ); VdmIoHandler->IoFunctions[0].UshortStringIo[(PortNumber & 2) >> 1] = (PDRIVER_IO_PORT_USHORT_STRING)EmulatorAccessEntry->Routine; } else { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[0].UshortIo[(PortNumber & 2) >> 1], ("Psp386InstallIoHandler : Ushort fns don't match\n") ); VdmIoHandler->IoFunctions[0].UshortIo[(PortNumber & 2) >> 1] = (PDRIVER_IO_PORT_USHORT)EmulatorAccessEntry->Routine; } break; case Ulong: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[0].UlongStringIo, ("Psp386InstallIoHandler : UlongString fns don't match\n") ); VdmIoHandler->IoFunctions[0].UlongStringIo = (PDRIVER_IO_PORT_ULONG_STRING)EmulatorAccessEntry->Routine; } else { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[0].UlongIo, ("Psp386InstallIoHandler : Ulong fns don't match\n") ); VdmIoHandler->IoFunctions[0].UlongIo = (PDRIVER_IO_PORT_ULONG)EmulatorAccessEntry->Routine; } break; } } if (EmulatorAccessEntry->AccessMode & EMULATOR_WRITE_ACCESS) { switch (EmulatorAccessEntry->AccessType) { case Uchar: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[1].UcharStringIo[PortNumber % 4], ("Psp386InstallIoHandler : UcharString fns don't match\n") ); VdmIoHandler->IoFunctions[1].UcharStringIo[PortNumber % 4] = (PDRIVER_IO_PORT_UCHAR_STRING)EmulatorAccessEntry->Routine; } else { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[1].UcharIo[PortNumber % 4], ("Psp386InstallIoHandler : Uchar fns don't match\n") ); VdmIoHandler->IoFunctions[1].UcharIo[PortNumber % 4] = (PDRIVER_IO_PORT_UCHAR)EmulatorAccessEntry->Routine; } break; case Ushort: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[1].UshortStringIo[(PortNumber & 2) >> 1], ("Psp386InstallIoHandler : UshortString fns don't match\n") ); VdmIoHandler->IoFunctions[1].UshortStringIo[(PortNumber & 2) >> 1] = (PDRIVER_IO_PORT_USHORT_STRING)EmulatorAccessEntry->Routine; } else { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[1].UshortIo[(PortNumber & 2) >> 1], ("Psp386InstallIoHandler : Ushort fns don't match\n") ); VdmIoHandler->IoFunctions[1].UshortIo[(PortNumber & 2) >> 1] = (PDRIVER_IO_PORT_USHORT)EmulatorAccessEntry->Routine; } break; case Ulong: if (EmulatorAccessEntry->StringSupport) { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[1].UlongStringIo, ("Psp386InstallIoHandler : UlongString fns don't match\n") ); VdmIoHandler->IoFunctions[1].UlongStringIo = (PDRIVER_IO_PORT_ULONG_STRING)EmulatorAccessEntry->Routine; } else { ASSERTEQUALBREAK( NULL, VdmIoHandler->IoFunctions[1].UlongIo, ("Psp386InstallIoHandler : Ulong fns don't match\n") ); VdmIoHandler->IoFunctions[1].UlongIo = (PDRIVER_IO_PORT_ULONG)EmulatorAccessEntry->Routine; } } } ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource); KeLowerIrql(OldIrql); return STATUS_SUCCESS; } NTSTATUS Psp386CreateVdmIoListHead( IN PEPROCESS Process ) /*++ Routine Description: This routine creates the head node of the Io handler list. This node contains the spin lock that protects the list. This routine also initializes the spin lock. Arguments: Process -- Supplies a pointer to the process Return Value: Notes: --*/ { PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects; NTSTATUS Status; PVDM_IO_LISTHEAD HandlerListHead=NULL; KIRQL OldIrql; PAGED_CODE(); Status = STATUS_SUCCESS; // if there isn't yet a head, grab the resource lock and create one if (pVdmObjects->VdmIoListHead == NULL) { KeRaiseIrql(APC_LEVEL, &OldIrql); ExAcquireResourceExclusiveLite(&VdmIoListCreationResource, TRUE); // if no head was created while we grabbed the spin lock if (pVdmObjects->VdmIoListHead == NULL) { try { // allocate space for the list head // and charge the quota for it HandlerListHead = ExAllocatePoolWithQuota( NonPagedPool, sizeof(VDM_IO_LISTHEAD) ); } except(EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); if (HandlerListHead) { ExFreePool(HandlerListHead); } } if ((!NT_SUCCESS(Status) || !HandlerListHead)) { ExReleaseResourceLite(&VdmIoListCreationResource); KeLowerIrql(OldIrql); return (Status == STATUS_SUCCESS ? STATUS_INSUFFICIENT_RESOURCES : Status); } ExInitializeResourceLite(&HandlerListHead->VdmIoResource); HandlerListHead->VdmIoHandlerList = NULL; // // Attach the list head to the process // and attach the handler to the list. // Since this was a new list pVdmObjects->VdmIoListHead = HandlerListHead; ExReleaseResourceLite(&VdmIoListCreationResource); KeLowerIrql(OldIrql); } } return STATUS_SUCCESS; } NTSTATUS Psp386InsertVdmIoHandlerBlock( IN PEPROCESS Process, IN PVDM_IO_HANDLER VdmIoHandler ) /*++ Routine Description: This routine inserts a new VdmIoHandler block into the process's io handler list. Arguments: Process -- Supplies a pointer to the process VdmIoHandler -- Supplies a pointer to the block to insert. Return Value: --*/ { PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects; PVDM_IO_HANDLER HandlerList, p; PVDM_IO_LISTHEAD HandlerListHead; PAGED_CODE(); HandlerListHead = pVdmObjects->VdmIoListHead; HandlerList = HandlerListHead->VdmIoHandlerList; p = NULL; while ((HandlerList != NULL) && (HandlerList->PortNumber < VdmIoHandler->PortNumber)) { #if DBG if (HandlerList->PortNumber == VdmIoHandler->PortNumber) { DbgPrint("Ps386InsertVdmIoHandlerBlock : handler list corrupt\n"); } #endif p = HandlerList; HandlerList = HandlerList->Next; } if (p == NULL) { // Beginning of list VdmIoHandler->Next = HandlerListHead->VdmIoHandlerList; HandlerListHead->VdmIoHandlerList = VdmIoHandler; } else if (HandlerList == NULL) { // End of list p->Next = VdmIoHandler; VdmIoHandler->Next = NULL; } else { // Middle of list VdmIoHandler->Next = HandlerList; p->Next = VdmIoHandler; } return STATUS_SUCCESS; } BOOLEAN Ps386GetVdmIoHandler( IN PEPROCESS Process, IN ULONG PortNumber, OUT PVDM_IO_HANDLER VdmIoHandler, OUT PULONG Context ) /*++ Routine Description: This routine finds the VdmIoHandler block for the specified port. Arguments: Process -- Supplies a pointer to the process PortNumber -- Supplies the port number VdmIoHandler -- Supplies a pointer to the destination for the lookup Returns: True -- A handler structure was found and copied False -- A handler structure was not found --*/ { PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects; PVDM_IO_HANDLER p; BOOLEAN Success; KIRQL OldIrql; PAGED_CODE(); if (pVdmObjects == NULL) { return FALSE; } if (PortNumber % 4) { #if DBG DbgPrint( "Ps386GetVdmIoHandler : Invalid Port Number %lx\n", PortNumber ); #endif return FALSE; } if (!pVdmObjects->VdmIoListHead) { return FALSE; } KeRaiseIrql(APC_LEVEL, &OldIrql); ExAcquireResourceExclusiveLite(&pVdmObjects->VdmIoListHead->VdmIoResource,TRUE); p = Psp386GetVdmIoHandler( Process, PortNumber ); if (p) { *VdmIoHandler = *p; *Context = pVdmObjects->VdmIoListHead->Context; Success = TRUE; } else { Success = FALSE; } ExReleaseResourceLite(&pVdmObjects->VdmIoListHead->VdmIoResource); KeLowerIrql(OldIrql); return Success; } PVDM_IO_HANDLER Psp386GetVdmIoHandler( IN PEPROCESS Process, IN ULONG PortNumber ) /*++ Routine Description: This routine finds the VdmIoHandler block for the specified port. Arguments: Process -- Supplies a pointer to the process PortNumber -- Supplies the port number Returns: NULL if no handler found non-NULL if handler found --*/ { PVDM_PROCESS_OBJECTS pVdmObjects = Process->VdmObjects; PVDM_IO_HANDLER p; PAGED_CODE(); if (PortNumber % 4) { #if DBG DbgPrint( "Ps386GetVdmIoHandler : Invalid Port Number %lx\n", PortNumber ); #endif return NULL; } p = pVdmObjects->VdmIoListHead->VdmIoHandlerList; while ((p) && (p->PortNumber != PortNumber)) { p = p->Next; } return p; } NTSTATUS PspVdmInitialize( ) /*++ Routine Description: This routine initializes the process based Vdm support for x86. Arguments: None Return Value: TBS --*/ { return ExInitializeResourceLite(&VdmIoListCreationResource); }