Click here to Skip to main content
15,881,381 members
Articles / Programming Languages / ASM

Hook Interrupts and Call Kernel Routines in User Mode

Rate me:
Please Sign up or sign in to vote.
4.92/5 (12 votes)
20 May 2009CPOL9 min read 75.4K   1.5K   65  
Inject user mode routine into kernel space and execute
/*++
PhyMem Driver
Ver: 1.2
Author: akui
Date: 2009/5/10
--*/

#include <ntddk.h>
#include "phymem.h"
#include "isr.h"
#include "DebugPrint.h"

//Mapped memory information list
typedef struct tagMAPINFO
{
	SINGLE_LIST_ENTRY	link;
	PMDL				pMdl;	//allocated mdl
	PVOID				pvk;	//kernel mode virtual address
	PVOID				pvu;	//user mode virtual address
	ULONG				memSize;//memory size in bytes
} MAPINFO, *PMAPINFO;

//ISR information list
typedef struct tagISRINFO
{
	SINGLE_LIST_ENTRY	link;
	UCHAR				intNo;				//interrupt number(0-255)
	PMDL				pIsrMdl;			//allocated mdl for isr code
	PMDL				pContextMdl;		//allocated mdl for isr context
	INTVECT				intVect;			//8 bytes IDT table entry
	UCHAR				isrCode[ISRCODE_LEN];//isr code buffer length
} ISRINFO, *PISRINFO;

SINGLE_LIST_ENTRY lstMapInfo;	//mapped memory information
SINGLE_LIST_ENTRY lstIsrInfo;	//isr information
PFILE_OBJECT pcifo=NULL;		//pci bus filter driver file object
PDEVICE_OBJECT pcifido=NULL;	//pci bus filter driver device object
PPCI_BUS_INTERFACE_STANDARD busInterface=NULL;	//pci driver interface

//forward function declaration
NTSTATUS PhyMemCreate(IN PDEVICE_OBJECT fdo, IN PIRP irp);
NTSTATUS PhyMemClose(IN PDEVICE_OBJECT fdo, IN PIRP irp);
NTSTATUS PhyMemIoCtl(IN PDEVICE_OBJECT fdo, IN PIRP irp);
VOID PhyMemUnload(IN PDRIVER_OBJECT dro);

NTSTATUS GetBusInterface(IN PDEVICE_OBJECT pcifido,
	OUT PPCI_BUS_INTERFACE_STANDARD	busInterface);

//local functions
static NTSTATUS PreGetBus();
static NTSTATUS ReadWriteConfig(PIRP irp, PPHYMEM_PCI pPci, BOOLEAN isRead);
static NTSTATUS MapUserToKernel(PVOID pUser, ULONG len, LOCK_OPERATION lo, PMDL *ppMdl, PVOID *ppSysAddr);
static PINTVECT GetStoredIntVector(UCHAR nIntNo);
static VOID RemoveIsrInfo(UCHAR nIntNo);

/*++
DriverEntry routine
--*/
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,
					  IN PUNICODE_STRING RegistryPath)
{
	UNICODE_STRING DeviceNameU;
	UNICODE_STRING DeviceLinkU;
	NTSTATUS ntStatus;
	PDEVICE_OBJECT fdo=NULL;

	UNREFERENCED_PARAMETER(RegistryPath);

	DebugPrintInit("PhyMem");
	DebugPrintMsg("Entering DriverEntry");

	lstMapInfo.Next=NULL;
	lstIsrInfo.Next=NULL;

	//initialize pci bus interface buffer
	busInterface=(PPCI_BUS_INTERFACE_STANDARD)ExAllocatePool(NonPagedPool,
		sizeof(PCI_BUS_INTERFACE_STANDARD));
	if (busInterface==NULL)
	{
		return STATUS_INSUFFICIENT_RESOURCES;
	}
	RtlZeroMemory(busInterface, sizeof(PCI_BUS_INTERFACE_STANDARD));

	RtlInitUnicodeString(&DeviceNameU, L"\\Device\\PhyMem");

	//Create an EXCLUSIVE device object
	ntStatus=IoCreateDevice(DriverObject,		//IN: Driver Object
							0,					//IN: Device Extension Size
							&DeviceNameU,		//IN: Device Name
							FILE_DEVICE_PHYMEM,	//IN: Device Type
							0,					//IN: Device Characteristics
							TRUE,				//IN: Exclusive
							&fdo);				//OUT:Created Device Object

	if (NT_SUCCESS(ntStatus))
	{
		if (NT_SUCCESS(ntStatus))
		{
			//Dispatch functions
			DriverObject->MajorFunction[IRP_MJ_CREATE]=PhyMemCreate;
			DriverObject->MajorFunction[IRP_MJ_CLOSE]=PhyMemClose;
			DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=PhyMemIoCtl;
			DriverObject->DriverUnload=PhyMemUnload;

			//Create a symbolic link
			RtlInitUnicodeString(&DeviceLinkU, L"\\DosDevices\\PhyMem");
			ntStatus=IoCreateSymbolicLink(&DeviceLinkU, &DeviceNameU);

			if (!NT_SUCCESS(ntStatus))
			{
				DebugPrintMsg("Error: IoCreateSymbolicLink failed");

				IoDeleteDevice(fdo);
			}
		}
		else
		{
			DebugPrintMsg("Error: IoGetDeviceObjectPointer failed");

			IoDeleteDevice(fdo);
		}
	}
	else
		DebugPrintMsg("Error: IoCreateDevice failed");

	DebugPrintMsg("Leaving DriverEntry");

	return ntStatus;
}

/*++
IRP_MJ_CREATE dispatch routine
--*/
NTSTATUS PhyMemCreate(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
	UNREFERENCED_PARAMETER(fdo);

	irp->IoStatus.Status=STATUS_SUCCESS;
	irp->IoStatus.Information=0;

	IoCompleteRequest(irp, IO_NO_INCREMENT);

	DebugPrintMsg("IRP_MJ_CREATE");

	return STATUS_SUCCESS;
}

/*++
IRP_MJ_CLOSE dispatch routine
--*/
NTSTATUS PhyMemClose(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
	UNREFERENCED_PARAMETER(fdo);

	irp->IoStatus.Status=STATUS_SUCCESS;
	irp->IoStatus.Information=0;

	IoCompleteRequest(irp, IO_NO_INCREMENT);

	DebugPrintMsg("IRP_MJ_CLOSE");

	return STATUS_SUCCESS;
}

