@@ -80,6 +80,25 @@ struct wc_thread_fpu_count_ent {
8080 unsigned int fpu_state ;
8181};
8282struct wc_thread_fpu_count_ent * wc_linuxkm_fpu_states = NULL ;
83+
84+ #ifdef WOLFSSL_COMMERCIAL_LICENSE
85+
86+ #pragma GCC diagnostic push
87+ #pragma GCC diagnostic ignored "-Wunused-parameter"
88+ #pragma GCC diagnostic ignored "-Wnested-externs"
89+ /* avoid dependence on "alternatives_patched" and "xfd_validate_state()". */
90+ #undef CONFIG_X86_DEBUG_FPU
91+ #include "../kernel/fpu/internal.h"
92+ #include "../kernel/fpu/xstate.h"
93+ #pragma GCC diagnostic pop
94+
95+ static union wc_linuxkm_fpu_savebuf {
96+ byte buf [1024 ]; /* must be 64-byte-aligned */
97+ struct fpstate fpstate ;
98+ } * wc_linuxkm_fpu_savebufs = NULL ;
99+
100+ #endif /* WOLFSSL_COMMERCIAL_LICENSE */
101+
83102#define WC_FPU_COUNT_MASK 0x7fffffffU
84103#define WC_FPU_SAVED_MASK 0x80000000U
85104
@@ -111,7 +130,37 @@ WARN_UNUSED_RESULT int allocate_wolfcrypt_linuxkm_fpu_states(void)
111130 return MEMORY_E ;
112131 }
113132
114- memset (wc_linuxkm_fpu_states , 0 , wc_linuxkm_fpu_states_n_tracked * sizeof (wc_linuxkm_fpu_states [0 ]));
133+ memset (wc_linuxkm_fpu_states , 0 , wc_linuxkm_fpu_states_n_tracked
134+ * sizeof (wc_linuxkm_fpu_states [0 ]));
135+
136+ #ifdef WOLFSSL_COMMERCIAL_LICENSE
137+ wc_linuxkm_fpu_savebufs = (union wc_linuxkm_fpu_savebuf * )malloc (
138+ wc_linuxkm_fpu_states_n_tracked * sizeof (* wc_linuxkm_fpu_savebufs ));
139+ if (! wc_linuxkm_fpu_savebufs ) {
140+ pr_err ("allocation of %lu bytes for "
141+ "wc_linuxkm_fpu_savebufs failed.\n" ,
142+ WC_LINUXKM_ROUND_UP_P_OF_2 (wc_linuxkm_fpu_states_n_tracked )
143+ * sizeof (* wc_linuxkm_fpu_savebufs ));
144+ free (wc_linuxkm_fpu_states );
145+ wc_linuxkm_fpu_states = NULL ;
146+ return MEMORY_E ;
147+ }
148+ if ((uintptr_t )wc_linuxkm_fpu_savebufs
149+ & (WC_LINUXKM_ROUND_UP_P_OF_2 (sizeof (* wc_linuxkm_fpu_savebufs )) - 1 ))
150+ {
151+ pr_err ("allocation of %lu bytes for "
152+ "wc_linuxkm_fpu_savebufs allocated with wrong alignment 0x%lx.\n" ,
153+ WC_LINUXKM_ROUND_UP_P_OF_2 (wc_linuxkm_fpu_states_n_tracked )
154+ * sizeof (* wc_linuxkm_fpu_savebufs ),
155+ (uintptr_t )wc_linuxkm_fpu_savebufs );
156+ free (wc_linuxkm_fpu_savebufs );
157+ wc_linuxkm_fpu_savebufs = NULL ;
158+ free (wc_linuxkm_fpu_states );
159+ wc_linuxkm_fpu_states = NULL ;
160+ return MEMORY_E ;
161+ }
162+
163+ #endif
115164
116165 return 0 ;
117166}
@@ -141,11 +190,17 @@ void free_wolfcrypt_linuxkm_fpu_states(void) {
141190 }
142191 }
143192
193+ #ifdef WOLFSSL_COMMERCIAL_LICENSE
194+ free (wc_linuxkm_fpu_savebufs );
195+ wc_linuxkm_fpu_savebufs = NULL ;
196+ #endif
144197 free (wc_linuxkm_fpu_states );
145198 wc_linuxkm_fpu_states = NULL ;
146199}
147200
148- /* lock-(mostly)-free thread-local storage facility for tracking recursive fpu pushing/popping */
201+ /* lock-(mostly)-free thread-local storage facility for tracking recursive fpu
202+ * pushing/popping
203+ */
149204static struct wc_thread_fpu_count_ent * wc_linuxkm_fpu_state_assoc (int create_p ) {
150205 struct wc_thread_fpu_count_ent * i , * i_endptr , * i_empty ;
151206 pid_t my_pid = task_pid_nr (current ), i_pid ;
@@ -194,7 +249,16 @@ static struct wc_thread_fpu_count_ent *wc_linuxkm_fpu_state_assoc(int create_p)
194249 }
195250}
196251
197- static void wc_linuxkm_fpu_state_free (struct wc_thread_fpu_count_ent * ent ) {
252+ #ifdef WOLFSSL_COMMERCIAL_LICENSE
253+ static struct fpstate * wc_linuxkm_fpstate_buf_from_fpu_state (
254+ struct wc_thread_fpu_count_ent * state )
255+ {
256+ size_t i = (size_t )(state - wc_linuxkm_fpu_states ) / sizeof (* state );
257+ return & wc_linuxkm_fpu_savebufs [i ].fpstate ;
258+ }
259+ #endif
260+
261+ static void wc_linuxkm_fpu_state_release (struct wc_thread_fpu_count_ent * ent ) {
198262 if (ent -> fpu_state != 0 ) {
199263 static int warned_nonzero_fpu_state = 0 ;
200264 if (! warned_nonzero_fpu_state ) {
@@ -228,25 +292,39 @@ WARN_UNUSED_RESULT int save_vector_registers_x86(void)
228292 }
229293
230294 if (irq_fpu_usable ()) {
231- #if defined(CONFIG_SMP ) && !defined(CONFIG_PREEMPT_COUNT ) && (LINUX_VERSION_CODE >= KERNEL_VERSION (5 , 7 , 0 ))
232- /* inhibit migration, which gums up the algorithm in kernel_fpu_{begin,end}(). */
295+ #ifdef WOLFSSL_COMMERCIAL_LICENSE
296+ struct fpstate * fpstate = wc_linuxkm_fpstate_buf_from_fpu_state (pstate );
297+ fpregs_lock ();
298+ fpstate -> xfeatures = ~0UL ;
299+ os_xsave (fpstate );
300+ #else /* !WOLFSSL_COMMERCIAL_LICENSE */
301+ #if defined(CONFIG_SMP ) && !defined(CONFIG_PREEMPT_COUNT ) && \
302+ (LINUX_VERSION_CODE >= KERNEL_VERSION (5 , 7 , 0 ))
303+ /* inhibit migration, which gums up the algorithm in
304+ * kernel_fpu_{begin,end}().
305+ */
233306 migrate_disable ();
234307#endif
235308 kernel_fpu_begin ();
236- pstate -> fpu_state = 1U ; /* set msb 0 to trigger kernel_fpu_end() at cleanup. */
309+ #endif /* !WOLFSSL_COMMERCIAL_LICENSE */
310+ /* set msb 0 to trigger kernel_fpu_end() at cleanup. */
311+ pstate -> fpu_state = 1U ;
237312 } else if (in_nmi () || (hardirq_count () > 0 ) || (softirq_count () > 0 )) {
238313 static int warned_fpu_forbidden = 0 ;
239314 if (! warned_fpu_forbidden )
240315 pr_err ("save_vector_registers_x86 called from IRQ handler.\n" );
241- wc_linuxkm_fpu_state_free (pstate );
316+ wc_linuxkm_fpu_state_release (pstate );
242317 return EPERM ;
243318 } else {
244- #if defined(CONFIG_SMP ) && !defined(CONFIG_PREEMPT_COUNT ) && (LINUX_VERSION_CODE >= KERNEL_VERSION (5 , 7 , 0 ))
319+ #if defined(CONFIG_SMP ) && !defined(CONFIG_PREEMPT_COUNT ) && \
320+ (LINUX_VERSION_CODE >= KERNEL_VERSION (5 , 7 , 0 )) && \
321+ !defined(WOLFSSL_COMMERCIAL_LICENSE )
245322 migrate_disable ();
246323#endif
247324 /* assume already safely in_kernel_fpu. */
325+ /* set msb 1 to inhibit kernel_fpu_end() at cleanup. */
248326 pstate -> fpu_state =
249- WC_FPU_SAVED_MASK + 1U ; /* set msb 1 to inhibit kernel_fpu_end() at cleanup. */
327+ WC_FPU_SAVED_MASK + 1U ;
250328 }
251329
252330 return 0 ;
@@ -265,15 +343,23 @@ void restore_vector_registers_x86(void)
265343 return ;
266344 }
267345
268- if (pstate -> fpu_state == 0U )
346+ if (pstate -> fpu_state == 0U ) {
347+ #ifdef WOLFSSL_COMMERCIAL_LICENSE
348+ struct fpstate * fpstate = wc_linuxkm_fpstate_buf_from_fpu_state (pstate );
349+ os_xrstor (fpstate , fpstate -> xfeatures );
350+ fpregs_unlock ();
351+ #else
269352 kernel_fpu_end ();
270- else
353+ #endif
354+ } else
271355 pstate -> fpu_state = 0U ;
272- #if defined(CONFIG_SMP ) && !defined(CONFIG_PREEMPT_COUNT ) && (LINUX_VERSION_CODE >= KERNEL_VERSION (5 , 7 , 0 ))
356+ #if defined(CONFIG_SMP ) && !defined(CONFIG_PREEMPT_COUNT ) && \
357+ (LINUX_VERSION_CODE >= KERNEL_VERSION (5 , 7 , 0 )) && \
358+ !defined(WOLFSSL_COMMERCIAL_LICENSE )
273359 migrate_enable ();
274360#endif
275361
276- wc_linuxkm_fpu_state_free (pstate );
362+ wc_linuxkm_fpu_state_release (pstate );
277363
278364 return ;
279365}
0 commit comments