章四.驱动程序的基本结构(上)

以下内容全部来自《Windows驱动开发技术详解》,作者张帆、史彩成等,属摘抄型笔记。

///

数据结构是计算机程序的核心,I/O管理器定义了一些数据结构,这些数据结构是编写驱动程序时所必须掌握的。

1.驱动对象结构

每个驱动程序都会有唯一的驱动对象与之对应,驱动对象在驱动加载时,被内核中的I/O管理器加载。

//驱动对象,以结构体的形式存在于内核驱动程序
typedef struct _DRIVER_OBJECT 
{
    CSHORT Type;  //标识驱动对象的类型
    CSHORT Size;  //标识驱动对象的大小
  
    PDEVICE_OBJECT DeviceObject;  //驱动创建的设备对象
    ULONG Flags;  //指定这个设备的缓冲策略
    
    PVOID DriverStart;   //标识驱动PE映像的基地址
    ULONG DriverSize;    //驱动的大小
    PVOID DriverSection; // 驱动节,指向LDR_DATA_TABLE_ENTRY结构
    PDRIVER_EXTENSION DriverExtension;  //指向Device Extension结构
    
    UNICODE_STRING DriverName;  //驱动程序的名字

    PUNICODE_STRING HardwareDatabase;  //HKEY_LOCAL_MACHINE/Hardware下的路径
  
    PFAST_IO_DISPATCH FastIoDispatch;  //文件驱动派遣函数
    
    PDRIVER_INITIALIZE DriverInit;  //驱动程序初始化例程
    PDRIVER_STARTIO DriverStartIo;  //StartIo例程入口
    PDRIVER_UNLOAD DriverUnload;    //驱动卸载例程
    PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];  //派遣例程
    
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT; 

DeviceObject:每个驱动程序会有一个或多个设备对象,每个设备对象都有一个指针指向下一个驱动对象,最后一个设备对象指向空。设备对象是由程序员自己创建的,而且非操作系统完成;在驱动被卸载的时候,遍历每个设备对象,并将其删除

DeviceName:驱动程序的名字

HardwareDatabase:硬件数据库键名

FastIoDispatch:文件驱动的派遣函数

DriverStartIo:记录StartIO例程的函数地址,用于串行化操作

DriverUnload:指定驱动卸载时所用回调函数的地址

MajorFunction:函数指针数组,处理IRP派遣函数



2.设备对象结构

每个驱动程序会创建一个或多个设备对象,用DEVICE_OBJECT数据结构表示;每一个设备对象都会有一个指针指向下一个设备对象,形成设备链。

typedef struct _DEVICE_OBJECT 
{
    CSHORT Type;
    USHORT Size;
    LONG ReferenceCount;
    struct _DRIVER_OBJECT *DriverObject;
    struct _DEVICE_OBJECT *NextDevice;
    struct _DEVICE_OBJECT *AttachedDevice;
    struct _IRP *CurrentIrp;
    PIO_TIMER Timer;
    ULONG Flags;
    ULONG Characteristics;
    PVPB Vpb;
    PVOID DeviceExtension;
    DEVICE_TYPE DeviceType;
    CCHAR StackSize;
    union 
    {
        LIST_ENTRY ListEntry;
        WAIT_CONTEXT_BLOCK Wcb;
    } Queue;
    ULONG AlignmentRequirement;
    KDEVICE_QUEUE DeviceQueue;
    KDPC Dpc;
    ULONG ActiveThreadCount;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    KEVENT DeviceLock;
    USHORT SectorSize;
    USHORT Spare1;
    struct _DEVOBJ_EXTENSION  *DeviceObjectExtension;
    PVOID  Reserved;
} DEVICE_OBJECT;

DriverObject:指向驱动程序中的驱动对象(同属于一个驱动程序的设备对象指向的是统一驱动对象)

NextDevice:指向下一个设备对象

AttachedDevice:指向更高一层的设备对象

Flags:32位无符号整形


DeviceExtension:指向设备拓展对象

DeviceType:设备类型,当写虚拟设备时,类型为FILE_DEVICE_UNKNOWN


从下图可以更清楚设备对象之间的关系。



3.设备拓展

