linuxkm: in {save,restore}_vector_registers_x86(), check if vector register file has already been saved and invalidated, and if so, inhibit the kernel_fpu_{begin,end}() wrap and instead just use preempt_{disable,enable}() wraps.

This commit is contained in:
Daniel Pouzzner
2023-04-27 17:48:32 -05:00
parent 8a89303b49
commit 448f1ec9e7
2 changed files with 46 additions and 11 deletions

View File

@@ -30,6 +30,8 @@
#endif #endif
#else #else
static unsigned int *wolfcrypt_linuxkm_fpu_states = NULL; static unsigned int *wolfcrypt_linuxkm_fpu_states = NULL;
#define WC_FPU_COUNT_MASK 0x7fffffffU
#define WC_FPU_SAVED_MASK 0x80000000U
#endif #endif
static WARN_UNUSED_RESULT inline int am_in_hard_interrupt_handler(void) static WARN_UNUSED_RESULT inline int am_in_hard_interrupt_handler(void)
@@ -223,8 +225,10 @@
*/ */
((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] = 1; ((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] = 1;
#else /* !LINUXKM_SIMD_IRQ */ #else /* !LINUXKM_SIMD_IRQ */
if (wolfcrypt_linuxkm_fpu_states[processor_id] != 0) { if (wolfcrypt_linuxkm_fpu_states[processor_id] != 0U) {
if (wolfcrypt_linuxkm_fpu_states[processor_id] == ~0U) { if ((wolfcrypt_linuxkm_fpu_states[processor_id] & WC_FPU_COUNT_MASK)
== WC_FPU_COUNT_MASK)
{
preempt_enable(); preempt_enable();
pr_err("save_vector_registers_x86 recursion register overflow for " pr_err("save_vector_registers_x86 recursion register overflow for "
"cpu id %d.\n", processor_id); "cpu id %d.\n", processor_id);
@@ -234,11 +238,28 @@
return 0; return 0;
} }
} }
kernel_fpu_begin();
preempt_enable(); /* kernel_fpu_begin() does its own /* if kernel_fpu_begin() won't actually save the reg file (because
* preempt_disable(). decrement ours. * it was already saved and invalidated, or because we're in a
*/ * kernel thread), don't call kernel_fpu_begin() here, nor call
wolfcrypt_linuxkm_fpu_states[processor_id] = 1; * kernel_fpu_end() in cleanup. this avoids pointless overhead. in
* kernels >=5.17.12 (from changes to irq_fpu_usable() in linux
* commit 59f5ede3bc0f, backported somewhere >5.17.5), this also
* fixes register corruption.
*/
if ((current->flags & PF_KTHREAD) ||
test_thread_flag(TIF_NEED_FPU_LOAD))
{
wolfcrypt_linuxkm_fpu_states[processor_id] =
WC_FPU_SAVED_MASK + 1U; /* set msb 1 to inhibit kernel_fpu_end() at cleanup. */
/* keep preempt_disable()d from above. */
} else {
kernel_fpu_begin();
preempt_enable(); /* kernel_fpu_begin() does its own
* preempt_disable(). decrement ours.
*/
wolfcrypt_linuxkm_fpu_states[processor_id] = 1U; /* set msb 0 to trigger kernel_fpu_end() at cleanup. */
}
#endif /* !LINUXKM_SIMD_IRQ */ #endif /* !LINUXKM_SIMD_IRQ */
return 0; return 0;
@@ -287,19 +308,29 @@
kernel_fpu_end(); kernel_fpu_end();
} }
#else /* !LINUXKM_SIMD_IRQ */ #else /* !LINUXKM_SIMD_IRQ */
if (wolfcrypt_linuxkm_fpu_states[processor_id] == 0) if ((wolfcrypt_linuxkm_fpu_states[processor_id] & WC_FPU_COUNT_MASK) == 0U)
{ {
pr_err("restore_vector_registers_x86 called for cpu id %d " pr_err("restore_vector_registers_x86 called for cpu id %d "
"without saved context.\n", processor_id); "without saved context.\n", processor_id);
return; return;
} }
if (--wolfcrypt_linuxkm_fpu_states[processor_id] > 0) { if ((--wolfcrypt_linuxkm_fpu_states[processor_id] & WC_FPU_COUNT_MASK) > 0U) {
preempt_enable(); /* preempt_disable count will still be nonzero after this decrement. */ preempt_enable(); /* preempt_disable count may still be nonzero
* after this decrement, but any remaining
* count(s) aren't ours.
*/
return; return;
} }
kernel_fpu_end(); if (wolfcrypt_linuxkm_fpu_states[processor_id] == 0U) {
kernel_fpu_end();
} else {
preempt_enable(); /* preempt_disable count will still be nonzero
* after this decrement.
*/
wolfcrypt_linuxkm_fpu_states[processor_id] = 0U;
}
#endif /* !LINUXKM_SIMD_IRQ */ #endif /* !LINUXKM_SIMD_IRQ */
return; return;

View File

@@ -24,6 +24,10 @@
#include <config.h> #include <config.h>
#endif #endif
#ifdef WOLFSSL_LINUXKM
#define WOLFSSL_NEED_LINUX_CURRENT
#endif
#include <wolfssl/wolfcrypt/settings.h> #include <wolfssl/wolfcrypt/settings.h>
/* check old macros @wc_fips */ /* check old macros @wc_fips */