Uso de punto flotante en un controlador WDM

Última actualización

  • Julio de 2016

Los controladores WDM en modo kernel para Windows deben seguir ciertas instrucciones al usar operaciones de punto flotante. Difieren entre los sistemas x86 y x64. De forma predeterminada, Windows desactiva las excepciones aritméticas para ambos sistemas.

Sistemas x86

Los controladores WDM en modo kernel para sistemas x86 deben ajustar el uso de cálculos de punto flotante entre llamadas a KeSaveExtendedProcessorState y KeRestoreExtendedProcessorState. Las operaciones de punto flotante deben colocarse en una subrutina no insertada para asegurarse de que los cálculos de punto flotante no se realizan antes de comprobar el valor devuelto de KeSaveExtendedProcessorState debido a la reordenación del compilador.

El compilador usa MMX/x87 también conocido como registros de unidad de punto flotante (FPU) para estos cálculos, que una aplicación en modo de usuario puede usar simultáneamente. Si no se guardan estos registros antes de usarlos, o si no se restauran cuando finaliza, se pueden producir errores de cálculo en las aplicaciones.

Los controladores para sistemas x86 pueden llamar a KeSaveExtendedProcessorState y realizar cálculos de punto flotante en IRQL <= DISPATCH_LEVEL. Las operaciones de punto flotante no se admiten en rutinas de servicio de interrupción (ISR) en sistemas x86.

Sistemas x64

El compilador de 64 bits no usa los registros MMX/x87 para las operaciones de punto flotante. En su lugar, usa los registros de SSE. El código del modo kernel x64 no puede acceder a los registros MMX/x87. El compilador también se encarga de guardar y restaurar correctamente el estado SSE, por lo que las llamadas a KeSaveExtendedProcessorState y KeRestoreExtendedProcessorState son innecesarias y las operaciones de punto flotante se pueden usar en ISR. El uso de otras características de procesador extendidas, como AVX, requiere guardar y restaurar el estado extendido. Para obtener más información, consulte Uso de características de procesador extendidas en controladores de Windows.

Nota: Arm64 en general, es similar a AMD64 en que no es necesario llamar primero al estado de guardado de punto flotante. Sin embargo, es posible que el código que tenga que ser portátil a x86 en kernels todavía tenga que hacerlo para que sea multiplataforma.

Ejemplo

En el ejemplo siguiente se muestra cómo un controlador WDM debe encapsular su acceso 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;
}

En el ejemplo, la asignación a la variable de punto flotante se produce entre las llamadas a KeSaveExtendedProcessorState y KeRestoreExtendedProcessorState. Dado que cualquier asignación a una variable de punto flotante usa la FPU, los controladores deben asegurarse de que KeSaveExtendedProcessorState se haya devuelto sin errores antes de inicializar dicha variable.

Las llamadas anteriores no son necesarias en un sistema x64 y son inofensivas cuando se especifica la marca XSTATE_MASK_LEGACY. Por lo tanto, no es necesario cambiar el código al compilar el controlador para un sistema x64.

En los sistemas basados en x86, la FPU se restablece a su estado predeterminado mediante una llamada a FNINIT, a cambio de keSaveExtendedProcessorState.