использование операций с плавающей запятой на высоком уровне 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);
}
}
Предостережения:
- Всегда проверяйте выравнивание буфера.
- С осторожностью используйте структурированную обработку исключений в режиме ядра. Есть некоторые особые соображения, о которых следует знать.
- Использование операций с плавающей запятой в ядре обычно не рекомендуется, за исключением случаев крайней необходимости. Убедитесь, что вы приняли необходимые меры предосторожности.
Надеюсь, это поможет всем, кто сталкивается с подобными проблемами! Обратная связь или дополнительная информация приветствуются!