mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 05:34:13 +08:00
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:
parent
dd39ecf522
commit
ab9e18587f
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user