MSDN Kernel-Mode Driver Architecture学习笔记(1)——Introduction to Windows Drivers(2)

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

3、Kernel-Mode Drivers(内核模式驱动程序)的设计目标

内核模式驱动程序涵盖了许多操作系统的设计目标,特别是系统的I/O管理器。

内核模式驱动程序的设计有下面七点:

1)     Portable(可移植性):便于从一个平台移植到另一个平台

所有的驱动程序必须对所有Windows支持的硬件平台是可移植的。

为了达到这个跨平台可移植的能力,驱动程序编写者需要做到下面两点:

l  使用C语言编写源代码,不要使用汇编语言

如果所有的内核模式驱动程序都使用C语言编写,那么可以在不需要重写或者替换任何代码的情况下,使用一个系统兼容的C编译器重新编译源代码,并链接生成可运行在非微软Windows平台下的驱动程序。大多数操作系统组件是完全使用C语言编写的,只有很少的HAL和内核组件使用汇编语言编写,因此操作系统很容易跨硬件平台移植。在内核模式驱动程序中不能使用许多C++语言的结构,对可以使用的C++语言的结构也要非常小心。欲了解更详细的关于含有C++特征的驱动程序发生问题时的信息,可参阅在Windows硬件开发人员中心(WHDC)网站上的白皮书C++ for Kernel Mode Drivers: Pros and Cons (使用C++开发内核模式驱动程序的优点和缺点)

驱动程序不要使用依赖于某个特定的系统兼容C编译器或者C支持库的特性,这些特性或许不被其他系统兼容编译器所支持。总的来说,就是驱动程序代码应该符合ANSI C标准,不能依赖于某些“implementation defined(由编译器定义的)所描述的标准。

为了写好可移植的驱动程序,尽可能避免以下几点:

u  使用的数据类型在不同的平台上具有不同的内存大小或者内存布局

u  调用任何还处于维护状态的标准C运行时库函数

u  调用任何操作系统已经提供替代支持例程的标准C运行时库函数

l  务必仅使用WDK支持的程序接口和头文件。

每个NT执行组件都对外提供了一套内核模式驱动支持例程,便于驱动程序和所有的其他内核模式组件调用。即使未来改变了支持例程的内部实现,但是对该组件的调用方式还是与以前保持一致,因为组件定义的接口并没有改变,所以这就保持了组件的可移植性。

WDK提供了一套定义了系统特定的数据类型和常量头文件,驱动程序(和其他所有内核模式组件)使用这些头文件来保持可移植性。所有的内核模式驱动程序都包含一个WDK主内核模式头文件:wdm.h或者ntddk.h。主头文件并不仅仅是那些定义基本内核模式类型的系统支持的头文件,还要包括使用恰当的编译指令来编译驱动程序时所选择的某一处理器架构特定的那些头文件。

有些驱动程序,例如SCSI miniport driversNDIS driversvideo miniport drivers,还需要包含其他的系统支持的头文件。

如果驱动程序要求特定平台定义,那么最好是使用#ifdef编译指令语句将相关代码包含其中以隔离起来。这样每个驱动程序就可以对合适的硬件平台进行编译链接了。不过,我们在驱动程序中几乎不需要使用任何特定平台的条件编译指令代码,只要使用WDK主头文件提供的支持例程、宏、常量和类型就可以了。

内核模式驱动程序可以使用内核模式Rtlxxx等例程,这些例程都在WDK文档中定义了。内核模式驱动程序不能调用用户模式驱动程序的Rtlxxx等例程。

2)     Configurable(可配置性):便于配置多样的硬件和软件平台

当前的外围设备必须是硬件可配置的,并且他们的驱动程序必须是软件可配置的。

如果一个设备可以接受不同的系统硬件资源的参数而不需要物理修改,那么这个设备就是可以配的,例如I/O端口数量。举个例子,在RAID磁盘冗余阵列装置中连接了一套支持热插拔的磁盘,用户可以在系统运行的时候调换磁盘。如果设备是硬件可配置的,那么他的驱动程序就不能包含与硬编码和系统相关数据。

具备下面两点特征的驱动程序就是软件可配置的:

n  可以动态的接受和改变它设备的硬件资源。

驱动程序支持即插即用,并且不包含设备硬件资源的硬编码值,而且驱动程序也不能轮询每个设备去确定他们的资源分配。换句话说,系统为设备动态的分配资源,并把这些资源数据提供给驱动程序。

n  在驱动程序栈中没有假定的高一级或者低一级的驱动程序。

例如,一个低级别的磁盘设备驱动程序的设计必须具有足够的灵活性以支持多种文件系统,这些文件系统由在一台计算机上的多种高级别的文件系统驱动陈新股来实现。

另外,如果一台计算机具有足够的存储容量,那么同样的低等级磁盘驱动程序不能干扰支持文件系统容错(使用镜像分区、带区集或者卷集来实现)的中间驱动程序。

PnP管理器和每个PnP硬件总线驱动协同工作来提供一个操作接口,特定类型的I/O总线硬件与系统软件之间通过这个接口来交互。PnP管理器构造了一个设备树,树的节点描述了系统中所有的设备和总线。

PnP管理器还为每个设备维护两个列表:

n   设备能够拥有的硬件资源列表。

n   当前分配给设备的硬件资源列表。

设备驱动程序协助PnP管理器创建他们列表,这些列表保存在注册表中。如果要从系统中添加和删除设备,那么PnP管理器将根据需要重新分配资源并且更新这些列表。

系统的HAL硬件抽象层组件是以动态连接库形式实现的。这样设计是因为有些系统组件需要一些硬件级、特定平台的支持,包括内核模式驱动程序也需要这些支持。

3)     永远是可抢占的和可中断的:

可抢占和可中断的设计目标是为了使系统获得最好的性能。任何一个线程都可以被具有更高优先权的线程抢断,任何一个驱动程序的终端服务程序都可以被拥有更高终端请求级别的程序中断。

内核组件确定何时运行某一个代码序列,依照下列两个优先次序准则:

n   由内核定义线程运行时优先方案

在系统中的每个线程都有一个关联的优先级属性。一般来说,大多数线程都有一个可变的优先级属性;它们总是以时间片循环的方式与其他具有相同优先级的线程进行抢占和排队的方式运行。有些线程具有实时运行优先属性;这些严格要求时间实时性的线程将持续运行直到事物处理完毕,除非被具有更高实时运行优先权属性的线程抢占。Windows体系架构没有提供实时系统。

当发生硬件中断或者特定类型的软件中断时,无论线程具有什么优先级属性都会被中断。

n   内核定义的中断请求等级(IRQL)作为一个特定的中断向量被分配给一个特定的平台。

内核将硬件和软件中断级别列为高优先,就像一些内核模式代码,包括大多数驱动程序,运行在较高的IRQL;这样就使得它们比系统中的其他线程具有高调度优先级。对于内核模式驱动程序代码块的特定IRQL的执行是由在其底层的设备硬件中断决定的。

内核模式代码始终是可中断的:具有更高IRQL值得中断可以在任意时刻触发,从而使得另一个具备系统分配的更高级别IRQL的内核模式代码块可以立即在处理器上运行。然而,当一个代码块运行在特定的IRQL时,内核将给所有的中断向量设置一个低一级的或者相等级别的IRQL值,以此达到在这个处理器上暂时屏蔽中断的目的。

最低级别的IRQL等级是 PASSIVE_LEVEL。在这个级别下,将没有中断向量被屏蔽。线程通常运行在 IRQL=PASSIVE_LEVEL下。比这个稍高级的IRQL级别用于软件中断。这些等级包括APC_LEVELDISPATCH_LEVEL或者用于内核调试的、WAKE_LEVEL。设备中断一直具有高级别的IRQL值。内核为系统关键的中断保留最高级别的IRQL值,就像系统系统或者总线错误。

有些系统支持历程运行在IRQL=PASSIVE_LEVEL级别,因为有些例程被视为可分页的代码或者访问可分页的数据,也可能因为有些内核模式组件创建它们自己的线程。

同样的,有些标准驱动程序例程也通常运行在IRQL=PASSIVE_LEVEL级别。但是,个别的标准驱动程序例程运行在IRQL=DISPATCH_LEVEL级别,对于最底层的驱动程序则运行在设备IRQL级别(也称为 DIRQL)。更详尽的关于IRQL的信息,参看MSDN中的Managing Hardware Priorities章节。

驱动程序中的每个例程都是可中断的。这包括任何一个运行于比PASSIVE_LEVEL更高级别的例程。在没有更高级别的IRQL中断发生的情况下,任何一个运行于特定IRQL的例程都将持续拥有处理器的控制权。

不像一些较早的个人电脑操作系统中的驱动程序,微软Windows驱动程序的ISR(中断服务程序)从来就不是一个巨大而复杂的处理大多数驱动程序的I/O的例程。这是因为任何一个驱动程序的ISR都可以被其他的运行于更高IRQL级别的例程中断。因此,驱动程序的ISR不需要从它运行开始至结束一直保持对CPU的控制权。

Windows驱动程序中,ISR(中断服务程序)通常是保存硬件状态信息,并插入到延时过程调用队列中(deferred procedure call=DPC),然后迅速退出。最后,系统从DPC队列中提取并处里这个驱动程序的请求,这样运行于低等级IRQL级别(DISPATCH_LEVEL)的驱动程序就可以完成I/O操作了。为了获得更好的系统性能,所有运行于高IRQL级别的例程必须尽快的交出CPU的控制权。

Windows中,所有的线程都有一个线程上下文。这个上下文包含拥有这个线程的进程识别信息,还有其他的特征信息,例如线程的访问权限等。

一般来说,当一个线程请求处理当前的I/O操作的驱动程序时,只有最高层的驱动程序会被调用,也就是这个最高层的驱动程序将运行在这个线程的上下文中。因此,中间层或者最底层的驱动程序不能假定自己正运行在曾申请I/O操作的那个线程的上下文中。

所以,驱动程序例程通常运行在一个任意的线程上下文中——这个上下文是属于当前调用标准驱动程序例程的那个线程。出于性能原因(为了避免上下文切换),只有极少的驱动程序会创建自己的线程。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值