您的位置:首页 > 移动开发

编写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);
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  NT驱动