x86, math-emu: fix init_fpu for task != current

Impact: fix math-emu related crash while using GDB/ptrace

init_fpu() calls finit to initialize a task's xstate, while finit always
works on the current task. If we use PTRACE_GETFPREGS on another
process and both processes did not already use floating point, we get
a null pointer exception in finit.

This patch creates a new function finit_task that takes a task_struct
parameter. finit becomes a wrapper that simply calls finit_task with
current. On the plus side this avoids many calls to get_current which
would each resolve to an inline assembler mov instruction.

An empty finit_task has been added to i387.h to avoid linker errors in
case the compiler still emits the call in init_fpu when
CONFIG_MATH_EMULATION is not defined.

The declaration of finit in i387.h has been removed as the remaining
code using this function gets its prototype from fpu_proto.h.

Signed-off-by: Daniel Glöckner <dg@emlix.com>
Cc: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: "Pallipadi Venkatesh" <venkatesh.pallipadi@intel.com>
Cc: Arjan van de Ven <arjan@infradead.org>
Cc: Bill Metzenthen <billm@melbpc.org.au>
LKML-Reference: <E1Lew31-0004il-Fg@mailer.emlix.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Daniel Glöckner 2009-03-04 19:42:27 +01:00 committed by Ingo Molnar
parent dd39ecf522
commit ab9e18587f
3 changed files with 28 additions and 13 deletions

View File

@ -172,7 +172,13 @@ static inline void __save_init_fpu(struct task_struct *tsk)
#else /* CONFIG_X86_32 */ #else /* CONFIG_X86_32 */
extern void finit(void); #ifdef CONFIG_MATH_EMULATION
extern void finit_task(struct task_struct *tsk);
#else
static inline void finit_task(struct task_struct *tsk)
{
}
#endif
static inline void tolerant_fwait(void) static inline void tolerant_fwait(void)
{ {

View File

@ -136,7 +136,7 @@ int init_fpu(struct task_struct *tsk)
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
if (!HAVE_HWFP) { if (!HAVE_HWFP) {
memset(tsk->thread.xstate, 0, xstate_size); memset(tsk->thread.xstate, 0, xstate_size);
finit(); finit_task(tsk);
set_stopped_child_used_math(tsk); set_stopped_child_used_math(tsk);
return 0; return 0;
} }

View File

@ -30,20 +30,29 @@ static void fclex(void)
} }
/* Needs to be externally visible */ /* Needs to be externally visible */
void finit(void) void finit_task(struct task_struct *tsk)
{ {
control_word = 0x037f; struct i387_soft_struct *soft = &tsk->thread.xstate->soft;
partial_status = 0; struct address *oaddr, *iaddr;
top = 0; /* We don't keep top in the status word internally. */ soft->cwd = 0x037f;
fpu_tag_word = 0xffff; soft->swd = 0;
soft->ftop = 0; /* We don't keep top in the status word internally. */
soft->twd = 0xffff;
/* The behaviour is different from that detailed in /* The behaviour is different from that detailed in
Section 15.1.6 of the Intel manual */ Section 15.1.6 of the Intel manual */
operand_address.offset = 0; oaddr = (struct address *)&soft->foo;
operand_address.selector = 0; oaddr->offset = 0;
instruction_address.offset = 0; oaddr->selector = 0;
instruction_address.selector = 0; iaddr = (struct address *)&soft->fip;
instruction_address.opcode = 0; iaddr->offset = 0;
no_ip_update = 1; iaddr->selector = 0;
iaddr->opcode = 0;
soft->no_update = 1;
}
void finit(void)
{
finit_task(current);
} }
/* /*