использование операций с плавающей запятой на высоком уровне irql

В моей процедуре ядра, которая выполняется с HIGH_LEVEL IRQL, я пытался управлять состоянием с плавающей запятой, напрямую вызывая FXSAVE и FXRSTOR. Поскольку KeSaveExtendedProcessorState и KeRestoreExtendedProcessorState на этом уровне использовать невозможно, мне пришлось прибегнуть к этому методу.

Вот моя текущая реализация:

В ассемблерном коде я определил две процедуры SaveFxState и 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

Эти процедуры предоставляются с помощью внешней связи «C» с моим кодом на C++:

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

Я использую эти процедуры следующим образом:

      FXSAVE_FORMAT g_FxSaveArea;

SaveFxState(&g_FxSaveArea);

// Floating-point operations are here

RestoreFxState(&g_FxSaveArea);

Может ли кто-нибудь подтвердить, является ли этот подход правильным и безопасным для управления состоянием с плавающей запятой на HIGH_LEVEL IRQL? Буду признателен за любые идеи и предложения по улучшению.

1 ответ

Я работал над программированием ядра, и мне нужно было выполнять операции с плавающей запятой. Одной из проблем при выполнении этого в режиме ядра является сохранение состояния с плавающей запятой и SIMD в irql высокого уровня. Я хотел поделиться методом, который показался мне эффективным с использованием встроенных функций _fxsave64 и _fxrstor64.

Предварительные требования: Убедитесь, что у вас есть веская причина использовать числа с плавающей запятой в ядре, поскольку это может привести к проблемам, которые трудно отладить.

Решение. Во-первых, объявите буфер для сохранения состояния FPU. Этот буфер должен быть 16-байтовым.

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

Затем оберните код с плавающей запятой между _fxsave64 и _fxrstor64:

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

Предостережения:

  • Всегда проверяйте выравнивание буфера.
  • С осторожностью используйте структурированную обработку исключений в режиме ядра. Есть некоторые особые соображения, о которых следует знать.
  • Использование операций с плавающей запятой в ядре обычно не рекомендуется, за исключением случаев крайней необходимости. Убедитесь, что вы приняли необходимые меры предосторожности.

Надеюсь, это поможет всем, кто сталкивается с подобными проблемами! Обратная связь или дополнительная информация приветствуются!

Другие вопросы по тегам