/*++
IRP_MJ_DEVICE_CONTROL dispatch routine
--*/
NTSTATUS PhyMemIoCtl(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
	PIO_STACK_LOCATION irpStack;
	ULONG dwInBufLen;
	ULONG dwOutBufLen;
	ULONG dwIoCtlCode;
	NTSTATUS ntStatus;
	PVOID pSysBuf;
	PPHYMEM_MEM pMem;
	PPHYMEM_PORT pPort;
	PPHYMEM_PCI pPci;
	PPHYMEM_ISR pIsr;
	PPHYMEM_SYSCALL pSyscall;

	DebugPrintMsg("Entering PhyMemIoCtl");

	//Init to default settings
	irp->IoStatus.Status=STATUS_SUCCESS;
	irp->IoStatus.Information=0;

	irpStack=IoGetCurrentIrpStackLocation(irp);

	//Get the pointer to the input/output buffer and it's length
	pSysBuf=(PVOID)irp->AssociatedIrp.SystemBuffer;
	pMem=(PPHYMEM_MEM)pSysBuf;
	pPort=(PPHYMEM_PORT)pSysBuf;
	pPci=(PPHYMEM_PCI)pSysBuf;
	pIsr=(PPHYMEM_ISR)pSysBuf;
	pSyscall=(PPHYMEM_SYSCALL)pSysBuf;
	dwInBufLen=irpStack->Parameters.DeviceIoControl.InputBufferLength;
	dwOutBufLen=irpStack->Parameters.DeviceIoControl.OutputBufferLength;

	switch (irpStack->MajorFunction)
	{
	case IRP_MJ_DEVICE_CONTROL:

		dwIoCtlCode=irpStack->Parameters.DeviceIoControl.IoControlCode;

		switch (dwIoCtlCode)
		{
		case IOCTL_PHYMEM_MAP:

			if (dwInBufLen==sizeof(PHYMEM_MEM) && dwOutBufLen==sizeof(PVOID))
			{
				PHYSICAL_ADDRESS phyAddr;
				PVOID pvk, pvu;

				phyAddr.QuadPart=(ULONGLONG)pMem->pvAddr;

				//get mapped kernel address
				pvk=MmMapIoSpace(phyAddr, pMem->dwSize, MmNonCached);

				if (pvk)
				{
					//allocate mdl for the mapped kernel address
					PMDL pMdl=IoAllocateMdl(pvk, pMem->dwSize, FALSE, FALSE, NULL);
					if (pMdl)
					{
						PMAPINFO pMapInfo;

						//build mdl and map to user space
						MmBuildMdlForNonPagedPool(pMdl);
						pvu=MmMapLockedPages(pMdl, UserMode);

						//insert mapped infomation to list
						pMapInfo=(PMAPINFO)ExAllocatePool(\
							NonPagedPool, sizeof(MAPINFO));
						pMapInfo->pMdl=pMdl;
						pMapInfo->pvk=pvk;
						pMapInfo->pvu=pvu;
						pMapInfo->memSize=pMem->dwSize;
						PushEntryList(&lstMapInfo, &pMapInfo->link);

						DebugPrint("Map physical 0x%x to virtual 0x%x, size %u", \
							pMem->pvAddr, pvu, pMem->dwSize);

						RtlCopyMemory(pSysBuf, &pvu, sizeof(PVOID));

						irp->IoStatus.Information=sizeof(PVOID);
					}
					else
					{
						//allocate mdl error, unmap the mapped physical memory
						MmUnmapIoSpace(pvk, pMem->dwSize);

						irp->IoStatus.Status=STATUS_INSUFFICIENT_RESOURCES;
					}
				}
				else
					irp->IoStatus.Status=STATUS_INSUFFICIENT_RESOURCES;
			}
			else
				irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

			break;

	    case IOCTL_PHYMEM_UNMAP:

			DebugPrintMsg("IOCTL_PHYMEM_UNMAP");

			if (dwInBufLen==sizeof(PHYMEM_MEM))
			{
				PMAPINFO pMapInfo;
				PSINGLE_LIST_ENTRY pLink, pPrevLink;

				//initialize to head
				pPrevLink=pLink=lstMapInfo.Next;
				while(pLink)
				{
					pMapInfo=CONTAINING_RECORD(pLink, MAPINFO, link);

					if (pMapInfo->pvu==pMem->pvAddr)
					{
						if (pMapInfo->memSize==pMem->dwSize)
						{
							//free mdl, unmap mapped memory
							MmUnmapLockedPages(pMapInfo->pvu, pMapInfo->pMdl); 
							IoFreeMdl(pMapInfo->pMdl);
							MmUnmapIoSpace(pMapInfo->pvk, pMapInfo->memSize);

							DebugPrint("Unmap virtual address 0x%x, size %u",\
								pMapInfo->pvu, pMapInfo->memSize);

							//delete matched element from the list
							if (pLink==lstMapInfo.Next)
								lstMapInfo.Next=pLink->Next;	//delete head elememt
							else
								pPrevLink->Next=pLink->Next;

							ExFreePool(pMapInfo);
						}
						else
							irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

						break;
					}

					pPrevLink=pLink;
					pLink=pLink->Next;
				}
			}
			else
				irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

			break;

		case IOCTL_PHYMEM_GETPORT:

			DebugPrintMsg("IOCTL_PHYMEM_GETPORT");

			if (dwInBufLen==sizeof(PHYMEM_PORT) && dwOutBufLen==sizeof(ULONG))
			{
				irp->IoStatus.Information=sizeof(ULONG);

				if (pPort->dwSize==1)
				{
					*(PULONG)pSysBuf=(ULONG)READ_PORT_UCHAR((PUCHAR)pPort->dwPort);
				}
				else if (pPort->dwSize==2)
				{
					*(PULONG)pSysBuf=(ULONG)READ_PORT_USHORT((PUSHORT)pPort->dwPort);
				}
				else if (pPort->dwSize==4)
				{
					*(PULONG)pSysBuf=READ_PORT_ULONG((PULONG)pPort->dwPort);
				}
				else
					irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
			}
			else
				irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

			break;

		case IOCTL_PHYMEM_SETPORT:

			DebugPrintMsg("IOCTL_PHYMEM_SETPORT");

			if (dwInBufLen==sizeof(PHYMEM_PORT))
			{
				if (pPort->dwSize==1)
				{
					WRITE_PORT_UCHAR((PUCHAR)pPort->dwPort, (UCHAR)pPort->dwValue);
				}
				else if (pPort->dwSize==2)
				{
					WRITE_PORT_USHORT((PUSHORT)pPort->dwPort, (USHORT)pPort->dwValue);
				}
				else if (pPort->dwSize==4)
				{
					WRITE_PORT_ULONG((PULONG)pPort->dwPort, pPort->dwValue);
				}
				else
					irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
			}
			else
				irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

			break;

		case IOCTL_PHYMEM_GETPCI:

			DebugPrintMsg("IOCTL_PHYMEM_GETPCI");

			//register offset + bytes to read cannnot exceed 256(pci config space limit)
			if (dwInBufLen==sizeof(PHYMEM_PCI) &&
				((pPci->dwRegOff + pPci->dwBytes)<=256) && (dwOutBufLen>=pPci->dwBytes))
			{
				irp->IoStatus.Status=ReadWriteConfig(irp, pPci, TRUE);

				if (NT_SUCCESS(irp->IoStatus.Status))
				{
					irp->IoStatus.Information=pPci->dwBytes;
				}
			}
			else
				irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

			break;

		case IOCTL_PHYMEM_SETPCI:

			DebugPrintMsg("IOCTL_PHYMEM_SETPCI");

			//register offset + bytes to write cannnot exceed 256(pci config space limit)
			//new values to write are stored in out buffer(strange but it works)
			if (dwInBufLen==sizeof(PHYMEM_PCI) &&
				((pPci->dwRegOff + pPci->dwBytes)<=256) && (dwOutBufLen>=pPci->dwBytes))
			{
				irp->IoStatus.Status=ReadWriteConfig(irp, pPci, FALSE);

				if (NT_SUCCESS(irp->IoStatus.Status))
				{
					irp->IoStatus.Information=pPci->dwBytes;
				}
			}
			else
				irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

			break;

		case IOCTL_PHYMEM_SETISR:

			DebugPrintMsg("IOCTL_PHYMEM_SETISR");

			if (dwInBufLen==sizeof(PHYMEM_ISR))
			{
				//map user mode address to kernel address
				PMDL pIsrMdl, pContextMdl;
				PVOID isrAddr;
				PVOID context;

				if (!GetStoredIntVector(pIsr->nIntNo))
				{
					irp->IoStatus.Status=MapUserToKernel(pIsr->pIsrAddr, pIsr->dwIsrSize, 
						IoReadAccess, &pIsrMdl, &(PVOID)isrAddr);

					if (NT_SUCCESS(irp->IoStatus.Status))
					{
						DebugPrint("Isr code: User 0x%x --> Kernel 0x%x", pIsr->pIsrAddr, isrAddr);

						irp->IoStatus.Status=MapUserToKernel(pIsr->pContext, pIsr->dwContextLen,
							IoModifyAccess, &pContextMdl, &context);

						if (NT_SUCCESS(irp->IoStatus.Status))
						{
							PISRINFO pIsrInfo;
							PUCHAR c;

							DebugPrint("Isr context: User 0x%x --> Kernel 0x%x", pIsr->pContext, context);

							//add info to link list
							pIsrInfo=(PISRINFO)ExAllocatePool(NonPagedPool, sizeof(ISRINFO));
							pIsrInfo->intNo=pIsr->nIntNo;
							pIsrInfo->pIsrMdl=pIsrMdl;
							pIsrInfo->pContextMdl=pContextMdl;
							c=pIsrInfo->isrCode;
							RtlZeroMemory(c, ISRCODE_LEN);
							PushEntryList(&lstIsrInfo, &pIsrInfo->link);

							HookIsr(pIsr->nIntNo, isrAddr, context, &pIsrInfo->intVect, c);

							DebugPrint("Interrupt #%d hooked", pIsr->nIntNo);
						}
						else
						{
							MmUnlockPages(pIsrMdl);
							IoFreeMdl(pIsrMdl);

							irp->IoStatus.Status=STATUS_UNSUCCESSFUL;
						}
					}
					else
						irp->IoStatus.Status=STATUS_UNSUCCESSFUL;
				}
				else
					irp->IoStatus.Status=STATUS_UNSUCCESSFUL;	//isr already installed
			}
			else
				irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

			break;

		case IOCTL_PHYMEM_CLRISR:

			DebugPrintMsg("IOCTL_PHYMEM_CLRISR");

			if (dwInBufLen==sizeof(UCHAR))
			{
				UCHAR nIntNo=*(UCHAR*)pSysBuf;

				PINTVECT piv=GetStoredIntVector(nIntNo);
				if (piv)
				{
					//restore system default isr
					UnhookIsr(nIntNo, piv);
					//remove isr info list entry
					RemoveIsrInfo(nIntNo);

					DebugPrint("Interrupt #%d unhooked", nIntNo);
				}
				else
					irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
			}
			else
				irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

			break;

		case IOCTL_PHYMEM_PROCADDR:

			DebugPrintMsg("IOCTL_PHYMEM_PROCADDR");

			if (dwOutBufLen==8)
			{
				*(FARPROC*)pSysBuf=IoCreateDevice;
				*(FARPROC*)(((BYTE*)pSysBuf)+4)=(FARPROC)READ_PORT_UCHAR;
				irp->IoStatus.Information=8;

				DebugPrint("NTOSKRNL.EXE, IoCreateDevice, 0x%x", IoCreateDevice);
				DebugPrint("HAL.DLL, READ_PORT_UCHAR, 0x%x", READ_PORT_UCHAR);
			}

			break;

		case IOCTL_PHYMEM_SYSCALL:

			DebugPrintMsg("IOCTL_PHYMEM_SYSCALL");

			if (dwInBufLen==sizeof(PHYMEM_SYSCALL))
			{
				//map user mode address to kernel address
				PMDL pCodeMdl, pContextMdl;
				PVOID codeAddr;
				PVOID context;

				//map code
				irp->IoStatus.Status=MapUserToKernel(pSyscall->pCodeAddr, pSyscall->dwCodeSize, 
					IoReadAccess, &pCodeMdl, &(PVOID)codeAddr);

				if (NT_SUCCESS(irp->IoStatus.Status))
				{
					DebugPrint("Syscall code: User 0x%x --> Kernel 0x%x", pSyscall->pCodeAddr, codeAddr);

					//map data
					irp->IoStatus.Status=MapUserToKernel(pSyscall->pContext, pSyscall->dwContextLen,
						IoModifyAccess, &pContextMdl, &context);

					if (NT_SUCCESS(irp->IoStatus.Status))
					{
						DebugPrint("Syscall context: User 0x%x --> Kernel 0x%x", pSyscall->pContext, context);

						DebugPrintMsg("Syscall starts");

						__asm { PUSH context };
						__asm { CALL codeAddr };

						DebugPrintMsg("Syscall ended");

						//free resources
						MmUnlockPages(pCodeMdl);
						IoFreeMdl(pCodeMdl);
						MmUnlockPages(pContextMdl);
						IoFreeMdl(pContextMdl);
					}
					else
					{
						MmUnlockPages(pCodeMdl);
						IoFreeMdl(pCodeMdl);

						irp->IoStatus.Status=STATUS_UNSUCCESSFUL;
					}
				}
				else
					irp->IoStatus.Status=STATUS_UNSUCCESSFUL;
			}
			else
				irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

			break;

		default:

			DebugPrintMsg("Error: Unknown IO CONTROL CODE");

			break;
		}

		break;
	}

	ntStatus=irp->IoStatus.Status;

	IoCompleteRequest(irp, IO_NO_INCREMENT);

	DebugPrintMsg("Leaving PhyMemIoCtl");

	return ntStatus;
}

/*++
Driver Unload routine
--*/
VOID PhyMemUnload(IN PDRIVER_OBJECT dro)
{
	UNICODE_STRING DeviceLinkU;
	NTSTATUS ntStatus;
	PMAPINFO pMapInfo;
	PISRINFO pIsrInfo;
	PSINGLE_LIST_ENTRY pLink;

	DebugPrintMsg("Entering PhyMemUnload");

	//free resources
	pLink=PopEntryList(&lstMapInfo);
	while(pLink)
	{
		pMapInfo=CONTAINING_RECORD(pLink, MAPINFO, link);

		DebugPrint("Unmap virtual address 0x%x, size %u",\
			pMapInfo->pvu, pMapInfo->memSize);

		MmUnmapLockedPages(pMapInfo->pvu, pMapInfo->pMdl); 
		IoFreeMdl(pMapInfo->pMdl);
		MmUnmapIoSpace(pMapInfo->pvk, pMapInfo->memSize);

		ExFreePool(pMapInfo);

		pLink=PopEntryList(&lstMapInfo);
	}

	pLink=PopEntryList(&lstIsrInfo);
	while(pLink)
	{
		pIsrInfo=CONTAINING_RECORD(pLink, ISRINFO, link);

		//restore system default isr
		UnhookIsr(pIsrInfo->intNo, &pIsrInfo->intVect);

		//free mdl
		MmUnlockPages(pIsrInfo->pIsrMdl);
		IoFreeMdl(pIsrInfo->pIsrMdl);
		MmUnlockPages(pIsrInfo->pContextMdl);
		IoFreeMdl(pIsrInfo->pContextMdl);

		ExFreePool(pIsrInfo);

		pLink=PopEntryList(&lstIsrInfo);
	}

	if (busInterface && busInterface->InterfaceDereference)
	{
		(*busInterface->InterfaceDereference)(busInterface->Context);

		ExFreePool(busInterface);
	}

	RtlInitUnicodeString(&DeviceLinkU, L"\\DosDevices\\PhyMem");

	ntStatus=IoDeleteSymbolicLink(&DeviceLinkU);

	if (NT_SUCCESS(ntStatus))
	{
		IoDeleteDevice(dro->DeviceObject);
	}
	else
	{
		DebugPrintMsg("Error: IoDeleteSymbolicLink failed");
	}

	DebugPrintMsg("Leaving PhyMemUnload");

	DebugPrintClose();
}

//prepare to get bus interface
static NTSTATUS PreGetBus()
{
	NTSTATUS ntStatus;
	UNICODE_STRING pcifidoNameU;

	ntStatus=STATUS_SUCCESS;

	//get pci filter driver do
	if (pcifido==NULL)
	{
		RtlInitUnicodeString(&pcifidoNameU, L"\\Device\\PhyMemPCIFilter");

		ntStatus=IoGetDeviceObjectPointer(&pcifidoNameU,
										  FILE_READ_DATA|FILE_WRITE_DATA,
										  &pcifo,
										  &pcifido);

		if (NT_SUCCESS(ntStatus))
		{
			DebugPrint("Got pci filter device object: 0x%x", pcifido);
		}
		else
		{
			DebugPrint("Get pci filter device object failed, code=0x%x", ntStatus);

			return STATUS_UNSUCCESSFUL;
		}
	}

	//get bus interface
	if (busInterface->ReadConfig==NULL)
	{
		ntStatus=GetBusInterface(pcifido, busInterface);

		if (NT_SUCCESS(ntStatus))
		{
			DebugPrint("Got pci bus filter driver interface");
		}
		else
		{
			DebugPrint("Get pci bus driver interface failed, code=0x%x", ntStatus);
		}
	}

	return ntStatus;
}

//read pci configuration
static NTSTATUS ReadWriteConfig(PIRP irp, PPHYMEM_PCI pPci, BOOLEAN isRead)
{
	NTSTATUS ntStatus;

	//get pci filter driver interface
	ntStatus=PreGetBus();

	if (NT_SUCCESS(ntStatus))
	{
		PVOID pValue;

		//get out buffer kernel address
		pValue=(PVOID)MmGetSystemAddressForMdlSafe(irp->MdlAddress,
			NormalPagePriority);

		if (pValue)
		{
			PCI_SLOT_NUMBER slot;
			ULONG ulRet;

			slot.u.AsULONG=0;
			slot.u.bits.DeviceNumber=pPci->dwDevNum;
			slot.u.bits.FunctionNumber=pPci->dwFuncNum;

			if (isRead)
				ulRet=(*busInterface->ReadConfig)(busInterface->Context,	//context
												  (UCHAR)pPci->dwBusNum,	//busoffset
												  slot.u.AsULONG,			//slot
												  pValue,					//buffer
												  pPci->dwRegOff,			//offset
												  pPci->dwBytes);			//length

			else
				ulRet=(*busInterface->WriteConfig)(busInterface->Context,	//context
												   (UCHAR)pPci->dwBusNum,	//busoffset
												   slot.u.AsULONG,			//slot
												   pValue,					//buffer
												   pPci->dwRegOff,			//offset
												   pPci->dwBytes);			//length

			if (ulRet==pPci->dwBytes)
			{
				ntStatus=STATUS_SUCCESS;

				if (isRead)
					DebugPrint("Read %d bytes from pci config space", ulRet);
				else
					DebugPrint("Write %d bytes to pci config space", ulRet);
			}
			else
				ntStatus=STATUS_UNSUCCESSFUL;
		}
		else
			ntStatus=STATUS_INVALID_PARAMETER;
	}

	return ntStatus;
}

//map user mode address to kernel address
static NTSTATUS MapUserToKernel(PVOID pUser, ULONG len, LOCK_OPERATION lo, PMDL *ppMdl, PVOID *ppSysAddr)
{
	NTSTATUS ntStatus=STATUS_UNSUCCESSFUL;
	PMDL pMdl;
	PVOID pSysAddr;

	//allocate mdl, probe user mode address
	pMdl=IoAllocateMdl(pUser, len, FALSE, FALSE, NULL);
	if (pMdl)
	{
		__try
		{
			MmProbeAndLockPages(pMdl, UserMode, lo);
		}
		__except(EXCEPTION_EXECUTE_HANDLER)
		{
			ntStatus=GetExceptionCode();
			DebugPrint("Exception while locking isr code 0x%x", ntStatus);
			IoFreeMdl(pMdl);
			pMdl=NULL;
		}
	}
	else
		ntStatus=STATUS_INSUFFICIENT_RESOURCES;

	//map isr code to kernel
	if (pMdl)
	{
		pSysAddr=MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
		if(pSysAddr)
		{
			ntStatus=STATUS_SUCCESS;
			*ppMdl=pMdl;
			*ppSysAddr=pSysAddr;
		}
		else
		{
			ntStatus=STATUS_INSUFFICIENT_RESOURCES;
			DebugPrintMsg("MmGetSystemAddressForMdlSafe error");
			MmUnlockPages(pMdl);
			IoFreeMdl(pMdl);
		}
	}

	return ntStatus;
}

//return the stored 8 bytes idt table entry for this interrupt
static PINTVECT GetStoredIntVector(UCHAR nIntNo)
{
	PINTVECT pi=NULL;
	PISRINFO pIsrInfo;
	PSINGLE_LIST_ENTRY pLink;

	pLink=lstIsrInfo.Next;
	while(pLink)
	{
		pIsrInfo=CONTAINING_RECORD(pLink, ISRINFO, link);

		if (pIsrInfo->intNo==nIntNo)
		{
			pi=&pIsrInfo->intVect;
			break;
		}

		pLink=pLink->Next;
	}

	return pi;
}

//remove isr info list entry
static VOID RemoveIsrInfo(UCHAR nIntNo)
{
	PISRINFO pIsrInfo;
	PSINGLE_LIST_ENTRY pLink, pPrevLink;

	//initialize to head
	pPrevLink=pLink=lstIsrInfo.Next;
	while(pLink)
	{
		pIsrInfo=CONTAINING_RECORD(pLink, ISRINFO, link);

		if (pIsrInfo->intNo==nIntNo)
		{
			//free mdl
			MmUnlockPages(pIsrInfo->pIsrMdl);
			IoFreeMdl(pIsrInfo->pIsrMdl);
			MmUnlockPages(pIsrInfo->pContextMdl);
			IoFreeMdl(pIsrInfo->pContextMdl);

			//delete matched element from the list
			if (pLink==lstIsrInfo.Next)
				lstIsrInfo.Next=pLink->Next;	//delete head elememt
			else
				pPrevLink->Next=pLink->Next;

			ExFreePool(pIsrInfo);

			break;
		}

		pPrevLink=pLink;
		pLink=pLink->Next;
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
China China
From Shanghai, China

Comments and Discussions