aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2009-02-09 08:17:39 -0500
committerIngo Molnar <mingo@elte.hu>2009-02-09 18:39:14 -0500
commitd315760ffa261c15ff92699ac6f514112543d7ca (patch)
tree3f7d185cf97a06e6686521a23a1c78d1809a51c4
parentae6af41f5a4841f06eb92bc86ad020ad44ae2a30 (diff)
x86: fix math_emu register frame access
do_device_not_available() is the handler for #NM and it declares that it takes a unsigned long and calls math_emu(), which takes a long argument and surprisingly expects the stack frame starting at the zero argument would match struct math_emu_info, which isn't true regardless of configuration in the current code. This patch makes do_device_not_available() take struct pt_regs like other exception handlers and initialize struct math_emu_info with pointer to it and pass pointer to the math_emu_info to math_emulate() like normal C functions do. This way, unless gcc makes a copy of struct pt_regs in do_device_not_available(), the register frame is correctly accessed regardless of kernel configuration or compiler used. This doesn't fix all math_emu problems but it at least gets it somewhat working. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/include/asm/math_emu.h4
-rw-r--r--arch/x86/include/asm/traps.h4
-rw-r--r--arch/x86/kernel/traps.c15
-rw-r--r--arch/x86/math-emu/fpu_entry.c4
-rw-r--r--arch/x86/math-emu/fpu_proto.h2
-rw-r--r--arch/x86/math-emu/fpu_system.h16
-rw-r--r--arch/x86/math-emu/get_address.c66
7 files changed, 55 insertions, 56 deletions
diff --git a/arch/x86/include/asm/math_emu.h b/arch/x86/include/asm/math_emu.h
index 302492c77956..031f6266f425 100644
--- a/arch/x86/include/asm/math_emu.h
+++ b/arch/x86/include/asm/math_emu.h
@@ -11,8 +11,8 @@
11struct math_emu_info { 11struct math_emu_info {
12 long ___orig_eip; 12 long ___orig_eip;
13 union { 13 union {
14 struct pt_regs regs; 14 struct pt_regs *regs;
15 struct kernel_vm86_regs vm86; 15 struct kernel_vm86_regs *vm86;
16 }; 16 };
17}; 17};
18#endif /* _ASM_X86_MATH_EMU_H */ 18#endif /* _ASM_X86_MATH_EMU_H */
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 2ee0a3bceedf..cf3bb053da0b 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -41,7 +41,7 @@ dotraplinkage void do_int3(struct pt_regs *, long);
41dotraplinkage void do_overflow(struct pt_regs *, long); 41dotraplinkage void do_overflow(struct pt_regs *, long);
42dotraplinkage void do_bounds(struct pt_regs *, long); 42dotraplinkage void do_bounds(struct pt_regs *, long);
43dotraplinkage void do_invalid_op(struct pt_regs *, long); 43dotraplinkage void do_invalid_op(struct pt_regs *, long);
44dotraplinkage void do_device_not_available(struct pt_regs *, long); 44dotraplinkage void do_device_not_available(struct pt_regs);
45dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *, long); 45dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *, long);
46dotraplinkage void do_invalid_TSS(struct pt_regs *, long); 46dotraplinkage void do_invalid_TSS(struct pt_regs *, long);
47dotraplinkage void do_segment_not_present(struct pt_regs *, long); 47dotraplinkage void do_segment_not_present(struct pt_regs *, long);
@@ -77,7 +77,7 @@ extern int panic_on_unrecovered_nmi;
77extern int kstack_depth_to_print; 77extern int kstack_depth_to_print;
78 78
79void math_error(void __user *); 79void math_error(void __user *);
80asmlinkage void math_emulate(long); 80void math_emulate(struct math_emu_info *);
81#ifdef CONFIG_X86_32 81#ifdef CONFIG_X86_32
82unsigned long patch_espfix_desc(unsigned long, unsigned long); 82unsigned long patch_espfix_desc(unsigned long, unsigned long);
83#else 83#else
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 98c2d055284b..7932338d7cb3 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -896,7 +896,7 @@ asmlinkage void math_state_restore(void)
896EXPORT_SYMBOL_GPL(math_state_restore); 896EXPORT_SYMBOL_GPL(math_state_restore);
897 897
898#ifndef CONFIG_MATH_EMULATION 898#ifndef CONFIG_MATH_EMULATION
899asmlinkage void math_emulate(long arg) 899void math_emulate(struct math_emu_info *info)
900{ 900{
901 printk(KERN_EMERG 901 printk(KERN_EMERG
902 "math-emulation not enabled and no coprocessor found.\n"); 902 "math-emulation not enabled and no coprocessor found.\n");
@@ -906,16 +906,19 @@ asmlinkage void math_emulate(long arg)
906} 906}
907#endif /* CONFIG_MATH_EMULATION */ 907#endif /* CONFIG_MATH_EMULATION */
908 908
909dotraplinkage void __kprobes 909dotraplinkage void __kprobes do_device_not_available(struct pt_regs regs)
910do_device_not_available(struct pt_regs *regs, long error)
911{ 910{
912#ifdef CONFIG_X86_32 911#ifdef CONFIG_X86_32
913 if (read_cr0() & X86_CR0_EM) { 912 if (read_cr0() & X86_CR0_EM) {
914 conditional_sti(regs); 913 struct math_emu_info info = { };
915 math_emulate(0); 914
915 conditional_sti(&regs);
916
917 info.regs = &regs;
918 math_emulate(&info);
916 } else { 919 } else {
917 math_state_restore(); /* interrupts still off */ 920 math_state_restore(); /* interrupts still off */
918 conditional_sti(regs); 921 conditional_sti(&regs);
919 } 922 }
920#else 923#else
921 math_state_restore(); 924 math_state_restore();
diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c
index c268abe72253..5d87f586f8d7 100644
--- a/arch/x86/math-emu/fpu_entry.c
+++ b/arch/x86/math-emu/fpu_entry.c
@@ -131,7 +131,7 @@ u_char emulating = 0;
131static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip, 131static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip,
132 overrides * override); 132 overrides * override);
133 133
134asmlinkage void math_emulate(long arg) 134void math_emulate(struct math_emu_info *info)
135{ 135{
136 u_char FPU_modrm, byte1; 136 u_char FPU_modrm, byte1;
137 unsigned short code; 137 unsigned short code;
@@ -161,7 +161,7 @@ asmlinkage void math_emulate(long arg)
161 RE_ENTRANT_CHECK_ON; 161 RE_ENTRANT_CHECK_ON;
162#endif /* RE_ENTRANT_CHECKING */ 162#endif /* RE_ENTRANT_CHECKING */
163 163
164 SETUP_DATA_AREA(arg); 164 FPU_info = info;
165 165
166 FPU_ORIG_EIP = FPU_EIP; 166 FPU_ORIG_EIP = FPU_EIP;
167 167
diff --git a/arch/x86/math-emu/fpu_proto.h b/arch/x86/math-emu/fpu_proto.h
index 51bfbb61c5b1..9779df436b7d 100644
--- a/arch/x86/math-emu/fpu_proto.h
+++ b/arch/x86/math-emu/fpu_proto.h
@@ -51,7 +51,7 @@ extern void ffreep(void);
51extern void fst_i_(void); 51extern void fst_i_(void);
52extern void fstp_i(void); 52extern void fstp_i(void);
53/* fpu_entry.c */ 53/* fpu_entry.c */
54asmlinkage extern void math_emulate(long arg); 54extern void math_emulate(struct math_emu_info *info);
55extern void math_abort(struct math_emu_info *info, unsigned int signal); 55extern void math_abort(struct math_emu_info *info, unsigned int signal);
56/* fpu_etc.c */ 56/* fpu_etc.c */
57extern void FPU_etc(void); 57extern void FPU_etc(void);
diff --git a/arch/x86/math-emu/fpu_system.h b/arch/x86/math-emu/fpu_system.h
index 6729c6a31348..50fa0ec2c8a5 100644
--- a/arch/x86/math-emu/fpu_system.h
+++ b/arch/x86/math-emu/fpu_system.h
@@ -16,10 +16,6 @@
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/mm.h> 17#include <linux/mm.h>
18 18
19/* This sets the pointer FPU_info to point to the argument part
20 of the stack frame of math_emulate() */
21#define SETUP_DATA_AREA(arg) FPU_info = (struct math_emu_info *) &arg
22
23/* s is always from a cpu register, and the cpu does bounds checking 19/* s is always from a cpu register, and the cpu does bounds checking
24 * during register load --> no further bounds checks needed */ 20 * during register load --> no further bounds checks needed */
25#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3]) 21#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3])
@@ -38,12 +34,12 @@
38#define I387 (current->thread.xstate) 34#define I387 (current->thread.xstate)
39#define FPU_info (I387->soft.info) 35#define FPU_info (I387->soft.info)
40 36
41#define FPU_CS (*(unsigned short *) &(FPU_info->regs.cs)) 37#define FPU_CS (*(unsigned short *) &(FPU_info->regs->cs))
42#define FPU_SS (*(unsigned short *) &(FPU_info->regs.ss)) 38#define FPU_SS (*(unsigned short *) &(FPU_info->regs->ss))
43#define FPU_DS (*(unsigned short *) &(FPU_info->regs.ds)) 39#define FPU_DS (*(unsigned short *) &(FPU_info->regs->ds))
44#define FPU_EAX (FPU_info->regs.ax) 40#define FPU_EAX (FPU_info->regs->ax)
45#define FPU_EFLAGS (FPU_info->regs.flags) 41#define FPU_EFLAGS (FPU_info->regs->flags)
46#define FPU_EIP (FPU_info->regs.ip) 42#define FPU_EIP (FPU_info->regs->ip)
47#define FPU_ORIG_EIP (FPU_info->___orig_eip) 43#define FPU_ORIG_EIP (FPU_info->___orig_eip)
48 44
49#define FPU_lookahead (I387->soft.lookahead) 45#define FPU_lookahead (I387->soft.lookahead)
diff --git a/arch/x86/math-emu/get_address.c b/arch/x86/math-emu/get_address.c
index 62daa7fcc44c..420b3b6e3915 100644
--- a/arch/x86/math-emu/get_address.c
+++ b/arch/x86/math-emu/get_address.c
@@ -29,43 +29,43 @@
29#define FPU_WRITE_BIT 0x10 29#define FPU_WRITE_BIT 0x10
30 30
31static int reg_offset[] = { 31static int reg_offset[] = {
32 offsetof(struct math_emu_info, regs.ax), 32 offsetof(struct pt_regs, ax),
33 offsetof(struct math_emu_info, regs.cx), 33 offsetof(struct pt_regs, cx),
34 offsetof(struct math_emu_info, regs.dx), 34 offsetof(struct pt_regs, dx),
35 offsetof(struct math_emu_info, regs.bx), 35 offsetof(struct pt_regs, bx),
36 offsetof(struct math_emu_info, regs.sp), 36 offsetof(struct pt_regs, sp),
37 offsetof(struct math_emu_info, regs.bp), 37 offsetof(struct pt_regs, bp),
38 offsetof(struct math_emu_info, regs.si), 38 offsetof(struct pt_regs, si),
39 offsetof(struct math_emu_info, regs.di) 39 offsetof(struct pt_regs, di)
40}; 40};
41 41
42#define REG_(x) (*(long *)(reg_offset[(x)]+(u_char *) FPU_info)) 42#define REG_(x) (*(long *)(reg_offset[(x)] + (u_char *)FPU_info->regs))
43 43
44static int reg_offset_vm86[] = { 44static int reg_offset_vm86[] = {
45 offsetof(struct math_emu_info, regs.cs), 45 offsetof(struct pt_regs, cs),
46 offsetof(struct math_emu_info, vm86.ds), 46 offsetof(struct kernel_vm86_regs, ds),
47 offsetof(struct math_emu_info, vm86.es), 47 offsetof(struct kernel_vm86_regs, es),
48 offsetof(struct math_emu_info, vm86.fs), 48 offsetof(struct kernel_vm86_regs, fs),
49 offsetof(struct math_emu_info, vm86.gs), 49 offsetof(struct kernel_vm86_regs, gs),
50 offsetof(struct math_emu_info, regs.ss), 50 offsetof(struct pt_regs, ss),
51 offsetof(struct math_emu_info, vm86.ds) 51 offsetof(struct kernel_vm86_regs, ds)
52}; 52};
53 53
54#define VM86_REG_(x) (*(unsigned short *) \ 54#define VM86_REG_(x) (*(unsigned short *) \
55 (reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info)) 55 (reg_offset_vm86[((unsigned)x)] + (u_char *)FPU_info->regs))
56 56
57static int reg_offset_pm[] = { 57static int reg_offset_pm[] = {
58 offsetof(struct math_emu_info, regs.cs), 58 offsetof(struct pt_regs, cs),
59 offsetof(struct math_emu_info, regs.ds), 59 offsetof(struct pt_regs, ds),
60 offsetof(struct math_emu_info, regs.es), 60 offsetof(struct pt_regs, es),
61 offsetof(struct math_emu_info, regs.fs), 61 offsetof(struct pt_regs, fs),
62 offsetof(struct math_emu_info, regs.ds), /* dummy, not saved on stack */ 62 offsetof(struct pt_regs, ds), /* dummy, not saved on stack */
63 offsetof(struct math_emu_info, regs.ss), 63 offsetof(struct pt_regs, ss),
64 offsetof(struct math_emu_info, regs.ds) 64 offsetof(struct pt_regs, ds)
65}; 65};
66 66
67#define PM_REG_(x) (*(unsigned short *) \ 67#define PM_REG_(x) (*(unsigned short *) \
68 (reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info)) 68 (reg_offset_pm[((unsigned)x)] + (u_char *)FPU_info->regs))
69 69
70/* Decode the SIB byte. This function assumes mod != 0 */ 70/* Decode the SIB byte. This function assumes mod != 0 */
71static int sib(int mod, unsigned long *fpu_eip) 71static int sib(int mod, unsigned long *fpu_eip)
@@ -346,34 +346,34 @@ void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
346 } 346 }
347 switch (rm) { 347 switch (rm) {
348 case 0: 348 case 0:
349 address += FPU_info->regs.bx + FPU_info->regs.si; 349 address += FPU_info->regs->bx + FPU_info->regs->si;
350 break; 350 break;
351 case 1: 351 case 1:
352 address += FPU_info->regs.bx + FPU_info->regs.di; 352 address += FPU_info->regs->bx + FPU_info->regs->di;
353 break; 353 break;
354 case 2: 354 case 2:
355 address += FPU_info->regs.bp + FPU_info->regs.si; 355 address += FPU_info->regs->bp + FPU_info->regs->si;
356 if (addr_modes.override.segment == PREFIX_DEFAULT) 356 if (addr_modes.override.segment == PREFIX_DEFAULT)
357 addr_modes.override.segment = PREFIX_SS_; 357 addr_modes.override.segment = PREFIX_SS_;
358 break; 358 break;
359 case 3: 359 case 3:
360 address += FPU_info->regs.bp + FPU_info->regs.di; 360 address += FPU_info->regs->bp + FPU_info->regs->di;
361 if (addr_modes.override.segment == PREFIX_DEFAULT) 361 if (addr_modes.override.segment == PREFIX_DEFAULT)
362 addr_modes.override.segment = PREFIX_SS_; 362 addr_modes.override.segment = PREFIX_SS_;
363 break; 363 break;
364 case 4: 364 case 4:
365 address += FPU_info->regs.si; 365 address += FPU_info->regs->si;
366 break; 366 break;
367 case 5: 367 case 5:
368 address += FPU_info->regs.di; 368 address += FPU_info->regs->di;
369 break; 369 break;
370 case 6: 370 case 6:
371 address += FPU_info->regs.bp; 371 address += FPU_info->regs->bp;
372 if (addr_modes.override.segment == PREFIX_DEFAULT) 372 if (addr_modes.override.segment == PREFIX_DEFAULT)
373 addr_modes.override.segment = PREFIX_SS_; 373 addr_modes.override.segment = PREFIX_SS_;
374 break; 374 break;
375 case 7: 375 case 7:
376 address += FPU_info->regs.bx; 376 address += FPU_info->regs->bx;
377 break; 377 break;
378 } 378 }
379 379