Partager via


Utilisation de virgule flottante dans un pilote WDM

Dernière mise à jour

  • Juillet 2016

Les pilotes WDM en mode noyau pour Windows doivent suivre certaines instructions lors de l’utilisation d’opérations à virgule flottante. Ceux-ci diffèrent entre les systèmes x86 et x64. Par défaut, Windows désactive les exceptions arithmétiques pour les deux systèmes.

Systèmes x86

Les pilotes WDM en mode noyau pour les systèmes x86 doivent encapsuler l’utilisation de calculs à virgule flottante entre les appels à KeSaveExtendedProcessorState et KeRestoreExtendedProcessorState. Les opérations à virgule flottante doivent être placées dans une sous-routine non inline pour s’assurer que les calculs à virgule flottante ne sont pas effectués avant de vérifier la valeur de retour de KeSaveExtendedProcessorState en raison d’une réorganisation du compilateur.

Le compilateur utilise mmx/x87, également appelés registres d’unités à virgule flottante (FPU) pour ces calculs, qui peuvent être utilisés simultanément par une application en mode utilisateur. L’échec de l’enregistrement de ces registres avant de les utiliser, ou l’échec de leur restauration lorsque vous avez terminé, peut entraîner des erreurs de calcul dans les applications.

Les pilotes pour les systèmes x86 peuvent appeler KeSaveExtendedProcessorState et effectuer des calculs à virgule flottante à IRQL <= DISPATCH_LEVEL. Les opérations à virgule flottante ne sont pas prises en charge dans les routines de service d’interruption (ISR) sur les systèmes x86.

Systèmes x64

Le compilateur 64 bits n’utilise pas les registres MMX/x87 pour les opérations à virgule flottante. Au lieu de cela, il utilise les registres SSE. Le code du mode noyau x64 n’est pas autorisé à accéder aux registres MMX/x87. Le compilateur s’occupe également de l’enregistrement et de la restauration corrects de l’état SSE. Par conséquent, les appels à KeSaveExtendedProcessorState et KeRestoreExtendedProcessorState ne sont pas nécessaires et les opérations à virgule flottante peuvent être utilisées dans les ISR. L’utilisation d’autres fonctionnalités de processeur étendues, telles qu’AVX, nécessite l’enregistrement et la restauration de l’état étendu. Pour plus d’informations, consultez Utilisation des fonctionnalités de processeur étendues dans les pilotes Windows.

Remarque : Arm64 en général, est similaire à AMD64 en ce que vous n’avez pas besoin d’appeler enregistrer l’état à virgule flottante en premier. Toutefois, le code qui doit être portable à x86 sur les noyaux peut encore avoir besoin de le faire pour être multiplateforme.

Exemple

L’exemple suivant montre comment un pilote WDM doit encapsuler son accès 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;
}

Dans l’exemple, l’affectation à la variable à virgule flottante se produit entre les appels à KeSaveExtendedProcessorState et KeRestoreExtendedProcessorState. Étant donné que toute affectation à une variable à virgule flottante utilise le processeur FPU, les pilotes doivent s’assurer que KeSaveExtendedProcessorState a retourné sans erreur avant d’initialiser une telle variable.

Les appels précédents sont inutiles sur un système x64 et inoffensifs lorsque l’indicateur XSTATE_MASK_LEGACY est spécifié. Par conséquent, il n’est pas nécessaire de modifier le code lors de la compilation du pilote pour un système x64.

Sur les systèmes x86, le FPU est réinitialisé à son état par défaut par un appel à FNINIT, au retour de KeSaveExtendedProcessorState.