Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/14408/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Paul Burton and committed by
Ralf Baechle
e11124d8 daa10170

+4 -22
+4
arch/mips/include/asm/stackframe.h
··· 364 364 365 365 .macro RESTORE_SP_AND_RET 366 366 LONG_L sp, PT_R29(sp) 367 + #ifdef CONFIG_CPU_MIPSR6 368 + eretnc 369 + #else 367 370 .set arch=r4000 368 371 eret 369 372 .set mips0 373 + #endif 370 374 .endm 371 375 372 376 #endif
-1
arch/mips/include/asm/thread_info.h
··· 27 27 unsigned long tp_value; /* thread pointer */ 28 28 __u32 cpu; /* current CPU */ 29 29 int preempt_count; /* 0 => preemptable, <0 => BUG */ 30 - int r2_emul_return; /* 1 => Returning from R2 emulator */ 31 30 mm_segment_t addr_limit; /* 32 31 * thread address space limit: 33 32 * 0x7fffffff for user-thead
-1
arch/mips/kernel/asm-offsets.c
··· 97 97 OFFSET(TI_TP_VALUE, thread_info, tp_value); 98 98 OFFSET(TI_CPU, thread_info, cpu); 99 99 OFFSET(TI_PRE_COUNT, thread_info, preempt_count); 100 - OFFSET(TI_R2_EMUL_RET, thread_info, r2_emul_return); 101 100 OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit); 102 101 OFFSET(TI_REGS, thread_info, regs); 103 102 DEFINE(_THREAD_SIZE, THREAD_SIZE);
-18
arch/mips/kernel/entry.S
··· 47 47 local_irq_disable # make sure we dont miss an 48 48 # interrupt setting need_resched 49 49 # between sampling and return 50 - #ifdef CONFIG_MIPSR2_TO_R6_EMULATOR 51 - lw k0, TI_R2_EMUL_RET($28) 52 - bnez k0, restore_all_from_r2_emul 53 - #endif 54 - 55 50 LONG_L a2, TI_FLAGS($28) # current->work 56 51 andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace) 57 52 bnez t0, work_pending ··· 114 119 RESTORE_SOME 115 120 RESTORE_SP_AND_RET 116 121 .set at 117 - 118 - #ifdef CONFIG_MIPSR2_TO_R6_EMULATOR 119 - restore_all_from_r2_emul: # restore full frame 120 - .set noat 121 - sw zero, TI_R2_EMUL_RET($28) # reset it 122 - RESTORE_TEMP 123 - RESTORE_AT 124 - RESTORE_STATIC 125 - RESTORE_SOME 126 - LONG_L sp, PT_R29(sp) 127 - eretnc 128 - .set at 129 - #endif 130 122 131 123 work_pending: 132 124 andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
-2
arch/mips/kernel/traps.c
··· 1108 1108 switch (status) { 1109 1109 case 0: 1110 1110 case SIGEMT: 1111 - task_thread_info(current)->r2_emul_return = 1; 1112 1111 return; 1113 1112 case SIGILL: 1114 1113 goto no_r2_instr; ··· 1115 1116 process_fpemu_return(status, 1116 1117 &current->thread.cp0_baduaddr, 1117 1118 fcr31); 1118 - task_thread_info(current)->r2_emul_return = 1; 1119 1119 return; 1120 1120 } 1121 1121 }