スキップしてメイン コンテンツへ

 none
PoCallDriver は Vista以後 と Server2003以前では呼び分けが必要ですか? RRS feed

  • 質問

  • WDK7600を用いて、bulkusbベースのカーネルドライバを x86/amd64 用に開発しています。
    問題なく動作をしているのですが、使用API(PoCallDriver/PoStartnextPowerIrp)に関してWDKドキュメントに気になる記述を見つけました。

    http://msdn.microsoft.com/en-us/library/ms806566.aspx
    Beginning with Windows Vista, drivers should call IoCallDriver , not PoCallDriver to pass a power IRP to the next-lower driver. However, on Windows Server 2003, Windows XP, and Windows 2000, drivers must call PoCallDriver , not IoCallDriver to pass a power IRP to the next-lower driver. On Windows Server 2003, Windows XP, an Windows 2000, drivers must also call PoStartNextPowerIrp before calling PoCallDriver .

    http://msdn.microsoft.com/en-us/library/ms806569.aspx
    Beginning with Windows Vista, the driver is not required to call PoStartNextPowerIrp and a call to this routine does not perform a power management operation. However, on Windows Server 2003, Windows XP, and Windows 2000, PoStartNextPowerIrp must be called by every driver in a device stack after the driver is finished with the previous power IRP, if any, and is ready to handle the next power IRP. It must be called once by each driver for every IRP_MN_QUERY_POWER or IRP_MN_SET_POWER request.

    要約すると
    Vista以後では、PoCallDriverのかわりにIoCallDriverをコールしろ(should call)、PoStartNextPowerIrpはコールする必要はなく、コールしても何も実行されない。
    Vista以前(2003/XP/2000)では、PoCallDriverとPoStartNextPowerIrpをコールしなければならない (must call)

    となりますが、これは
    Vista以前・以後を実行時に判定して、PoCallDriver/IoCallDriverを呼び分ける必要があるということでしょうか?
    それとも、Vista以後でもPoCallDriverを
    (mustではなくなっただけで) 使うことはできるということでしょうか?

    開発ドライバのベースソースは、WDK6000(Vista-WDK)の bulkusb ですが、
    PoCallDriver使用箇所(bulkpwr.c)を見ても、呼び分けは行っているように見えません。
    WDK6001.18002(2008SP1-WDK)のbulkusbソースも確認しましたが、ソースの修正はされていません。
    • 移動 Mike Wang (MSCS) 2012年10月2日 12:35 (移動元:Windows デバイスドライバー開発)
    2010年3月17日 1:56

回答

  • 私も以前に hkuno さんと全く同じ疑問を持って調べたのですが、
    私が調べた限りでは、Vista 以降でも PoCallDriver / PoStartNextPowerIrp をコールしても
    実害は無いと思います。

    その時は WinDBG を Vista にカーネル デバッグ接続させてデバッグしてみたのですが、
    Vista の NT カーネル内にも、PoCallDriver / PoStartNextPowerIrp の各ルーチンは実装されていました。

    で、Vista での nt!PoCallDriver と nt!PoStartNextPowerIrp の各ルーチンのアセンブラ コードも確認しましたが、
    nt!PoCallDriver は単純に内部で nt!IofCallDriver ルーチンを呼び出しているだけで、その実装は
    nt!IoCallDriver とまったく一緒でした。
    nt!PoStartNextPowerIrp に至っては、何もせずにただリターンしているだけでした。

    (採取したデバッグ ログも載せようと思ったのですが、
      「それってリバース エンジニアリングでは?」
      と突っ込みを受けそうなので、やめておきます...)

    なので私なりの結論としては、

    「Vista よりも以前のプラットフォームもターゲットとするのであれば、
      Power IRP のハンドリングには PoCallDriver / PoStartNextPowerIrp 関数の使用が必須で、
      その場合でも同一バイナリで Vista 以降のプラットフォーム環境でも動くけど、
      Vista 以降のプラットフォームだけがターゲットであれば通常の IRP と同様に IoCallDriver で OK。」

    ということで、自分では納得しました。

    • 回答としてマーク hkuno-reg 2010年3月17日 8:02
    2010年3月17日 6:30
  • 再びこんにちは。
    疑問がすっきりされたとのことで、何よりです。

    今たまたま Vista SP2 のデバッグ環境が立ちあがっていたので、ちょっと確認してみました。
    (小心者の私は、自分が書いた返信が正しかった不安になってしまったので...)

    結果、先ほど書いた内容は間違いではないのですが、ちょっと訂正です。

    >nt!PoCallDriver は単純に内部で nt!IofCallDriver ルーチンを呼び出しているだけで、その実装は
    >nt!IoCallDriver とまったく一緒でした。

    上記返信の 「その実装は nt!IoCallDriver とまったく一緒でした」部分ですが、
    実装が同じ。。。というよりも、nt!PoCallDriver ルーチン自身が nt!IoCallDriver ルーチンでした!!

    採取したデバッグ ログです。
    ------------------------------------------------------------------
    0: kd> vertarget
    Windows Server 2008/Windows Vista Kernel Version 6002 (Service Pack 2) MP (2 procs) Free x86 compatible
    Product: WinNt, suite: TerminalServer SingleUserTS
    Built by: 6002.18082.x86fre.vistasp2_gdr.090803-2339
    Machine Name:
    Kernel base = 0x81844000 PsLoadedModuleList = 0x8195bc70
    Debug session time: Wed Mar 17 14:47:40.332 2010 (GMT+9)
    System Uptime: 5 days 4:04:15.208

    0: kd> x nt!PoCallDriver
    8184a47a nt!PoCallDriver = <no type information>
    ^^^^^^^^
    0: kd> x nt!IoCallDriver
    8184a47a nt!IoCallDriver = <no type information>
    ^^^^^^^^
    ------------------------------------------------------------------

    よくよく見たら、nt!PoCallDriver と nt!IoCallDriver のアドレスが全く同じでした。
    つまり、NT カーネルの内部的な動作としては、

      PoCallDriver() == IoCallDriver()

    ということですね。
    なので、わざわざ u コマンドでアセンブラ コードを表示させるまでもなく、
    当然の如く全く同じものが表示される。。。と言うオチでした。

    • 回答としてマーク hkuno-reg 2010年4月7日 2:53
    2010年3月17日 8:44

