MIPS: Avoid clobbering struct pt_regs in kthreads
The resume() implementation octeon_switch.S examines the saved cp0_status register. We were clobbering the entire pt_regs structure in kernel threads leading to random crashes. When switching away from a kernel thread, the saved cp0_status is examined and if bit 30 is set it is cleared and the CP2 state saved into the pt_regs structure. Since the kernel thread stack overlaid the pt_regs structure this resulted in a corrupt stack. When the kthread with the corrupt stack was resumed, it could crash if it used any of the data in the stack that was clobbered. We fix it by moving the kernel thread stack down so it doesn't overlay pt_regs. Signed-off-by: David Daney <ddaney@caviumnetworks.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
1de010a270
commit
484889fc85
|
@ -311,8 +311,9 @@ extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long
|
|||
|
||||
unsigned long get_wchan(struct task_struct *p);
|
||||
|
||||
#define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + THREAD_SIZE - 32)
|
||||
#define task_pt_regs(tsk) ((struct pt_regs *)__KSTK_TOS(tsk) - 1)
|
||||
#define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + \
|
||||
THREAD_SIZE - 32 - sizeof(struct pt_regs))
|
||||
#define task_pt_regs(tsk) ((struct pt_regs *)__KSTK_TOS(tsk))
|
||||
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->cp0_epc)
|
||||
#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[29])
|
||||
#define KSTK_STATUS(tsk) (task_pt_regs(tsk)->cp0_status)
|
||||
|
|
|
@ -188,7 +188,8 @@ NESTED(kernel_entry, 16, sp) # kernel entry point
|
|||
|
||||
MTC0 zero, CP0_CONTEXT # clear context register
|
||||
PTR_LA $28, init_thread_union
|
||||
PTR_LI sp, _THREAD_SIZE - 32
|
||||
/* Set the SP after an empty pt_regs. */
|
||||
PTR_LI sp, _THREAD_SIZE - 32 - PT_SIZE
|
||||
PTR_ADDU sp, $28
|
||||
set_saved_sp sp, t0, t1
|
||||
PTR_SUBU sp, 4 * SZREG # init stack pointer
|
||||
|
|
|
@ -115,7 +115,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
|
|||
{
|
||||
struct thread_info *ti = task_thread_info(p);
|
||||
struct pt_regs *childregs;
|
||||
long childksp;
|
||||
unsigned long childksp;
|
||||
p->set_child_tid = p->clear_child_tid = NULL;
|
||||
|
||||
childksp = (unsigned long)task_stack_page(p) + THREAD_SIZE - 32;
|
||||
|
@ -132,6 +132,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
|
|||
|
||||
/* set up new TSS. */
|
||||
childregs = (struct pt_regs *) childksp - 1;
|
||||
/* Put the stack after the struct pt_regs. */
|
||||
childksp = (unsigned long) childregs;
|
||||
*childregs = *regs;
|
||||
childregs->regs[7] = 0; /* Clear error flag */
|
||||
|
||||
|
|
Loading…
Reference in New Issue