Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d315760f authored by Tejun Heo's avatar Tejun Heo Committed by Ingo Molnar
Browse files

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: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent ae6af41f
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -11,8 +11,8 @@
struct math_emu_info {
	long ___orig_eip;
	union {
		struct pt_regs regs;
		struct kernel_vm86_regs vm86;
		struct pt_regs *regs;
		struct kernel_vm86_regs *vm86;
	};
};
#endif /* _ASM_X86_MATH_EMU_H */
+2 −2
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ dotraplinkage void do_int3(struct pt_regs *, long);
dotraplinkage void do_overflow(struct pt_regs *, long);
dotraplinkage void do_bounds(struct pt_regs *, long);
dotraplinkage void do_invalid_op(struct pt_regs *, long);
dotraplinkage void do_device_not_available(struct pt_regs *, long);
dotraplinkage void do_device_not_available(struct pt_regs);
dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *, long);
dotraplinkage void do_invalid_TSS(struct pt_regs *, long);
dotraplinkage void do_segment_not_present(struct pt_regs *, long);
@@ -77,7 +77,7 @@ extern int panic_on_unrecovered_nmi;
extern int kstack_depth_to_print;

void math_error(void __user *);
asmlinkage void math_emulate(long);
void math_emulate(struct math_emu_info *);
#ifdef CONFIG_X86_32
unsigned long patch_espfix_desc(unsigned long, unsigned long);
#else
+9 −6
Original line number Diff line number Diff line
@@ -896,7 +896,7 @@ asmlinkage void math_state_restore(void)
EXPORT_SYMBOL_GPL(math_state_restore);

#ifndef CONFIG_MATH_EMULATION
asmlinkage void math_emulate(long arg)
void math_emulate(struct math_emu_info *info)
{
	printk(KERN_EMERG
		"math-emulation not enabled and no coprocessor found.\n");
@@ -906,16 +906,19 @@ asmlinkage void math_emulate(long arg)
}
#endif /* CONFIG_MATH_EMULATION */

dotraplinkage void __kprobes
do_device_not_available(struct pt_regs *regs, long error)
dotraplinkage void __kprobes do_device_not_available(struct pt_regs regs)
{
#ifdef CONFIG_X86_32
	if (read_cr0() & X86_CR0_EM) {
		conditional_sti(regs);
		math_emulate(0);
		struct math_emu_info info = { };

		conditional_sti(&regs);

		info.regs = &regs;
		math_emulate(&info);
	} else {
		math_state_restore(); /* interrupts still off */
		conditional_sti(regs);
		conditional_sti(&regs);
	}
#else
	math_state_restore();
+2 −2
Original line number Diff line number Diff line
@@ -131,7 +131,7 @@ u_char emulating = 0;
static int valid_prefix(u_char *Byte, u_char __user ** fpu_eip,
			overrides * override);

asmlinkage void math_emulate(long arg)
void math_emulate(struct math_emu_info *info)
{
	u_char FPU_modrm, byte1;
	unsigned short code;
@@ -161,7 +161,7 @@ asmlinkage void math_emulate(long arg)
	RE_ENTRANT_CHECK_ON;
#endif /* RE_ENTRANT_CHECKING */

	SETUP_DATA_AREA(arg);
	FPU_info = info;

	FPU_ORIG_EIP = FPU_EIP;

+1 −1
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ extern void ffreep(void);
extern void fst_i_(void);
extern void fstp_i(void);
/* fpu_entry.c */
asmlinkage extern void math_emulate(long arg);
extern void math_emulate(struct math_emu_info *info);
extern void math_abort(struct math_emu_info *info, unsigned int signal);
/* fpu_etc.c */
extern void FPU_etc(void);
Loading