1027 lines
28 KiB
C
1027 lines
28 KiB
C
/*++
|
||
|
||
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);
|
||
}
|
||
|