x86: Prepare removal of previous_esp from i386 thread_info structure
The i386 thread_info contains a previous_esp field that is used to daisy chain the different stacks for dump_stack() (ie. irq, softirq, thread stacks). The goal is to eventual make i386 handling of thread_info the same as x86_64, which means that the thread_info will not be in the stack but as a per_cpu variable. We will no longer depend on thread_info being able to daisy chain different stacks as it will only exist in one location (the thread stack). By moving previous_esp to the end of thread_info and referencing it as an offset instead of using a thread_info field, this becomes a stepping stone to moving the thread_info. The offset to get to the previous stack is rather ugly in this patch, but this is only temporary and the prev_esp will be changed in the next commit. This commit is more for sanity checks of the change. Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Brian Gerst <brgerst@gmail.com> Cc: Robert Richter <rric@kernel.org> Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Link: http://lkml.kernel.org/r/20110806012353.891757693@goodmis.org Link: http://lkml.kernel.org/r/20140206144321.608754481@goodmis.org Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
parent
b807902a88
commit
0788aa6a23
4 changed files with 28 additions and 11 deletions
|
@ -32,13 +32,14 @@ struct thread_info {
|
|||
mm_segment_t addr_limit;
|
||||
struct restart_block restart_block;
|
||||
void __user *sysenter_return;
|
||||
unsigned int sig_on_uaccess_error:1;
|
||||
unsigned int uaccess_err:1; /* uaccess failed */
|
||||
#ifdef CONFIG_X86_32
|
||||
unsigned long previous_esp; /* ESP of the previous stack in
|
||||
case of nested (IRQ) stacks
|
||||
(Moved to end, to be removed soon)
|
||||
*/
|
||||
#endif
|
||||
unsigned int sig_on_uaccess_error:1;
|
||||
unsigned int uaccess_err:1; /* uaccess failed */
|
||||
};
|
||||
|
||||
#define INIT_THREAD_INFO(tsk) \
|
||||
|
|
|
@ -22,6 +22,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
|
|||
const struct stacktrace_ops *ops, void *data)
|
||||
{
|
||||
int graph = 0;
|
||||
u32 *prev_esp;
|
||||
|
||||
if (!task)
|
||||
task = current;
|
||||
|
@ -44,9 +45,17 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
|
|||
((unsigned long)stack & (~(THREAD_SIZE - 1)));
|
||||
bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph);
|
||||
|
||||
stack = (unsigned long *)context->previous_esp;
|
||||
/* Stop if not on irq stack */
|
||||
if (task_stack_page(task) == context)
|
||||
break;
|
||||
|
||||
/* The previous esp is just above the context */
|
||||
prev_esp = (u32 *) ((char *)context + sizeof(struct thread_info) -
|
||||
sizeof(long));
|
||||
stack = (unsigned long *)*prev_esp;
|
||||
if (!stack)
|
||||
break;
|
||||
|
||||
if (ops->stack(data, "IRQ") < 0)
|
||||
break;
|
||||
touch_nmi_watchdog();
|
||||
|
|
|
@ -81,7 +81,7 @@ static inline int
|
|||
execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
|
||||
{
|
||||
union irq_ctx *curctx, *irqctx;
|
||||
u32 *isp, arg1, arg2;
|
||||
u32 *isp, *prev_esp, arg1, arg2;
|
||||
|
||||
curctx = (union irq_ctx *) current_thread_info();
|
||||
irqctx = __this_cpu_read(hardirq_ctx);
|
||||
|
@ -98,7 +98,10 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
|
|||
/* build the stack frame on the IRQ stack */
|
||||
isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
|
||||
irqctx->tinfo.task = curctx->tinfo.task;
|
||||
irqctx->tinfo.previous_esp = current_stack_pointer;
|
||||
/* Save the next esp after thread_info */
|
||||
prev_esp = (u32 *) ((char *)irqctx + sizeof(struct thread_info) -
|
||||
sizeof(long));
|
||||
*prev_esp = current_stack_pointer;
|
||||
|
||||
if (unlikely(overflow))
|
||||
call_on_stack(print_stack_overflow, isp);
|
||||
|
@ -149,16 +152,20 @@ void do_softirq_own_stack(void)
|
|||
{
|
||||
struct thread_info *curctx;
|
||||
union irq_ctx *irqctx;
|
||||
u32 *isp;
|
||||
u32 *isp, *prev_esp;
|
||||
|
||||
curctx = current_thread_info();
|
||||
irqctx = __this_cpu_read(softirq_ctx);
|
||||
irqctx->tinfo.task = curctx->task;
|
||||
irqctx->tinfo.previous_esp = current_stack_pointer;
|
||||
|
||||
/* build the stack frame on the softirq stack */
|
||||
isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
|
||||
|
||||
/* Push the previous esp onto the stack */
|
||||
prev_esp = (u32 *) ((char *)irqctx + sizeof(struct thread_info) -
|
||||
sizeof(long));
|
||||
*prev_esp = current_stack_pointer;
|
||||
|
||||
call_on_stack(__do_softirq, isp);
|
||||
}
|
||||
|
||||
|
|
|
@ -184,14 +184,14 @@ unsigned long kernel_stack_pointer(struct pt_regs *regs)
|
|||
{
|
||||
unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1);
|
||||
unsigned long sp = (unsigned long)®s->sp;
|
||||
struct thread_info *tinfo;
|
||||
u32 *prev_esp;
|
||||
|
||||
if (context == (sp & ~(THREAD_SIZE - 1)))
|
||||
return sp;
|
||||
|
||||
tinfo = (struct thread_info *)context;
|
||||
if (tinfo->previous_esp)
|
||||
return tinfo->previous_esp;
|
||||
prev_esp = (u32 *)(context + sizeof(struct thread_info) - sizeof(long));
|
||||
if (prev_esp)
|
||||
return (unsigned long)prev_esp;
|
||||
|
||||
return (unsigned long)regs;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue