x86/stackframe/32: Provide consistent pt_regs
Currently pt_regs on x86_32 has an oddity in that kernel regs (!user_mode(regs)) are short two entries (esp/ss). This means that any code trying to use them (typically: regs->sp) needs to jump through some unfortunate hoops. Change the entry code to fix this up and create a full pt_regs frame. This then simplifies various trampolines in ftrace and kprobes, the stack unwinder, ptrace, kdump and kgdb. Much thanks to Josh for help with the cleanups! Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com> Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:

committed by
Ingo Molnar

parent
ea1ed38dba
commit
3c88c692c2
@@ -70,22 +70,6 @@ struct kimage;
|
||||
#define KEXEC_BACKUP_SRC_START (0UL)
|
||||
#define KEXEC_BACKUP_SRC_END (640 * 1024UL - 1) /* 640K */
|
||||
|
||||
/*
|
||||
* CPU does not save ss and sp on stack if execution is already
|
||||
* running in kernel mode at the time of NMI occurrence. This code
|
||||
* fixes it.
|
||||
*/
|
||||
static inline void crash_fixup_ss_esp(struct pt_regs *newregs,
|
||||
struct pt_regs *oldregs)
|
||||
{
|
||||
#ifdef CONFIG_X86_32
|
||||
newregs->sp = (unsigned long)&(oldregs->sp);
|
||||
asm volatile("xorl %%eax, %%eax\n\t"
|
||||
"movw %%ss, %%ax\n\t"
|
||||
:"=a"(newregs->ss));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is responsible for capturing register states if coming
|
||||
* via panic otherwise just fix up the ss and sp if coming via kernel
|
||||
@@ -96,7 +80,6 @@ static inline void crash_setup_regs(struct pt_regs *newregs,
|
||||
{
|
||||
if (oldregs) {
|
||||
memcpy(newregs, oldregs, sizeof(*newregs));
|
||||
crash_fixup_ss_esp(newregs, oldregs);
|
||||
} else {
|
||||
#ifdef CONFIG_X86_32
|
||||
asm volatile("movl %%ebx,%0" : "=m"(newregs->bx));
|
||||
|
@@ -166,14 +166,10 @@ static inline bool user_64bit_mode(struct pt_regs *regs)
|
||||
#define compat_user_stack_pointer() current_pt_regs()->sp
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
extern unsigned long kernel_stack_pointer(struct pt_regs *regs);
|
||||
#else
|
||||
static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
|
||||
{
|
||||
return regs->sp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define GET_IP(regs) ((regs)->ip)
|
||||
#define GET_FP(regs) ((regs)->bp)
|
||||
@@ -201,14 +197,6 @@ static inline unsigned long regs_get_register(struct pt_regs *regs,
|
||||
if (unlikely(offset > MAX_REG_OFFSET))
|
||||
return 0;
|
||||
#ifdef CONFIG_X86_32
|
||||
/*
|
||||
* Traps from the kernel do not save sp and ss.
|
||||
* Use the helper function to retrieve sp.
|
||||
*/
|
||||
if (offset == offsetof(struct pt_regs, sp) &&
|
||||
regs->cs == __KERNEL_CS)
|
||||
return kernel_stack_pointer(regs);
|
||||
|
||||
/* The selector fields are 16-bit. */
|
||||
if (offset == offsetof(struct pt_regs, cs) ||
|
||||
offset == offsetof(struct pt_regs, ss) ||
|
||||
@@ -234,8 +222,7 @@ static inline unsigned long regs_get_register(struct pt_regs *regs,
|
||||
static inline int regs_within_kernel_stack(struct pt_regs *regs,
|
||||
unsigned long addr)
|
||||
{
|
||||
return ((addr & ~(THREAD_SIZE - 1)) ==
|
||||
(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
|
||||
return ((addr & ~(THREAD_SIZE - 1)) == (regs->sp & ~(THREAD_SIZE - 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,7 +236,7 @@ static inline int regs_within_kernel_stack(struct pt_regs *regs,
|
||||
*/
|
||||
static inline unsigned long *regs_get_kernel_stack_nth_addr(struct pt_regs *regs, unsigned int n)
|
||||
{
|
||||
unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
|
||||
unsigned long *addr = (unsigned long *)regs->sp;
|
||||
|
||||
addr += n;
|
||||
if (regs_within_kernel_stack(regs, (unsigned long)addr))
|
||||
|
@@ -78,7 +78,7 @@ static inline unsigned long *
|
||||
get_stack_pointer(struct task_struct *task, struct pt_regs *regs)
|
||||
{
|
||||
if (regs)
|
||||
return (unsigned long *)kernel_stack_pointer(regs);
|
||||
return (unsigned long *)regs->sp;
|
||||
|
||||
if (task == current)
|
||||
return __builtin_frame_address(0);
|
||||
|
Reference in New Issue
Block a user