MSDN Kernel-Mode Driver Architecture学习笔记(3)——Device Objects and Device Stacks (3)

随学随记,暂时未经编程验证 Written by HOOK_TTG(Jamie Jiang)

 

6、            Device Extensions设备扩展

对于大多数中间层或者最底层的驱动程序,设备扩展是设备对象非常重要的数据结构。它的内部结构是由驱动程序定义的,通常用于:

l  维护设备状态信息。

l  为任何内核定义的对象或者其他系统资源提供存储空间,比如自旋锁,驱动程序需要用到这些信息。

l  容纳任何驱动程序必须在系统空间常驻的用于执行其I/O操作的数据。

由于大多数总线、功能和过滤驱动程序(底层和中间层驱动程序)运行在一个任意的线程上下文中,所以设备扩展是每个驱动程序主要的存储信息的地方,用于维护驱动程序需要的设备状态和所有其他设备特定数据。例如,任何执行了CustomTimerDpc或者CustomDpc例程的驱动程序,通常需要为其请求到的内核定义的定时器和DPC对象在设备扩展中提供一个存储区。

每个有ISR的驱动程序必须为一个指针提供储存区,这个指针指向一套内核定义的中断对象,大多数设备驱动对象在设备扩展中存储这个指针。每个驱动程序在其创建一个设备对象的时候就确定了设备扩展所需的内存大小,而且每个设备定义其设备扩展的内容和结构。

I/O管理器的IoCreateDeviceIoCreateDeviceSecure例程从非分页内存池中为设备对象分配内存。

每个标准驱动程序例程会接收到一个IRP,还会接收到一个指向设备对象的指针,这个设备对象就代表被请求I/O操作的目标设备。这些驱动程序例程可以通过这个指针访问相应的设备扩展。通常,DeviceObject指针也是一个底层驱动程序ISR的输入参数。

下图显示一个底层驱动程序设备对象的设备扩展中典型的一组驱动程序定义数据。 高层的驱动程序不需要为下列中断对象指针提供存储区,IoConnectInterrupt返回的指针、传递给KeSynchronizeExecutionIoDisconnectInterrupt的指针。不过,如果驱动程序有一个CustomTimerDpc例程,那么高层驱动程序需要为定时器和DPC对象提供存储区,

 

 

除了要为一个中断对象指针提供存储区外,如果底层设备驱动程序的ISR在不同的向量上处理两个或更多设备中断,或者其有多于一个的ISR,那么这个驱动程序必须为中断自旋锁提供存储区。更多关于注册一个ISR的信息,参看MSDN中的 Registering an ISR章节。

通常,驱动程序在他们的设备扩展中存储其设备对象的指针,就像上图所示那样。驱动程序还应该保存一个设备扩展中设备的资源列表备份。

高层驱动程序通常还会在其设备扩展中保存一个指向低一层驱动程序设备对象的指针。高层驱动程序在一个IRP中建立低一层驱动程序的I/O栈后,还必须向IoCallDriver例程传递一个指向低一层驱动程序设备对象的指针。参看MSDN中的 Handling IRPs章节。

还需要注意,为低一层驱动程序分配IRPs的高层驱动程序还需要指定这些新的IRPs应该有多少栈位置。尤其是,如果一个较高层驱动程序调用IoMakeAssociateIrpIoAllocateIrp或者IoInitializeIrp,为了为这些支持例程提供正确的StackSize参数,那么它必须访问紧邻的低一层驱动程序的目标设备对象并读取它的StackSize值。

当一个较高层驱动程序能通过IoAttackDeviceToDeviceStack返回的指针从紧邻的低一层驱动程序的设备对象中读取数据,那么这个驱动程序必须遵循这些执行指导方针:

l  永远不要尝试向低一层驱动程序的设备对象写入数据。

这个指导方针的唯一例外就是文件系统,文件系统会设置和清除低一层可移动介质驱动器的设备对象的Flags中的DO_VERIFY_VOLUME掩码位。

l  永远不要尝试访问低一层驱动程序的设备扩展,原因如下:

¡  在两个驱动程序之间,还没有一个安全的方法来同步访问一个单一设备扩展。

¡  一对的驱动程序不能单独升级其中一个,比如实现一个后门通讯方案,在不改变现有驱动程序源程序的情况下,在他们之间不能插入一个中间层驱动程序,而且也不能被重新编译,也不能容易的从一个Windows平台移到下一个。

为了保持底层驱动程序从一个Windows平台或者版本到下一个版本之间的互通性,高层驱动程序必须重新使用给它们的IRPs或者必须创建一个新的IRPs,而且它们还必须使用IoCallDriver向底层驱动程序传递请求。

7、            设备对象的属性

每个设备对象都有某些属性,用于描述设备和设备对象如何与系统相配合。

设备对象属性包括:

l  设备类型。指定设备的硬件类型。

l  设备特性。指定设备的补充信息。

l  独占访问。指定设备对象是否代表一个独占设备。如果设备是独占的,那么在某一时刻设备只能打开一个设备句柄。(如果底层设备支持重叠I/O,那么同一进程的多个线程可以通过这一个句柄发送操作请求。)

l  安全描述符。设备对象有一个控制设备访问权的安全描述符。

对于其中的每一个属性,在设备对象被创建的时候都会被设置一个默认值。设备对象的属性值也可以放在注册表中。

1)         指定设备类型

每个设备对象都有一个设备类型,它保存在DEVICE_OBJECT结构的DeviceType成员中。这个设备类型为驱动程序描述了底层硬件的类型。

每个创建设备对象的内核模式驱动程序必须在调用IoCreateDevice时指定一个合适的设备类型。IoCreateDevice例程使用提供的设备类型来初始化DEVICE_OBJECT结构中的DeviceType成员。

系统定义了下列设备类型值,列表如下,按字母次序排列:

 

 

这些常量在ntddk.hwdm.h中定义。检查这些文件看看是否定义了其他设备类型。

这个FILE_DEVICE_DISK类型包括了软盘和固定磁盘设备,还有磁盘分区。

中间层驱动程序通常要指定设备类型。例如,系统提供的容错磁盘驱动程序,ftdisk,创建FILE_DEVICE_DISK类型的设备对象;它不为其管理的景象集、带区集和卷集定义新的设备类型。

FILE_DEVICE_XXX032767之间的值是为微软专用的。所有的驱动程序编写者必须为属于系统定义的设备类型的设备使用这些系统定义的常量。

如果一个硬件的类型不匹配任何定义的类型,那么可以指定一个FILE_DEVICE_UNKNOW值,也可以使用3276865535之间的一个值。

2)         指定设备特性

每个设备对象可以有一个或者多个设备特性。设备特性保存在设备对象的DEVICE_OBJECT结构的Characteristics成员中。

大多数驱动程序仅仅指定FILE_DEVICE_SECURE_OPEN特性。这就确保了拥有同样安全设定的任何打开请求可以被接受到设备的名字空间中。更多信息,参看MSDN Controlling Device Namespace Access章节。

FILE_AUTOGENERATED_DEVICE_NAME特性仅被PDOs使用。FILE_FLOPPY_DISKETTEFILE_REMOVEABLE_MEDIAFILE_WRITE_ONCE_MEDIA特性用于特定存储设备。更多可能的设备特性标记的描述,参看DEVICE_OBJECTCharacteristics成员。

某些设备特性,比如FILE_AUTOGENERATED_DEVICE_NAME,仅用于个别设备对象。当驱动程序通过调用IoCreateDevice或者IoCreateDeviceSecure来创建设备对象的时候,它们可以为这些个别的设备对象指定一个设备特性设置。

下面的特性适用于整个设备栈:

FILE_DEVICE_SECURE_OPEN

FILE_FLOPPY_DISKETTE

FILE_READ_ONLY_DEVICE

FILE_REMOVABLE_MEDIA

FILE_WRITE_ONCE_MEDIA

驱动程序可以通过调用IoCreateDevice或者IoCreateDeviceSecure来设置用于整个设备栈的设备特性。另外,无论设备还是设备的安装类,用于整个设备栈的设备特性可以设置在注册表中。

PnP管理器为设备特性确定注册表设定值列举如下:

l  如果设定值是指定用于个别设备的,那么PnP管理器使用那个值。

l  另外,如果设定值是指定用于设备安装类的,那么PnP管理器使用那个值。

l  否则,PnP管理器使用一个零值作为注册表设定值。

如果在注册中的一个设备特性被设置成用于整个设备栈,或者被设置成用于栈中的任一FDO或者过滤DO,那么PnP管理器为栈中的每个设备对象设置一个特性。(如果设备具有原始模式功能,那就没有FDO,那么PnP管理器会使用PDO替代。)

3)         指定设备对象是否独占访问

如果一个设备启用了独占访问,那么在某一时刻只能打开一个设备句柄。为了让I/O管理器强制独占访问设备,必须为设备栈中的命名设备对象设置独占属性。

由于一个WDM设备栈有一个PDO还一个FDO,那么其独占属性只能使用INF文件来设置,通过使用一个 INF AddReg 指令。PDO是栈中的一个命名设备,但是由总线驱动程序代表功能驱动程序创建这个PDO。指示总线驱动程序为PDO设置独占标记的唯一方法就是通过类或者设备INF文件。(调用IoCreateDevice例程创建FDO;位FDO设置独占标记是没有效果的。)

设备对象不能入栈的驱动程序,比如非WDM驱动程序和以原始模式操作的设备,可以使用IoCreateDeviceSecure例程为它们的命名设备对象设置独占属性。

I/O管理器在命名设备对象的每个名字的基础上执行独占性,不管后缀名。例如,假设一个设备对象有一个名字“/Device/DeviceName”,那么I/O管理器为一个打开“/Device/DeviceName/Filename1”的请求执行独占性,通过“/Device/DeviceName/FileName2”方式。如果在设备栈中的两个对象都命名了(不推荐),I/O管理器为每个对象允许一个句柄被打开。在这样的情形下,驱动程序必须在它们DispatchCreate例程中执行它们自己的独占性。I/O管理器也不为另一个文件举兵的打开强制执行独占性。

4)         将设备对象的属性放在注册表中

设备对象的属性可以设置在注册表中,列举如下:

l  对于WDM驱动程序,可以为每个设备模型的属性设置,或者为整个设备安装类设置。(更多关于设备安装类的信息,参看MSDN中的Device Setup Classes章节。)

l  对于非WDM驱动程序,可以为一个命名设备对象的设备安装类的属性设置。驱动程序在使用IoCreateDeviceSecure创建设备对象的时候设置设备安装类。更多关于如何指定一个设备安装类,参看IoCreateDeviceSecure

任何注册表中的设置都会覆盖掉驱动程序创建设备对象时提供的属性。

在设备安装过程中使用的注册设定值由一个INF文件指定,或者也可以在安装之后,通过调用device installation functions(设备安装函数)来指定。

在安装过程中设置设备对象注册属性

为了在安装过程中设置设备对象属性,你必须提供一个描述这些属性的INF文件。你可以为设备或设备安装类指定设备对象属性。

描述如下:

l  对于个别设备,为设备将属性设置在add-registry-sectionINF AddReg指令在设备的DDInstall中。HW节指定设备的add-registry-section

l  对于一个设备安装类,设备安装类的属性被设置在add-registry-sectionINF ClassInstall32节中的AddReg指令指定了类的类描述节add-rehistry-section

add-registry-section中,下列关键字可以用来为个别设备对象属性。

 

Keyword

Device object property

DeviceType

Device type

DeviceCharacteristics

Device characteristics

Exclusive

Exclusive

Security

Security descriptor

 

更多使用这些关键字的信息,参看MSDN INF AddReg Directive

这些设置可以由用户模式组件通过使用设备安装函数来设置。

在安装后设置设备对象注册属性

用户模式程序可以使用设备安装函数来获取和设置作为驱动程序的设备对象属性的注册设定值。通常这些函数由安装软件来使用,但是它们可以被任何用户模式程序使用。(这个程序必须由具有管理员访问权限的用户执行。)

SetupDiGetDeviceRegistryPropertySetupDiSetDeviceRegistryProperty函数用来获取和设置每个指定属性的注册键值。Property参数指定了要获取或设置的属性。PropertyBuffer指向属性的目标缓冲区(在获取属性的时候)或者源缓冲区(在设置属性的时候)。

Property参数值与实际属性之间的对应关系如下:

 

Value for Property parameter

Device object property

SPDRP_CHARACTERISTICS

Device characteristics

SPDRP_DEVTYPE

Device type

SPDRP_EXCLUSIVE

Exclusive

SPDRP_SECURITY Security

Security descriptor as a SECURITY_DESCRIPTOR structure

SPDRP_SECURITY_SDS

Security descriptor as an SDDL string

 

需要注意的是,提供了两个不同的途径来获取或者设置安全描述符。你可以指定SPDRP_SECURITY作为SECURITY_DESCRIPTOR结构的安全描述符,也可以指定SPDRP_SECURITY_SDS作为一个SDDL字符串安全描述符。

对于Windows XP或者更近版本的操作系统,程序还可以获取和设置一个设备安装类的属性值。使用SetupDiGetClassRegistryPropertySetupDiSetClassRegistryProperty函数来获取和设置一个设备安装类的属性值。

更多关于使用SetupDiXxx函数的信息,参看MSDN中的Using Device Installation Functions

 

 

 

在SPARC体系结构中,堆栈(stack)和寄存器(register)是重要的组成部分。 首先,堆栈是一种数据结构,用来存储程序在执行过程中的局部变量、函数调用的返回地址以及调用函数之间的参数。堆栈按照后进先出(Last-In-First-Out, LIFO)的原则工作,即最后进入堆栈的数据最先出栈。在SPARC架构中,堆栈的操作主要通过两个寄存器实现:栈指针寄存器(stack pointer register, SP)和帧指针寄存器(frame pointer register, FP)。栈指针寄存器指向堆栈的顶部,即最新入栈的数据;而帧指针寄存器用于定位函数调用的堆栈帧,即每个函数在堆栈中的存储单元。 其次,寄存器在SPARC架构中被广泛运用,包括用于存储中间结果、操作数以及控制流信息。SPARC架构中有通用寄存器(general-purpose registers, GPR)、浮点寄存器(floating-point registers, FPR)和控制寄存器(control registers)等类型的寄存器。通用寄存器用于存储整数类型的数据,浮点寄存器用于存储浮点数类型的数据,而控制寄存器则用于管理指令流程。 SPARC体系结构中的寄存器主要用于提高数据访问速度和执行指令效率。通过将数据存储在寄存器中,这些数据可以更快速地被指令访问和处理,从而提高程序的执行效率。同时,SPARC还通过寄存器窗口(register windows)技术来提高函数调用的效率。寄存器窗口允许在函数调用时保存和恢复寄存器的状态,减少了数据的堆栈访问,并且使得函数调用的开销更小。 综上所述,了解和掌握SPARC体系结构中的堆栈和寄存器是在进行SPARC架构编程和优化时至关重要的。堆栈提供了一种方便的方式来管理函数调用和局部变量,而寄存器则可以提高程序执行效率和指令访问速度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值