第一卷驱动程序编写者指南 第1章驱动程序开发环境 第2章测试驱动程序
1 第一卷 驱动程序编写者指南 第 1 章 驱动程序开发环境 第 2 章 测试驱动程序
第1章驱动程序开发环境 为 Microsoft Windows82000开发驱动程序至少需要两台机器:一台用于开发,一台用于调 试 如果驱动程序依赖于基本设备,包括高端工作站和服务器,驱动程序也可在一台多处理器计 算机上调试和测试。 本章讨论如下主题: 1.1自由构建( Free Build)和检查构建( Checked build 1.2调试环境 1.1自由构建和检查构建 微软的 Windows2000驱动程序的测试和调试需要 Windows82000的自由构建和检查构建 自由构建(或零星构建)是操作系统的终端用户版本,系统和驱动程序以最优化方式构建, 不可用调试断言,且调试信息已从二进制码中去除。自由系统和驱动程序更小更快,对内存 的需求更小。 检査构建用于操作系统和内核模式驱动程序的测试和调试,检査构建包括意外错误检査、参 数检查和在自由构建中不可用的调试信息。一个检查的系统或驱动程序能帮助区分和记录驱 动程序的某些问题,如内存泄漏或不当的设备配置,这些问题将导致不可预测的后果。 尽管检查构建提供额外的保护,但它比自由构建消耗更多的内存和硬盘空间,且由于下列原 因,系统和驱动程序运行得更慢 可执行程序含有符号调试信息。 由于参数检查和调试输出,执行了附加的代码(诊断信息)。 新的驱动程序开发通常包括以下步骤 1.编写驱动程序代码,应包括条件编译标记的调试检査。 2.测试和调试基于操作系统的检査构建的驱动程序的检查构建。 3.测试和调试基于自由构建的驱动程序的自由构建。 4.基于自由构建的驱动程序的调整 5.使用了检查构建和自由构建的驱动程序和操作系统附加的测试和调试。 6.使用了自由构建的最终的测试和检查。 在驱动程序开发的早期,需要 Windows2000检查构建来调试驱动程序,检查构建的附加调试 代码保护了驱动程序可能导致的许多错误(比如复发的自旋锁)。 执行调整、最终测试和检査驱动程序应该基于自由构建而完成,自由构建的速度越快越有可 能发现竞争条件和其他同步性的问题。 由于自由构建与 Windows2000的零星版本相同,最终测试和检查也应该基于自由构建而完 驱动程序代码通常包括预处理器符号,该符号允许被编译成自由和检查构建。 DBG标记是一个保留的符号,可用它来决定编译时 Windows2000的什么构建在运行,如果
2 第1章 驱动程序开发环境 为 Microsoft® Windows® 2000 开发驱动程序至少需要两台机器:一台用于开发,一台用于调 试。 如果驱动程序依赖于基本设备,包括高端工作站和服务器,驱动程序也可在一台多处理器计 算机上调试和测试。 本章讨论如下主题: ◼ 1.1 自由构建(Free Build)和检查构建(Checked Build) ◼ 1.2 调试环境 1.1 自由构建和检查构建 微软的 Windows2000 驱动程序的测试和调试需要 Windows® 2000 的自由构建和检查构建。 ◼ 自由构建(或零星构建)是操作系统的终端用户版本,系统和驱动程序以最优化方式构建, 不可用调试断言,且调试信息已从二进制码中去除。自由系统和驱动程序更小更快,对内存 的需求更小。 ◼ 检查构建用于操作系统和内核模式驱动程序的测试和调试,检查构建包括意外错误检查、参 数检查和在自由构建中不可用的调试信息。一个检查的系统或驱动程序能帮助区分和记录驱 动程序的某些问题,如内存泄漏或不当的设备配置,这些问题将导致不可预测的后果。 尽管检查构建提供额外的保护,但它比自由构建消耗更多的内存和硬盘空间,且由于下列原 因,系统和驱动程序运行得更慢。 ◼ 可执行程序含有符号调试信息。 ◼ 由于参数检查和调试输出,执行了附加的代码(诊断信息)。 新的驱动程序开发通常包括以下步骤: 1. 编写驱动程序代码,应包括条件编译标记的调试检查。 2. 测试和调试基于操作系统的检查构建的驱动程序的检查构建。 3. 测试和调试基于自由构建的驱动程序的自由构建。 4. 基于自由构建的驱动程序的调整。 5. 使用了检查构建和自由构建的驱动程序和操作系统附加的测试和调试。 6. 使用了自由构建的最终的测试和检查。 在驱动程序开发的早期,需要 Windows2000 检查构建来调试驱动程序,检查构建的附加调试 代码保护了驱动程序可能导致的许多错误(比如复发的自旋锁)。 执行调整、最终测试和检查驱动程序应该基于自由构建而完成,自由构建的速度越快越有可 能发现竞争条件和其他同步性的问题。 由于自由构建与 Windows2000 的零星版本相同,最终测试和检查也应该基于自由构建而完 成。 驱动程序代码通常包括预处理器符号,该符号允许被编译成自由和检查构建。 DBG 标记是一个保留的符号,可用它来决定编译时 Windows2000 的什么构建在运行,如果
Windows2000检查构建运行,设置DBG为1,如果自由构建运行,不定义DBG(或设置为0,如 果或者包括头文件wdmh,或者包括 ntddk h)。 驱动程序也应该在至少一个多处理器平台和至少一个单处理器平台上测试和调试:且这两个 平台应该运行 Windows2000的当前版本。 12调试环境 内核模式调试需要一个目标机和一个主机,目标机用来运行驱动程序或另一内核模式的应用 程序,主机运行调试程序。 图1.1显示使用调试驱动程序的典型 Windows2000设置。内核调试不需要自由或检查构建的 特别结合,从一自由或检査系统调试一自由系统或检査系统是可行的。然而,总体上说,主机没 有理由运行较慢的检查构建。 图1.1典型的 Windows2000调试设置 参看在线DDK的 Debugging drivers和微软的调试程序使用文献来获得更多细节
3 Windows2000 检查构建运行,设置 DBG 为 1,如果自由构建运行,不定义 DBG(或设置为 0,如 果或者包括头文件 wdm.h ,或者包括 ntddk.h)。 驱动程序也应该在至少一个多处理器平台和至少一个单处理器平台上测试和调试;且这两个 平台应该运行 Windows2000 的当前版本。 1.2 调试环境 内核模式调试需要一个目标机和一个主机,目标机用来运行驱动程序或另一内核模式的应用 程序,主机运行调试程序。 图 1.1 显示使用调试驱动程序的典型 Windows2000 设置。内核调试不需要自由或检查构建的 特别结合,从一自由或检查系统调试一自由系统或检查系统是可行的。然而,总体上说,主机没 有理由运行较慢的检查构建。 图 1.1 典型的 Windows2000 调试设置 参看在线 DDK 的 Debugging Drivers 和微软的调试程序使用文献来获得更多细节
第2章检查驱动程序 在 Windows2000上, Driver verifier是新的可用工具,它执行几项测试和调试内核模式驱动程 序的任务 2.1 Driver Verifier Driver verifier是一可帮助监视一个或多个内核模式驱动程序以证实他们没有非法函数调用 或引起系统讹误的工具, Driver Verifier在目标驱动程序上执行广泛的测试和检査任务。例如,如 果驱动程序以非正当的IRQL使用了内存,不正当地调用或释放自旋锁和内存分配,或者释放内 存池时没有首先删除任何定时器, Driver verifier将发布合适的错误检查。 当未装载驱动程序时, Driver Verifier检査确信驱动程序已经正确地清理了队列、线程和其他 项目 此外, Driver verifier能够执行以下任何情况 ■从一个特别内存池分配驱动程序内存请求,该过程测试驱动程序是否访问它的内存分配之外 的内存,或者在释放它的分配之后访问内存。 通过使内存分页代码无效而给驱动程序极端的内存压力,这个过程揭示了访问分页内存的企 图,分页的内存发生在当错误的IRQL或当保留一自旋锁时 池分配的随机失效或其他的内存请求,该过程测试了驱动程序处理低内存状况的能力 未装载的驱动程序检查所有的内存分配,以确信驱动程序没有漏掉内存。 从一特别池分配驱动程序的IRP,监视驱动程序IO以处理其他不一致的行为 这些能力可以分别激活或禁止,此外, Driver verifier可同时用于任何数目的驱动程序。 下面的部分解释了驱动程序的工作方面 2.1.1 Driver verifier的能力 详细描述了 Driver verifier各个作用,它应用于除过图形驱动程序之外的所有内核模式驱动程 ■2.1.2图形驱动程序的 Driver verifier的能力 描述了 Driver verifier对内核模式图形驱动程序的作用,这里内核模式图形驱动程序使用了图 形驱动程序接口(GD)。 ■2.1.3激活和监视 Driver verifier 解释了怎样启动 Driver verifier,怎样选择所要的功能,怎样选择所要检査的驱动程序,也解 释了如何利用 Driver verifier manager来监视正被检查的驱动程序的行为。 注意: Driver verifier能够检査任何数目的驱动程序,然而,当特别内存池和IO检査选项同 时运用于一驱动程序时,其效果将更为有效
4 第2章 检查驱动程序 在 Windows2000 上,Driver Verifier 是新的可用工具,它执行几项测试和调试内核模式驱动程 序的任务。 2.1 Driver Verifier Driver Verifier 是一可帮助监视一个或多个内核模式驱动程序以证实他们没有非法函数调用 或引起系统讹误的工具,Driver Verifier 在目标驱动程序上执行广泛的测试和检查任务。例如,如 果驱动程序以非正当的 IRQL 使用了内存,不正当地调用或释放自旋锁和内存分配,或者释放内 存池时没有首先删除任何定时器,Driver Verifier 将发布合适的错误检查。 当未装载驱动程序时,Driver Verifier 检查确信驱动程序已经正确地清理了队列、线程和其他 项目。 此外,Driver Verifier 能够执行以下任何情况: ◼ 从一个特别内存池分配驱动程序内存请求,该过程测试驱动程序是否访问它的内存分配之外 的内存,或者在释放它的分配之后访问内存。 ◼ 通过使内存分页代码无效而给驱动程序极端的内存压力,这个过程揭示了访问分页内存的企 图,分页的内存发生在当错误的 IRQL 或当保留一自旋锁时。 ◼ 池分配的随机失效或其他的内存请求,该过程测试了驱动程序处理低内存状况的能力。 ◼ 未装载的驱动程序检查所有的内存分配,以确信驱动程序没有漏掉内存。 ◼ 从一特别池分配驱动程序的 IRP,监视驱动程序 I/O 以处理其他不一致的行为。 这些能力可以分别激活或禁止,此外,Driver Verifier 可同时用于任何数目的驱动程序。 下面的部分解释了驱动程序的工作方面: ◼ 2.1.1 Driver Verifier 的能力 详细描述了 Driver Verifier 各个作用,它应用于除过图形驱动程序之外的所有内核模式驱动程 序。 ◼ 2.1.2 图形驱动程序的 Driver Verifier 的能力 描述了 Driver Verifier 对内核模式图形驱动程序的作用,这里内核模式图形驱动程序使用了图 形驱动程序接口(GDI)。 ◼ 2.1.3 激活和监视 Driver Verifier 解释了怎样启动 Driver Verifier,怎样选择所要的功能,怎样选择所要检查的驱动程序,也解 释了如何利用 Driver Verifier Manager 来监视正被检查的驱动程序的行为。 注意:Driver Verifier 能够检查任何数目的驱动程序,然而,当特别内存池和 I/O 检查选项同 时运用于一驱动程序时,其效果将更为有效
211 Driver verifier的能力 Driver Verifier有两种能力:一种是一直起作用,另一种只有被选择时才起作用 以下是对 Driver verifier所有能力的描述 ■2.1.1.1自动检查 这些是一直起作用的功能,比如IRQL和内存例程的检查,检查定时器检查释放的内存池, 检查驱动程序的正确卸载。 21.1.2特别内存池 这个功能使用了一个特别池来测试内存的上溢和下溢,及在内存释放之后的访问。 ■2.1.1.3强迫IRQL检查 这个功能给驱动程序极端的内存压力来揭示内存分页的故障。 2.1.1.4低资源模拟 这个功能注入随机分配错误和其他被拒决的请求来测试驱动程序在低内存状况下的响应。 2.1.1.5内存池跟踪 这个功能检查当驱动程序被卸载时所有内存分配已经释放。 ■2.1.1.6I/O检查 这个功能监视驱动程序IO对非法或不一致的行为的处理。 21.1.1自动检查 不论 Driver verifier检查一个或多个驱动程序,它将执行以下功能,这些功能不受任何 Driver Verifier选项的允许和禁止之影响。 IRQL和内存例程的检查 Driver verifier为下面被禁止的功能而监视所选择的驱动程序。 通过调用 KeLowerIrql提高IRQL 通过调用 KeRaiselrql降低IRQL 零内存分配请求 在 APC LEVER之上的IRQL分配和释放分页池 在 DIPATCH LEVER之上的IRQL分配和释放非分页池 尝试释放一个没有从前面的分配里返回的地址 尝试释放一个已被释放的地址。 ■在 APC LEⅤER之上的在IRQL获取和释放一个快速的互斥体 ■在IRQL而非在 DIPATCH LEⅤER之上获取和释放一个自旋锁 双倍释放一个自旋锁 指定一非法或随机(未初始化的)参数给任一API。 如果 Driver verifier没有运行,在所有状况下,这些故障不大可能会引起立即的系统崩溃,如 果以上任何故障发生,则 Driver verifier监视驱动程序的行为并发布错误检测αxC4。(参看微软调 试程序文档的使用来获得错误检查参数。) 检查被释放的内存池定时器 Driver verifier检查所有被检查驱动程序所释放的内存池,如果任何定时器保留在该池里,发 布错误检测0xC7。(遗忘的定时器能导致最终系统崩溃,这是最难考虑到的。)
5 2.1.1 Driver Verifier 的能力 Driver Verifier 有两种能力:一种是一直起作用,另一种只有被选择时才起作用。 以下是对 Driver Verifier 所有能力的描述: ◼ 2.1.1.1 自动检查 这些是一直起作用的功能,比如 IRQL 和内存例程的检查,检查定时器检查释放的内存池, 检查驱动程序的正确卸载。 ◼ 2.1.1.2 特别内存池 这个功能使用了一个特别池来测试内存的上溢和下溢,及在内存释放之后的访问。 ◼ 2.1.1.3 强迫 IRQL 检查 这个功能给驱动程序极端的内存压力来揭示内存分页的故障。 ◼ 2.1.1.4 低资源模拟 这个功能注入随机分配错误和其他被拒决的请求来测试驱动程序在低内存状况下的响应。 ◼ 2.1.1.5 内存池跟踪 这个功能检查当驱动程序被卸载时所有内存分配已经释放。 ◼ 2.1.1.6 I/O 检查 这个功能监视驱动程序 I/O 对非法或不一致的行为的处理。 2.1.1.1 自动检查 不论 Driver Verifier 检查一个或多个驱动程序,它将执行以下功能,这些功能不受任何 Driver Verifier 选项的允许和禁止之影响。 IRQL 和内存例程的检查 Driver Verifier 为下面被禁止的功能而监视所选择的驱动程序。 ◼ 通过调用 KeLowerIrql 提高 IRQL ◼ 通过调用 KeRaiseIrql 降低 IRQL ◼ 零内存分配请求 ◼ 在 APC_LEVER 之上的 IRQL 分配和释放分页池 ◼ 在 DIPATCH_LEVER 之上的 IRQL 分配和释放非分页池 ◼ 尝试释放一个没有从前面的分配里返回的地址。 ◼ 尝试释放一个已被释放的地址。 ◼ 在 APC_LEVER 之上的在 IRQL 获取和释放一个快速的互斥体 ◼ 在 IRQL 而非在 DIPATCH_LEVER 之上获取和释放一个自旋锁 ◼ 双倍释放一个自旋锁 ◼ 指定一非法或随机(未初始化的)参数给任一 API。 如果 Driver Verifier 没有运行,在所有状况下,这些故障不大可能会引起立即的系统崩溃,如 果以上任何故障发生,则 Driver Verifier 监视驱动程序的行为并发布错误检测 0xC4。(参看微软调 试程序文档的使用来获得错误检查参数。) 检查被释放的内存池定时器 Driver Verifier 检查所有被检查驱动程序所释放的内存池,如果任何定时器保留在该池里,发 布错误检测 0xC7。(遗忘的定时器能导致最终系统崩溃,这是最难考虑到的。)
检查驱动程序的卸裁 当一个正被检査的驱动程序卸载后, Driver verifier执行几个检查来确信驱动程序已被清空 特别地, Driver Verifier寻找下面部分: 未删除的定时 未定的DPC 未删除的辅助列表 未删除的工作线程 未删除的队列 其他类似的资源 诸如以上的问题能潜在地引起系统错误检査在驱动程序卸载后被发布,引起这些错误检测的 原因难于判断。当 Driver verifier运行时,这种故障将导致错误检测0xC7在驱动程序卸载之后立 即发布。(参看微软的调试程序文件的使用来获得错误检测参数的列表。) 图形驱动程序 当检查一个驱动程序时,这些自动检查没有执行 2112特别内存池( Special Memory Pool) 内存讹误是一个普通的驱动程序问题,驱动程序错误能在错误出现的长时间后导致崩溃。这些 错误中最普通要数访问已被释放的内存,并分配n字节然后是n+1字节 为发现内存讹误, Driver verifier能够从一特别池分配驱动程序内存并监视该池防止不正确的 访问 两个特别池定位是可行的, Ver ify End定位更易于发现访问上溢, Verify Start分配更易发现 下溢。(注意:主要的内存讹误是由于上溢,而非下溢。) 当特别内存池运行并且选择了 Verify End时,驱动程序请求的每一个内存分配被放置到不同 的内存页码上。允许分配适合分页的最高可能地址被返回,这样内存被定位于页末。分页的前面 部分用特殊的模式写入,前面的页码和紧邻的页码被标记为不可访问的 如果驱动程序在分配结束之后试图访问内存, Driver verifier将立即发现并发布错误检测 0xCD,如果驱动程序在缓冲区的开始之前写内存,这将(大概)更改这种模式。当缓冲区被释放 Driver verifier将发现更改并报告错误检测OxCl。 如果驱动程序在缓冲区释放以后读出或写入, Driver Verifier将报告错误检测oxCC。 当选择 Verify Start时,内存缓冲区定位于分页的开始,在这种设置下,下溢立即引起错误检 测,而上溢只有当内存被释放时才引起错误检测。这个选项的其他方面与 Verify End选项是相同 由于驱动程序上溢错误比下溢错误普遍的多,所以 Verify End是默认的定位。为改变这种设 置,使用全局标记应用程序( Global Flags Utility) 个单独的内存分配推翻这种设置,并通过调用 ExAllocate With Tag Priority的 Priority参数来 设置成 Xxx SpecialPoolOverrun或 XxxS pecial Pool Underrun来选择它的定位。(这个例程不能够激 活或去活特别池,或者请求一个特别的内存分配,否则的话,这个内存分配将从普通池得到,只 有此种定位才能够被这个例程控制。) 池标记 Driver verifier将给已选择要检查的驱动程序指定特别池,另外一种使用特别池的方法是指定 它到被一个专用 pool tag标记的内存池
6 检查驱动程序的卸载 当一个正被检查的驱动程序卸载后,Driver Verifier 执行几个检查来确信驱动程序已被清空。 特别地,Driver Verifier 寻找下面部分: ◼ 未删除的定时器 ◼ 未定的 DPC ◼ 未删除的辅助列表 ◼ 未删除的工作线程 ◼ 未删除的队列 ◼ 其他类似的资源 诸如以上的问题能潜在地引起系统错误检查在驱动程序卸载后被发布,引起这些错误检测的 原因难于判断。当 Driver Verifier 运行时,这种故障将导致错误检测 0xC7 在驱动程序卸载之后立 即发布。(参看微软的调试程序文件的使用来获得错误检测参数的列表。) 图形驱动程序 当检查一个驱动程序时,这些自动检查没有执行。 2.1.1.2 特别内存池(Special Memory Pool) 内存讹误是一个普通的驱动程序问题,驱动程序错误能在错误出现的长时间后导致崩溃。这些 错误中最普通要数访问已被释放的内存,并分配 n 字节然后是 n+1 字节。 为发现内存讹误,Driver Verifier 能够从一特别池分配驱动程序内存并监视该池防止不正确的 访问。 两个特别池定位是可行的,Verify End 定位更易于发现访问上溢,Verify Start 分配更易发现 下溢。(注意:主要的内存讹误是由于上溢,而非下溢。) 当特别内存池运行并且选择了 Verify End 时,驱动程序请求的每一个内存分配被放置到不同 的内存页码上。允许分配适合分页的最高可能地址被返回,这样内存被定位于页末。分页的前面 部分用特殊的模式写入,前面的页码和紧邻的页码被标记为不可访问的。 如果驱动程序在分配结束之后试图访问内存,Driver Verifier 将立即发现并发布错误检测 0xCD,如果驱动程序在缓冲区的开始之前写内存,这将(大概)更改这种模式。当缓冲区被释放, Driver Verifier 将发现更改并报告错误检测 0xC1。 如果驱动程序在缓冲区释放以后读出或写入,Driver Verifier 将报告错误检测 0xCC。 当选择 Verify Start 时,内存缓冲区定位于分页的开始,在这种设置下,下溢立即引起错误检 测,而上溢只有当内存被释放时才引起错误检测。这个选项的其他方面与 Verify End 选项是相同 的。 由于驱动程序上溢错误比下溢错误普遍的多,所以 Verify End 是默认的定位。为改变这种设 置,使用全局标记应用程序(Global Flags Utility)。 一个单独的内存分配推翻这种设置,并通过调用 ExAllocateWithTagPriority 的 Priority 参数来 设置成 XxxSpecialPoolOverrun 或 XxxSpecialPoolUnderrun 来选择它的定位。(这个例程不能够激 活或去活特别池,或者请求一个特别的内存分配,否则的话,这个内存分配将从普通池得到,只 有此种定位才能够被这个例程控制。) 池标记 Driver Verifier 将给已选择要检查的驱动程序指定特别池,另外一种使用特别池的方法是指定 它到被一个专用 pool tag 标记的内存池
Global Flags Utility能够用来将特别池给具有一给定标记的池。 同时通过 Driver verifier和 Global Flags Utility来请求特别池是允许的,如果这么做,微软的 Windows2000将试图利用特别池给指定标记的所有的池和来自指定驱动程序所有的池分配请求 特别池效率 每个来自特别池的分配使用一个不可分页的内存页码和两个具有虚拟地址空间的页码,如果 此池被耗尽,内存通过标准的方式分配,直到特别池再次变得可用为止。这样,如果特别内存池 ( Special Memory Pool)正在使用,不推荐同时检查多驱动程序。 发出了大量小内存请求的单个驱动程序也能够耗尽此池,出现这种情况,给驱动程序内存分 配指定池标记且一次使特别池给一个池标记是可以选择的。 特别池的大小随着系统物理内存的增大而增加,理想地,其容量至少1GB。在ⅹ86机器上 当虚拟空间(还有物理空间)被消耗时,引导而没有/3GB开关也是可选的。增加分页文件达最 小最大数量(通过二,三当中的一个因子)也是一个好主意 如果特别内存池可用,但是不到95%的所有池分配已经从特别池指定,在驱动程序测试管理 器( Driver Verifier Manager)的 Driver status screen上将出现一个警告。发生这种情况,你应该 检查一个更短的驱动程序列表,通过池标记检查单个池,或者给你的系统增加更多的物理内存。 为确信所有的驱动程序分配已被测试,推荐加强驱动程序较长时间周期 监视特别池 Driver verifier manager的 Global Counters screen能被用来监视特别池的使用 如果是 Allocations Succeeded,特别池计数器等同于 Allocations Succeeded计数器,于是特 别池足够覆盖所有的内存分配。如果 Allocations Succeeded:特别池少于 Allocations Succeeded, 则特别池至少已经被耗尽过一次。 由于特别池没运用于这些计数器,所以计数器不跟踪大小为一页或更多的分配 内核调试程序扩展! verifier也能够运用于监视特别池使用,它展示了与 Driver Verifier Manager 相似的信息。欲获取关于调试程序扩展的信息,请参看微软调试程序使用文件。 图形驱动程序 为获取这种选项怎样作用显示于驱动程序和内核模式打印驱动程序,参看图形驱动程序的特 别内存池。 21.1.3强迫IRQL检查( Forcing IRQL Checking) 尽管内核模式驱动程序被禁止在高IRQL或保持一种自旋锁时访问分页内存,但如果分页实 际上没被修剪,这种动作将不会被注意到。 当 Forcing IROL Checking可用时, Driver Verifier将给所选择的驱动程序施加极端的内存压 力。不论何时IRQL被抬伸到 DISPATCH LEⅤEL或更高,或当一自旋锁被请求时,所有的驱动 程序的可分页代码和数据(和系统可分页的池、代码、数据)被标记为修剪过。如果驱动程序试 图访问任何一个这种内存, Driver verifier发布一个错误检测。 既然别的驱动程序的IRQL抬伸不会引起这个动作,这个内存压力将不会直接作用于未被选 择检查的驱动程序。然而,当一个正在检查的驱动程序抬伸IRQL时, Driver verifier修剪分页 该分页能在未被检査的驱动程序所使用。当这个选项运行时,未被检查的驱动程序的这种错误可 能偶然被捕获。 图形驱动程序 Forτ ing IROL Checking选项不用于图形驱动程序,如被选中,将不起作用
7 Global Flags Utility 能够用来将特别池给具有一给定标记的池。 同时通过 Driver Verifier 和 Global Flags Utility 来请求特别池是允许的,如果这么做,微软的 Windows2000 将试图利用特别池给指定标记的所有的池和来自指定驱动程序所有的池分配请求。 特别池效率 每个来自特别池的分配使用一个不可分页的内存页码和两个具有虚拟地址空间的页码,如果 此池被耗尽,内存通过标准的方式分配,直到特别池再次变得可用为止。这样,如果特别内存池 (Special Memory Pool)正在使用,不推荐同时检查多驱动程序。 发出了大量小内存请求的单个驱动程序也能够耗尽此池,出现这种情况,给驱动程序内存分 配指定池标记且一次使特别池给一个池标记是可以选择的。 特别池的大小随着系统物理内存的增大而增加,理想地,其容量至少 1 GB。在 x86 机器上, 当虚拟空间(还有物理空间)被消耗时,引导而没有/3 GB 开关也是可选的。增加分页文件达最 小/最大数量(通过二,三当中的一个因子)也是一个好主意。 如果特别内存池可用,但是不到 95%的所有池分配已经从特别池指定,在驱动程序测试管理 器(Driver Verifier Manager)的 Driver Status screen 上将出现一个警告。发生这种情况,你应该 检查一个更短的驱动程序列表,通过池标记检查单个池,或者给你的系统增加更多的物理内存。 为确信所有的驱动程序分配已被测试,推荐加强驱动程序较长时间周期。 监视特别池 Driver Verifier Manager 的 Global Counters screen 能被用来监视特别池的使用。 如果是 Allocations Succeeded ,特别池计数器等同于 Allocations Succeeded 计数器,于是特 别池足够覆盖所有的内存分配。如果 Allocations Succeeded:特别池少于 Allocations Succeeded , 则特别池至少已经被耗尽过一次。 由于特别池没运用于这些计数器,所以计数器不跟踪大小为一页或更多的分配。 内核调试程序扩展!verifier 也能够运用于监视特别池使用,它展示了与Driver Verifier Manager 相似的信息。欲获取关于调试程序扩展的信息,请参看微软调试程序使用文件。 图形驱动程序 为获取这种选项怎样作用显示于驱动程序和内核模式打印驱动程序,参看图形驱动程序的特 别内存池。 2.1.1.3 强迫 IRQL 检查(Forcing IRQL Checking) 尽管内核模式驱动程序被禁止在高 IRQL 或保持一种自旋锁时访问分页内存,但如果分页实 际上没被修剪,这种动作将不会被注意到。 当 Forcing IRQL Checking 可用时,Driver Verifier 将给所选择的驱动程序施加极端的内存压 力。不论何时 IRQL 被抬伸到 DISPATCH_LEVEL 或更高,或当一自旋锁被请求时,所有的驱动 程序的可分页代码和数据(和系统可分页的池、代码、数据)被标记为修剪过。如果驱动程序试 图访问任何一个这种内存,Driver Verifier 发布一个错误检测。 既然别的驱动程序的 IRQL 抬伸不会引起这个动作,这个内存压力将不会直接作用于未被选 择检查的驱动程序。然而,当一个正在检查的驱动程序抬伸 IRQL 时,Driver Verifier 修剪分页, 该分页能在未被检查的驱动程序所使用。当这个选项运行时,未被检查的驱动程序的这种错误可 能偶然被捕获。 图形驱动程序 Forcing IRQL Checking 选项不用于图形驱动程序,如被选中,将不起作用
21.1.4低资源模拟( Low Resources simulation) 当 Low re soues simulation可用时, Driver verifier将引起驱动程序内存分配的一个随机选择 失效,这个过程测试驱动程序对低内存和其他低资源状况下正常反应的能力。 为精确模拟一低内存条件,这些分配故障直到系统启动后的7分钟被注入,因此,在该过程 中暴露的任何驱动程序错误将以合法的运行问题对待,而非不切实际的情况 标记为 MUST SUCCEED的分配请求不服从于这一动作, MUST SUCCEED池的每页最大 值被禁止 Driver verifier能同时检查所选择的驱动程序或所有的驱动程序。 图形驱动程序 参看图形驱动程序的 Low resources simulation来获得该选项如何作用于显示驱动程序和内核 模式驱动程序的细节。 211.5内存池跟踪( Memory Pool Tracking) Memory Pool Tracking监视驱动程序所做的内存分配,当驱动程序未装载时, Driver verifier 确保驱动程序所决定的任何分配都已经释放。 不能释放的内存分配(也叫内存泄露)是引起低操作系统执行的通常原因,这些能引起系统 池破碎,最终导致系统崩溃 当这一选项运行时,如一驱动程序没有释放其所有的分配就卸载, Driver verifier将发布错误 检测0xC4(参数1等于0x60)。 如果 Driver verifier发布错误检测的参数1等于0x51,0x52,0x53,0x54或0x59,则该驱动 程序已经写入分配之外的内存里,在这种状况下,你应该能够让特别内存池来定位错源 参看微软调试程序文件的使用来获得所有错误检测参数0xC4的列表 监视内存池跟踪 Driver Verifier Manager的 Pool Tracking screen能够用来监视有分页和无分页的池分配。 内核调试程序扩展! verifier2能被用于驱动程序卸载之后未决的内存分配,或当驱动程序运行 时跟踪当前的内存分配。这个扩展也表明了池标记,池大小和每一个分配的分配器地址。为更多 的调试程序信息,请参看微软的调试程序使用文件 图形驱动程序 Memory Pool Tracking选项不适用于图形驱动程序,如被选中,不起作用 21.16O检查 Driver Verifier有两个IO检查构建,1级IO检查从一特别池分配驱动程序的IRP和监视驱 动程序的I/O对各种不当的动作的处理,2级IO检查执行所有1级的动作,和许多更细更广驱动 程序IO的使用。 2级I/O检查是一更有力的检测驱动程序LO的使用的方法,然而,这种高级的详细审查占用 了更多的内存,且它也能降低操作系统的执行级别。 1级O检查 当1级O检查可用时,通过 loAllocatelrp获得的所有IRP从一特别池分配,且它们的使用 受到跟踪
8 2.1.1.4 低资源模拟(Low Resources Simulation) 当 Low Resources Simulation 可用时,Driver Verifier 将引起驱动程序内存分配的一个随机选择 失效,这个过程测试驱动程序对低内存和其他低资源状况下正常反应的能力。 为精确模拟一低内存条件,这些分配故障直到系统启动后的 7 分钟被注入,因此,在该过程 中暴露的任何驱动程序错误将以合法的运行问题对待,而非不切实际的情况。 标记为 MUST_SUCCEED 的分配请求不服从于这一动作, MUST_SUCCEED 池的每页最大 值被禁止。 Driver Verifier 能同时检查所选择的驱动程序或所有的驱动程序。 图形驱动程序 参看图形驱动程序的Low Resources Simulation 来获得该选项如何作用于显示驱动程序和内核 模式驱动程序的细节。 2.1.1.5 内存池跟踪(Memory Pool Tracking) Memory Pool Tracking 监视驱动程序所做的内存分配,当驱动程序未装载时,Driver Verifier 确保驱动程序所决定的任何分配都已经释放。 不能释放的内存分配(也叫内存泄露)是引起低操作系统执行的通常原因,这些能引起系统 池破碎,最终导致系统崩溃。 当这一选项运行时,如一驱动程序没有释放其所有的分配就卸载,Driver Verifier 将发布错误 检测 0xC4(参数 1 等于 0x60)。 如果 Driver Verifier 发布错误检测的参数 1 等于 0x51,0x52,0x53,0x54 或 0x59,则该驱动 程序已经写入分配之外的内存里,在这种状况下,你应该能够让特别内存池来定位错源。 参看微软调试程序文件的使用来获得所有错误检测参数 0xC4 的列表。 监视内存池跟踪 Driver Verifier Manager 的 Pool Tracking screen 能够用来监视有分页和无分页的池分配。 内核调试程序扩展!verifer2 能被用于驱动程序卸载之后未决的内存分配,或当驱动程序运行 时跟踪当前的内存分配。这个扩展也表明了池标记,池大小和每一个分配的分配器地址。为更多 的调试程序信息,请参看微软的调试程序使用文件。 图形驱动程序 Memory Pool Tracking 选项不适用于图形驱动程序,如被选中,不起作用。 2.1.1.6 I/O 检查 Driver Verifier 有两个 I/O 检查构建,1 级 I/O 检查从一特别池分配驱动程序的 IRP 和监视驱 动程序的 I/O 对各种不当的动作的处理,2 级 I/O 检查执行所有 1 级的动作,和许多更细更广驱动 程序 I/O 的使用。 2 级 I/O 检查是一更有力的检测驱动程序 I/O 的使用的方法,然而,这种高级的详细审查占用 了更多的内存,且它也能降低操作系统的执行级别。 1 级 I/O 检查 当 1 级 I/O 检查可用时,通过 IoAllocateIrp 获得的所有 IRP 从一特别池分配,且它们的使用 受到跟踪
此外, Driver verifier检查非法的I/O调用,包括: 尝试释放一个非 IO TYPE IRP类型的IRP 传递非法设备对象给 lo callDriver 传递一IRP给含有非法的状态或仍保留一已取消的例程集的 lo CompleteRequest 通过驱动程序调度例程的调用来改变IRQL 尝试释放保留关联的一个线程的IRP 传递一个设备对象给已经有初始化过的定时器的 lo lnitializetimer 传递 个非法的缓冲区给 lo Build Asynchronous sdRequest或 lo Build Devicelo ControlRequest 当一个IO状态块分配给一极松散的堆栈时,传递一个I/O状态块给一个IRP 当一个事件对象分配给一极松散的堆栈时,传递一个事件对象给一个IRP 由于特别IRP池有大小限制,只有当一次使用于一个驱动程序时,IO检查才最有效 1级IO检查失效将引起错误检测0xC9发布,错误检测的第一个参数表明有什么违背发生 欲得一个全部的错误检测0xC9参数的列表,参看微软的调试程序文件。 级ⅣO检查 2级O检查错误以不同的方式显示:在一个蓝屏上、在一个崩溃的转储文件里和在一个内 核调试程序里。 在一个蓝屏上,信息 IO SYSTEMⅤ ERIFICATION ERROR和信息串 WDM DRIVER ERROR XXX记下了这些错误,这里XXX是一个LO的错误代码 个崩溃的转储文件里 信息 BugCheck0xC9 ( DRIVERⅤ ERIFIER IOMANAGER VIOLATION)与IO错误代码一道,记下了这些错误 在此情况下,IO错误代码以错误检测0xC9的第一个参数出现。 个内核调试程序里(KD或 WinDbg)这些错误以信息 WDM DRIⅤ ER ERROR和一描述 的文本信息串出现,当内核调试程序运行时,忽略2级错误和恢复系统操作是可能的。(不可能出 现别的错误检测。) 在以上的每一情况下,额外信息(例如驱动程序名和各种可用的指针)也被显示,欲知2级 L/O检査错误信息的全面描述,参看微软的调试程序文件中关于错误检测0xC9的部分。 图形驱动程序 I/O检查选项不适用于图形驱动程序,如被选中,不起作用 212 Driver verifier对图形驱动程序的能力 微软的 Windows2000内核模式图形驱动程序不直接分配内存池,相反,这些驱动程序使用 GDⅠ(图形驱动程序接口)服务例程,该例程由win32ksys提供。 由于这个差异, Driver verifier对待图形驱动程序与内核模式驱动程序不同。 下面的部分描述了 Driver verifier在显示驱动程序和内核模式打印驱动程序上的作用。 2.12.1图形驱动程序的特别内存池 该动作使用一特别池来检测内存的上溢和下溢,还有在其释放后访问内存 2.1.2.2图形驱动程序的低资源模拟 该动作注入随机的分配故障和其他被拒绝的请求来检测驱动程序在一个低内存状况下的反
9 此外,Driver Verifier 检查非法的 I/O 调用,包括: ◼ 尝试释放一个非 IO_TYPE_IRP 类型的 IRP ◼ 传递非法设备对象给 IoCallDriver ◼ 传递一 IRP 给含有非法的状态或仍保留一已取消的例程集的 IoCompleteRequest ◼ 通过驱动程序调度例程的调用来改变 IRQL ◼ 尝试释放保留关联的一个线程的 IRP ◼ 传递一个设备对象给已经有初始化过的定时器的 IoInitializeTimer ◼ 传 递 一 个 非 法 的 缓 冲 区 给 IoBuildAsynchronousFsdRequest 或 IoBuildDeviceIoControlRequest ◼ 当一个 I/O 状态块分配给一极松散的堆栈时,传递一个 I/O 状态块给一个 IRP ◼ 当一个事件对象分配给一极松散的堆栈时,传递一个事件对象给一个 IRP 由于特别 IRP 池有大小限制,只有当一次使用于一个驱动程序时,I/O 检查才最有效。 1 级 I/O 检查失效将引起错误检测 0xC9 发布,错误检测的第一个参数表明有什么违背发生。 欲得一个全部的错误检测 0xC9 参数的列表,参看微软的调试程序文件。 2 级 I/O 检查 2 级 I/O 检查错误以不同的方式显示:在一个蓝屏上、在一个崩溃的转储文件里和在一个内 核调试程序里。 在一个蓝屏上,信息 IO SYSTEM VERIFICATION ERROR 和信息串 WDM DRIVER ERROR XXX 记下了这些错误,这里 XXX 是一个 I/O 的错误代码。 在 一 个 崩 溃 的 转 储 文 件 里 , 信 息 BugCheck 0xC9 (DRIVER_VERIFIER_IOMANAGER_VIOLATION)与 I/O 错误代码一道,记下了这些错误。 在此情况下,I/O 错误代码以错误检测 0xC9 的第一个参数出现。 一个内核调试程序里(KD 或 WinDbg)这些错误以信息 WDM DRIVER ERROR 和一描述 的文本信息串出现,当内核调试程序运行时,忽略 2 级错误和恢复系统操作是可能的。(不可能出 现别的错误检测。) 在以上的每一情况下,额外信息(例如驱动程序名和各种可用的指针)也被显示,欲知 2 级 I/O 检查错误信息的全面描述,参看微软的调试程序文件中关于错误检测 0xC9 的部分。 图形驱动程序 I/O 检查选项不适用于图形驱动程序,如被选中,不起作用。 2.1.2 Driver Verifier 对图形驱动程序的能力 微软的 Windows2000 内核模式图形驱动程序不直接分配内存池,相反,这些驱动程序使用 GDI(图形驱动程序接口)服务例程,该例程由 win32k.sys 提供。 由于这个差异,Driver Verifier 对待图形驱动程序与内核模式驱动程序不同。 下面的部分描述了 Driver Verifier 在显示驱动程序和内核模式打印驱动程序上的作用。 ◼ 2.1.2.1 图形驱动程序的特别内存池 该动作使用一特别池来检测内存的上溢和下溢,还有在其释放后访问内存。 ◼ 2.1.2.2 图形驱动程序的低资源模拟 该动作注入随机的分配故障和其他被拒绝的请求来检测驱动程序在一个低内存状况下的反
图形驱动程序的不可用选项 当在检查一个图形驱动程序时, Driver verifier经常执行的自动检查(IRQL和内存例程的检 查,检査定时器释放的内存池,检査驱动程序卸载)并不执行。 强迫IRL检测、内存池跟踪和1/O检査选项不被用于图形驱动程序,如被选择,没有作用。 注意: Driver Verifier能被设置检查win32kss自身。然而,这对同时检查的所有图形驱动程 序都有影响。为获得更多关于图形驱动程序的具体信息, Driver verifier应该仅当驱动程序在调查 状态下才被检查 2121图形驱动程序的特别内存池 内存讹误是一个常见的驱动程序问题,驱动程序错误能导致在它们建立起来很长时间后崩溃 这些错误当中最常见的要数访问已释放的内存,并分配n字节然后是n+1字节。 当特别内存池功能应用到图形驱动程序时, EngAlloc men例程分配的内存将被移出特别内存 池, Driver verifier将监视该池以发现不正确的使用 两种特别内存池定位是可行的, Verify End定位能更好的发现访问上溢, Verify Start定位能 更好的发现访问下溢。(注意:最主要的内存讹误是由于上溢,而非下溢。) 当特别内存池运行且选择Ⅴ /erify End时,驱动程序所请求的每一内存分配被放到分别的各分 页上,在每页上允许分配的最高可能地址被返回,以便内存分配到页末。每页前面的部分以特别 形式写出。前页与下一页被标记为不可访问。 如果驱动程序在分配之后尝试访问内存, Driver verifier将立即发现并发布错误检测0xCD。 如果驱动程序先于缓冲区开始写入内存,这很有可能改变形式。当缓冲区被释放时, Driver verifier 将发现并报告错误检测0xCl。 如果驱动程序在释放缓冲区之后读或写, Driver verifier将报告错误检测xCC 当 Verify Start被选择,内存缓冲区被定位到页的开端,在这种设置下,下溢引起立即的错误 检测,而上溢当内存释放时才引起内存检测。这种选项在其他方面与 Verify End选项相同 Verify End是缺省定位,是由于驱动程序上溢错误比下溢错误要普遍的多。为改变这种设置,请 使用全局标记应用程序 池标记 Driver verifier将给已选择检查的驱动程序分配特别内存池,使用特别内存池的另一个方法是 分配它给一个具有特别标记的内存池。 可利用全局标记应用程序致力于将特别池给具有给定标记的池。 同时通过 Driver verifier和全局标记应用程序来请求特别池是允许的,如果这么做, Windows2000将尝试为所有具有指定标记的池和所有指定的驱动程序的池分配请求使用特别池。 特别池效率 特别池的每一个分配使用不可分页内存的一页和有虚拟地址空间的两页。如果池耗尽,内存 以标准方法分配,直到特别池再次变得可用为止。这样,如果特别内存池在用,多驱动程序同时 被检查则不受推荐 有大量小内存请求的一个单一驱动程序也会耗尽此池,出现此情况,给驱动程序内存指定池 标记和致力于一次给特别池一个池标记将是更可取的 特别池的大小随系统里的物理内存的大小增长而增长,理想的池大小至少1GB。在x86机器
10 应。 图形驱动程序的不可用选项 当在检查一个图形驱动程序时,Driver Verifier 经常执行的自动检查(IRQL 和内存例程的检 查,检查定时器释放的内存池,检查驱动程序卸载)并不执行。 强迫 IRQL 检测、内存池跟踪和 I/O 检查选项不被用于图形驱动程序,如被选择,没有作用。 注意:Driver Verifier 能被设置检查 win32k.sys 自身。然而,这对同时检查的所有图形驱动程 序都有影响。为获得更多关于图形驱动程序的具体信息,Driver Verifier 应该仅当驱动程序在调查 状态下才被检查。 2.1.2.1 图形驱动程序的特别内存池 内存讹误是一个常见的驱动程序问题,驱动程序错误能导致在它们建立起来很长时间后崩溃。 这些错误当中最常见的要数访问已释放的内存,并分配 n 字节然后是 n+1 字节。 当特别内存池功能应用到图形驱动程序时,EngAllocMem 例程分配的内存将被移出特别内存 池,Driver Verifier 将监视该池以发现不正确的使用。 两种特别内存池定位是可行的,Verify End 定位能更好的发现访问上溢,Verify Start 定位能 更好的发现访问下溢。(注意:最主要的内存讹误是由于上溢,而非下溢。) 当特别内存池运行且选择 Verify End 时,驱动程序所请求的每一内存分配被放到分别的各分 页上,在每页上允许分配的最高可能地址被返回,以便内存分配到页末。每页前面的部分以特别 形式写出。前页与下一页被标记为不可访问。 如果驱动程序在分配之后尝试访问内存,Driver Verifier 将立即发现并发布错误检测 0xCD。 如果驱动程序先于缓冲区开始写入内存,这很有可能改变形式。当缓冲区被释放时,Driver Verifier 将发现并报告错误检测 0xC1。 如果驱动程序在释放缓冲区之后读或写,Driver Verifier 将报告错误检测 0xCC。 当 Verify Start 被选择,内存缓冲区被定位到页的开端,在这种设置下,下溢引起立即的错误 检测,而上溢当内存释放时才引起内存检测。这种选项在其他方面与 Verify End 选项相同。 Verify End 是缺省定位,是由于驱动程序上溢错误比下溢错误要普遍的多。为改变这种设置,请 使用全局标记应用程序。 池标记 Driver Verifier 将给已选择检查的驱动程序分配特别内存池,使用特别内存池的另一个方法是 分配它给一个具有特别标记的内存池。 可利用全局标记应用程序致力于将特别池给具有给定标记的池。 同时通过 Driver Verifier 和全局标记应用程序来请求特别池是允许的,如果这么做, Windows2000 将尝试为所有具有指定标记的池和所有指定的驱动程序的池分配请求使用特别池。 特别池效率 特别池的每一个分配使用不可分页内存的一页和有虚拟地址空间的两页。如果池耗尽,内存 以标准方法分配,直到特别池再次变得可用为止。这样,如果特别内存池在用,多驱动程序同时 被检查则不受推荐。 有大量小内存请求的一个单一驱动程序也会耗尽此池,出现此情况,给驱动程序内存指定池 标记和致力于一次给特别池一个池标记将是更可取的。 特别池的大小随系统里的物理内存的大小增长而增长,理想的池大小至少 1GB。在 x86 机器