diff options
| author | Daniel Glöckner <dg@emlix.com> | 2009-03-04 13:42:27 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-03-04 14:33:16 -0500 |
| commit | ab9e18587f4cdb5f3fb3854c732f27a36f98e8f6 (patch) | |
| tree | b8d77d5fbdbdf919e4c0134762ff36ef11626802 | |
| parent | dd39ecf522ba86c70809715af46e6557f6491131 (diff) | |
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>
| -rw-r--r-- | arch/x86/include/asm/i387.h | 8 | ||||
| -rw-r--r-- | arch/x86/kernel/i387.c | 2 | ||||
| -rw-r--r-- | arch/x86/math-emu/fpu_aux.c | 31 |
3 files changed, 28 insertions, 13 deletions
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 48f0004db8c9..71c9e5183982 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h | |||
| @@ -172,7 +172,13 @@ static inline void __save_init_fpu(struct task_struct *tsk) | |||
| 172 | 172 | ||
| 173 | #else /* CONFIG_X86_32 */ | 173 | #else /* CONFIG_X86_32 */ |
| 174 | 174 | ||
| 175 | extern void finit(void); | 175 | #ifdef CONFIG_MATH_EMULATION |
| 176 | extern void finit_task(struct task_struct *tsk); | ||
| 177 | #else | ||
| 178 | static inline void finit_task(struct task_struct *tsk) | ||
| 179 | { | ||
| 180 | } | ||
| 181 | #endif | ||
| 176 | 182 | ||
| 177 | static inline void tolerant_fwait(void) | 183 | static inline void tolerant_fwait(void) |
| 178 | { | 184 | { |
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index b0f61f0dcd0a..f2f8540a7f3d 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
| @@ -136,7 +136,7 @@ int init_fpu(struct task_struct *tsk) | |||
| 136 | #ifdef CONFIG_X86_32 | 136 | #ifdef CONFIG_X86_32 |
| 137 | if (!HAVE_HWFP) { | 137 | if (!HAVE_HWFP) { |
| 138 | memset(tsk->thread.xstate, 0, xstate_size); | 138 | memset(tsk->thread.xstate, 0, xstate_size); |
| 139 | finit(); | 139 | finit_task(tsk); |
| 140 | set_stopped_child_used_math(tsk); | 140 | set_stopped_child_used_math(tsk); |
| 141 | return 0; | 141 | return 0; |
| 142 | } | 142 | } |
diff --git a/arch/x86/math-emu/fpu_aux.c b/arch/x86/math-emu/fpu_aux.c index 491e737ce547..aa0987088774 100644 --- a/arch/x86/math-emu/fpu_aux.c +++ b/arch/x86/math-emu/fpu_aux.c | |||
| @@ -30,20 +30,29 @@ static void fclex(void) | |||
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | /* Needs to be externally visible */ | 32 | /* Needs to be externally visible */ |
| 33 | void finit(void) | 33 | void finit_task(struct task_struct *tsk) |
| 34 | { | 34 | { |
| 35 | control_word = 0x037f; | 35 | struct i387_soft_struct *soft = &tsk->thread.xstate->soft; |
| 36 | partial_status = 0; | 36 | struct address *oaddr, *iaddr; |
| 37 | top = 0; /* We don't keep top in the status word internally. */ | 37 | soft->cwd = 0x037f; |
| 38 | fpu_tag_word = 0xffff; | 38 | soft->swd = 0; |
| 39 | soft->ftop = 0; /* We don't keep top in the status word internally. */ | ||
| 40 | soft->twd = 0xffff; | ||
| 39 | /* The behaviour is different from that detailed in | 41 | /* The behaviour is different from that detailed in |
| 40 | Section 15.1.6 of the Intel manual */ | 42 | Section 15.1.6 of the Intel manual */ |
| 41 | operand_address.offset = 0; | 43 | oaddr = (struct address *)&soft->foo; |
| 42 | operand_address.selector = 0; | 44 | oaddr->offset = 0; |
| 43 | instruction_address.offset = 0; | 45 | oaddr->selector = 0; |
| 44 | instruction_address.selector = 0; | 46 | iaddr = (struct address *)&soft->fip; |
| 45 | instruction_address.opcode = 0; | 47 | iaddr->offset = 0; |
| 46 | no_ip_update = 1; | 48 | iaddr->selector = 0; |
| 49 | iaddr->opcode = 0; | ||
| 50 | soft->no_update = 1; | ||
| 51 | } | ||
| 52 | |||
| 53 | void finit(void) | ||
| 54 | { | ||
| 55 | finit_task(current); | ||
| 47 | } | 56 | } |
| 48 | 57 | ||
| 49 | /* | 58 | /* |
