设备驱动程序 IRQL 和线程/上下文切换

发布于 2024-08-22 15:27:37 字数 463 浏览 7 评论 0原文

我是 Windows 设备驱动程序编程的新手。我知道某些操作只能在 IRQL PASSIVE_LEVEL 下执行。例如,Microsoft 有以下示例代码,说明如何从内核驱动程序写入文件:

if (KeGetCurrentIrql() != PASSIVE_LEVEL)
    return STATUS_INVALID_DEVICE_STATE; 

Status = ZwCreateFile(...);

我的问题是:在上面的 KeGetCurrentIrql() 检查之后,是什么阻止了 IRQL 被引发?假设发生了上下文或线程切换,当 IRQL 返回到我的驱动程序时,它不会突然变为 DISPATCH_LEVEL 吗?这会导致系统崩溃吗?

如果这是不可能的,那么为什么不直接检查 DriverEntry 函数中的 IRQL 并一次性完成呢?

I'm new to Windows device driver programming. I know that certain operations can only be performed at IRQL PASSIVE_LEVEL. For example, Microsoft have this sample code of how to write to a file from a kernel driver:

if (KeGetCurrentIrql() != PASSIVE_LEVEL)
    return STATUS_INVALID_DEVICE_STATE; 

Status = ZwCreateFile(...);

My question is this: What is preventing the IRQL from being raised after the KeGetCurrentIrql() check above? Say a context or thread swithch occurs, couldn't the IRQL suddenly be DISPATCH_LEVEL when it gets back to my driver which would then result in a system crash?

If this is NOT possible then why not just check the IRQL in the DriverEntry function and be done with it once for all?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

拥醉 2024-08-29 15:27:37

线程的irql只能由其自身引发。

因为你是从上层/下层驱动调用的,所以当前运行上下文的irql可能不同。还有几个函数可以提高/降低 irql。

几个例子:

IRP_MJ_READ

   NTSTATUS DispatchRead(
    __in struct _DEVICE_OBJECT  *DeviceObject,
    __in struct _IRP  *Irp
    )
  {
     // this will be called at irql == PASSIVE_LEVEL
     ...
     // we have acquire a spinlock
     KSSPIN_LOCK lck;
     KeInititializeSpinLock( &lck );
     KIRQL prev_irql;
     KeAcquireSpinLock( &lck,&prev_irql );

     // KeGetCurrentIrql() == DISPATCH_LEVEL 

     KeReleaseSpinLock( &lck, prev_irql );
     // KeGetCurrentIrql() == PASSIVE_LEVEL 
     ...
  }

(Io-)Completion 例程可以在 DISPATCH_LEVEL 处调用,因此应该进行相应的操作。

NTSTATUS CompleteSth(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)
{
    // KeGetCurrentIrql() >= PASSIVE_LEVEL
}

The irql of a thread can only be raised by itself.

Because you are called from upper/lower drivers, the irql of the current running context may be different. And there are a couple of functions that raise/lower the irql.

A couple examples :

IRP_MJ_READ

   NTSTATUS DispatchRead(
    __in struct _DEVICE_OBJECT  *DeviceObject,
    __in struct _IRP  *Irp
    )
  {
     // this will be called at irql == PASSIVE_LEVEL
     ...
     // we have acquire a spinlock
     KSSPIN_LOCK lck;
     KeInititializeSpinLock( &lck );
     KIRQL prev_irql;
     KeAcquireSpinLock( &lck,&prev_irql );

     // KeGetCurrentIrql() == DISPATCH_LEVEL 

     KeReleaseSpinLock( &lck, prev_irql );
     // KeGetCurrentIrql() == PASSIVE_LEVEL 
     ...
  }

(Io-)Completion routines may be called at DISPATCH_LEVEL and so should behave accordingly.

NTSTATUS CompleteSth(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)
{
    // KeGetCurrentIrql() >= PASSIVE_LEVEL
}
○闲身 2024-08-29 15:27:37

IRQL 只能通过设置在您的控制下以任何有意义的方式进行更改。有两个“线程特定”IRQL - PASSIVE_LEVEL 和 APC_LEVEL。您可以使用快速互斥体等控制进出这些级别,并且线程的上下文切换将始终使您保持在之前所在的级别。上面是“处理器特定的”IRQL。即 DISPATCH_LEVEL 或以上。在这些级别中不能发生上下文切换。您可以使用自旋锁等进入这些级别。 ISR 将在您的线程上以更高的 IRQL 发生,但您看不到它们。当他们将控制权返回给您时,您的 IRQL 就会恢复。

The IRQL can only change in any meaningful way under your control by setting it. There are two "thread specific" IRQLs - PASSIVE_LEVEL and APC_LEVEL. You control going in and out of these levels with things like fast mutexes, and a context switch to your thread will always leave you at the level you were in before. Above that are "processor specific" IRQLs. That is DISPATCH_LEVEL or above. In these levels a context switch cannot occur. You get into these levels using spin locks and such. ISRs will occur at higher IRQLs on your thread, but you can't see them. When they return control to you your IRQL is restored.

风吹雨成花 2024-08-29 15:27:37

DriverEntry 也在 PASSIVE_LEVEL 被调用。

如果您想在 PASSIVE_LEVEL 完成工作,请使用 IoQueueWorkItem

DriverEntry is also called at PASSIVE_LEVEL.

If you want to have a job done at PASSIVE_LEVEL then use functions like IoQueueWorkItem

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文