Share via


Verwenden von Gleitkomma in einem WDM-Treiber

Zuletzt aktualisiert

  • Juli 2016

Kernelmodus-WDM-Treiber für Windows müssen bestimmte Richtlinien befolgen, wenn Gleitkommavorgänge verwendet werden. Diese unterscheiden sich zwischen x86- und x64-Systemen. Standardmäßig deaktiviert Windows arithmetische Ausnahmen für beide Systeme.

x86-Systeme

Kernelmodus-WDM-Treiber für x86-Systeme müssen die Verwendung von Gleitkommaberechnungen zwischen Aufrufen von KeSaveExtendedProcessorState und KeRestoreExtendedProcessorState umschließen. Die Gleitkommavorgänge müssen in einer Nicht-Inline-Unterroutine platziert werden, um sicherzustellen, dass Gleitkommaberechnungen nicht ausgeführt werden, bevor der Rückgabewert von KeSaveExtendedProcessorState aufgrund der Compilerumordnung überprüft wird.

Der Compiler verwendet MMX/x87, auch bekannt als Gleitkommaeinheitsregister (FPU) für solche Berechnungen, die gleichzeitig von einer Benutzermodusanwendung verwendet werden können. Fehler beim Speichern dieser Register vor der Verwendung oder Fehler bei der Wiederherstellung nach Abschluss können zu Berechnungsfehlern in Anwendungen führen.

Treiber für x86-Systeme können KeSaveExtendedProcessorState aufrufen und Gleitkommaberechnungen unter IRQL <= DISPATCH_LEVEL ausführen. Gleitkommavorgänge werden in Interruptdienstroutinen (ISRs) auf x86-Systemen nicht unterstützt.

x64-Systeme

Der 64-Bit-Compiler verwendet die MMX/x87-Register nicht für Gleitkommavorgänge. Stattdessen werden die SSE-Register verwendet. x64-Kernelmoduscode darf nicht auf die MMX/x87-Register zugreifen. Der Compiler kümmert sich auch um das ordnungsgemäße Speichern und Wiederherstellen des SSE-Zustands, daher sind Aufrufe von KeSaveExtendedProcessorState und KeRestoreExtendedProcessorState nicht erforderlich, und Gleitkommavorgänge können in ISRs verwendet werden. Die Verwendung anderer erweiterter Prozessorfunktionen wie AVX erfordert das Speichern und Wiederherstellen des erweiterten Zustands. Weitere Informationen finden Sie unter Verwenden erweiterter Prozessorfeatures in Windows-Treibern.

Hinweis: Arm64 ähnelt im Allgemeinen AMD64 darin, dass Sie nicht zuerst den Gleitkommazustand des Speicherns aufrufen müssen. Code, der in x86-Kernels portierbar sein muss, muss dies jedoch möglicherweise weiterhin tun, um plattformübergreifend zu sein.

Beispiel

Das folgende Beispiel zeigt, wie ein WDM-Treiber seinen FPU-Zugriff umschließen soll:

__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;
}

Im Beispiel erfolgt die Zuweisung zur Gleitkommavariable zwischen Aufrufen von KeSaveExtendedProcessorState und KeRestoreExtendedProcessorState. Da bei jeder Zuweisung zu einer Gleitkommavariablen die FPU verwendet wird, müssen Treiber sicherstellen, dass KeSaveExtendedProcessorState ohne Fehler zurückgegeben wurde, bevor sie eine solche Variable initialisieren.

Die vorherigen Aufrufe sind auf einem x64-System unnötig und harmlos, wenn das XSTATE_MASK_LEGACY-Flag angegeben wird. Daher ist es nicht erforderlich, den Code beim Kompilieren des Treibers für ein x64-System zu ändern.

Auf x86-basierten Systemen wird die FPU durch einen Aufruf von FNINIT auf ihren Standardzustand zurückgesetzt, wenn sie von KeSaveExtendedProcessorState zurückgegeben wird.