每个设备对象都会指定一个设备拓展对象,记录设备自己定义的特殊结构体。在驱动程序中,尽量避免使用全局变量,对全局变量进行同步会产生较大的代价。最好的方法是将全局变量存在设备拓展中。

拓展设备由程序员指定内容和大小,由I/O管理器创建,并保存在非分页内存中,在驱动程序的头文件中定义。


4.驱动入口函数DriverEntry

DriverEntry主要是对驱动程序进行才初始化工作,它是由系统进程所调用的。

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegPath)
驱动加载的时候,系统进程System启动新的线程,调用执行体组件只能够的对象管理器,创建一个驱动对象(结构DRIVER_OBJECT),并进行初始化。

而pRegPath至存在于函数生命周期内,如果之后需要使用,则需要将其拷贝到安全的地方。

至于UNICODE_STRING结构:

typedef struct _UNICODE_STRING 
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING;

Length:记录这个字符串用多少 字节记录,如果字符串有N个字符,那么Length为2N。

MaximumLength:记录Buffer的大小,此结构能记录的最大字节数。

Buffer:使用的是UNICODE字符串。

在驱动中可以直接打印UNICODE的信息,

KdPrint(("%S\n", pRegPath->Buffer));


DriverEntry返回值为NTSTATUS的数据,typedef LONG NTSTATUS;,被定义为32位长整型。

其中0x000000000--0x7FFFFFFF被认为是正确的状态;而0x80000000--0xFFFFFFFF被认为是错误的状态。

#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

NT_SUCCESS()是一个判断返回是否正确的宏,可以在驱动中尝试使用。

以下为常用的NTSTATUS值,除过第一个是正确数值,其他都代表不同的错误。


5.创建设备对象

在NT式驱动中,创建设备对象是由IoCreateDevice内核函数完成的。

NTSTATUS
IoCreateDevice(
    IN PDRIVER_OBJECT DriverObject,
    IN ULONG DeviceExtensionSize,
    IN PUNICODE_STRING DeviceName OPTIONAL,
    IN DEVICE_TYPE DeviceType,
    IN ULONG DeviceCharacteristics,
    IN BOOLEAN Exclusive,
    OUT PDEVICE_OBJECT *DeviceObject
    );
DriverObject:每个驱动有唯一驱动对象,确可以有多个设备对象,此指针指向驱动对象。

DeviceExtensionSize:设备拓展的大小,I/O管理器会根据这个大小,在内存创建设备拓展,并与驱动对相关联。

DeviceName:设置设备对象的名字。

DeviceObject:输出参数,设备对象的地址。

IoCreateDevice(pDriverObject, sizeof(PDEVICE_EXTENSION), 
							&devName, FILE_DEVICE_UNKNOWN,
							0, TRUE, &pDeviceObject);
pDeviceObject->Flags |= DO_BUFFERED_IO;

如果在IoCreateDevice中没有指定设备对象 的名字,I/O管理器会自动分配一个数字作为设备的设备名。如果指定了设备名,只能被内核程序识别,应用程序无法识别这个设备,如果需要应用程序能够识别,还需要通过符号链接将设备名称暴露。

在创建设备对象时,设备类型设定的为FILE_DEVICE_UNKNOWN,说明此设备为常用设备之外的设备,一般虚拟设备常使用此作为设备类型。

而此后将Flags设置为DO_BUFFER_IO缓冲区设备。


6.DriverUnload例程

NT式驱动,DriverUnload一般负责删除在DriverEntry中创建的设备对象,并且将设备对象所关联的符号链接删除。

#pragma PAGECODE
VOID FrameUnload(IN PDRIVER_OBJECT pDriverObject)
{
	PDEVICE_OBJECT pNextDev;
	KdPrint(("Enter FrameUnload\r\n"));

	//由驱动对象得到设备对象
	pNextDev = pDriverObject->DeviceObject;
	while (pNextDev != NULL)
	{
		PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextDev->DeviceExtension;

		//删除设备对象符号链接
		UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
		IoDeleteSymbolicLink(&pLinkName);

		pNextDev = pNextDev->NextDevice;
		IoDeleteDevice(pDevExt->pDevice);
	}
}


