Skip to content

Commit 8474c53

Browse files
author
Ingo Molnar
committed
Merge branch 'WIP.x86/fpu' into x86/fpu, because it's ready
Signed-off-by: Ingo Molnar <[email protected]>
2 parents e365806 + 738f48c commit 8474c53

File tree

15 files changed

+375
-315
lines changed

15 files changed

+375
-315
lines changed

arch/x86/ia32/ia32_signal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
231231
ksig->ka.sa.sa_restorer)
232232
sp = (unsigned long) ksig->ka.sa.sa_restorer;
233233

234-
if (fpu->fpstate_active) {
234+
if (fpu->initialized) {
235235
unsigned long fx_aligned, math_size;
236236

237237
sp = fpu__alloc_mathframe(sp, 1, &fx_aligned, &math_size);

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

Lines changed: 22 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@
2323
/*
2424
* High level FPU state handling functions:
2525
*/
26-
extern void fpu__activate_curr(struct fpu *fpu);
27-
extern void fpu__activate_fpstate_read(struct fpu *fpu);
28-
extern void fpu__activate_fpstate_write(struct fpu *fpu);
29-
extern void fpu__current_fpstate_write_begin(void);
30-
extern void fpu__current_fpstate_write_end(void);
26+
extern void fpu__initialize(struct fpu *fpu);
27+
extern void fpu__prepare_read(struct fpu *fpu);
28+
extern void fpu__prepare_write(struct fpu *fpu);
3129
extern void fpu__save(struct fpu *fpu);
3230
extern void fpu__restore(struct fpu *fpu);
3331
extern int fpu__restore_sig(void __user *buf, int ia32_frame);
@@ -120,20 +118,11 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu);
120118
err; \
121119
})
122120

123-
#define check_insn(insn, output, input...) \
124-
({ \
125-
int err; \
121+
#define kernel_insn(insn, output, input...) \
126122
asm volatile("1:" #insn "\n\t" \
127123
"2:\n" \
128-
".section .fixup,\"ax\"\n" \
129-
"3: movl $-1,%[err]\n" \
130-
" jmp 2b\n" \
131-
".previous\n" \
132-
_ASM_EXTABLE(1b, 3b) \
133-
: [err] "=r" (err), output \
134-
: "0"(0), input); \
135-
err; \
136-
})
124+
_ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_fprestore) \
125+
: output : input)
137126

138127
static inline int copy_fregs_to_user(struct fregs_state __user *fx)
139128
{
@@ -153,20 +142,16 @@ static inline int copy_fxregs_to_user(struct fxregs_state __user *fx)
153142

154143
static inline void copy_kernel_to_fxregs(struct fxregs_state *fx)
155144
{
156-
int err;
157-
158145
if (IS_ENABLED(CONFIG_X86_32)) {
159-
err = check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
146+
kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
160147
} else {
161148
if (IS_ENABLED(CONFIG_AS_FXSAVEQ)) {
162-
err = check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
149+
kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
163150
} else {
164151
/* See comment in copy_fxregs_to_kernel() below. */
165-
err = check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx));
152+
kernel_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx));
166153
}
167154
}
168-
/* Copying from a kernel buffer to FPU registers should never fail: */
169-
WARN_ON_FPU(err);
170155
}
171156

172157
static inline int copy_user_to_fxregs(struct fxregs_state __user *fx)
@@ -183,9 +168,7 @@ static inline int copy_user_to_fxregs(struct fxregs_state __user *fx)
183168

184169
static inline void copy_kernel_to_fregs(struct fregs_state *fx)
185170
{
186-
int err = check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
187-
188-
WARN_ON_FPU(err);
171+
kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
189172
}
190173

191174
static inline int copy_user_to_fregs(struct fregs_state __user *fx)
@@ -281,18 +264,13 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
281264
* Use XRSTORS to restore context if it is enabled. XRSTORS supports compact
282265
* XSAVE area format.
283266
*/
284-
#define XSTATE_XRESTORE(st, lmask, hmask, err) \
267+
#define XSTATE_XRESTORE(st, lmask, hmask) \
285268
asm volatile(ALTERNATIVE(XRSTOR, \
286269
XRSTORS, X86_FEATURE_XSAVES) \
287270
"\n" \
288-
"xor %[err], %[err]\n" \
289271
"3:\n" \
290-
".pushsection .fixup,\"ax\"\n" \
291-
"4: movl $-2, %[err]\n" \
292-
"jmp 3b\n" \
293-
".popsection\n" \
294-
_ASM_EXTABLE(661b, 4b) \
295-
: [err] "=r" (err) \
272+
_ASM_EXTABLE_HANDLE(661b, 3b, ex_handler_fprestore)\
273+
: \
296274
: "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \
297275
: "memory")
298276

@@ -336,7 +314,10 @@ static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)
336314
else
337315
XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
338316

339-
/* We should never fault when copying from a kernel buffer: */
317+
/*
318+
* We should never fault when copying from a kernel buffer, and the FPU
319+
* state we set at boot time should be valid.
320+
*/
340321
WARN_ON_FPU(err);
341322
}
342323

@@ -350,7 +331,7 @@ static inline void copy_xregs_to_kernel(struct xregs_state *xstate)
350331
u32 hmask = mask >> 32;
351332
int err;
352333

353-
WARN_ON(!alternatives_patched);
334+
WARN_ON_FPU(!alternatives_patched);
354335

355336
XSTATE_XSAVE(xstate, lmask, hmask, err);
356337

@@ -365,12 +346,8 @@ static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask)
365346
{
366347
u32 lmask = mask;
367348
u32 hmask = mask >> 32;
368-
int err;
369-
370-
XSTATE_XRESTORE(xstate, lmask, hmask, err);
371349

372-
/* We should never fault when copying from a kernel buffer: */
373-
WARN_ON_FPU(err);
350+
XSTATE_XRESTORE(xstate, lmask, hmask);
374351
}
375352

376353
/*
@@ -526,37 +503,16 @@ static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)
526503
*/
527504
static inline void fpregs_deactivate(struct fpu *fpu)
528505
{
529-
WARN_ON_FPU(!fpu->fpregs_active);
530-
531-
fpu->fpregs_active = 0;
532506
this_cpu_write(fpu_fpregs_owner_ctx, NULL);
533507
trace_x86_fpu_regs_deactivated(fpu);
534508
}
535509

536510
static inline void fpregs_activate(struct fpu *fpu)
537511
{
538-
WARN_ON_FPU(fpu->fpregs_active);
539-
540-
fpu->fpregs_active = 1;
541512
this_cpu_write(fpu_fpregs_owner_ctx, fpu);
542513
trace_x86_fpu_regs_activated(fpu);
543514
}
544515