すべての返信

  • 私も以前に hkuno さんと全く同じ疑問を持って調べたのですが、
    私が調べた限りでは、Vista 以降でも PoCallDriver / PoStartNextPowerIrp をコールしても
    実害は無いと思います。

    その時は WinDBG を Vista にカーネル デバッグ接続させてデバッグしてみたのですが、
    Vista の NT カーネル内にも、PoCallDriver / PoStartNextPowerIrp の各ルーチンは実装されていました。

    で、Vista での nt!PoCallDriver と nt!PoStartNextPowerIrp の各ルーチンのアセンブラ コードも確認しましたが、
    nt!PoCallDriver は単純に内部で nt!IofCallDriver ルーチンを呼び出しているだけで、その実装は
    nt!IoCallDriver とまったく一緒でした。
    nt!PoStartNextPowerIrp に至っては、何もせずにただリターンしているだけでした。

    (採取したデバッグ ログも載せようと思ったのですが、
      「それってリバース エンジニアリングでは?」
      と突っ込みを受けそうなので、やめておきます...)

    なので私なりの結論としては、

    「Vista よりも以前のプラットフォームもターゲットとするのであれば、
      Power IRP のハンドリングには PoCallDriver / PoStartNextPowerIrp 関数の使用が必須で、
      その場合でも同一バイナリで Vista 以降のプラットフォーム環境でも動くけど、
      Vista 以降のプラットフォームだけがターゲットであれば通常の IRP と同様に IoCallDriver で OK。」

    ということで、自分では納得しました。

    • 回答としてマーク hkuno-reg 2010年3月17日 8:02
    2010年3月17日 6:30
  • Vistaカーネルにおいては、PoCallDriverはIofCallDriverへのラッパーとのこと。納得です。結論にも同意です。
    WDKのドキュメントに、そう一言書いてあると良いですね(カーネルデバッグしないと裏が取れないなんて...)。

    おかげさまで疑問がすっきり解決しました。ありがとうございました。

    2010年3月17日 8:09
  • 再びこんにちは。
    疑問がすっきりされたとのことで、何よりです。

    今たまたま Vista SP2 のデバッグ環境が立ちあがっていたので、ちょっと確認してみました。
    (小心者の私は、自分が書いた返信が正しかった不安になってしまったので...)

    結果、先ほど書いた内容は間違いではないのですが、ちょっと訂正です。

    >nt!PoCallDriver は単純に内部で nt!IofCallDriver ルーチンを呼び出しているだけで、その実装は
    >nt!IoCallDriver とまったく一緒でした。

    上記返信の 「その実装は nt!IoCallDriver とまったく一緒でした」部分ですが、
    実装が同じ。。。というよりも、nt!PoCallDriver ルーチン自身が nt!IoCallDriver ルーチンでした!!

    採取したデバッグ ログです。
    ------------------------------------------------------------------
    0: kd> vertarget
    Windows Server 2008/Windows Vista Kernel Version 6002 (Service Pack 2) MP (2 procs) Free x86 compatible
    Product: WinNt, suite: TerminalServer SingleUserTS
    Built by: 6002.18082.x86fre.vistasp2_gdr.090803-2339
    Machine Name:
    Kernel base = 0x81844000 PsLoadedModuleList = 0x8195bc70
    Debug session time: Wed Mar 17 14:47:40.332 2010 (GMT+9)
    System Uptime: 5 days 4:04:15.208

    0: kd> x nt!PoCallDriver
    8184a47a nt!PoCallDriver = <no type information>
    ^^^^^^^^
    0: kd> x nt!IoCallDriver
    8184a47a nt!IoCallDriver = <no type information>
    ^^^^^^^^
    ------------------------------------------------------------------

    よくよく見たら、nt!PoCallDriver と nt!IoCallDriver のアドレスが全く同じでした。
    つまり、NT カーネルの内部的な動作としては、

      PoCallDriver() == IoCallDriver()

    ということですね。
    なので、わざわざ u コマンドでアセンブラ コードを表示させるまでもなく、
    当然の如く全く同じものが表示される。。。と言うオチでした。

    • 回答としてマーク hkuno-reg 2010年4月7日 2:53
    2010年3月17日 8:44