Uso della virgola mobile in un driver WDM

Ultimo aggiornamento

  • Luglio 2016

I driver WDM in modalità kernel per Windows devono seguire determinate linee guida quando si usano operazioni a virgola mobile. Queste differenze variano tra sistemi x86 e x64. Per impostazione predefinita, Windows disattiva le eccezioni aritmetiche per entrambi i sistemi.

Sistemi x86

I driver WDM in modalità kernel per sistemi x86 devono eseguire il wrapping dell'uso di calcoli a virgola mobile tra le chiamate a KeSaveExtendedProcessorState e KeRestoreExtendedProcessorState. Le operazioni a virgola mobile devono essere inserite in una subroutine non inline per assicurarsi che i calcoli a virgola mobile non vengano eseguiti prima di controllare il valore restituito di KeSaveExtendedProcessorState a causa del riordinamento del compilatore.

Il compilatore usa MMX/x87 noto anche come registri di unità a virgola mobile (FPU) per tali calcoli, che possono essere usati simultaneamente da un'applicazione in modalità utente. Se non si salvano questi registri prima di usarli o non è possibile ripristinarli al termine, possono causare errori di calcolo nelle applicazioni.

I driver per sistemi x86 possono chiamare KeSaveExtendedProcessorState ed eseguire calcoli a virgola mobile in IRQL <= DISPATCH_LEVEL. Le operazioni a virgola mobile non sono supportate nelle routine del servizio di interrupt (ISR) nei sistemi x86.

Sistemi x64

Il compilatore a 64 bit non usa i registri MMX/x87 per le operazioni a virgola mobile. Usa invece i registri della crittografia del servizio di archiviazione. Il codice in modalità kernel x64 non è autorizzato ad accedere ai registri MMX/x87. Il compilatore si occupa anche del corretto salvataggio e del ripristino dello stato della crittografia del servizio di archiviazione, pertanto le chiamate a KeSaveExtendedProcessorState e KeRestoreExtendedProcessorState non sono necessarie e le operazioni a virgola mobile possono essere usate nelle richieste isr. L'uso di altre funzionalità del processore estese, ad esempio AVX, richiede il salvataggio e il ripristino dello stato esteso. Per altre informazioni, vedere Uso delle funzionalità estese del processore nei driver di Windows.

Nota: Arm64 in generale, è simile a AMD64 in quanto non è necessario chiamare prima salva stato a virgola mobile. Tuttavia, il codice che deve essere portabile a x86 nei kernel potrebbe comunque dover eseguire questa operazione per essere multipiattaforma.

Esempio

L'esempio seguente mostra come un driver WDM deve eseguire il wrapping dell'accesso 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;
}

Nell'esempio, l'assegnazione alla variabile a virgola mobile avviene tra le chiamate a KeSaveExtendedProcessorState e KeRestoreExtendedProcessorState. Poiché qualsiasi assegnazione a una variabile a virgola mobile usa la FPU, i driver devono assicurarsi che KeSaveExtendedProcessorState abbia restituito senza errori prima di inizializzare tale variabile.

Le chiamate precedenti non sono necessarie in un sistema x64 e innocue quando viene specificato il flag di XSTATE_MASK_LEGACY. Non è quindi necessario modificare il codice durante la compilazione del driver per un sistema x64.

Nei sistemi basati su x86, la FPU viene reimpostata sullo stato predefinito da una chiamata a FNINIT, al ritorno da KeSaveExtendedProcessorState.