WDM ドライバーでの浮動小数点の使用

最終更新日

  • 2016 年 7 月

Windows 用のカーネルモード WDM ドライバーは、浮動小数点演算を使用する場合に特定のガイドラインに従う必要があります。 これらは x86 システムと x64 システムで異なります。 既定では、Windows はどちらのシステムでも演算例外をオフにします。

x86 システム

x86 システムのカーネルモード WDM ドライバーは、KeSaveExtendedProcessorStateKeRestoreExtendedProcessorState の呼び出しの間で浮動小数点計算の使用をラップする必要があります。 コンパイラの並べ替えにより KeSaveExtendedProcessorState の戻り値をチェックする前に浮動小数点計算が実行されないようにするには、浮動小数点演算をインラインではないサブルーチンに配置する必要があります。

コンパイラは、このような計算に浮動小数点ユニット (FPU) レジスタとも呼ばれる MMX/x87 を使用します。これは、ユーザーモード アプリケーションで同時に使用できます。 これらのレジスタを使用する前に保存しなかったり、完了したときに復元できなかったりすると、アプリケーションで計算エラーが発生する可能性があります。

x86 システムのドライバーは、KeSaveExtendedProcessorState を呼び出し、IRQL <= DISPATCH_LEVEL で浮動小数点計算を実行できます。 浮動小数点演算は、x86 システムの割り込みサービス ルーチン (ISR) ではサポートされていません。

x64 システム

64 ビット コンパイラは、浮動小数点演算に MMX/x87 レジスタを使用しません。 代わりに、SSE レジスタを使用します。 x64 カーネルモード コードは MMX/x87 レジスタにアクセスできません。 コンパイラでは、SSE 状態の適切な保存と復元も行われるため、KeSaveExtendedProcessorStateKeRestoreExtendedProcessorState の呼び出しは不要であり、ISR では浮動小数点演算を使用できます。 AVX などの他の拡張プロセッサ機能を使用するには、拡張状態の保存と復元が必要です。 詳細については、「Windows ドライバー での拡張プロセッサ機能の使用」を参照してください。

注: Arm64 は一般に、最初に save 浮動小数点状態を呼び出す必要がない点で AMD64 に似ています。 ただし、カーネル上で x86 に移植する必要があるコードは、クロスプラットフォームであるためにその必要があるかもしれません。

次の例は、WDM ドライバーが FPU アクセスをラップする方法を示しています。

__declspec(noinline)
VOID
DoFloatingPointCalculation(
    VOID
    )
{
    double Duration;
    LARGE_INTEGER Frequency;

    Duration = 1000000.0;
    DbgPrint("%I64x\n", *(LONGLONG*)&Duration);
    KeQueryPerformanceCounter(&Frequency);
    Duration /= (double)Frequency.QuadPart;
    DbgPrint("%I64x\n", *(LONGLONG*)&Duration);
}

NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PUNICODE_STRING RegistryPath
    )
{

    XSTATE_SAVE SaveState;
    NTSTATUS Status;

    Status = KeSaveExtendedProcessorState(XSTATE_MASK_LEGACY, &SaveState);
    if (!NT_SUCCESS(Status)) {
        goto exit;
    }

    __try {
        DoFloatingPointCalculation();
    }
    __finally {
        KeRestoreExtendedProcessorState(&SaveState);
    }

exit:
    return Status;
}

この例では、浮動小数点変数への割り当ては、KeSaveExtendedProcessorStateKeRestoreExtendedProcessorState の呼び出しの間に発生します。 浮動小数点変数への代入では FPU が使用されるため、ドライバーは、このような変数を初期化する前に、エラーなしで KeSaveExtendedProcessorState が返されていることを確認する必要があります。

上記の呼び出しは x64 システムでは不要であり、XSTATE_MASK_LEGACY フラグが指定されている場合は無害です。 したがって、x64 システムのドライバーをコンパイルするときにコードを変更する必要はありません。

x86 ベースのシステムでは、KeSaveExtendedProcessorState から戻ると、FPU は FNINIT の呼び出しによって既定の状態にリセットされます。