7.用WinObj观察驱动对象和设备对象

在微软的SysinternalsSuite工具包中有一个WinObj工具,可以查看驱动对象、设备对象、符号链接,以及设备对象的名字。





8.用DeviceTree观察驱动对象和设备对象

DDK自带的工具包有一个DeviceTree,比WinObj能获得更详细的信息。

驱动对象页面,基本上所需的信息都能看到。



设备对象页面



之后可能做各种实验都要用的这个工具,真是十分给力啊。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Linux设备驱动程序 第三版》是一本针对Linux设备驱动程序开发的专业书籍。该书详细介绍了Linux下常见的设备驱动程序开发技术,包括字符设备、块设备和网络设备等方面。这本书主要面向Linux系统内核开发领域的工程师、软件开发人员、嵌入式系统开发者和设备驱动程序编写者等,也适合对Linux设备驱动程序开发感兴趣的读者使用。 《Linux设备驱动程序 第三版》共分为14章,涵盖了设备驱动的基本知识、字符设备驱动程序、块设备驱动程序、内存映射、中断、高级字符驱动程序、USB驱动程序、串行通讯、网络接口卡驱动程序、媒体网关控制协议、显示屏驱动程序、电源管理、高级块驱动程序等方面。每一章的内容非常详细,涵盖了理论知识和例子,并且还提供了配套的示例代码,方便读者进行实践操作。 这本书的重点在于教授读者如何使用Linux内核框架编写驱动程序,如何开发Linux设备驱动程序,以及如何与设备进行交互。同时,还详细介绍了内核数据结构和编程规范、编译驱动程序等技术,使读者更加深入了解Linux设备驱动程序的开发过程。 总之,《Linux设备驱动程序 第三版》是一本非常优秀的Linux设备驱动程序开发教程,书中内容涵盖面广,基本知识详细介绍,适合初学者和进阶者使用。读者通过学习本书,可以更好地掌握Linux设备驱动程序的开发技术,提高自身的技术水平。 ### 回答2: 《Linux设备驱动程序》第三版PDF,是一本深入介绍Linux驱动程序开发的经典著作之一。本书主要介绍了Linux设备驱动程序的编写和调试方法,以及Linux内核的一些基本特性。 本书首先介绍了Linux内核框架和设备驱动模型,包括字符设备、块设备和网络接口设备等。接着,本书深入分析了设备驱动程序结构和实现,详细介绍了内核的I/O系统、中断处理、定时器、内存管理、锁等基本特性,以及与硬件相关的总线、中断控制器、DMA等。此外,本书还介绍了如何使用ioctl和procfs接口,以及注册和使用内核模块等典型应用场景。 总体来说,这本书深入浅出,详细介绍了Linux设备驱动程序的开发与调试方法,为读者提供了全面了解内核和驱动开发的实战指南,是Linux驱动程序开发者必不可少的参考读物。 ### 回答3: 《Linux设备驱动程序 第三版 pdf》是一本介绍Linux设备驱动程序方面的经典教材,其内容包括了Linux设备驱动程序的开发、编写以及调试等相关知识。这本教材适合那些想要理解和开发嵌入式操作系统和设备驱动程序的程序员和工程师们。 该教材主要分为三部分,第一部分介绍了驱动程序的基础知识,包括设备文件、设备驱动程序机制、字符设备以及模块加载和卸载等内容;第二部分则介绍了高级设备驱动程序的开发,如块设备、网络设备以及USB设备驱动程序等;最后一部分则介绍了调试和测试驱动程序的方法和工具。 该教材有以下几个亮点:一是该教材的内容严谨,通俗易懂;二是该教材使用的代码清晰简单,易于理解和实践;三是该教材不仅仅局限于硬件设备的驱动,还涉及了Linux内核模块的编写、网络驱动的开发等内容。同时,该教材也提供了大量的实例代码和案例,可以帮助读者更好地理解和掌握Linux设备驱动程序的开发和调试。 总之,《Linux设备驱动程序 第三版 pdf》是一本非常优秀的Linux设备驱动程序教材,不仅适合于嵌入式开发工程师,也适合于Linux内核爱好者学习和参考。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值