From 510d86362a27577f5ee23f46cfb354ad49731e61 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Mon, 19 Dec 2016 14:20:58 +0000 Subject: MIPS: Only change $28 to thread_info if coming from user mode The SAVE_SOME macro is used to save the execution context on all exceptions. If an exception occurs while executing user code, the stack is switched to the kernel's stack for the current task, and register $28 is switched to point to the current_thread_info, which is at the bottom of the stack region. If the exception occurs while executing kernel code, the stack is left, and this change ensures that register $28 is not updated. This is the correct behaviour when the kernel can be executing on the separate irq stack, because the thread_info will not be at the base of it. With this change, register $28 is only switched to it's kernel conventional usage of the currrent thread info pointer at the point at which execution enters kernel space. Doing it on every exception was redundant, but OK without an IRQ stack, but will be erroneous once that is introduced. Signed-off-by: Matt Redfearn Acked-by: Jason A. Donenfeld Cc: Thomas Gleixner Cc: James Hogan Cc: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14742/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/stackframe.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'arch/mips/include/asm/stackframe.h') diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h index eebf39549606..2f182bdf024f 100644 --- a/arch/mips/include/asm/stackframe.h +++ b/arch/mips/include/asm/stackframe.h @@ -216,12 +216,19 @@ LONG_S $25, PT_R25(sp) LONG_S $28, PT_R28(sp) LONG_S $31, PT_R31(sp) + + /* Set thread_info if we're coming from user mode */ + mfc0 k0, CP0_STATUS + sll k0, 3 /* extract cu0 bit */ + bltz k0, 9f + ori $28, sp, _THREAD_MASK xori $28, _THREAD_MASK #ifdef CONFIG_CPU_CAVIUM_OCTEON .set mips64 pref 0, 0($28) /* Prefetch the current pointer */ #endif +9: .set pop .endm -- cgit v1.2.3 From e11124d8ffcdf893d64e0b29624fd88e0ae4ceac Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 17 Oct 2016 15:34:35 +0100 Subject: MIPS: Remove r2_emul_return from struct thread_info The r2_emul_return field in struct thread_info was used in order to take an alternate codepath when returning to userland, which (besides not implementing certain features) effectively used the eretnc instruction in place of eret. The difference is that eretnc doesn't clear LLBit, and therefore doesn't cause a linked load & store sequence to fail due to emulation like eret would. The reason eret would usually be used to clear LLBit is so that after context switching we ensure that a load performed by one task doesn't influence another task. However commit 7c151d3d5d7a ("MIPS: Make use of the ERETNC instruction on MIPS R6") which introduced the r2_emul_return field and conditional use of eretnc also for some reason began explicitly clearing LLBit during context switches - despite retaining the use of eret for everything but returns from the pre-r6 instruction emulation code. As LLBit is cleared upon context switches anyway, simplify this by using eretnc unconditionally for MIPSr6 kernels. This allows us to remove the 4 byte r2_emul_return boolean from struct thread_info, simplify the return to user code in entry.S and avoid the overhead of tracking & checking state which we don't need. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14408/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/stackframe.h | 4 ++++ arch/mips/include/asm/thread_info.h | 1 - arch/mips/kernel/asm-offsets.c | 1 - arch/mips/kernel/entry.S | 18 ------------------ arch/mips/kernel/traps.c | 2 -- 5 files changed, 4 insertions(+), 22 deletions(-) (limited to 'arch/mips/include/asm/stackframe.h') diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h index 2f182bdf024f..6c74a804fe98 100644 --- a/arch/mips/include/asm/stackframe.h +++ b/arch/mips/include/asm/stackframe.h @@ -364,9 +364,13 @@ .macro RESTORE_SP_AND_RET LONG_L sp, PT_R29(sp) +#ifdef CONFIG_CPU_MIPSR6 + eretnc +#else .set arch=r4000 eret .set mips0 +#endif .endm #endif diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index e309d8fcb516..b439e512792b 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -27,7 +27,6 @@ struct thread_info { unsigned long tp_value; /* thread pointer */ __u32 cpu; /* current CPU */ int preempt_count; /* 0 => preemptable, <0 => BUG */ - int r2_emul_return; /* 1 => Returning from R2 emulator */ mm_segment_t addr_limit; /* * thread address space limit: * 0x7fffffff for user-thead diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index a7277698d328..bb5c5d34ba81 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -97,7 +97,6 @@ void output_thread_info_defines(void) OFFSET(TI_TP_VALUE, thread_info, tp_value); OFFSET(TI_CPU, thread_info, cpu); OFFSET(TI_PRE_COUNT, thread_info, preempt_count); - OFFSET(TI_R2_EMUL_RET, thread_info, r2_emul_return); OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit); OFFSET(TI_REGS, thread_info, regs); DEFINE(_THREAD_SIZE, THREAD_SIZE); diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 7791840cf22c..8d83fc2a96b7 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -47,11 +47,6 @@ resume_userspace: local_irq_disable # make sure we dont miss an # interrupt setting need_resched # between sampling and return -#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR - lw k0, TI_R2_EMUL_RET($28) - bnez k0, restore_all_from_r2_emul -#endif - LONG_L a2, TI_FLAGS($28) # current->work andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace) bnez t0, work_pending @@ -120,19 +115,6 @@ restore_partial: # restore partial frame RESTORE_SP_AND_RET .set at -#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR -restore_all_from_r2_emul: # restore full frame - .set noat - sw zero, TI_R2_EMUL_RET($28) # reset it - RESTORE_TEMP - RESTORE_AT - RESTORE_STATIC - RESTORE_SOME - LONG_L sp, PT_R29(sp) - eretnc - .set at -#endif - work_pending: andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS beqz t0, work_notifysig diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 9ea6959cd5bb..cb479be31a50 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1108,7 +1108,6 @@ asmlinkage void do_ri(struct pt_regs *regs) switch (status) { case 0: case SIGEMT: - task_thread_info(current)->r2_emul_return = 1; return; case SIGILL: goto no_r2_instr; @@ -1116,7 +1115,6 @@ asmlinkage void do_ri(struct pt_regs *regs) process_fpemu_return(status, ¤t->thread.cp0_baduaddr, fcr31); - task_thread_info(current)->r2_emul_return = 1; return; } } -- cgit v1.2.3 From 3ae34beb5ec9b04769708daf40cd5fff85cc537f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 17 Oct 2016 15:34:38 +0100 Subject: MIPS: Remove RESTORE_ALL_AND_RET The RESTORE_ALL_AND_RET macro is never used. Remove the dead code. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14411/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/stackframe.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'arch/mips/include/asm/stackframe.h') diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h index 6c74a804fe98..eaa5a4d7d5e5 100644 --- a/arch/mips/include/asm/stackframe.h +++ b/arch/mips/include/asm/stackframe.h @@ -387,14 +387,6 @@ RESTORE_SP .endm - .macro RESTORE_ALL_AND_RET - RESTORE_TEMP - RESTORE_STATIC - RESTORE_AT - RESTORE_SOME - RESTORE_SP_AND_RET - .endm - /* * Move to kernel mode and disable interrupts. * Set cp0 enable bit as sign that we're running on the kernel stack -- cgit v1.2.3