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
#else
static unsigned int *wolfcrypt_linuxkm_fpu_states = NULL;
#define WC_FPU_COUNT_MASK 0x7fffffffU
#define WC_FPU_SAVED_MASK 0x80000000U
#endif
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;
#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();
pr_err("save_vector_registers_x86 recursion register overflow for "
"cpu id %d.\n", processor_id);
@@ -234,11 +238,28 @@
return 0;
}
}
kernel_fpu_begin();
preempt_enable(); /* kernel_fpu_begin() does its own
* preempt_disable(). decrement ours.
*/
wolfcrypt_linuxkm_fpu_states[processor_id] = 1;
/* if kernel_fpu_begin() won't actually save the reg file (because
* it was already saved and invalidated, or because we're in a
* kernel thread), don't call kernel_fpu_begin() here, nor call
* 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 */
return 0;
@@ -287,19 +308,29 @@
kernel_fpu_end();
}
#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 "
"without saved context.\n", processor_id);
return;
}
if (--wolfcrypt_linuxkm_fpu_states[processor_id] > 0) {
preempt_enable(); /* preempt_disable count will still be nonzero after this decrement. */
if ((--wolfcrypt_linuxkm_fpu_states[processor_id] & WC_FPU_COUNT_MASK) > 0U) {
preempt_enable(); /* preempt_disable count may still be nonzero
* after this decrement, but any remaining
* count(s) aren't ours.
*/
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 */
return;

View File

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