Skip to content

Commit e451228

Browse files
amlutosuryasaimadhu
authored andcommitted
x86/fpu: Add kernel_fpu_begin_mask() to selectively initialize state
Currently, requesting kernel FPU access doesn't distinguish which parts of the extended ("FPU") state are needed. This is nice for simplicity, but there are a few cases in which it's suboptimal: - The vast majority of in-kernel FPU users want XMM/YMM/ZMM state but do not use legacy 387 state. These users want MXCSR initialized but don't care about the FPU control word. Skipping FNINIT would save time. (Empirically, FNINIT is several times slower than LDMXCSR.) - Code that wants MMX doesn't want or need MXCSR initialized. _mmx_memcpy(), for example, can run before CR4.OSFXSR gets set, and initializing MXCSR will fail because LDMXCSR generates an #UD when the aforementioned CR4 bit is not set. - Any future in-kernel users of XFD (eXtended Feature Disable)-capable dynamic states will need special handling. Add a more specific API that allows callers to specify exactly what they want. Signed-off-by: Andy Lutomirski <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Tested-by: Krzysztof Piotr Olędzki <[email protected]> Link: https://lkml.kernel.org/r/aff1cac8b8fc7ee900cf73e8f2369966621b053f.1611205691.git.luto@kernel.org
1 parent 1eb8f69 commit e451228

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

arch/x86/include/asm/fpu/api.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,25 @@
1616
* Use kernel_fpu_begin/end() if you intend to use FPU in kernel context. It
1717
* disables preemption so be careful if you intend to use it for long periods
1818
* of time.
19-
* If you intend to use the FPU in softirq you need to check first with
19+
* If you intend to use the FPU in irq/softirq you need to check first with
2020
* irq_fpu_usable() if it is possible.
2121
*/
22-
extern void kernel_fpu_begin(void);
22+
23+
/* Kernel FPU states to initialize in kernel_fpu_begin_mask() */
24+
#define KFPU_387 _BITUL(0) /* 387 state will be initialized */
25+
#define KFPU_MXCSR _BITUL(1) /* MXCSR will be initialized */
26+
27+
extern void kernel_fpu_begin_mask(unsigned int kfpu_mask);
2328
extern void kernel_fpu_end(void);
2429
extern bool irq_fpu_usable(void);
2530
extern void fpregs_mark_activate(void);
2631

32+
/* Code that is unaware of kernel_fpu_begin_mask() can use this */
33+
static inline void kernel_fpu_begin(void)
34+
{
35+
kernel_fpu_begin_mask(KFPU_387 | KFPU_MXCSR);
36+
}
37+
2738
/*
2839
* Use fpregs_lock() while editing CPU's FPU registers or fpu->state.
2940
* A context switch will (and softirq might) save CPU's FPU registers to

arch/x86/kernel/fpu/core.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ int copy_fpregs_to_fpstate(struct fpu *fpu)
121121
}
122122
EXPORT_SYMBOL(copy_fpregs_to_fpstate);
123123

124-
void kernel_fpu_begin(void)
124+
void kernel_fpu_begin_mask(unsigned int kfpu_mask)
125125
{
126126
preempt_disable();
127127

@@ -141,13 +141,14 @@ void kernel_fpu_begin(void)
141141
}
142142
__cpu_invalidate_fpregs_state();
143143

144-
if (boot_cpu_has(X86_FEATURE_XMM))
144+
/* Put sane initial values into the control registers. */
145+
if (likely(kfpu_mask & KFPU_MXCSR) && boot_cpu_has(X86_FEATURE_XMM))
145146
ldmxcsr(MXCSR_DEFAULT);
146147

147-
if (boot_cpu_has(X86_FEATURE_FPU))
148+
if (unlikely(kfpu_mask & KFPU_387) && boot_cpu_has(X86_FEATURE_FPU))
148149
asm volatile ("fninit");
149150
}
150-
EXPORT_SYMBOL_GPL(kernel_fpu_begin);
151+
EXPORT_SYMBOL_GPL(kernel_fpu_begin_mask);
151152

152153
void kernel_fpu_end(void)
153154
{

0 commit comments

Comments
 (0)