阅读:2024回复:1
一个关于在DISPATCH_LEVEL上,分页,非分页内存的问题IoSetCompletionRoutine(,,context,)例程在DDK文档中明确要求第三个参数必须是在非分页内存中分配的内存区域,这是因为IoSetCompletionRoutine例程会提升IRQL到DISPATCH_LEVEL。我在DDK自带的例子tobaster的busenum.sys -> pnp.c ->Bus_SendIrpSynchronously()函数中看到,传递给IoSetCompletionRoutine的变量event却是在分页内存中分配的程序运行不会有任何错误或蓝屏发生,代码片段如下: KEVENT event; NTSTATUS status; PAGED_CODE(); KeInitializeEvent(&event, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, Bus_CompletionRoutine, &event, TRUE, TRUE, TRUE ); status = IoCallDriver(DeviceObject, Irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL ); status = Irp->IoStatus.Status; } return status; 请问这种情况该如何解释,在DISPATCH_LEVEL级访问非分页内存唯一方法是访问前必须先锁定,但在该函数中明显没有锁定,为什么? |
|
沙发#
发布于:2011-12-23 01:40
:o:找到答案了,原来event占用的内存是在内核栈中分配的,当然没有分页的问题了,看来我还是菜啊 连内核栈都不知道
驱动程序肯定是在CPU的RING 0层运行,使用的堆栈是内核栈(Kernel Stack),而内核栈中的变量是不会被分页的,而如何判断内核栈是不是被用光了?要确定是否存在足够的堆栈空间来调用函数或执行任务,驱动程序可以调用 IoGetStackLimits 和 IoGetRemainingStackSize 例程。如果没有足够的堆栈空间可用,那么驱动程序可以将任务排队到一个工作项(在单独的线程中运行,因此拥有其自身的内核模式堆栈)。但是,请记住,工作项将以 PASSIVE_LEVEL 级别在系统工作线程中运行。请记住,在原始版本的 Windows Server 2003 RTM 和早期版本的 Windows 中,必须以 IRQL PASSIVE_LEVEL 或 IRQL APC_LEVEL 调用 IoGetStackLimits 和 IoGetRemainingStackSize,因此不能以 DISPATCH_LEVEL 或更高级别(例如 DPC 例程)从任何例程调用它们。从 Windows Server 2003 SP1 开始,可以以任何 IRQL 调用 IoGetStackLimits 和 IoGetRemainingStackSize。 重要:驱动程序不应该另外分配内存并将其作为内核模式堆栈使用。这绝不是任何平台的建议实践,因为它会影响操作系统的稳定性和可靠性。在基于 x64 的系统上,如果操作系统检测到未经授权的内核模式堆栈,那么它将生成一个错误检查并关闭系统。 |
|