编写NT驱动使得APP能够读取PCI设备配置信息
2013-08-24 10:03
399 查看
驱动程序是一个软件组件,可以让操作系统和设备之间实现通信。一般操作系统可以分为两个主要组成部分,即User Mode和Kernel Mode。用户的APP运行在系统的User Mode下,而驱动程序则运行在系统的Kernel Mode下。由于Windows在User
Mode下做了许多限制,使得在用户模式下的APP有很多资源不能访问到,这时候就可以通过驱动来实现对Kernel Mode下的资源进行访问,如图5.1所示。
图 5.1
NT驱动程序一般是由3部分组成,即DriverEntry、DispatchRoutine和DriveUnload。其中DriverEntry主要进行驱动程序的初始化,即:创建设备和DispatchRoutine的注册工作。当Driver被加载时,DriverEntry会被系统进程调用;DriverUnLoad在驱动被卸载时被调用,做回收资源操作,如删除创建的设备与设备符号连接、删除程序中定义的句柄等;DispatchRoutine是由一系列回调函数组成,系统在对设备进行操作或者响应设备中断时会调用这些回调函数。与此对应的,需要在User
Mode中的APP编写驱动的加载函数LoadDriver,驱动的卸载函数UnLoadDriver以及APP给Driver的派遣函数IRP。APP指令与NT
Driver指令的对应关系如图5.2所示。
图 5.2
其中APP与NT Driver之间的通信流程如下图5.3所示。
图 5.3
DispatchRoutine得到IRP函数后,根据MajorFunction找到对应的派遣函数,随后再根据MiniFunction完成相应的任务。
//////////////////////////////////////////////////////////////////////////////////////////
NT Driver代码如下:
#include "ntddk.h" typedef unsigned long DWORD; #define IN #define DEBUGMSG //IOCTL宏 #define DEVICE_PCI_INDEX 0x860 #define READ_PCI_INFO CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_PCI_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS) #define NT_DEVICE_NAME L"\\Device\\wdkApp" #define DOS_DEVICE_NAME L"\\DosDevices\\wdkApp" //符号连接 ,应该与App中的CreateFile里的“\\\\.\\wakApp对应起来” typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT pDevice; UNICODE_STRING DeviceName; UNICODE_STRING SymLinkName; }DEVICE_EXTENSION,*PDEVICE_EXTENSION; VOID DriverUnload (IN PDRIVER_OBJECT DriverObject); NTSTATUS DispatchRoutine (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp); extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { NTSTATUS ntStatus = STATUS_SUCCESS; PDEVICE_OBJECT lpDeviceObject = NULL; UNICODE_STRING DeviceNameString = {0}; UNICODE_STRING DeviceLinkString = {0}; RtlInitUnicodeString(&DeviceNameString,NT_DEVICE_NAME); //创建设备 ntStatus = IoCreateDevice(DriverObject,0,&DeviceNameString,FILE_DEVICE_UNKNOWN,0,false,&lpDeviceObject); if (!NT_SUCCESS(ntStatus)) { return ntStatus; } RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME); //创建符号链接 ntStatus=IoCreateSymbolicLink(&DeviceLinkString,&DeviceNameString); if (!NT_SUCCESS(ntStatus)) { if (lpDeviceObject) { IoDeleteDevice(lpDeviceObject); } return ntStatus; } DriverObject->DriverUnload = DriverUnload; DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchRoutine; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchRoutine; return STATUS_SUCCESS; } NTSTATUS DispatchRoutine (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp) { NTSTATUS ntStatus=STATUS_SUCCESS; PIO_STACK_LOCATION IrpStack=NULL; //IRP堆栈 ULONG IoControlCodes=0; //I/O控制代码 //设置IRP状态 pIrp->IoStatus.Status=STATUS_SUCCESS; pIrp->IoStatus.Information=0; #ifdef DEBUGMSG DbgPrint("Starting HelloWorldDispatch()\n"); #endif IrpStack=IoGetCurrentIrpStackLocation(pIrp); //得到当前调用者的IRP switch (IrpStack->MajorFunction) { case IRP_MJ_CREATE: #ifdef DEBUGMSG DbgPrint("IRP_MJ_CREATE\n"); #endif break; case IRP_MJ_DEVICE_CONTROL: #ifdef DEBUGMSG DbgPrint("IRP_MJ_DEVICE_CONTROL\n"); #endif //取得I/O控制代码 IoControlCodes=IrpStack->Parameters.DeviceIoControl.IoControlCode; switch (IoControlCodes) { case READ_PCI_INFO: { #ifdef DEBUGMSG DbgPrint("READ_PCI_INFO\n"); #endif //获得PCI设备信息 ULONG *INBuffer = (PULONG)pIrp->AssociatedIrp.SystemBuffer; WRITE_PORT_ULONG((PULONG)0xCF8,INBuffer[0]); ULONG *OutBuffer = (PULONG)pIrp->AssociatedIrp.SystemBuffer; OutBuffer[0] = READ_PORT_ULONG((PULONG)0xCFC); #ifdef DEBUGMSG DbgPrint("%lx\n",OutBuffer[0]); #endif break; } default: pIrp->IoStatus.Status=STATUS_INVALID_PARAMETER; break; } break; default: break; } ntStatus=pIrp->IoStatus.Status; pIrp->IoStatus.Information = 4; IoCompleteRequest(pIrp,IO_NO_INCREMENT); return ntStatus; } VOID DriverUnload (IN PDRIVER_OBJECT DriverObject) { UNICODE_STRING DeviceLinkString={0}; PDEVICE_OBJECT DeviceObjectTemp1=NULL; PDEVICE_OBJECT DeviceObjectTemp2=NULL; #ifdef DEBUGMSG DbgPrint("Starting HelloWorldUnLoad()\n"); #endif RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME); if (DeviceLinkString.Buffer) IoDeleteSymbolicLink(&DeviceLinkString); if (DriverObject) { DeviceObjectTemp1=DriverObject->DeviceObject; while (DeviceObjectTemp1) { DeviceObjectTemp2=DeviceObjectTemp1; DeviceObjectTemp1=DeviceObjectTemp1->NextDevice; IoDeleteDevice(DeviceObjectTemp2); } } }
////////////////////////////////////////////////////////////////////////////////////
对应的APP代码如下:
// App.cpp #include "stdafx.h" #include <windows.h> #include <stdio.h> #define DEVICE_PCI_INDEX 0x860 //IOCTL宏 #define READ_PCI_INFO CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_PCI_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS) //用来判断CreateFile是否成功 int flag = 0; void TestDriver(); //加载驱动 //lpszDriverName:驱动程序在注册表中的名字 //分为3部,1.新建驱动服务并判断是否有错误发生;2.打开驱动服务;3.开始驱动服务 bool LoadNTDriver(wchar_t* lpszDriverName, wchar_t* lpszDriverPath) //驱动名&&驱动路径 { wchar_t szDriverPath[MAX_PATH]; GetFullPathName(lpszDriverPath, MAX_PATH, szDriverPath, NULL); printf("%s\n", szDriverPath); //输出C,表示C盘 SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hSCM == NULL) { printf("OpenSCManager error:%d\n", GetLastError()); return false; } //创建驱动服务 SC_HANDLE hDriver = CreateService(hSCM, lpszDriverName, lpszDriverName, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, szDriverPath, NULL, NULL, NULL, NULL, NULL); DWORD dwError; if (hDriver == NULL) { dwError = GetLastError(); if (dwError != ERROR_IO_PENDING && dwError != ERROR_SERVICE_EXISTS) { printf("CreateService error:%d\n", dwError); CloseServiceHandle(hSCM); return false; } else { printf("Service already Created.\n"); } hDriver = OpenService(hSCM, lpszDriverName, SERVICE_ALL_ACCESS); if (h a02d Driver == NULL) { printf("OpenService error:%d\n", GetLastError()); CloseServiceHandle(hSCM); return false; } else { printf("OpenService OK!\n"); } } else { printf("CreateService OK!\n"); } dwError = StartService(hDriver,NULL,NULL); if (!dwError) { dwError = GetLastError(); if (dwError != ERROR_IO_PENDING && dwError != ERROR_SERVICE_ALREADY_RUNNING) { printf("StartService error:%d\n", dwError); CloseServiceHandle(hSCM); CloseServiceHandle(hDriver); return false; } else { printf("Service already run\n"); CloseServiceHandle(hSCM); CloseServiceHandle(hDriver); return true; } } return true; } //卸载驱动 //szSrvName:即为lpServiceName //3步:1.找到对应的驱动服务;2.停止此驱动服务;3.删除该驱动服务 bool UnLoadNTDriver(wchar_t* szSrvName) { SC_HANDLE hSCM = NULL; SC_HANDLE hSrv = NULL; hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hSCM == NULL) { printf("OpenSCManager error:%d\n", GetLastError()); return false; } else { printf("OpenSCManager OK!\n"); } hSrv = OpenService(hSCM, szSrvName, SERVICE_ALL_ACCESS); if (hSrv == NULL) { printf("OpenService error:%d\n", GetLastError()); CloseServiceHandle(hSCM); return false; } else { printf("OpenService OK!\n"); } SERVICE_STATUS ss; if (!ControlService(hSrv, SERVICE_CONTROL_STOP, &ss)) { printf("ControlService error:%d\n", GetLastError()); CloseServiceHandle(hSCM); CloseServiceHandle(hSrv); return false; } else { printf("ControlService ok!\n"); } if (!DeleteService(hSrv)) { printf("DeleteService error:%d\n", GetLastError()); CloseServiceHandle(hSCM); CloseServiceHandle(hSrv); return false; } else { printf("DeleteService ok!\n"); } return TRUE; } int main(void) { bool bRet = LoadNTDriver(L"wdkApp",L"C:\\wdkApp.sys"); if (!bRet) { printf("LoadNTDriver error\n"); return -1; } printf("Press any key to Test Driver!\n"); getchar(); TestDriver(); printf("Press any key to Unload Driver!\n"); getchar(); bRet = UnLoadNTDriver(L"wdkApp"); if (!bRet) { printf("UnLoadNTDriver error\n"); return -1; } return 0; } void TestDriver() { DWORD PCI_Addr,PCI_Data; DWORD bus,dev,func; ULONG nOutput; HANDLE hDriver = CreateFile(L"\\\\.\\wdkApp", GENERIC_READ|GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (hDriver!= INVALID_HANDLE_VALUE) { printf("Open Driver OK!\n"); flag = 1; /* 接收数据 */ for(bus = 0;bus<=0xFF;++bus) { for (dev = 0; dev<=0x1F; ++dev) { for (func = 0; func<=0x07; ++func) { PCI_Addr = 0x80000000 + (bus<<16) + (dev<<11) + (func<<8); DeviceIoControl(hDriver,READ_PCI_INFO,&PCI_Addr,4,&PCI_Data,4,&nOutput,NULL); if((PCI_Data&0xFFFF)!=0xFFFF) { printf("%04x\t%04x\t%04x\t%04x\t%04x\n",bus,dev,func,PCI_Data>>16,PCI_Data); } } } } getchar(); } else { printf("Open Driver fail,error:%d\n", GetLastError()); flag = 0; } CloseHandle(hDriver); }
相关文章推荐
- Linux环境下无配置信息PCI设备的驱动开发
- Linux PCI/PCI-E设备配置空间读取与修改
- Linux PCI/PCI-E设备配置空间读取与修改
- PCI设备读取配置空间
- PCI Express设备驱动 (4,PCIe配置空间和PCI设备中的寄存器)
- 【实用方法】Linux PCI/PCI-E设备配置空间读取与修改
- 读取app.config配置文件信息
- PCI设备读取配置空间
- 基于vxworks的PCI设备驱动编写
- Linux下SPI和IIC驱动免在设备树上添加设备信息的编写方法
- PCI设备读取配置空间
- VB.NET WinForm读取App.config配置信息
- Linux读取PCI设备的信息
- PCI Express设备驱动 (4,PCIe配置空间和PCI设备中的寄存器)
- Linux PCI/PCI-E设备配置空间读取与修改
- PCI设备读取配置空间
- Linux设备驱动前的工作准备 ---- 内核的配置及Makefile编写
- Linux PCI/PCI-E设备配置空间读取与修改
- C# 使用app.config文件方法 读取外部配置信息
- linux 驱动编写之虚拟字符设备的编写实例详解