📄 skeleton.c
字号:
/* *---------------------------------------------------------------------- * * Module Name: * skeleton.c * * Abstract: * This module contains the code for a skeleton driver that * can just map a board into user space memory. * * Environment: * Kernel mode * * Author: * Gordon Chaffee * *---------------------------------------------------------------------- */#include <ntddk.h>#include <stdarg.h>/* * Skeleton includes */#include "skeleton_nt.h"#include "skeleton_dev.h"/* *---------------------------------------------------------------------- * Static Variables *---------------------------------------------------------------------- */static int nopens;/* * Internally defined routines */static NTSTATUS CloseDevice(IN PDEVICE_OBJECT devObj, IN PFILE_OBJECT fileObj);static NTSTATUS Dispatch(IN PDEVICE_OBJECT devObj, IN PIRP Irp);static NTSTATUS MapMemory(IN PDEVICE_OBJECT, IN OUT PVOID, IN ULONG, IN ULONG);static NTSTATUS OpenDevice(IN PDEVICE_OBJECT devObj, IN PFILE_OBJECT fileObj);static NTSTATUS ProbePCI(IN PDRIVER_OBJECT drvObj, IN PUNICODE_STRING regPath);static BOOLEAN ServiceInterrupt(IN PKINTERRUPT Interrupt, IN PVOID ServiceContext);static VOID StartIo(IN PDEVICE_OBJECT devObj, IN PIRP Irp);static VOID Unload(IN PDRIVER_OBJECT);static NTSTATUS UnmapMemory(IN PDEVICE_OBJECT, IN OUT PVOID, IN ULONG, IN ULONG);/* *---------------------------------------------------------------------- * Under NT, we can specify the parts of the code that are no longer * needed after initialization with the pragma alloc_text. *---------------------------------------------------------------------- */#if 0#ifdef ALLOC_PRAGMA# pragma alloc_text(INIT,DriverEntry)#endif#endif/* *---------------------------------------------------------------------- * DriverEntry -- * * This routine is called at system initialization time to initialize * this driver. * * Arguments: * DriverObject - Supplies the driver object. * RegistryPath - Supplies the registry path for this driver. * * Return Value: * STATUS_SUCCESS - We could initialize at least one device. * STATUS_NO_SUCH_DEVICE - We could not initialize even one device. * STATUS_UNSUCCESSFUL - For other errors? *---------------------------------------------------------------------- */NTSTATUSDriverEntry(IN PDRIVER_OBJECT drvObj, IN PUNICODE_STRING regPath){ NTSTATUS status; KdPrint(("SKELETON.SYS(DriverEntry): Entering\n")); status = ProbePCI(drvObj, regPath); if (NT_SUCCESS(status)) { /* * Create dispatch points for device control, create, close. */ drvObj->MajorFunction[IRP_MJ_CREATE] = Dispatch; drvObj->MajorFunction[IRP_MJ_CLOSE] = Dispatch; drvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Dispatch; drvObj->MajorFunction[IRP_MJ_READ] = Dispatch; drvObj->MajorFunction[IRP_MJ_WRITE] = Dispatch; drvObj->DriverUnload = Unload; drvObj->DriverStartIo = StartIo; } KdPrint(("SKELETON.SYS(DriverEntry): Exiting\n")); return status;}/* *---------------------------------------------------------------------- * Dispatch -- * * This routine handles all IRPs sent to this device. * * Arguments: * devObj: Pointer to the device object * irp: Pointer to an I/O request packet * * Results: * Standard NT result * * Notes: * We only handle ioctls to map and unmap the skeleton board. *---------------------------------------------------------------------- */static NTSTATUSDispatch(IN PDEVICE_OBJECT devObj, IN PIRP irp){ PIO_STACK_LOCATION irpStack; PVOID ioBuf; ULONG inBufLen; ULONG outBufLen; ULONG ioctlCode; NTSTATUS status; PSKELETON_DEVICE skelDev; ULONG key; skelDev = devObj->DeviceExtension; /* * enter device mutex to ensure one request at a time */ ExAcquireFastMutex(&skelDev->IrpMutex); irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Information = 0; irpStack = IoGetCurrentIrpStackLocation(irp); ioBuf = irp->AssociatedIrp.SystemBuffer; switch (irpStack->MajorFunction) { case IRP_MJ_CREATE: KdPrint(("SKELETON.SYS: IRP_MJ_CREATE\n")); status = OpenDevice(devObj, irpStack->FileObject); break; case IRP_MJ_CLOSE: KdPrint(("SKELETON.SYS: IRP_MJ_CLOSE\n")); status = CloseDevice(devObj, irpStack->FileObject); break; case IRP_MJ_DEVICE_CONTROL: ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; inBufLen = irpStack->Parameters.DeviceIoControl.InputBufferLength; outBufLen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; switch (ioctlCode) { case IOCTL_SKELETON_MAP_USER_PHYSICAL_MEMORY: /* PV_MMAP */ status = MapMemory(devObj, ioBuf, inBufLen, outBufLen); if (NT_SUCCESS(status)) { /* * Success! Set the following to sizeof(PVOID) to * indicate we're passing valid data back. */ irp->IoStatus.Information = sizeof(PVOID); } else { status = STATUS_INVALID_PARAMETER; KdPrint(("SKELETON.SYS: memory map failed :(\n")); } break; case IOCTL_SKELETON_UNMAP_USER_PHYSICAL_MEMORY: status = UnmapMemory(devObj, ioBuf, inBufLen, outBufLen); break; default: KdPrint(("SKELETON.SYS: unknown IRP_MJ_DEVICE_CONTROL\n")); status = STATUS_INVALID_PARAMETER; break; } break; default: KdPrint(("SKELETON.SYS: unknown Major Function\n")); status = STATUS_INVALID_PARAMETER; } /* * Don't get cute and try to use the status field of * the irp in the return status. That IRP IS GONE as * soon as you call IoCompleteRequest. */ if (status != STATUS_PENDING) { irp->IoStatus.Status = status; IoCompleteRequest(irp, IO_VIDEO_INCREMENT); } else { IoMarkIrpPending(irp); IoStartPacket(devObj, irp, &key, NULL); } ExReleaseFastMutex(&skelDev->IrpMutex); return status;}/* *---------------------------------------------------------------------- * Unload -- * * Just delete the associated device and return * * Arguments: * drvObj: Pointer to the driver object * * Results: * None *---------------------------------------------------------------------- */static VOIDUnload(IN PDRIVER_OBJECT drvObj){ WCHAR devLinkBuf[] = L"\\DosDevices\\SKELETON0"; UNICODE_STRING devLinkUniStr; WCHAR devNum; PDEVICE_OBJECT devObj, nextDev; PSKELETON_DEVICE skelDev; int tmp; CM_RESOURCE_LIST EmptyList; BOOLEAN ResourceConflict; /* * For each device that is on the machine: * * 1. Delete the symbolic links * 2. Turn off the board interrupts and disconnect the interrupt. * 3. Unmap the board memory from system space. * 4. Unreport the resources that were assigned by HalAssignSlotResources * 5. Delete the device object */ for (devNum = 0, devObj = drvObj->DeviceObject; devObj != NULL; devObj = nextDev, devNum++) { devLinkBuf[sizeof(devLinkBuf) - 1] = L'0' + devNum; RtlInitUnicodeString(&devLinkUniStr, devLinkBuf); IoDeleteSymbolicLink(&devLinkUniStr); skelDev = devObj->DeviceExtension; IoDisconnectInterrupt(skelDev->KIntrObj); MmUnmapIoSpace(skelDev->FrameBase, skelDev->MemLength); /* un-report any resources used by the driver and the device */ EmptyList.Count = 0; IoReportResourceUsage(NULL, drvObj, &EmptyList, sizeof(ULONG), drvObj->DeviceObject, &EmptyList, sizeof(ULONG), FALSE, &ResourceConflict); nextDev = devObj->NextDevice; IoDeleteDevice(devObj); } KdPrint(("SKELETON.SYS: unloading\n"));}/* *---------------------------------------------------------------------- * StartIo -- * * This gets called when we are about to start another graphics * or DMA operation. This can occur because another operation * just completed, or it can occur because this is the first * operation. Either way, we don't expect anything to interfere * with its operation. * * Results: * None *---------------------------------------------------------------------- */static VOIDStartIo(IN PDEVICE_OBJECT devObj, IN PIRP irp){ irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(irp, IO_VIDEO_INCREMENT); IoStartNextPacket(devObj, TRUE); return;}/* *---------------------------------------------------------------------- * OpenDevice -- * * Open the device. We will allow multiple opens to the device, * but all drawing after initialization needs to occur only * through the driver interface. Since we only do PutImage and * GetImage type operations as well as setting and clearing the * overlay regions in response to Windows changes on the screen, * this doesn't seem to be a big problem. We just need to: * * XXX: Allocate a page when the device the first open is done. * This page will be used to hold the settings for open channels. * This will only allow a limited number of applications * to simultaneously access the device, so this many not be what * we want, but this should not be a problem. * * (1) Allocate some memory for the channel we are opening. * (2) Have an ioctl for setting the grabbing and capturing * position for this open channel. This is stored in the * allocated memory for this channel. When images are * put or captured, the parameters are taken from these values. * This lets the I/O manager do all the locking down of memory * so that we don't have to send two buffers down with the * same ioctl. * (3) Use the FileObject field of the IO_STACK_LOCATION of the * irp to manage which video control block has been allocated for * this channel. * * Results: * A standard NT result *---------------------------------------------------------------------- */static NTSTATUSOpenDevice(IN PDEVICE_OBJECT devObj, IN PFILE_OBJECT fileObj){ PSKELETON_DEVICE skelDev; KdPrint(("SKELETON.SYS: OpenDevice called\n")); skelDev = devObj->DeviceExtension; ++nopens; /* inc global open */ return STATUS_SUCCESS;}/* *---------------------------------------------------------------------- * CloseDevice -- * * Close up device and free resources allocated by OpenDevice * * Results: * A standard NT result *---------------------------------------------------------------------- */static NTSTATUSCloseDevice(IN PDEVICE_OBJECT devObj, IN PFILE_OBJECT fileObj){ PSKELETON_DEVICE skelDev; skelDev = devObj->DeviceExtension; nopens--; /* decrement global open */ return STATUS_SUCCESS;}/* *---------------------------------------------------------------------- * MapMemory -- * * Given a physical address, maps this address into a user mode * process's address space * * Arguments: * devObj pointer to a device object * ioBuf pointer to the I/O buffer * inBufLen input buffer length * outBufLen output buffer length * * Results: * STATUS_SUCCESS * STATUS_UNSUCCESSFUL * STATUS_BUFFER_TOO_SMALL, * (other STATUS_* as returned by kernel APIs) *---------------------------------------------------------------------- */static NTSTATUSMapMemory(IN PDEVICE_OBJECT devObj, IN OUT PVOID ioBuf, IN ULONG inBufLen, IN ULONG outBufLen){ INTERFACE_TYPE interfaceType; ULONG busNumber; PHYSICAL_ADDRESS physicalAddr; ULONG len; UNICODE_STRING physicalMemUniStr; OBJECT_ATTRIBUTES objAttrs; HANDLE physicalMemHandle = NULL; PVOID physicalMemSection = NULL; ULONG inIoSpace, inIoSpace2; NTSTATUS status; PHYSICAL_ADDRESS physicalAddrBase; PHYSICAL_ADDRESS physicalAddrEnd; PHYSICAL_ADDRESS viewBase; PHYSICAL_ADDRESS mappedLen; BOOLEAN xlateBaseAddr; BOOLEAN xlateEndAddr; PVOID virtualAddr; PSKELETON_DEVICE skelDev; skelDev = devObj->DeviceExtension; if (outBufLen < sizeof(PVOID)) { KdPrint(("SKELETON.SYS(MapMemory): Insufficient output buffer\n")); status = STATUS_BUFFER_TOO_SMALL; goto done; } /* * Get a pointer to physical memory... * * - Create the name * - Initialize the data to find the object * - Open a handle to the oject and check the status * - Get a pointer to the object * - Free the handle */ RtlInitUnicodeString(&physicalMemUniStr, L"\\Device\\PhysicalMemory"); InitializeObjectAttributes(&objAttrs, &physicalMemUniStr, OBJ_CASE_INSENSITIVE, (HANDLE) NULL, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenSection(&physicalMemHandle, SECTION_ALL_ACCESS, &objAttrs); if (!NT_SUCCESS(status)) { KdPrint(("SKELETON.SYS: ZwOpenSection failed\n")); goto done; } status = ObReferenceObjectByHandle(physicalMemHandle, SECTION_ALL_ACCESS, (POBJECT_TYPE) NULL, KernelMode, &physicalMemSection, (POBJECT_HANDLE_INFORMATION) NULL); if (!NT_SUCCESS(status)) { KdPrint(("SKELETON.SYS: ObReferenceObjectByHandle failed\n")); goto close_handle; } interfaceType = PCIBus; busNumber = skelDev->BusId; physicalAddr = skelDev->MemStart; len = skelDev->MemLength; inIoSpace = skelDev->FrameMemType; inIoSpace2 = skelDev->FrameMemType; /* * Initialize the physical addresses that will be translated */ physicalAddrEnd = RtlLargeIntegerAdd(physicalAddr, RtlConvertUlongToLargeInteger(len)); /* * Translate the physical addresses. */ xlateBaseAddr = HalTranslateBusAddress(interfaceType, busNumber, physicalAddr, &inIoSpace, &physicalAddrBase); xlateEndAddr = HalTranslateBusAddress(interfaceType, busNumber, physicalAddrEnd, &inIoSpace2, &physicalAddrEnd); if (!(xlateBaseAddr && xlateEndAddr)) { KdPrint(("SKELETON.SYS: HalTranslatephysicalAddress failed\n")); status = STATUS_UNSUCCESSFUL; goto close_handle; } /* * Calculate the length of the memory to be mapped */ mappedLen = RtlLargeIntegerSubtract(physicalAddrEnd, physicalAddrBase); /* * If the mappedlen is zero, somthing very weird happened in the HAL * since the Length was checked against zero. */ if (mappedLen.LowPart == 0) { KdPrint(("SKELETON.SYS: mappedLen.LowPart == 0\n")); status = STATUS_UNSUCCESSFUL; goto close_handle;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -