Pnp管理器(1)
2016-06-27 22:08
447 查看
以前写过一篇Pnp管理器的文章,感觉写的有点肤浅,因此打算另起一篇写Pnp管理器。Pnp管理器是个大的组件:从内核到用户态都有涉及,因此需要分若干篇章分析。本篇立足于Pnp管理器中连接各个模块之间消息流。
系统引导过程中会初始化IO管理器,由IO管理器调用PnpInit对Pnp管理器进行初始化。跟Pnp消息相关的有两处:
内核中用树结构来管理设备,在PnpInit中IopRootDriverObject驱动创建一个Pdo作为整个设备树的根对象,当有新设备加入时,就加到连在根设备对象各个总线下,同时产生通知消息。根设备也是设备,所以在PnpInit中,IopRootDriverObject驱动创建Pdo的同时也向才创建不久的IopPnpEventQueueHead队列插入一条消息(第一条消息),通知内核有新设备加入,当然,现在还没组件处理这些消息。
NtGetPlugPlayEvent函数是个无限等待函数,直到IopPnpNotifyEvent有事件,才从IopPnpEventQueueHead队列中取出一个元素。Pnp管理器的目的是为设备对象加载驱动,因此当线程从阻塞中返回到PnpEventThread中,PnpEventThread就获得设备信息,然后通知Pnp管理器其他组件部分准备安装驱动
谁会触发IopPnpNotifyEvent事件?搜索对IopPnpNotifyEvent的调用会发现IopActionInterrogateDeviceStack函数会间接触发IopPnpNotifyEvent事件。
NTSTATUS
IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
PVOID Context)
{
/* Report the device to the user-mode pnp manager */
IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
&DeviceNode->InstancePath);
} 每当总线设备枚举到到有新设备加入系统就会IoSynchronousInvalidateDeviceRelations,通知Pnp管理器原来的设备树发生变动,期间调用IopActionInterrogateDeviceStack使得总线上已有的设备重新获得设备信息(DeviceID,Resource等,这像是一个社区人员发生了变动,要通知社区中所有社员一样),变更设备信息后调用IopQueueTargetDeviceEvent准备为设备加载驱动~
系统引导过程中会初始化IO管理器,由IO管理器调用PnpInit对Pnp管理器进行初始化。跟Pnp消息相关的有两处:
NTSTATUS INIT_FUNCTION IopInitPlugPlayEvents(VOID) { InitializeListHead(&IopPnpEventQueueHead); KeInitializeEvent(&IopPnpNotifyEvent, SynchronizationEvent, FALSE); return STATUS_SUCCESS; }初始化Pnp消息队列和用于同步Pnp管理器间各个模块的事件。从这段代码可以大致看出Pnp管理器属于生产者-消费者模型:内核把设备相关的动态信息加入到IopPnpEventQueueHead队列中,然后通知其他模块取走消息并处理。
内核中用树结构来管理设备,在PnpInit中IopRootDriverObject驱动创建一个Pdo作为整个设备树的根对象,当有新设备加入时,就加到连在根设备对象各个总线下,同时产生通知消息。根设备也是设备,所以在PnpInit中,IopRootDriverObject驱动创建Pdo的同时也向才创建不久的IopPnpEventQueueHead队列插入一条消息(第一条消息),通知内核有新设备加入,当然,现在还没组件处理这些消息。
IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &IopRootDeviceNode->InstancePath);随着初始化进程的推进,IO管理器最终会创建一个内核线程,周而复始的处理IopPnpEventQueueHead中排队的消息:
hThread = CreateThread(NULL, 0, PnpEventThread, NULL, 0, &dwThreadId);
static DWORD WINAPI PnpEventThread(LPVOID lpParameter) { for (;;) { /* Wait for the next pnp event */ //这是个等待操作,等待PnpEvent有信号 Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize); if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus)) { InterlockedPushEntrySList(&DeviceInstallListHead, &Params->ListEntry); #else InsertTailList(&DeviceInstallListHead, &Params->ListEntry); #endif SetEvent(hDeviceInstallListNotEmpty); }
}
NtGetPlugPlayEvent函数是个无限等待函数,直到IopPnpNotifyEvent有事件,才从IopPnpEventQueueHead队列中取出一个元素。Pnp管理器的目的是为设备对象加载驱动,因此当线程从阻塞中返回到PnpEventThread中,PnpEventThread就获得设备信息,然后通知Pnp管理器其他组件部分准备安装驱动
谁会触发IopPnpNotifyEvent事件?搜索对IopPnpNotifyEvent的调用会发现IopActionInterrogateDeviceStack函数会间接触发IopPnpNotifyEvent事件。
NTSTATUS
IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
PVOID Context)
{
/* Report the device to the user-mode pnp manager */
IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
&DeviceNode->InstancePath);
} 每当总线设备枚举到到有新设备加入系统就会IoSynchronousInvalidateDeviceRelations,通知Pnp管理器原来的设备树发生变动,期间调用IopActionInterrogateDeviceStack使得总线上已有的设备重新获得设备信息(DeviceID,Resource等,这像是一个社区人员发生了变动,要通知社区中所有社员一样),变更设备信息后调用IopQueueTargetDeviceEvent准备为设备加载驱动~
相关文章推荐
- 如何重装TCP/IP协议
- Windows 8 官方高清壁纸欣赏与下载
- 谁是桌面王者?Win PK Linux三大镇山之宝
- 对《大家都在点赞 Windows Terminal,我决定给你泼一盆冷水》一文的商榷
- Windows Clang开发环境备忘
- 从Windows系统下访问Linux分区相关软件
- 对《大家都在点赞 Windows Terminal,我决定给你泼一盆冷水》一文的商榷
- Windows下搭建本地SVN服务器
- 使用Windows原生命令一键清空剪贴板
- windows用windeployqt发布qt quick application程序
- 利用开源软件打造自己的全功能远程工具
- Windows 8虚拟机不能全屏的解决方法
- Visual Studio 2012 示例代码浏览器 - 数以千计的开发示例近在手边,唾手可得
- Visual Studio 2012 示例代码浏览器 - 数以千计的开发示例近在手边,唾手可得
- 微软镜像下载
- windows server域用户提升到本地更高权限组中的方法
- 使用命令修改注册表键值及权限