zoukankan      html  css  js  c++  java
  • 驱动学习1

    WDM要导入的的头文件是WDM.h

    和NT式驱动程序一样,入口函数同样是DriverEntry,且在C++编译的时候需要用extern"C"修饰

    	pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
    	pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;
    	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = 
    	pDriverObject->MajorFunction[IRP_MJ_CREATE] = 
    	pDriverObject->MajorFunction[IRP_MJ_READ] = 
    	pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMDispatchRoutine;
    	pDriverObject->DriverUnload = HelloWDMUnload;

    和NT驱动不同在于WDM多了一个叫个AddDevice的回调

    这个回调来自DriverExtension->AddDevice中,此回调的作用是创建设备对象并由PNP(即插即用)管理器调用.

    同时,通过MajorFuntion[IRP_MJ_PNP]设置了PNP的IRP处理,也是和NT驱动不同点之一

    所以,在WDM的驱动程序中,创建设备对象的任务不再由DriverEntry来承担,

    而是需要驱动程序向系统注册一个称为AddDevice的函数,此函数由PNP管理器负责调用,主要就是创建设备对象,函数原型如下:

    NTSTATUS
    DRIVER_ADD_DEVICE (
        __in struct _DRIVER_OBJECT *DriverObject,
        __in struct _DEVICE_OBJECT *PhysicalDeviceObject
        );

    第一个是driverentry传过来的驱动对象,

    第二个是PNP管理器传进来的底层驱动设备对象,这个概念在NT驱动是没有的


    下面来看下这个函数:

    #define PAGED_CODE() {                                                       
        if (KeGetCurrentIrql() > APC_LEVEL) {                                    
            KdPrint(("EX: Pageable code called at IRQL %d
    ", KeGetCurrentIrql())); 
            PAGED_ASSERT(FALSE);                                                    
    
    

    也就是IRQL超过了APC_LEVEL时,在check版中会产生一个断言,断言会使程序终止,


    下面解释下IRQL:

    IRQL是Interrupt ReQuest Level 中断请求级别。一个由windows虚拟出来的概念,划分在windows下中断的优先级

    IRP是I/O Request Packet I/O请求包

    IRQL是分0-31级的,中断的意思就是正常运行的程序被打断,而转向做其他事,这个有个level,就是说程序如果level大于或等于中断源的level,它就可以无视中断源(官大一级压死人,平起平坐也不用鸟你)

    引入一些小概念:

     引起中断的事件称为中断源

    中断源向CPU提出处理的请求称为中断请求

    发生中断时被打断程序的暂停点称为断点

    CPU暂停现行程序而转为响应中断请求的过程称为中断响应

    处理中断源的程序称为中断处理程序

    一般level如下:

    PASSIVE_LEVEL

    线程即运行在该中断级别上,它对所有中断都作出响应。用户模式代码都是运行在该中断级别上。

    APC_LEVEL

    当I/o 操作完成时,系统会产生这个中断。为了响应这个中断,应用程序向I/O 完成中断处理例程队列中插入一个APC回调函数,当I/O完成时,该APC函数被调用。如果你不想对这个中断做出响应,你就可以将IRQL提升至APC_LEVEL。这时当I/O完成时,应用程序将不会受到该中断信号。可以调用KeEnterCriticalRegion或KeEnterGuardedRegion将IRQL提升至该级别。APC中断通常是由处理器引发,可以想自己发出也可是像其他处理器发出。一般情况下,是不应该的使用的APC_LEVEL的,除非你想使用Fast Mutexes之类的东西。

    DISPATCH_LEVEL 

    为了能够执行多任务,系统必须允许线程调度。而线程调度的根本就是靠时钟中断来保证的,该级别的中断即调度中断。当你的代码运行的IRQL被提升为DISPATH_LEVEL时,就意味着你的代码不在受线程中断影响力。你的代码会一直运行直到你将IRQL设置为低于DISPATH_LEVEL为止。这中间如果发生缺页错误之类的IRQL级别在DISPATH_LEVEL之下的严重中断时,这些中断均不会被处理。这时,代码将无法正常运行。所以,DISPATH_LEVEL的使用绝对要慎之又慎。只有在是自旋锁时,你才应该考虑选择该IRQL。

    相对于NT驱动,扩展结构中多了一个参数:

    typedef struct _DEVICE_EXTENSION
    {
        PDEVICE_OBJECT fdo;
        PDEVICE_OBJECT NextStackDevice;
    	UNICODE_STRING ustrDeviceName;	// 设备名
    	UNICODE_STRING ustrSymLinkName;	// 符号链接名
    } DEVICE_EXTENSION, *PDEVICE_EXTENSION;

    NextStackDevice!
    pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);

    IoAttachDeviceToDeviceStack函数简介:

    如果一个设备被其他设备绑定,它们在一起的一组设备,被称为设备栈,这个函数返回了最终被绑定的设备指针,也就是最顶层设备

    MSDN:The IoAttachDeviceToDeviceStack routine attaches the caller's device object to the highest device object in the chain and returns a pointer to the previously highest device object.(把调用者设备对象加到设备对象链的最上层,同时返回原来最上层的设备对象)

    比如原来有一个Device A,在这个Device的上层有一个过滤驱动程序的设备Device B, 
    可以用这个图表示: 
    +---+ 
    | B | (最上层)
    +---+  
    | A | 
    +---+ 
      
    然后我们有一个新的Device C,用IoAttachDeviceToDeviceStack(C, A)之后,就把C放到了A所在的链的末端,如下: 
    +---+ 
    | C | (最上层)
    +---+ 
    | B | (次上层,原来的最上层)
    +---+ 
    | A | 
    +---+ 
    同时返回B(原来的最上层)。

    下面看下HelloWDM处理PNP的回调函数

    其中,IRP_MJ_PNP会细分为若干个字类,如,IRP_MN_START_DEVICE,IRP_MN_REMOVE_DEVICE,IRP_MN_STOP_DEVICE

    首先用:

    PAGED_CODE();

    保证运行在低于APC_LEVEL的中断优先级的级别上

    PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

    得到设备的扩展结构

    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

    得到当前IRP的堆栈

     IRP可以看成是窗口程序中的消息(Message),DEVICE_OBJECT可以看成是窗口程序中的窗口(Window)

    任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的 IO_STACK_LOCATION 结构数组:数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序,另外还有一个堆栈单元供IRP的创建者使用,如下图:


    io_stack_location的结构如下图:


    继续上面的代码:

    	ULONG fcn = stack->MinorFunction;

    fcn指定了IRP_MN_START_DEVICE,IRP_MN_QUERY_REMOVE_DEVICE,IRP_MN_REMOVE_DEVICE

    static NTSTATUS (*fcntab[])(PDEVICE_EXTENSION pdx, PIRP Irp) = 
    	{
    		DefaultPnpHandler,		// IRP_MN_START_DEVICE
    		DefaultPnpHandler,		// IRP_MN_QUERY_REMOVE_DEVICE
    		HandleRemoveDevice,		// IRP_MN_REMOVE_DEVICE
    		DefaultPnpHandler,		// IRP_MN_CANCEL_REMOVE_DEVICE

    不在上述列表中的fcn,默认调DefaultPnpHandler函数:

    	if (fcn >= arraysize(fcntab))
    	{						// 未知的子功能代码
    		status = DefaultPnpHandler(pdx, Irp); // some function we don't know about
    		return status;
    	}	

    否则调对应列表中的函数:

    	status = (*fcntab[fcn])(pdx, Irp);

    可以看下MajorFunction的类型:

    UCHAR MajorFunction;
    typedef unsigned char UCHAR;
    最多也就255种

    下面看下卸载:

    	HandleRemoveDevice,		// IRP_MN_REMOVE_DEVICE
    而原来的外部卸载函数是没有东西的:

    	pDriverObject->DriverUnload = HelloWDMUnload;


    #pragma PAGEDCODE
    void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject)
    {
    	PAGED_CODE();
    	KdPrint(("Enter HelloWDMUnload
    "));
    	KdPrint(("Leave HelloWDMUnload
    "));
    }

    所以直接卸载函数是HandleRemoveDevice:

    #pragma PAGEDCODE
    NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
    {
    	PAGED_CODE();
    	KdPrint(("Enter HandleRemoveDevice
    "));
    
    	Irp->IoStatus.Status = STATUS_SUCCESS;//设置虎IRP状态为顺利完成
    	NTSTATUS status = DefaultPnpHandler(pdx, Irp);//调用默认的PNP的IRP的处理函数
    	IoDeleteSymbolicLink(&(UNICODE_STRING)pdx->ustrSymLinkName);//删除此设备对象的符号链接
    
        //调用IoDetachDevice()把fdo从设备栈中脱开:
        if (pdx->NextStackDevice)
            IoDetachDevice(pdx->NextStackDevice);
    	
        //删除fdo:
        IoDeleteDevice(pdx->fdo);//删除设备对象.
    	KdPrint(("Leave HandleRemoveDevice
    "));
    	return status;
    }







  • 相关阅读:
    图论算法 有图有代码 万字总结 向前辈致敬
    关闭和打开键盘的通知
    (copy)赋值构造函数的4种调用时机or方法
    构造函数的分类
    Uva
    Uva
    The 2018 ACM-ICPC Asia Qingdao Regional Contest F
    The 2018 ACM-ICPC Asia Qingdao Regional Contest E Plants vs. Zombies(ZOJ 4062)
    K Color Graph
    Cow and Fields
  • 原文地址:https://www.cnblogs.com/hgy413/p/3693369.html
Copyright © 2011-2022 走看看