Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 287653
b: refs/heads/master
c: 6d59d7a
h: refs/heads/master
i:
  287651: 19c0235
v: v3
  • Loading branch information
Linus Torvalds committed Feb 16, 2012
1 parent e937426 commit e975dba
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 24 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b6c66418dcad0fcf83cd1d0a39482db37bf4fc41
refs/heads/master: 6d59d7a9f5b723a7ac1925c136e93ec83c0c3043
75 changes: 55 additions & 20 deletions trunk/arch/x86/include/asm/i387.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,47 @@ static inline int restore_fpu_checking(struct task_struct *tsk)
return fpu_restore_checking(&tsk->thread.fpu);
}

/*
* Software FPU state helpers. Careful: these need to
* be preemption protection *and* they need to be
* properly paired with the CR0.TS changes!
*/
static inline int __thread_has_fpu(struct thread_info *ti)
{
return ti->status & TS_USEDFPU;
}

/* Must be paired with an 'stts' after! */
static inline void __thread_clear_has_fpu(struct thread_info *ti)
{
ti->status &= ~TS_USEDFPU;
}

/* Must be paired with a 'clts' before! */
static inline void __thread_set_has_fpu(struct thread_info *ti)
{
ti->status |= TS_USEDFPU;
}

/*
* Encapsulate the CR0.TS handling together with the
* software flag.
*
* These generally need preemption protection to work,
* do try to avoid using these on their own.
*/
static inline void __thread_fpu_end(struct thread_info *ti)
{
__thread_clear_has_fpu(ti);
stts();
}

static inline void __thread_fpu_begin(struct thread_info *ti)
{
clts();
__thread_set_has_fpu(ti);
}

/*
* Signal frame handlers...
*/
Expand All @@ -287,38 +328,36 @@ extern int restore_i387_xstate(void __user *buf);

static inline void __unlazy_fpu(struct task_struct *tsk)
{
if (task_thread_info(tsk)->status & TS_USEDFPU) {
if (__thread_has_fpu(task_thread_info(tsk))) {
__save_init_fpu(tsk);
task_thread_info(tsk)->status &= ~TS_USEDFPU;
stts();
__thread_fpu_end(task_thread_info(tsk));
} else
tsk->fpu_counter = 0;
}

static inline void __clear_fpu(struct task_struct *tsk)
{
if (task_thread_info(tsk)->status & TS_USEDFPU) {
if (__thread_has_fpu(task_thread_info(tsk))) {
/* Ignore delayed exceptions from user space */
asm volatile("1: fwait\n"
"2:\n"
_ASM_EXTABLE(1b, 2b));
task_thread_info(tsk)->status &= ~TS_USEDFPU;
stts();
__thread_fpu_end(task_thread_info(tsk));
}
}

/*
* Were we in an interrupt that interrupted kernel mode?
*
* We can do a kernel_fpu_begin/end() pair *ONLY* if that
* pair does nothing at all: TS_USEDFPU must be clear (so
* pair does nothing at all: the thread must not have fpu (so
* that we don't try to save the FPU state), and TS must
* be set (so that the clts/stts pair does nothing that is
* visible in the interrupted kernel thread).
*/
static inline bool interrupted_kernel_fpu_idle(void)
{
return !(current_thread_info()->status & TS_USEDFPU) &&
return !__thread_has_fpu(current_thread_info()) &&
(read_cr0() & X86_CR0_TS);
}

Expand Down Expand Up @@ -356,9 +395,9 @@ static inline void kernel_fpu_begin(void)

WARN_ON_ONCE(!irq_fpu_usable());
preempt_disable();
if (me->status & TS_USEDFPU) {
if (__thread_has_fpu(me)) {
__save_init_fpu(me->task);
me->status &= ~TS_USEDFPU;
__thread_clear_has_fpu(me);
/* We do 'stts()' in kernel_fpu_end() */
} else
clts();
Expand Down Expand Up @@ -422,24 +461,21 @@ static inline void irq_ts_restore(int TS_state)
*/
static inline int user_has_fpu(void)
{
return current_thread_info()->status & TS_USEDFPU;
return __thread_has_fpu(current_thread_info());
}

static inline void user_fpu_end(void)
{
preempt_disable();
current_thread_info()->status &= ~TS_USEDFPU;
stts();
__thread_fpu_end(current_thread_info());
preempt_enable();
}

static inline void user_fpu_begin(void)
{
preempt_disable();
if (!user_has_fpu()) {
clts();
current_thread_info()->status |= TS_USEDFPU;
}
if (!user_has_fpu())
__thread_fpu_begin(current_thread_info());
preempt_enable();
}

Expand All @@ -448,11 +484,10 @@ static inline void user_fpu_begin(void)
*/
static inline void save_init_fpu(struct task_struct *tsk)
{
WARN_ON_ONCE(!(task_thread_info(tsk)->status & TS_USEDFPU));
WARN_ON_ONCE(!__thread_has_fpu(task_thread_info(tsk)));
preempt_disable();
__save_init_fpu(tsk);
task_thread_info(tsk)->status &= ~TS_USEDFPU;
stts();
__thread_fpu_end(task_thread_info(tsk));
preempt_enable();
}

Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/x86/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ void __math_state_restore(void)
return;
}

thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */
__thread_set_has_fpu(thread); /* clts in caller! */
tsk->fpu_counter++;
}

Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/x86/kernel/xsave.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void __sanitize_i387_state(struct task_struct *tsk)
if (!fx)
return;

BUG_ON(task_thread_info(tsk)->status & TS_USEDFPU);
BUG_ON(__thread_has_fpu(task_thread_info(tsk)));

xstate_bv = tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv;

Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/x86/kvm/vmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1457,7 +1457,7 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
#ifdef CONFIG_X86_64
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
#endif
if (current_thread_info()->status & TS_USEDFPU)
if (__thread_has_fpu(current_thread_info()))
clts();
load_gdt(&__get_cpu_var(host_gdt));
}
Expand Down

0 comments on commit e975dba

Please sign in to comment.