📄 comem.c
字号:
//////////////////////////////////////////////////////////////////////
CONFIGRET GetPCIConfigData(
DEVNODE Devnode,
DWORD StartByteOffset,
DWORD* ConfigDataBuffer,
ULONG nBytes)
{
return
CONFIGMG_Call_Enumerator_Function(
Devnode,
PCI_ENUM_FUNC_GET_DEVICE_INFO,
StartByteOffset,
ConfigDataBuffer,
nBytes,
0);
}
//////////////////////////////////////////////////////////////////////
CONFIGRET SetPCIConfigData(
DEVNODE Devnode,
DWORD StartByteOffset,
DWORD* ConfigDataBuffer,
ULONG nBytes)
{
return
CONFIGMG_Call_Enumerator_Function(
Devnode,
PCI_ENUM_FUNC_SET_DEVICE_INFO,
StartByteOffset,
ConfigDataBuffer,
nBytes,
0);
}
// Create an entry for the comemDev array.
// Returns:
// Pointer to allocated memory, NULL if couldn't allocate.
comemDevStruct * comemDevStructConstructor()
{
int i;
comemDevStruct *retPtr = _HeapAllocate(sizeof(comemDevStruct), HEAPZEROINIT);
if (!retPtr)
return(retPtr);
// Initialize our variables
// retPtr->fragCount = 0; done by HEAPZEROINIT
// retPtr->allocatedBlocks = NULL; done by HEAPZEROINIT
// retPtr->linBAR[xx] = NULL; done by HEAPZEROINIT
return(retPtr);
}
// Return the PCI config block for the specified device
void COMEM_Get_PCICfg( PIOCTLPARAMS p )
{
WORD DeviceId;
WORD VendorId;
DWORD comemID;
DEVNODE dn[COMEM_MAX_DEVICES];
CONFIGRET status;
PCI_CONFIG_HEADER_0 *pcicfg;
int count;
GetPciCfgIn *inptr = p->dioc_InBuf;
GetPciCfgOut *outptr = p->dioc_OutBuf;
comemID = inptr->ComemId;
pcicfg = (PCI_CONFIG_HEADER_0*)p->dioc_OutBuf;
*p->dioc_bytesret = 0;
if (comemID > COMEM_MAX_DEVICES)
{
outptr->status = ERROR_INVALID_COMEM_ID;
return;
}
if (!comemDev[comemID])
{
outptr->status = ERROR_INVALID_COMEM_ID;
return;
}
status = GetPCIConfigData(comemDev[comemID]->devNode, 0, (ULONG*)pcicfg, sizeof(PCI_CONFIG_HEADER_0));
if (status != CR_SUCCESS)
{
comemDev[comemID]->pcicfg.VendorID = comemDev[comemID]->pcicfg.DeviceID = 0;
outptr->status = ERROR_DEVICE_NOT_FOUND;
return;
}
else
{
*p->dioc_bytesret = sizeof(GetPciCfgOut);
memcpy(&comemDev[comemID]->pcicfg, pcicfg, sizeof(PCI_CONFIG_HEADER_0));
}
outptr->status = NO_ERROR;
}
// Return the PCI config block for the specified device
void COMEM_Set_PCICfg( PIOCTLPARAMS p )
{
SetPciCfgIn *inptr = p->dioc_InBuf;
SetPciCfgOut *outptr = p->dioc_OutBuf;
DWORD comemID;
DEVNODE dn[COMEM_MAX_DEVICES];
CONFIGRET status;
PCI_CONFIG_HEADER_0 *pcicfg;
int count;
comemID = ((SetPciCfgIn*)(p->dioc_InBuf))->ComemID;
pcicfg = (PCI_CONFIG_HEADER_0*)p->dioc_InBuf;
*p->dioc_bytesret = 4;
if (comemID > COMEM_MAX_DEVICES)
{
*p->dioc_bytesret = 4;
outptr->status = ERROR_INVALID_COMEM_ID;
return;
}
if (!comemDev[comemID])
{
*p->dioc_bytesret = 4;
outptr->status = ERROR_INVALID_COMEM_ID;
return;
}
status = SetPCIConfigData(comemDev[comemID]->devNode, 0, (ULONG*)pcicfg, sizeof(PCI_CONFIG_HEADER_0));
if (status != CR_SUCCESS)
{
comemDev[comemID]->pcicfg.VendorID = comemDev[comemID]->pcicfg.DeviceID = 0;
}
outptr->status = NO_ERROR;
}
void COMEM_CreateBarPtr(PIOCTLPARAMS p)
{
int i;
DWORD comemID;
DWORD status;
PCI_CONFIG_HEADER_0 pcicfg;
CreateBarPtrIn *inptr = p->dioc_InBuf;
CreateBarPtrOut *outptr = p->dioc_OutBuf;
comemID = inptr->comemID;
if (comemID > COMEM_MAX_DEVICES)
{
*p->dioc_bytesret = 4;
outptr->status = ERROR_INVALID_COMEM_ID;
return;
}
if (!comemDev[comemID])
{
*p->dioc_bytesret = 4;
outptr->status = ERROR_INVALID_COMEM_ID;
return;
}
status = GetPCIConfigData(comemDev[comemID]->devNode, 0, (ULONG*)&pcicfg, sizeof(PCI_CONFIG_HEADER_0));
if (status != CR_SUCCESS)
{
comemDev[comemID]->pcicfg.VendorID = comemDev[comemID]->pcicfg.DeviceID = 0;
outptr->status = ERROR_DEVICE_NOT_FOUND;
return;
}
*p->dioc_bytesret = sizeof(CreateBarPtrOut);
outptr->status = Assign_Linear_To_BARs(&pcicfg, comemID);
for (i = 0; i < COMEM_MAX_BARS; i++ )
{
outptr->linBAR[i] = comemDev[comemID]->linBAR[i];
}
outptr->linPage = 0;
outptr->physPage = 0;
}
// In win95 it is ok (actually, it's necessary to allow multiple calls to createBarPtr.
// If two tasks want to talk to the same co-mem, they both need linear pointers.
// The flip side of this is that the destroy call cannot do anything in W95. The
// pointers live until the vxd is stopped.
void COMEM_DestroyBarPtr( PIOCTLPARAMS p )
{
int i;
DestroyBarPtrIn *inptr = p->dioc_InBuf;
DestroyBarPtrOut *outptr = p->dioc_OutBuf;
*p->dioc_bytesret = 4;
outptr->status = NO_ERROR;
if (inptr->comemID > COMEM_MAX_DEVICES)
{
*p->dioc_bytesret = 4;
outptr->status = ERROR_INVALID_COMEM_ID;
return;
}
if (!comemDev[inptr->comemID])
{
*p->dioc_bytesret = 4;
outptr->status = ERROR_INVALID_COMEM_ID;
return;
}
}
// Function
// OnDeviceInit - Handler for DEVICE_INIT control message
//
// Input
// hSysVM Handle of system virtual machine
// CommandTail Pointer to Windows command line
//
// Remarks
// This routine is responsible for hooking the PCI
// interrupt and configuring it.
//
// Returns
// Returns TRUE if successfully initialized
//
BOOL installIRQHandler(DWORD comemID)
{
BYTE statreg;
DWORD status;
// Hooking a hardware interrupt requires calling the Virtual Programmable
// Interrupt Controlloer Device (VPICD), to inform that this VxD will
// be responsible for the IRQ. VPICD provides five different notifications
// of events related to the IRQ, but this VxD uses only one of them, namely,
// that of the actual hardware interrupt event. The VPICD_Virtualize_IRQ
// call takes one parameter which points to a structure containing the
// address of this VxD's hardware interrupt handler, along with additional
// information related to the IRQ.
struct VPICD_IRQ_Descriptor IRQdesc; // struct to pass to
// VPICD_Virtualize_IRQ
// Set up the structure to pass to VPICD_Virtualize_IRQ
IRQdesc.VID_IRQ_Number = comemDev[comemID]->pcicfg.InterruptLine; // IRQ to virtualize
IRQdesc.VID_Options = VPICD_OPT_CAN_SHARE; // Allow IRQ sharing
// To set the address of the our handler in the structure that will be
// passed to VPICD_Virtualize_IRQ, we pass the address of the handler's
// thunk to VPICD_Thunk_HWInt, which initializes the thunk and returns
// its address.
IRQdesc.VID_Hw_Int_Proc = // set address of handler
(DWORD)VPICD_Thunk_HWInt_Ex(COMEMInt_Handler, &ComemIntThunk);
// The other callbacks are not used.
IRQdesc.VID_EOI_Proc = 0;
IRQdesc.VID_Virt_Int_Proc = 0;
IRQdesc.VID_Mask_Change_Proc = 0;
IRQdesc.VID_IRET_Proc = 0;
IRQdesc.VID_IRET_Time_Out = 500;
IRQdesc.VID_Hw_Int_Ref = comemDev[comemID];
IRQdesc.VID_Options |= VPICD_OPT_REF_DATA;
// Now pass the structure to VPICD. VPICD returns the IRQ handle.
comemDev[comemID]->IRQHandle = VPICD_Virtualize_IRQ(&IRQdesc);
if (comemDev[comemID]->IRQHandle == 0)
return FALSE; // failed to virtualize
// Make sure the IRQ is unmasked on the PIC. Otherwise, the interrupt
// will never occur.
VPICD_Physically_Unmask(comemDev[comemID]->IRQHandle);
return TRUE; // initialized successfully
}
// Function
// COMEMInt_Handler - handler for VID_Hw_Int callback
//
// Input
// hVM handle of current virtual machine
// hIRQ handle of this virtualized IRQ
//
// Remarks
// VPICD invokes this routine (via the thunk) when the COMEM
// interrupt (IRQ 8) occurrs.
//
BOOL __stdcall COMEMInt_Handler(VMHANDLE hVM, IRQHANDLE hIRQ, DWORD devPtr)
{
int i;
BOOL retval = FALSE;
static DWORD counter[0x10] =
{
0
};
DWORD comemID;
DWORD scrap32;
if ((comemDevStruct *)devPtr)
{
if (((comemDevStruct *)devPtr)->linBAR[0])
{
DWORD * hintPtr = ((DWORD *)(((comemDevStruct *)devPtr)->linBAR[0])) + ADDR_HINT/sizeof(DWORD);
// Read the interrupts that we have received via BAR0
scrap32 = *hintPtr;
if (scrap32 & 0x3ff)
retval = TRUE;
// Clear the active interrupts
*hintPtr |= scrap32 & 0x3ff;
// Count the interrupts received
for (i = 0; i < 0x10; i++)
{
if (scrap32 & 1)
counter[i]++;
scrap32 >>= 1;
}
}
Call_Global_Event(ComemEventService,
(PVOID)devPtr, &ComemEventThunk);
}
if (retval)
VPICD_Phys_EOI(hIRQ); // tell VPICD to clear the interrupt
return retval; // Tell VPICD that it wasn't our interrupt -- we're sitting on someone else's
}
// Function
// ComemEventService - handler for hour event
//
// Input
// hVM handle of current VM
// Refdata not used
// pRegs pointer to client register structure
//
// Remarks
// This routine is the handler for the event scheduled by the interrupt
// handler. It is called on a co-mem interrupt. If you wish to add
// interrupt processing in the VxD, do it here, not in the ISR. The ISR
// cannot use most of the windows library functions, since they are not
// re-entrant.
//
VOID __stdcall ComemEventService(VMHANDLE hVM, PVOID Refdata, PCLIENT_STRUCT pRegs)
{
// Dummy routine -- we could service it here, or post an event to Ring 3
// using TBD method.
}
CONFIGRET OnPnpNewDevnode(DEVNODE Node, DWORD LoadType)
{
CONFIGRET rc;
CONFIGRET status;
switch (LoadType)
{
case DLVXD_LOAD_DRIVER:
{
int comemID = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -