windows驱动开发-内核调度(一)

驱动层面的调度和同步一向是内核中比较困难的部分,和应用层不一样,内核位于系统进程下,所以它的调度和同步一旦出现纰漏,那会影响所有的程序,而内核并不具备对于这种情况下的纠错能力,没有异常手段能够让挂起的系统恢复原样,除了关闭电源之外,并且这个过程可能会需要进入安全模式来处理,这对于病毒来说可能是一个好消息,但对于要稳定运行的驱动程序来说,就意味着编写难度的上升。

内核定义一组称为内核调度程序对象的对象类型,或仅定义调度程序对象。分发器对象包括计时器对象、事件对象、信号灯对象、互斥对象和线程对象。

驱动程序可以将调度程序对象用作非比特线程上下文中的同步机制,同时在 IRQL 执行时等于PASSIVE_LEVEL。

内核对象对于windows开发工程师来说并不是很稀奇的名称,在应用层编程的时候,事件、信号量、线程这些对象本身就是内核对象,看起来它们的用法和应用层一样,不过,区别在于,某些情况下使用内核对象不当,后果是灾难性的。

分发器的对象状态

每个内核定义的调度程序对象类型都有一个状态,该状态要么设置为 Signaled,要么设置为 Not-Signaled。

如果一个或多个线程调用 KeWaitForSingleObject、KeWaitForMutexObject 或 KeWaitForMultipleObjects,则一组线程可以同步其操作。 这些函数将调度程序对象指针作为输入并等待,直到另一个例程或线程将一个或多个调度程序对象设置为“已信号”状态。

当线程调用 KeWaitForSingleObject 以等待调度程序对象 (或 KeWaitForMutexObject 以获取互斥) 时,线程将进入等待状态,直到调度程序对象设置为Signaled状态。 线程可以调用 KeWaitForMultipleObjects 来等待一组调度程序对象的任意或全部设置为Signaled。

每当调度程序对象设置为“已发出信号”状态时,内核就会更改等待该对象 就绪的任何线程的状态。 (同步计时器和同步事件是此规则的例外情况;当向同步事件或计时器发出信号时,只会将一个等待线程设置为就绪状态。有关详细信息,请参阅 计时器对象和 DPC 和 事件对象。) 处于就绪状态的线程将根据其当前运行时 线程优先级 和具有该优先级的任何线程的处理器的当前可用性来计划运行。

如何等待分发器对象?

通常,仅当以下至少一种情况为 true 时,驱动程序才能等待调度程序对象设置:

  • 驱动程序在非比特线程上下文中执行,可以标识将进入等待状态的线程。 实际上,在非比特线程上下文中执行的唯一驱动程序例程是任何驱动程序的 DriverEntry、 AddDevice、 Reinitialize 和 Unload 例程,以及最高级别驱动程序的调度例程。 所有这些例程都由系统直接调用。
  • 驱动程序正在执行完全同步的 I/O 请求,在处理 I/O 请求时,没有驱动程序会将任何操作排入队列,并且直到其下面的驱动程序处理完请求,否则不会返回任何驱动程序。

此外,如果驱动程序在 IRQL 或高于等于 DISPATCH_LEVEL 执行,则无法进入等待状态。根据这些限制,必须使用以下规则:

  • 任何驱动程序的 DriverEntry、 AddDevice、 Reinitialize 和 Unload 例程都可以等待调度程序对象;
  • 最高级别驱动程序的调度例程可以等待调度程序对象;
  • 如果 I/O操作是同步的,则较低级别驱动程序的调度例程可以等待调度对象,例如创建、刷新、关闭和关闭操作、某些设备 I/O 控制操作以及某些 PnP 和电源操作;
  • 较低级别驱动程序的调度例程不能等待调度程序对象完成异步 I/O 操作;
  • 在 IRQL DISPATCH_LEVEL或更高位置执行的驱动程序例程不得等待调度程序对象设置为“已信号”状态;
  • 驱动程序不得尝试等待调度程序对象设置为信号状态,以便完成与分页设备的传输操作;
  • 为读/写请求提供服务的驱动程序调度例程通常不能等待调度程序对象设置为“已信号”状态;
  • 仅当 I/O 控制代码的传输类型METHOD_BUFFERED时,设备 I/O 控制请求的调度例程才能等待调度程序对象设置为“已信号”状态;
  • SCSI 微型端口驱动程序不应使用内核调度程序对象。 SCSI 微型端口驱动程序应仅调用 SCSI 端口库例程;

所有其他标准驱动程序例程在任意线程上下文中执行:调用驱动程序例程处理排队操作或处理设备中断时,任何线程的线程都恰好是当前线程。 此外,大多数标准驱动程序例程都是在引发的 IRQL 中运行,无论是在 DISPATCH_LEVEL还是DIRQL 。

如有必要,驱动程序可以创建设备专用线程,该线程可以等待驱动程序的其他例程 ,但 ISR 或 SynchCritSection 例程除外, 将调度程序对象设置为信号状态并重置为Not-Signaled状态。

一般指导原则是,如果预计新设备驱动程序在 I/O 操作期间等待设备状态更改时通常需要停止超过 50 微秒,请考虑使用设备专用线程实现驱动程序。 如果设备驱动程序也是最高级别的驱动程序,请考虑使用 系统工作线程 并实现一个或多个工作线程回调例程。 

事件

任何使用事件对象的驱动程序都必须调用 KeInitializeEvent、 IoCreateNotificationEvent 或 IoCreateSynchronizationEvent ,然后才能等待、设置、清除或重置事件。 下图演示了具有线程的驱动程序如何使用事件对象进行同步:

如上图所示,此类驱动程序必须为事件对象提供存储,该事件对象必须是驻留的。 驱动程序可以使用驱动程序创建的设备对象的设备扩展 、控制器扩展或驱动程序分配的非分页池。

当驱动程序调用 KeInitializeEvent 时,它必须传递指向事件对象的驱动程序常驻存储的指针。 此外,调用方必须为事件对象指定初始状态 (已发出信号或未发出信号) 。 调用方还必须指定事件类型,可以是以下任一类型:

  • SynchronizationEvent: 当同步事件设置为“已信号”状态时,等待事件重置为Not-Signaled的单个线程将有资格执行,并且事件的状态会自动重置为“未发出信号”。这种类型的事件有时称为 自动清理事件,因为每次满足等待时,其信号状态都会自动重置。
  • NotificationEvent:当通知事件设置为“已信号”状态时,等待事件重置为Not-Signaled的所有线程都将符合执行条件,并且事件将保持为“已信号”状态,直到发生显式重置Not-Signaled:也就是说,使用给定的事件指针调用 KeClearEvent 或 KeResetEvent。

很少有设备或中间驱动程序具有单个驱动程序专用线程,更不用说一组线程,这些线程可能会通过等待保护共享资源的事件来同步其操作。

大多数使用事件对象等待 I/O操作完成的驱动程序在调用 KeInitializeEvent 时将输入类型设置为 NotificationEvent。 为驱动程序使用 IoBuildSynchronousFsdRequest 或 IoBuildDeviceIoControlRequest 创建的 IRP 设置的事件对象几乎总是初始化为 NotificationEvent, 因为调用方将等待事件的通知,指示其请求已被一个或多个较低级别的驱动程序满足。

驱动程序初始化自身后,其驱动程序专用线程(如果有)和其他例程可以同步其在事件上的操作。 例如,具有管理 IRP 排队的线程的驱动程序(例如系统软盘控制器驱动程序)可能会同步事件上的 IRP 处理,如上图所示:

  • 1. 线程已取消排队以在设备上处理 IRP,它使用指向初始化事件对象的驱动程序提供的存储的指针调用 KeWaitForSingleObject ;
  • 2. 其他驱动程序例程执行满足 IRP 所需的 I/O 操作,当这些操作完成时,驱动程序的 DpcForIsr 例程使用指向事件对象的指针调用 KeSetEvent ,驱动程序确定的线程优先级提升 (增量,如上图) 所示,布尔 等待 设置为 FALSE。 调用 KeSetEvent 会将事件对象设置为“已信号”状态,从而将等待线程的状态更改为“就绪”;
  • 3. 当处理器可用时,内核会立即调度线程以执行:也就是说,当前没有其他具有更高优先级的线程处于就绪状态,并且没有内核模式例程可在更高的IRQL上运行。如果DpcForIsr尚未使用 IRP 调用 IoCompleteRequest ,线程现在可以完成 IRP,并且可以取消排队以在设备上处理的另一个 IRP;

调用将 Wait 参数设置为 TRUE 的 KeSetEvent 表示调用方打算在从 KeSetEvent 返回时立即调用 KeWaitForSingleObject 或 KeWaitForMultipleObjects 支持例程。

请考虑以下有关将Wait参数设置为KeSetEvent 的准则:

  • 在 IRQL < DISPATCH_LEVEL运行的可分页线程或可分页驱动程序例程不应调用将 Wait 参数设置为 TRUE 的 KeSetEvent。 如果调用方碰巧在调用 KeSetEvent 和 KeWaitForSingleObject 或KeWaitForMultipleObjects 之间分页,则此类调用会导致严重页面错误;
  • 在 IRQL = DISPATCH_LEVEL 下运行的任何标准驱动程序例程都不能等待任何调度程序对象的非零间隔,而不会关闭系统。 但是,此类例程可以在 IRQL 小于或等于 DISPATCH_LEVEL 运行时调用 KeSetEvent ;
  • KeResetEvent 返回给定 事件的先前状态:调用 KeResetEvent 时,它是否设置为 Signaled。 KeClearEvent 只是将给定 事件 的状态设置为“未发出信号”;

对于何时调用上述支持例程,请考虑以下准则:

为了提高性能,每个驱动程序都应调用 KeClearEvent ,除非调用方需要 KeResetEvent 返回的信息来确定接下来要执行的操作。

标准事件

系统提供多个标准事件对象。 驱动程序可以使用这些事件对象,每当出现某些情况时,系统就会收到通知。 以下列出了系统包含标准事件对象:

\KernelObjects\HighMemoryCondition:每当可用物理内存量超过系统定义的量时,将设置此事件。 驱动程序可以等待将此事件设置为主动分配内存的信号。

\KernelObjects\LowMemoryCondition:每当可用物理内存量低于系统定义的量时,将设置此事件。 已分配大量内存的驱动程序可以等待将此事件设置为释放未使用的内存的信号。

对于 Microsoft Windows Server 2003 及更高版本的 Windows,驱动程序还可以使用以下其他标准事件对象:

\KernelObjects\HighPagedPoolCondition:每当可用分页池的数量超过系统定义的量时,将设置此事件。 驱动程序可以等待将此事件设置为主动从分页池分配内存的信号。

\KernelObjects\LowPagedPoolCondition:每当可用分页池的数量低于系统定义的量时,将设置此事件。 已分配大量内存的驱动程序可以等待将此事件设置为从分页池中释放未使用的内存的信号。

\KernelObjects\HighNonPagedPoolCondition:每当可用非分页池的数量超过系统定义的量时,将设置此事件。 驱动程序可以等待将此事件设置为主动分配非分页池内存的信号。

\KernelObjects\LowNonPagedPoolCondition:每当可用非分页池的数量低于系统定义的量时,将设置此事件。 已分配大量内存的驱动程序可以等待将此事件设置为从非分页池中释放未使用的内存的信号。

对于 Windows Vista 和更高版本的 Windows,驱动程序还可以使用以下其他标准事件对象:

\KernelObjects\LowCommitCondition:当操作系统的 提交费用 相对于 当前提交限制较低时,将设置此事件。 换句话说,内存使用率较低,物理内存或分页文件中有大量可用空间。

\KernelObjects\HighCommitCondition:当操作系统的提交费用相对于当前提交限制较高时,将设置此事件。 换句话说,内存使用率较高,物理内存或分页文件中的可用空间非常少,但操作系统可能能够增加其分页文件的大小。

\KernelObjects\MaximumCommitCondition:当操作系统的提交费用接近 最大提交限制时,将设置此事件。 换句话说,内存使用率非常高,物理内存或分页文件中的可用空间非常少,操作系统无法增加其分页文件的大小。 如果存在足够的存储资源,系统管理员始终可以增加分页文件的大小或数量,而无需重新启动计算机。

其中每个事件都是通知事件。 只要触发条件保持为 true,它们就会保持设置。

若要打开其中任何事件的句柄,请使用 IoCreateNotificationEvent 例程。 等待其中任何事件的驱动程序应创建一个专用线程来执行等待。 线程可以通过调用 KeWaitForSingleObject 或 KeWaitForMultipleObjects 来等待其中一个或多个事件。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/593961.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

workminer之dht通信部分

workminer是通过SSH爆破传播的挖矿木马&#xff0c;感染后会释放xmrig挖矿程序利用主机的CPU挖取北方门罗币。该样本能够执行特定的指令&#xff0c;指令保存在一个配置文件config中&#xff0c;config文件类似于xml文件&#xff0c;里面有要执行的指令和参数&#xff0c;样本中…

BUUCTF---misc---[BJDCTF2020]纳尼

1、下载附件是一个gif图片&#xff0c;但是图片打不开 2、用winhex分析&#xff0c;看到缺少了文件头 3、将文件头通过ASCII码方式粘贴后&#xff0c;保存&#xff0c;图片恢复了正常 4、是一张动图&#xff0c;一共四张&#xff0c;每张都有base64编码 5、用stegsolve分解图…

【竞技宝jjb.lol】LOL:TES顺利晋级却暴露问题

北京时间2024年5月5日,英雄联盟2024MSI季中赛正在如火如荼的进行之中,目前入围赛阶段的比赛已经进入尾声,入围赛实力最强的两支战队T1、TES都已经顺利晋级淘汰赛阶段,在昨天的比赛结束之后,A组的FLY、PSG,B组的FNC、GAM将争夺剩下的两个出线名额。 回顾这次入围赛中,T1和TES的比…

buu相册

010分析是一个rar文件&#xff0c;7z打开发现是一个apk文件 但没发现什么敏感信息 全局搜索mail 然后就是查看引用与出处 base解密完是一个邮箱&#xff0c;提交对了。

vivado 在硬件中调试串行 I/O 设计-属性窗口

只要在“硬件 (Hardware) ”窗口中选中 GT 或 COMMON 块、在“链接 (Link) ”窗口中选中链接 &#xff0c; 或者在“扫描 (Scan)”窗口中选中扫描 &#xff0c; 那么就会在“ Properties ”窗口中显示该对象的属性。对于 GT 和 COMMON &#xff0c; 包括这些对象的所有属性、…

01 JVM -- JVM 体系结构、HotSpot

1. JVM、HotSpot、 OpenJDK 的区别 JVM (Java Virtual Machine) 是一个虚拟机HotSpot 是 JVM 规范的一个实现。HotSpot 虚拟机通过即时编译 (JIT) 技术将 Java 字节码转换为本地机器码&#xff0c;以提高程序的执行效率。OpenJDK 是一个项目名&#xff0c;它在 HotSpot 的基础…

常见的零拷贝技术

传统IO 基于传统的IO方式&#xff0c;底层实际上通过调用read()和write()来实现。通过read()把数据从硬盘读取到内核缓冲区&#xff0c;再复制到用户缓冲区&#xff1b;然后再通过write()写入到socket缓冲区&#xff0c;最后写入网卡设备。整个过程发生了4次用户态和内核态的上…

[Kubernetes] 安装KubeSphere

选择4核8G&#xff08;master&#xff09;、8核16G&#xff08;node1&#xff09;、8核16G&#xff08;node2&#xff09; 三台机器&#xff0c;按量付费进行实验&#xff0c;CentOS7.9安装Docker安装Kubernetes安装KubeSphere前置环境: nfs和监控安装KubeSphere masternode1no…

RK3568 学习笔记 : 精简 u-boot env 默认复杂的多种引导启动设置

前言 环境&#xff1a; 正点原子 Atompi-CA1 RK3568 开发板、正点原子 DLRK3568 开发板&#xff0c;&#xff08;一时脑热买了两块 RK3568 开发板&#xff09;&#xff0c;Atompi-CA1 RK3568 开发板比较小巧&#xff0c;利于一些前期的嵌入式 Linux 开发学习与实践。 RK3568 开…

小红的循环移位

