x86_vector_register_glue.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. /* x86_vector_register_glue.c -- glue logic to save and restore vector registers
  2. * on x86
  3. *
  4. * Copyright (C) 2006-2024 wolfSSL Inc.
  5. *
  6. * This file is part of wolfSSL.
  7. *
  8. * wolfSSL is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * wolfSSL is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  21. */
  22. /* included by linuxkm/module_hooks.c */
  23. #if !defined(WOLFSSL_LINUXKM_USE_SAVE_VECTOR_REGISTERS) || !defined(CONFIG_X86)
  24. #error x86_vector_register_glue.c included in non-vectorized/non-x86 project.
  25. #endif
  26. /* kernel 4.19 -- the most recent LTS before 5.4 -- lacks the necessary safety
  27. * checks in __kernel_fpu_begin(), and lacks TIF_NEED_FPU_LOAD.
  28. */
  29. #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0))
  30. #error WOLFSSL_LINUXKM_USE_SAVE_VECTOR_REGISTERS on x86 requires kernel 5.4.0 or higher.
  31. #endif
  32. static unsigned int wc_linuxkm_fpu_states_n_tracked = 0;
  33. struct wc_thread_fpu_count_ent {
  34. volatile pid_t pid;
  35. unsigned int fpu_state;
  36. };
  37. struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_states = NULL;
  38. #ifdef WOLFSSL_COMMERCIAL_LICENSE
  39. #ifndef LINUXKM_FPU_STATES_FOLLOW_THREADS
  40. #error WOLFSSL_COMMERCIAL_LICENSE requires LINUXKM_FPU_STATES_FOLLOW_THREADS
  41. #endif
  42. #pragma GCC diagnostic push
  43. #pragma GCC diagnostic ignored "-Wunused-parameter"
  44. #pragma GCC diagnostic ignored "-Wnested-externs"
  45. /* avoid dependence on "alternatives_patched" and "xfd_validate_state()". */
  46. #undef CONFIG_X86_DEBUG_FPU
  47. #include "../kernel/fpu/internal.h"
  48. #include "../kernel/fpu/xstate.h"
  49. #pragma GCC diagnostic pop
  50. static union wc_linuxkm_fpu_savebuf {
  51. byte buf[1024]; /* must be 64-byte-aligned */
  52. struct fpstate fpstate;
  53. } *wc_linuxkm_fpu_savebufs = NULL;
  54. #endif /* WOLFSSL_COMMERCIAL_LICENSE */
  55. #define WC_FPU_COUNT_MASK 0x7fffffffU
  56. #define WC_FPU_SAVED_MASK 0x80000000U
  57. WARN_UNUSED_RESULT int allocate_wolfcrypt_linuxkm_fpu_states(void)
  58. {
  59. if (wc_linuxkm_fpu_states != NULL) {
  60. #ifdef HAVE_FIPS
  61. /* see note below in wc_linuxkm_fpu_state_assoc_unlikely(). */
  62. return 0;
  63. #else
  64. static int warned_for_repeat_alloc = 0;
  65. if (! warned_for_repeat_alloc) {
  66. pr_err("attempt at repeat allocation"
  67. " in allocate_wolfcrypt_linuxkm_fpu_states\n");
  68. warned_for_repeat_alloc = 1;
  69. }
  70. return BAD_STATE_E;
  71. #endif
  72. }
  73. #ifdef LINUXKM_FPU_STATES_FOLLOW_THREADS
  74. if (nr_cpu_ids >= 16)
  75. wc_linuxkm_fpu_states_n_tracked = nr_cpu_ids * 2;
  76. else
  77. wc_linuxkm_fpu_states_n_tracked = 32;
  78. #else
  79. wc_linuxkm_fpu_states_n_tracked = nr_cpu_ids;
  80. #endif
  81. wc_linuxkm_fpu_states =
  82. (struct wc_thread_fpu_count_ent *)malloc(
  83. wc_linuxkm_fpu_states_n_tracked * sizeof(wc_linuxkm_fpu_states[0]));
  84. if (! wc_linuxkm_fpu_states) {
  85. pr_err("allocation of %lu bytes for "
  86. "wc_linuxkm_fpu_states failed.\n",
  87. nr_cpu_ids * sizeof(struct fpu_state *));
  88. return MEMORY_E;
  89. }
  90. memset(wc_linuxkm_fpu_states, 0, wc_linuxkm_fpu_states_n_tracked
  91. * sizeof(wc_linuxkm_fpu_states[0]));
  92. #ifdef WOLFSSL_COMMERCIAL_LICENSE
  93. wc_linuxkm_fpu_savebufs = (union wc_linuxkm_fpu_savebuf *)malloc(
  94. wc_linuxkm_fpu_states_n_tracked * sizeof(*wc_linuxkm_fpu_savebufs));
  95. if (! wc_linuxkm_fpu_savebufs) {
  96. pr_err("allocation of %lu bytes for "
  97. "wc_linuxkm_fpu_savebufs failed.\n",
  98. WC_LINUXKM_ROUND_UP_P_OF_2(wc_linuxkm_fpu_states_n_tracked)
  99. * sizeof(*wc_linuxkm_fpu_savebufs));
  100. free(wc_linuxkm_fpu_states);
  101. wc_linuxkm_fpu_states = NULL;
  102. return MEMORY_E;
  103. }
  104. if ((uintptr_t)wc_linuxkm_fpu_savebufs
  105. & (WC_LINUXKM_ROUND_UP_P_OF_2(sizeof(*wc_linuxkm_fpu_savebufs)) - 1))
  106. {
  107. pr_err("allocation of %lu bytes for "
  108. "wc_linuxkm_fpu_savebufs allocated with wrong alignment 0x%lx.\n",
  109. WC_LINUXKM_ROUND_UP_P_OF_2(wc_linuxkm_fpu_states_n_tracked)
  110. * sizeof(*wc_linuxkm_fpu_savebufs),
  111. (uintptr_t)wc_linuxkm_fpu_savebufs);
  112. free(wc_linuxkm_fpu_savebufs);
  113. wc_linuxkm_fpu_savebufs = NULL;
  114. free(wc_linuxkm_fpu_states);
  115. wc_linuxkm_fpu_states = NULL;
  116. return MEMORY_E;
  117. }
  118. #endif
  119. return 0;
  120. }
  121. void free_wolfcrypt_linuxkm_fpu_states(void) {
  122. struct wc_thread_fpu_count_ent *i, *i_endptr;
  123. pid_t i_pid;
  124. if (wc_linuxkm_fpu_states == NULL) {
  125. pr_err("free_wolfcrypt_linuxkm_fpu_states called"
  126. " before allocate_wolfcrypt_linuxkm_fpu_states.\n");
  127. return;
  128. }
  129. for (i = wc_linuxkm_fpu_states,
  130. i_endptr = &wc_linuxkm_fpu_states[wc_linuxkm_fpu_states_n_tracked];
  131. i < i_endptr;
  132. ++i)
  133. {
  134. i_pid = __atomic_load_n(&i->pid, __ATOMIC_CONSUME);
  135. if (i_pid == 0)
  136. continue;
  137. if (i->fpu_state != 0) {
  138. pr_err("free_wolfcrypt_linuxkm_fpu_states called"
  139. " with nonzero state 0x%x for pid %d.\n", i->fpu_state, i_pid);
  140. i->fpu_state = 0;
  141. }
  142. }
  143. #ifdef WOLFSSL_COMMERCIAL_LICENSE
  144. free(wc_linuxkm_fpu_savebufs);
  145. wc_linuxkm_fpu_savebufs = NULL;
  146. #endif
  147. free(wc_linuxkm_fpu_states);
  148. wc_linuxkm_fpu_states = NULL;
  149. }
  150. #ifdef LINUXKM_FPU_STATES_FOLLOW_THREADS
  151. /* legacy thread-local storage facility for tracking recursive fpu
  152. * pushing/popping
  153. */
  154. static struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc(int create_p) {
  155. struct wc_thread_fpu_count_ent *i, *i_endptr, *i_empty;
  156. pid_t my_pid = task_pid_nr(current), i_pid;
  157. {
  158. static int _warned_on_null = 0;
  159. if (wc_linuxkm_fpu_states == NULL)
  160. {
  161. #ifdef HAVE_FIPS
  162. /* FIPS needs to use SHA256 for the core verify HMAC, before
  163. * reaching the regular wolfCrypt_Init() logic. to break the
  164. * dependency loop on intelasm builds, we allocate here.
  165. * this is not thread-safe and doesn't need to be.
  166. */
  167. if ((! create_p) || (allocate_wolfcrypt_linuxkm_fpu_states() != 0))
  168. #endif
  169. {
  170. if (_warned_on_null == 0) {
  171. pr_err("wc_linuxkm_fpu_state_assoc called by pid %d"
  172. " before allocate_wolfcrypt_linuxkm_fpu_states.\n", my_pid);
  173. _warned_on_null = 1;
  174. }
  175. return NULL;
  176. }
  177. }
  178. }
  179. i_endptr = &wc_linuxkm_fpu_states[wc_linuxkm_fpu_states_n_tracked];
  180. for (;;) {
  181. for (i = wc_linuxkm_fpu_states,
  182. i_empty = NULL;
  183. i < i_endptr;
  184. ++i)
  185. {
  186. i_pid = __atomic_load_n(&i->pid, __ATOMIC_CONSUME);
  187. if (i_pid == my_pid)
  188. return i;
  189. if ((i_empty == NULL) && (i_pid == 0))
  190. i_empty = i;
  191. }
  192. if ((i_empty == NULL) || (! create_p))
  193. return NULL;
  194. i_pid = 0;
  195. if (__atomic_compare_exchange_n(
  196. &(i_empty->pid),
  197. &i_pid,
  198. my_pid,
  199. 0 /* weak */,
  200. __ATOMIC_SEQ_CST /* success_memmodel */,
  201. __ATOMIC_SEQ_CST /* failure_memmodel */))
  202. {
  203. return i_empty;
  204. }
  205. }
  206. }
  207. #else /* !LINUXKM_FPU_STATES_FOLLOW_THREADS */
  208. /* lock-free O(1)-lookup CPU-local storage facility for tracking recursive fpu
  209. * pushing/popping.
  210. *
  211. * caller must have already called kernel_fpu_begin() or preempt_disable()
  212. * before entering this or the streamlined inline version of it below.
  213. */
  214. static struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc_unlikely(int create_p) {
  215. int my_cpu = raw_smp_processor_id();
  216. pid_t my_pid = task_pid_nr(current), slot_pid;
  217. struct wc_thread_fpu_count_ent *slot;
  218. {
  219. static int _warned_on_null = 0;
  220. if (wc_linuxkm_fpu_states == NULL)
  221. {
  222. #ifdef HAVE_FIPS
  223. /* FIPS needs to use SHA256 for the core verify HMAC, before
  224. * reaching the regular wolfCrypt_Init() logic. to break the
  225. * dependency loop on intelasm builds, we allocate here.
  226. * this is not thread-safe and doesn't need to be.
  227. */
  228. int ret = allocate_wolfcrypt_linuxkm_fpu_states();
  229. if (ret != 0)
  230. #endif
  231. {
  232. if (_warned_on_null == 0) {
  233. pr_err("wc_linuxkm_fpu_state_assoc called by pid %d"
  234. " before allocate_wolfcrypt_linuxkm_fpu_states.\n", my_pid);
  235. _warned_on_null = 1;
  236. }
  237. return NULL;
  238. }
  239. }
  240. }
  241. slot = &wc_linuxkm_fpu_states[my_cpu];
  242. slot_pid = __atomic_load_n(&slot->pid, __ATOMIC_CONSUME);
  243. if (slot_pid == my_pid) {
  244. if (create_p) {
  245. static int _warned_on_redundant_create_p = 0;
  246. if (_warned_on_redundant_create_p < 10) {
  247. pr_err("wc_linuxkm_fpu_state_assoc called with create_p=1 by"
  248. " pid %d on cpu %d with cpu slot already reserved by"
  249. " said pid.\n", my_pid, my_cpu);
  250. ++_warned_on_redundant_create_p;
  251. }
  252. }
  253. return slot;
  254. }
  255. if (create_p) {
  256. if (slot_pid == 0) {
  257. __atomic_store_n(&slot->pid, my_pid, __ATOMIC_RELEASE);
  258. return slot;
  259. } else {
  260. /* if the slot is already occupied, that can be benign due to a
  261. * migration, but it will require fixup by the thread that owns the
  262. * slot, which will happen when it releases its lock, or sooner (see
  263. * below).
  264. */
  265. static int _warned_on_mismatched_pid = 0;
  266. if (_warned_on_mismatched_pid < 10) {
  267. pr_warn("wc_linuxkm_fpu_state_assoc called by pid %d on cpu %d"
  268. " but cpu slot already reserved by pid %d.\n",
  269. my_pid, my_cpu, slot_pid);
  270. ++_warned_on_mismatched_pid;
  271. }
  272. return NULL;
  273. }
  274. } else {
  275. /* check for migration. this can happen despite our best efforts if any
  276. * I/O occured while locked, e.g. kernel messages like "uninitialized
  277. * urandom read". since we're locked now, we can safely migrate the
  278. * entry in wc_linuxkm_fpu_states[], freeing up the slot on the previous
  279. * cpu.
  280. */
  281. unsigned int cpu_i;
  282. for (cpu_i = 0; cpu_i < wc_linuxkm_fpu_states_n_tracked; ++cpu_i) {
  283. if (__atomic_load_n(
  284. &wc_linuxkm_fpu_states[cpu_i].pid,
  285. __ATOMIC_CONSUME)
  286. == my_pid)
  287. {
  288. wc_linuxkm_fpu_states[my_cpu] = wc_linuxkm_fpu_states[cpu_i];
  289. __atomic_store_n(&wc_linuxkm_fpu_states[cpu_i].fpu_state, 0,
  290. __ATOMIC_RELEASE);
  291. __atomic_store_n(&wc_linuxkm_fpu_states[cpu_i].pid, 0,
  292. __ATOMIC_RELEASE);
  293. return &wc_linuxkm_fpu_states[my_cpu];
  294. }
  295. }
  296. return NULL;
  297. }
  298. }
  299. static inline struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc(
  300. int create_p)
  301. {
  302. int my_cpu = raw_smp_processor_id(); /* my_cpu is only trustworthy if we're
  303. * already nonpreemptible -- we'll
  304. * determine that soon enough by
  305. * checking if the pid matches or,
  306. * failing that, if create_p.
  307. */
  308. pid_t my_pid = task_pid_nr(current), slot_pid;
  309. struct wc_thread_fpu_count_ent *slot;
  310. if (unlikely(wc_linuxkm_fpu_states == NULL))
  311. return wc_linuxkm_fpu_state_assoc_unlikely(create_p);
  312. slot = &wc_linuxkm_fpu_states[my_cpu];
  313. slot_pid = __atomic_load_n(&slot->pid, __ATOMIC_CONSUME);
  314. if (slot_pid == my_pid) {
  315. if (unlikely(create_p))
  316. return wc_linuxkm_fpu_state_assoc_unlikely(create_p);
  317. else
  318. return slot;
  319. }
  320. if (likely(create_p)) {
  321. if (likely(slot_pid == 0)) {
  322. __atomic_store_n(&slot->pid, my_pid, __ATOMIC_RELEASE);
  323. return slot;
  324. } else {
  325. return wc_linuxkm_fpu_state_assoc_unlikely(create_p);
  326. }
  327. } else {
  328. return wc_linuxkm_fpu_state_assoc_unlikely(create_p);
  329. }
  330. }
  331. #endif /* !LINUXKM_FPU_STATES_FOLLOW_THREADS */
  332. #ifdef WOLFSSL_COMMERCIAL_LICENSE
  333. static struct fpstate *wc_linuxkm_fpstate_buf_from_fpu_state(
  334. struct wc_thread_fpu_count_ent *state)
  335. {
  336. size_t i = (size_t)(state - wc_linuxkm_fpu_states) / sizeof(*state);
  337. return &wc_linuxkm_fpu_savebufs[i].fpstate;
  338. }
  339. #endif
  340. static void wc_linuxkm_fpu_state_release_unlikely(
  341. struct wc_thread_fpu_count_ent *ent)
  342. {
  343. if (ent->fpu_state != 0) {
  344. static int warned_nonzero_fpu_state = 0;
  345. if (! warned_nonzero_fpu_state) {
  346. pr_err("wc_linuxkm_fpu_state_free for pid %d"
  347. " with nonzero fpu_state 0x%x.\n", ent->pid, ent->fpu_state);
  348. warned_nonzero_fpu_state = 1;
  349. }
  350. ent->fpu_state = 0;
  351. }
  352. __atomic_store_n(&ent->pid, 0, __ATOMIC_RELEASE);
  353. }
  354. static inline void wc_linuxkm_fpu_state_release(
  355. struct wc_thread_fpu_count_ent *ent)
  356. {
  357. if (unlikely(ent->fpu_state != 0))
  358. return wc_linuxkm_fpu_state_release_unlikely(ent);
  359. __atomic_store_n(&ent->pid, 0, __ATOMIC_RELEASE);
  360. }
  361. WARN_UNUSED_RESULT int can_save_vector_registers_x86(void)
  362. {
  363. if (irq_fpu_usable())
  364. return 1;
  365. else if (in_nmi() || (hardirq_count() > 0) || (softirq_count() > 0))
  366. return 0;
  367. else if (test_thread_flag(TIF_NEED_FPU_LOAD))
  368. return 1;
  369. return 0;
  370. }
  371. WARN_UNUSED_RESULT int save_vector_registers_x86(void)
  372. {
  373. #ifdef LINUXKM_FPU_STATES_FOLLOW_THREADS
  374. struct wc_thread_fpu_count_ent *pstate = wc_linuxkm_fpu_state_assoc(1);
  375. #else
  376. struct wc_thread_fpu_count_ent *pstate = wc_linuxkm_fpu_state_assoc(0);
  377. #endif
  378. /* allow for nested calls */
  379. #ifdef LINUXKM_FPU_STATES_FOLLOW_THREADS
  380. if (pstate == NULL)
  381. return MEMORY_E;
  382. #endif
  383. if (
  384. #ifndef LINUXKM_FPU_STATES_FOLLOW_THREADS
  385. (pstate != NULL) &&
  386. #endif
  387. (pstate->fpu_state != 0U))
  388. {
  389. if (unlikely((pstate->fpu_state & WC_FPU_COUNT_MASK)
  390. == WC_FPU_COUNT_MASK))
  391. {
  392. pr_err("save_vector_registers_x86 recursion register overflow for "
  393. "pid %d.\n", pstate->pid);
  394. return BAD_STATE_E;
  395. } else {
  396. ++pstate->fpu_state;
  397. return 0;
  398. }
  399. }
  400. if (irq_fpu_usable()
  401. #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0))
  402. /* work around a kernel bug -- see linux commit 59f5ede3bc0f0.
  403. * what we really want here is this_cpu_read(in_kernel_fpu), but
  404. * in_kernel_fpu is an unexported static array.
  405. */
  406. && !test_thread_flag(TIF_NEED_FPU_LOAD)
  407. #endif
  408. )
  409. {
  410. #ifdef WOLFSSL_COMMERCIAL_LICENSE
  411. struct fpstate *fpstate = wc_linuxkm_fpstate_buf_from_fpu_state(pstate);
  412. fpregs_lock();
  413. fpstate->xfeatures = ~0UL;
  414. os_xsave(fpstate);
  415. #else /* !WOLFSSL_COMMERCIAL_LICENSE */
  416. #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \
  417. (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
  418. /* inhibit migration, which gums up the algorithm in
  419. * kernel_fpu_{begin,end}().
  420. */
  421. migrate_disable();
  422. #endif
  423. kernel_fpu_begin();
  424. #ifndef LINUXKM_FPU_STATES_FOLLOW_THREADS
  425. pstate = wc_linuxkm_fpu_state_assoc(1);
  426. if (pstate == NULL) {
  427. kernel_fpu_end();
  428. #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \
  429. (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) && \
  430. !defined(WOLFSSL_COMMERCIAL_LICENSE)
  431. migrate_enable();
  432. #endif
  433. return BAD_STATE_E;
  434. }
  435. #endif
  436. #endif /* !WOLFSSL_COMMERCIAL_LICENSE */
  437. /* set msb to 0 to trigger kernel_fpu_end() at cleanup. */
  438. pstate->fpu_state = 1U;
  439. } else if (in_nmi() || (hardirq_count() > 0) || (softirq_count() > 0)) {
  440. static int warned_fpu_forbidden = 0;
  441. if (! warned_fpu_forbidden)
  442. pr_err("save_vector_registers_x86 called from IRQ handler.\n");
  443. #ifdef LINUXKM_FPU_STATES_FOLLOW_THREADS
  444. wc_linuxkm_fpu_state_release(pstate);
  445. #endif
  446. return BAD_STATE_E;
  447. } else if (!test_thread_flag(TIF_NEED_FPU_LOAD)) {
  448. static int warned_fpu_forbidden = 0;
  449. if (! warned_fpu_forbidden)
  450. pr_err("save_vector_registers_x86 called with !irq_fpu_usable from"
  451. " thread without previous FPU save.\n");
  452. #ifdef LINUXKM_FPU_STATES_FOLLOW_THREADS
  453. wc_linuxkm_fpu_state_release(pstate);
  454. #endif
  455. return BAD_STATE_E;
  456. } else {
  457. /* assume already safely in_kernel_fpu from caller, but recursively
  458. * preempt_disable() to be extra-safe.
  459. */
  460. preempt_disable();
  461. #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \
  462. (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) && \
  463. !defined(WOLFSSL_COMMERCIAL_LICENSE)
  464. migrate_disable();
  465. #endif
  466. #ifndef LINUXKM_FPU_STATES_FOLLOW_THREADS
  467. pstate = wc_linuxkm_fpu_state_assoc(1);
  468. if (pstate == NULL) {
  469. #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \
  470. (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) && \
  471. !defined(WOLFSSL_COMMERCIAL_LICENSE)
  472. migrate_enable();
  473. #endif
  474. preempt_enable();
  475. return BAD_STATE_E;
  476. }
  477. #endif
  478. /* set msb to 1 to inhibit kernel_fpu_end() at cleanup. */
  479. pstate->fpu_state =
  480. WC_FPU_SAVED_MASK + 1U;
  481. }
  482. return 0;
  483. }
  484. void restore_vector_registers_x86(void)
  485. {
  486. struct wc_thread_fpu_count_ent *pstate = wc_linuxkm_fpu_state_assoc(0);
  487. if (unlikely(pstate == NULL)) {
  488. pr_err("restore_vector_registers_x86 called by pid %d on CPU %d "
  489. "with no saved state.\n", task_pid_nr(current),
  490. raw_smp_processor_id());
  491. return;
  492. }
  493. if ((--pstate->fpu_state & WC_FPU_COUNT_MASK) > 0U) {
  494. return;
  495. }
  496. if (pstate->fpu_state == 0U) {
  497. #ifdef WOLFSSL_COMMERCIAL_LICENSE
  498. struct fpstate *fpstate = wc_linuxkm_fpstate_buf_from_fpu_state(pstate);
  499. os_xrstor(fpstate, fpstate->xfeatures);
  500. fpregs_unlock();
  501. #else
  502. #ifndef LINUXKM_FPU_STATES_FOLLOW_THREADS
  503. wc_linuxkm_fpu_state_release(pstate);
  504. #endif
  505. kernel_fpu_end();
  506. #endif
  507. } else {
  508. pstate->fpu_state = 0U;
  509. #ifndef LINUXKM_FPU_STATES_FOLLOW_THREADS
  510. wc_linuxkm_fpu_state_release(pstate);
  511. #endif
  512. preempt_enable();
  513. }
  514. #if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_COUNT) && \
  515. (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) && \
  516. !defined(WOLFSSL_COMMERCIAL_LICENSE)
  517. migrate_enable();
  518. #endif
  519. #ifdef LINUXKM_FPU_STATES_FOLLOW_THREADS
  520. wc_linuxkm_fpu_state_release(pstate);
  521. #endif
  522. return;
  523. }