hc
2024-11-01 2f529f9b558ca1c1bd74be7437a84e4711743404
kernel/arch/x86/kernel/fpu/core.c
....@@ -15,6 +15,7 @@
1515
1616 #include <linux/hardirq.h>
1717 #include <linux/pkeys.h>
18
+#include <linux/cpuhotplug.h>
1819
1920 #define CREATE_TRACE_POINTS
2021 #include <asm/trace/fpu.h>
....@@ -76,9 +77,10 @@
7677 */
7778 bool irq_fpu_usable(void)
7879 {
79
- return !in_interrupt() ||
80
- interrupted_user_mode() ||
81
- interrupted_kernel_fpu_idle();
80
+ return running_inband() &&
81
+ (!in_interrupt() ||
82
+ interrupted_user_mode() ||
83
+ interrupted_kernel_fpu_idle());
8284 }
8385 EXPORT_SYMBOL(irq_fpu_usable);
8486
....@@ -123,10 +125,14 @@
123125
124126 void kernel_fpu_begin_mask(unsigned int kfpu_mask)
125127 {
128
+ unsigned long flags;
129
+
126130 preempt_disable();
127131
128132 WARN_ON_FPU(!irq_fpu_usable());
129133 WARN_ON_FPU(this_cpu_read(in_kernel_fpu));
134
+
135
+ flags = hard_cond_local_irq_save();
130136
131137 this_cpu_write(in_kernel_fpu, true);
132138
....@@ -139,6 +145,7 @@
139145 */
140146 copy_fpregs_to_fpstate(&current->thread.fpu);
141147 }
148
+
142149 __cpu_invalidate_fpregs_state();
143150
144151 /* Put sane initial values into the control registers. */
....@@ -147,6 +154,8 @@
147154
148155 if (unlikely(kfpu_mask & KFPU_387) && boot_cpu_has(X86_FEATURE_FPU))
149156 asm volatile ("fninit");
157
+
158
+ hard_cond_local_irq_restore(flags);
150159 }
151160 EXPORT_SYMBOL_GPL(kernel_fpu_begin_mask);
152161
....@@ -166,9 +175,11 @@
166175 */
167176 void fpu__save(struct fpu *fpu)
168177 {
178
+ unsigned long flags;
179
+
169180 WARN_ON_FPU(fpu != &current->thread.fpu);
170181
171
- fpregs_lock();
182
+ flags = fpregs_lock();
172183 trace_x86_fpu_before_save(fpu);
173184
174185 if (!test_thread_flag(TIF_NEED_FPU_LOAD)) {
....@@ -178,7 +189,7 @@
178189 }
179190
180191 trace_x86_fpu_after_save(fpu);
181
- fpregs_unlock();
192
+ fpregs_unlock(flags);
182193 }
183194
184195 /*
....@@ -214,6 +225,7 @@
214225 {
215226 struct fpu *dst_fpu = &dst->thread.fpu;
216227 struct fpu *src_fpu = &src->thread.fpu;
228
+ unsigned long flags;
217229
218230 dst_fpu->last_cpu = -1;
219231
....@@ -236,14 +248,14 @@
236248 * ( The function 'fails' in the FNSAVE case, which destroys
237249 * register contents so we have to load them back. )
238250 */
239
- fpregs_lock();
251
+ flags = fpregs_lock();
240252 if (test_thread_flag(TIF_NEED_FPU_LOAD))
241253 memcpy(&dst_fpu->state, &src_fpu->state, fpu_kernel_xstate_size);
242254
243255 else if (!copy_fpregs_to_fpstate(dst_fpu))
244256 copy_kernel_to_fpregs(&dst_fpu->state);
245257
246
- fpregs_unlock();
258
+ fpregs_unlock(flags);
247259
248260 set_tsk_thread_flag(dst, TIF_NEED_FPU_LOAD);
249261
....@@ -321,7 +333,9 @@
321333 */
322334 void fpu__drop(struct fpu *fpu)
323335 {
324
- preempt_disable();
336
+ unsigned long flags;
337
+
338
+ flags = hard_preempt_disable();
325339
326340 if (fpu == &current->thread.fpu) {
327341 /* Ignore delayed exceptions from user space */
....@@ -333,7 +347,7 @@
333347
334348 trace_x86_fpu_dropped(fpu);
335349
336
- preempt_enable();
350
+ hard_preempt_enable(flags);
337351 }
338352
339353 /*
....@@ -361,15 +375,19 @@
361375 */
362376 static void fpu__clear(struct fpu *fpu, bool user_only)
363377 {
378
+ unsigned long flags;
379
+
364380 WARN_ON_FPU(fpu != &current->thread.fpu);
365381
366382 if (!static_cpu_has(X86_FEATURE_FPU)) {
383
+ flags = hard_cond_local_irq_save();
367384 fpu__drop(fpu);
368385 fpu__initialize(fpu);
386
+ hard_cond_local_irq_restore(flags);
369387 return;
370388 }
371389
372
- fpregs_lock();
390
+ flags = fpregs_lock();
373391
374392 if (user_only) {
375393 if (!fpregs_state_valid(fpu, smp_processor_id()) &&
....@@ -382,7 +400,7 @@
382400 }
383401
384402 fpregs_mark_activate();
385
- fpregs_unlock();
403
+ fpregs_unlock(flags);
386404 }
387405
388406 void fpu__clear_user_states(struct fpu *fpu)
....@@ -400,10 +418,14 @@
400418 */
401419 void switch_fpu_return(void)
402420 {
421
+ unsigned long flags;
422
+
403423 if (!static_cpu_has(X86_FEATURE_FPU))
404424 return;
405425
426
+ flags = hard_cond_local_irq_save();
406427 __fpregs_load_activate();
428
+ hard_cond_local_irq_restore(flags);
407429 }
408430 EXPORT_SYMBOL_GPL(switch_fpu_return);
409431
....@@ -503,3 +525,70 @@
503525 */
504526 return 0;
505527 }
528
+
529
+#ifdef CONFIG_DOVETAIL
530
+
531
+/*
532
+ * Holds the in-kernel fpu state when preempted by a task running on
533
+ * the out-of-band stage.
534
+ */
535
+static DEFINE_PER_CPU(struct fpu *, in_kernel_fpstate);
536
+
537
+static int fpu__init_kernel_fpstate(unsigned int cpu)
538
+{
539
+ struct fpu *fpu;
540
+
541
+ fpu = kzalloc(sizeof(*fpu) + fpu_kernel_xstate_size, GFP_KERNEL);
542
+ if (fpu == NULL)
543
+ return -ENOMEM;
544
+
545
+ this_cpu_write(in_kernel_fpstate, fpu);
546
+ fpstate_init(&fpu->state);
547
+
548
+ return 0;
549
+}
550
+
551
+static int fpu__drop_kernel_fpstate(unsigned int cpu)
552
+{
553
+ struct fpu *fpu = this_cpu_read(in_kernel_fpstate);
554
+
555
+ kfree(fpu);
556
+
557
+ return 0;
558
+}
559
+
560
+void fpu__suspend_inband(void)
561
+{
562
+ struct fpu *kfpu = this_cpu_read(in_kernel_fpstate);
563
+ struct task_struct *tsk = current;
564
+
565
+ if (kernel_fpu_disabled()) {
566
+ copy_fpregs_to_fpstate(kfpu);
567
+ __cpu_invalidate_fpregs_state();
568
+ oob_fpu_set_preempt(&tsk->thread.fpu);
569
+ }
570
+}
571
+
572
+void fpu__resume_inband(void)
573
+{
574
+ struct fpu *kfpu = this_cpu_read(in_kernel_fpstate);
575
+ struct task_struct *tsk = current;
576
+
577
+ if (oob_fpu_preempted(&tsk->thread.fpu)) {
578
+ copy_kernel_to_fpregs(&kfpu->state);
579
+ __cpu_invalidate_fpregs_state();
580
+ oob_fpu_clear_preempt(&tsk->thread.fpu);
581
+ } else if (!(tsk->flags & PF_KTHREAD) &&
582
+ test_thread_flag(TIF_NEED_FPU_LOAD))
583
+ switch_fpu_return();
584
+}
585
+
586
+static void __init fpu__init_dovetail(void)
587
+{
588
+ cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
589
+ "platform/x86/dovetail:online",
590
+ fpu__init_kernel_fpstate, fpu__drop_kernel_fpstate);
591
+}
592
+core_initcall(fpu__init_dovetail);
593
+
594
+#endif