题目描述&#xff1a;小红拿到了一个数字串&#xff0c;她每次操作可以使得其向左循环移动一位。将串 ss0 s1...sn−1s ​ 向左循环移动一位&#xff0c;将得到串s1...sn−1s0。小红想知道&#xff0c;使得该数字串变成4的倍数&#xff0c;需要最少操作多少次&#xff1f;&…

推荐网站(1)懒人Excel,函数公式、操作技巧等,一看就看会

相信很多小伙伴打开excel表的时候&#xff0c;不知道要怎么操作&#xff0c;也不知道该如何搜索自己想要的结果&#xff0c;那么我推荐个网站懒人Excel&#xff0c;它可以帮我们快速了解使用 EXCEL的基本操作&#xff0c;也可以帮我们解决使用 EXCEL的遇到的问题。 可以看到他…

PCIe总线-事物层之TLP格式介绍(五)

1.概述 PCIe总线事务层位于应用层和数据链路层之间。发送时将应用层的数据请求转换成PCIe总线事务&#xff0c;然后发送到数据链路层。接收时&#xff0c;从来自数据链路层报文中提取PCIe总线事务&#xff0c;并将数据提交到应用层。事务层使用TLP表示PCIe总线事务&#xff0c…

RK3568笔记二十四:基于Flask的网页监控系统

若该文为原创文章&#xff0c;转载请注明原文出处。 此实验参考 《鲁班猫监控检测》&#xff0c;原代码有点BUG&#xff0c;已经下载不了。2. 鲁班猫监控检测 — [野火]嵌入式AI应用开发实战指南—基于LubanCat-RK系列板卡 文档 (embedfire.com) 一、简介 记录简单的摄像头监…

C++程序设计:C++的内存分布与管理

C的内存分布与管理 栈区堆区全局区代码区常量区 栈区 &#xff08;1&#xff09;什么是栈区&#xff1f; 栈区&#xff08;Stack&#xff09; 是用于存储函数调用&#xff0c;局部变量和函数参数的一种内存区域&#xff0c;它的特性就是先进后出&#xff08;FILO&#xff09;。…

ES数据存储与查询基本原理

Elasticsearch&#xff08;ES&#xff09;简介 Elasticsearch&#xff08;ES&#xff09;是一个分布式、可扩展、近实时的搜索和分析引擎&#xff0c;它基于Lucene&#xff0c;设计用于云计算中&#xff0c;处理大规模文档检索和数据分析任务&#xff0c;常用于实现内部搜索引…

【LAMMPS学习】八、基础知识(5.7)Drude感应偶极子

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语&#xff0c;以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

记录PR学习查漏补缺(持续补充中。。。)

记录PR学习查漏补缺 常用快捷键文件编辑素材序列标记字幕窗口帮助 效果基本3D高斯模糊查找边缘色彩颜色平衡超级键马赛克中间值变形稳定器轨道遮罩键 常用 快捷键 注意&#xff1a;比较常用的用红色字体显示 文件 快捷键作用Ctrl Alt N新建项目Ctrl O打开项目Ctrl I导入…

Samsung三星NP930XCJ-K01CN笔记本原厂Win10系统安装包下载

三星SAMSUNG笔记本电脑原装出厂Windows10预装OEM系统&#xff0c;恢复开箱状态自带系统 链接&#xff1a;https://pan.baidu.com/s/1Y3576Tsp8MtDxIpJGDucbA?pwdt0ox 提取码&#xff1a;t0ox 三星原装W10系统自带声卡,网卡,显卡,指纹,蓝牙等所有驱动、三星出厂主题专用壁纸…

以太网基础-IP、ICMP、ARP协议

一、IP协议 参考&#xff1a;rfc791.txt.pdf (rfc-editor.org) IP协议&#xff08;Internet Protocol&#xff09;是TCP/IP协议族中最核心的协议&#xff0c;提供不可靠的、无连接的、尽力而为的数据报传输服务。 IP报文数据头如下 Version&#xff1a;4bit&#xff0c;4表示…

上位机图像处理和嵌入式模块部署(树莓派4b和qt应用全屏占有)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 我们都知道&#xff0c;嵌入式应用一般都是为了某一个特定应用而存在的。也就是说&#xff0c;和pc不同&#xff0c;这个嵌入式板子一般都是为了解…