[PATCH 2/4] xtensa: put stack pointer into a1 for call12 spill case

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



call12 spill procedure starts with the following code:

	s32e    a4, a1, -16     # a1 is valid with an empty spill area
	l32e    a4, a5, -12
	s32e    a8, a4, -48
	mov     a8, a4
	l32e    a4, a1, -16
	j       .Lc12c

a1 is expected to point to the topmost stack frame, but this is almost
never the case after the initial register window rotation. The result is
either stack corruption or infinite attempt to call fixup routine after the
first s32e.

This may be reproduced by invoking spill syscall after the following
sequence of calls: 4 -> 12 -> 12 -> 8 on configuration with 32 physical
registers.

The rest of the patch fixes two _spill_registers call sites, functions
spill_registers and _switch_to, re-arranging live registers so that they
don't get clobbered, saving/restoring them across the call or explicitly
marking them as clobbered for gcc.

Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Max Filippov <jcmvbkbc@xxxxxxxxx>
---
 arch/xtensa/include/asm/traps.h | 19 +++++++++++------
 arch/xtensa/kernel/entry.S      | 46 +++++++++++++++++++++++++----------------
 2 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/arch/xtensa/include/asm/traps.h b/arch/xtensa/include/asm/traps.h
index 8c194f6..3ccf24f 100644
--- a/arch/xtensa/include/asm/traps.h
+++ b/arch/xtensa/include/asm/traps.h
@@ -27,21 +27,28 @@ static inline void spill_registers(void)
 	__asm__ __volatile__ (
 		"movi	a14, "__stringify((1 << PS_EXCM_BIT) | LOCKLEVEL)"\n\t"
 		"mov	a12, a0\n\t"
-		"rsr	a13, sar\n\t"
+		"rsr	a10, sar\n\t"
 		"xsr	a14, ps\n\t"
 		"movi	a0, _spill_registers\n\t"
+#ifdef CONFIG_FRAME_POINTER
+		"mov	a8, a7\n\t"
+#endif
 		"rsync\n\t"
 		"callx0 a0\n\t"
+#ifdef CONFIG_FRAME_POINTER
+		"mov	a7, a8\n\t"
+#endif
 		"mov	a0, a12\n\t"
-		"wsr	a13, sar\n\t"
+		"wsr	a10, sar\n\t"
 		"wsr	a14, ps\n\t"
 		: :
-#if defined(CONFIG_FRAME_POINTER)
-		: "a2", "a3", "a4",       "a11", "a12", "a13", "a14", "a15",
+		: "a2", "a3", "a4", "a5",
+#ifdef CONFIG_FRAME_POINTER
+		  "a8",
 #else
-		: "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15",
+		  "a7",
 #endif
-		  "memory");
+		  "a9", "a10", "a11", "a12", "a13", "a14", "a15", "memory");
 }
 
 #endif /* _XTENSA_TRAPS_H */
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 80b3eea..af6e66a 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -1082,19 +1082,22 @@ ENTRY(fast_syscall_spill_registers)
 	rsr	a0, sar
 	s32i	a3, a2, PT_AREG3
 	s32i	a4, a2, PT_AREG4
-	s32i	a0, a2, PT_AREG5	# store SAR to PT_AREG5
+	s32i	a0, a2, PT_SAR
 
-	/* The spill routine might clobber a7, a11, and a15. */
+	/* The spill routine might clobber a5, a7, a9, a11, a13 and a15. */
 
+	s32i	a5, a2, PT_AREG5
 	s32i	a7, a2, PT_AREG7
+	s32i	a9, a2, PT_AREG9
 	s32i	a11, a2, PT_AREG11
+	s32i	a13, a2, PT_AREG13
 	s32i	a15, a2, PT_AREG15
 
 	call0	_spill_registers	# destroys a3, a4, and SAR
 
 	/* Advance PC, restore registers and SAR, and return from exception. */
 
-	l32i	a3, a2, PT_AREG5
+	l32i	a3, a2, PT_SAR
 	l32i	a4, a2, PT_AREG4
 	l32i	a0, a2, PT_AREG0
 	wsr	a3, sar
@@ -1102,8 +1105,11 @@ ENTRY(fast_syscall_spill_registers)
 
 	/* Restore clobbered registers. */
 
+	l32i	a5, a2, PT_AREG5
 	l32i	a7, a2, PT_AREG7
+	l32i	a9, a2, PT_AREG9
 	l32i	a11, a2, PT_AREG11
+	l32i	a13, a2, PT_AREG13
 	l32i	a15, a2, PT_AREG15
 
 	movi	a2, 0
@@ -1228,6 +1234,7 @@ ENDPROC(fast_syscall_spill_registers_fixup_return)
  *  - must be called with call0.
  *  - uses a3, a4 and SAR.
  *  - the last 'valid' register of each frame are clobbered.
+ *  - a5, a9 or a13 may be clobbered.
  *  - the caller must have registered a fixup handler
  *    (or be inside a critical section)
  *  - PS_EXCM must be set (PS_WOE cleared?)
@@ -1273,6 +1280,7 @@ ENTRY(_spill_registers)
 	rsr	a3, windowbase
 	add	a3, a3, a4
 	rsr	a4, depc		# restore a4
+	wsr	a1, depc		# copy a1 to depc
 	wsr	a3, windowbase
 	rsync
 
@@ -1294,6 +1302,7 @@ ENTRY(_spill_registers)
 
 	_bbci.l	a3, 3, .Lc12	# bit 3 shouldn't be zero! (Jump to Lc12 first)
 
+	rsr	a1, depc	# a1 = original a1
 	s32e	a4, a1, -16	# a1 is valid with an empty spill area
 	l32e	a4, a5, -12
 	s32e	a8, a4, -48
@@ -1808,16 +1817,16 @@ ENTRY(_switch_to)
 
 	entry	a1, 16
 
-	mov	a12, a2			# preserve 'prev' (a2)
-	mov	a13, a3			# and 'next' (a3)
+	mov	a10, a2			# preserve 'prev' (a2)
+	mov	a12, a3			# and 'next' (a3)
 
 	l32i	a4, a2, TASK_THREAD_INFO
-	l32i	a5, a3, TASK_THREAD_INFO
+	l32i	a6, a3, TASK_THREAD_INFO
 
-	save_xtregs_user a4 a6 a8 a9 a10 a11 THREAD_XTREGS_USER
+	save_xtregs_user a4 a5 a8 a9 a11 a13 THREAD_XTREGS_USER
 
-	s32i	a0, a12, THREAD_RA	# save return address
-	s32i	a1, a12, THREAD_SP	# save stack pointer
+	s32i	a0, a10, THREAD_RA	# save return address
+	s32i	a1, a10, THREAD_SP	# save stack pointer
 
 	/* Disable ints while we manipulate the stack pointer. */
 
@@ -1830,14 +1839,15 @@ ENTRY(_switch_to)
 	/* Switch CPENABLE */
 
 #if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
-	l32i	a3, a5, THREAD_CPENABLE
+	l32i	a3, a6, THREAD_CPENABLE
 	xsr	a3, cpenable
 	s32i	a3, a4, THREAD_CPENABLE
 #endif
 
 	/* Flush register file. */
 
-	call0	_spill_registers	# destroys a3, a4, and SAR
+	/* It destroys a4, SAR and all odd-numbered registers except a1 */
+	call0	_spill_registers
 
 	/* Set kernel stack (and leave critical section)
 	 * Note: It's save to set it here. The stack will not be overwritten
@@ -1846,20 +1856,20 @@ ENTRY(_switch_to)
 	 */
 
 	rsr	a3, excsave1		# exc_table
-	movi	a6, 0
-	addi	a7, a5, PT_REGS_OFFSET
-	s32i	a6, a3, EXC_TABLE_FIXUP
+	movi	a5, 0
+	addi	a7, a6, PT_REGS_OFFSET
+	s32i	a5, a3, EXC_TABLE_FIXUP
 	s32i	a7, a3, EXC_TABLE_KSTK
 
 	/* restore context of the task 'next' */
 
-	l32i	a0, a13, THREAD_RA	# restore return address
-	l32i	a1, a13, THREAD_SP	# restore stack pointer
+	l32i	a0, a12, THREAD_RA	# restore return address
+	l32i	a1, a12, THREAD_SP	# restore stack pointer
 
-	load_xtregs_user a5 a6 a8 a9 a10 a11 THREAD_XTREGS_USER
+	load_xtregs_user a6 a5 a8 a9 a11 a13 THREAD_XTREGS_USER
 
 	wsr	a14, ps
-	mov	a2, a12			# return 'prev'
+	mov	a2, a10			# return 'prev'
 	rsync
 
 	retw
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]