windowskernelmasmfloatingirql

using floating-point operations at high_level irql


In my kernel routine that executes at HIGH_LEVEL IRQL, I've been trying to manage the floating-point state by directly invoking FXSAVE and FXRSTOR. As KeSaveExtendedProcessorState and KeRestoreExtendedProcessorState are not usable at this level, I had to resort to this method.

Here's my current implementation:

In the assembly code, I've defined two procedures SaveFxState and RestoreFxState:

SaveFxState PROC
    ; Save the floating point state
    mov rax, rcx
    fxsave [rax]
    ret
SaveFxState ENDP

RestoreFxState PROC
    ; Restore the floating point state
    mov rax, rcx
    fxrstor [rax]
    ret
RestoreFxState ENDP

These procedures are exposed with extern "C" linkage to my C++ code:

extern "C" {
    void SaveFxState(void* saveArea);
    void RestoreFxState(void* saveArea);
}

I use these procedures as follows:

FXSAVE_FORMAT g_FxSaveArea;

SaveFxState(&g_FxSaveArea);

// Floating-point operations are here

RestoreFxState(&g_FxSaveArea);

Can anyone confirm whether this approach is correct and safe for managing floating-point state at HIGH_LEVEL IRQL? I would appreciate any insights or suggestions for improvement.


Solution

  • I've been working on kernel programming and needed to perform floating-point operations. One of the challenges with doing this in kernel mode is preserving the floating-point and SIMD state in high level irql . I wanted to share a method I've found to be effective using the _fxsave64 and _fxrstor64 intrinsics.

    Prerequisites: Ensure you have a good reason to use floating-point in the kernel, as it can introduce hard-to-debug issues.

    Solution: Firstly, declare a buffer to save the FPU state. This buffer should be 16-byte

    aligned:
    __declspec(align(16)) BYTE FpuState[512];  // Ensure the memory area is 16-byte aligned
    

    Next, wrap your floating-point code between _fxsave64 and _fxrstor64:

    void KernelFunctionWithFPUOperations()
    {
        _fxsave64(FpuState);
        __try {
            DoFloatingPointCalculation();
        }
        __finally {
            _fxrstor64(FpuState);
        }
    }
    

    Caveats:

    I hope this helps anyone facing similar challenges! Feedback or further insights are welcome!