545-
/*
546-
* The question "does this thread have fpu access?"
547-
* is slightly racy, since preemption could come in
548-
* and revoke it immediately after the test.
549-
*
550-
* However, even in that very unlikely scenario,
551-
* we can just assume we have FPU access - typically
552-
* to save the FP state - we'll just take a #NM
553-
* fault and get the FPU access back.
554-
*/
555-
static inline int fpregs_active(void)
556-
{
557-
return current->thread.fpu.fpregs_active;
558-
}
559-
560516
/*
561517
* FPU state switching for scheduling.
562518
*
@@ -571,14 +527,13 @@ static inline int fpregs_active(void)
571527
static inline void
572528
switch_fpu_prepare(struct fpu *old_fpu, int cpu)
573529
{
574-
if (old_fpu->fpregs_active) {
530+
if (old_fpu->initialized) {
575531
if (!copy_fpregs_to_fpstate(old_fpu))
576532
old_fpu->last_cpu = -1;
577533
else
578534
old_fpu->last_cpu = cpu;
579535

580536
/* But leave fpu_fpregs_owner_ctx! */
581-
old_fpu->fpregs_active = 0;
582537
trace_x86_fpu_regs_deactivated(old_fpu);
583538
} else
584539
old_fpu->last_cpu = -1;
@@ -595,7 +550,7 @@ switch_fpu_prepare(struct fpu *old_fpu, int cpu)
595550
static inline void switch_fpu_finish(struct fpu *new_fpu, int cpu)
596551
{
597552
bool preload = static_cpu_has(X86_FEATURE_FPU) &&
598-
new_fpu->fpstate_active;
553+
new_fpu->initialized;
599554

600555
if (preload) {
601556
if (!fpregs_state_valid(new_fpu, cpu))
@@ -617,8 +572,7 @@ static inline void user_fpu_begin(void)
617572
struct fpu *fpu = &current->thread.fpu;
618573

619574
preempt_disable();
620-
if (!fpregs_active())
621-
fpregs_activate(fpu);
575+
fpregs_activate(fpu);
622576
preempt_enable();
623577
}
624578

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

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ struct fxregs_state {
6868
/* Default value for fxregs_state.mxcsr: */
6969
#define MXCSR_DEFAULT 0x1f80
7070

71+
/* Copy both mxcsr & mxcsr_flags with a single u64 memcpy: */
72+
#define MXCSR_AND_FLAGS_SIZE sizeof(u64)
73+
7174
/*
7275
* Software based FPU emulation state. This is arbitrary really,
7376
* it matches the x87 format to make it easier to understand:
@@ -290,36 +293,13 @@ struct fpu {
290293
unsigned int last_cpu;
291294

292295
/*
293-
* @fpstate_active:
296+
* @initialized:
294297
*
295-
* This flag indicates whether this context is active: if the task
298+
* This flag indicates whether this context is initialized: if the task
296299
* is not running then we can restore from this context, if the task
297300
* is running then we should save into this context.
298301
*/
299-
unsigned char fpstate_active;
300-
301-
/*
302-
* @fpregs_active:
303-
*
304-
* This flag determines whether a given context is actively
305-
* loaded into the FPU's registers and that those registers
306-
* represent the task's current FPU state.
307-
*
308-
* Note the interaction with fpstate_active:
309-
*
310-
* # task does not use the FPU:
311-
* fpstate_active == 0
312-
*
313-
* # task uses the FPU and regs are active:
314-
* fpstate_active == 1 && fpregs_active == 1
315-
*
316-
* # the regs are inactive but still match fpstate:
317-
* fpstate_active == 1 && fpregs_active == 0 && fpregs_owner == fpu
318-
*
319-
* The third state is what we use for the lazy restore optimization
320-
* on lazy-switching CPUs.
321-
*/
322-
unsigned char fpregs_active;
302+
unsigned char initialized;
323303

324304
/*
325305
* @state:

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,12 @@ void fpu__xstate_clear_all_cpu_caps(void);
4848
void *get_xsave_addr(struct xregs_state *xsave, int xstate);
4949
const void *get_xsave_field_ptr(int xstate_field);
5050
int using_compacted_format(void);
51-
int copyout_from_xsaves(unsigned int pos, unsigned int count, void *kbuf,
52-
void __user *ubuf, struct xregs_state *xsave);
53-
int copyin_to_xsaves(const void *kbuf, const void __user *ubuf,
54-
struct xregs_state *xsave);
51+
int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset, unsigned int size);
52+
int copy_xstate_to_user(void __user *ubuf, struct xregs_state *xsave, unsigned int offset, unsigned int size);
53+
int copy_kernel_to_xstate(struct xregs_state *xsave, const void *kbuf);
54+
int copy_user_to_xstate(struct xregs_state *xsave, const void __user *ubuf);
55+
56+
/* Validate an xstate header supplied by userspace (ptrace or sigreturn) */
57+
extern int validate_xstate_header(const struct xstate_header *hdr);
58+
5559
#endif

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

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,22 @@ DECLARE_EVENT_CLASS(x86_fpu,
1212

1313
TP_STRUCT__entry(
1414
__field(struct fpu *, fpu)
15-
__field(bool, fpregs_active)
16-
__field(bool, fpstate_active)
15+
__field(bool, initialized)
1716
__field(u64, xfeatures)
1817
__field(u64, xcomp_bv)
1918
),
2019

2120
TP_fast_assign(
2221
__entry->fpu = fpu;
23-
__entry->fpregs_active = fpu->fpregs_active;
24-
__entry->fpstate_active = fpu->fpstate_active;
22+
__entry->initialized = fpu->initialized;
2523
if (boot_cpu_has(X86_FEATURE_OSXSAVE)) {
2624
__entry->xfeatures = fpu->state.xsave.header.xfeatures;
2725
__entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv;
2826
}
2927
),
30-
TP_printk("x86/fpu: %p fpregs_active: %d fpstate_active: %d xfeatures: %llx xcomp_bv: %llx",
28+
TP_printk("x86/fpu: %p initialized: %d xfeatures: %llx xcomp_bv: %llx",
3129
__entry->fpu,
32-
__entry->fpregs_active,
33-
__entry->fpstate_active,
30+
__entry->initialized,
3431
__entry->xfeatures,
3532
__entry->xcomp_bv
3633
)

0 commit comments

Comments
 (0)