[parisc-linux] 2.5 randomly kills applications with page faults

James Bottomley James.Bottomley@steeleye.com
Fri, 20 Dec 2002 16:12:37 -0600

This is a multipart MIME message.

Content-Type: text/plain; charset=us-ascii

randolph@tausq.org said:
> that's what i thought too, so i went through entry.S as well to see
> what i can find. haven't found anything yet :( 

OK, I think I found the cause of this and the solution.

The cause is in syscall.S in linux_gateway_entry.  Some person (herinafter 
referred to as "the guilty party") added a patch to store the user stack on 
the kernel stack temporarily before stashing it correctly in the user pt_regs:

	STREG	%r1,0(%r30)			/* Stick r1 (usp) here for now */

The problem is that they forgot to increment the stack pointer.  Thus, if we 
take an interruption between this instruction and the corresponding retrieval, 
the value can be trashed.

The fix is simple: increment the stack pointer.  I chose 16 to preserve every 
alignment I can think of is that also safe for 64 bit?

With this fix, my system seems fairly solid.  It survives my bitkeeper and 
stress tests so far (about 30 min) previously it always collapsed within a few 


P.S. After this little debug frenzy, I don't personally care if I ever see 
another line of parisc assembly again, so if another obscure register trashing 
problem turns up, my good deed is done...


Content-Type: text/plain ; name="tmp.diff"; charset=us-ascii
Content-Description: tmp.diff
Content-Disposition: attachment; filename="tmp.diff"

===== arch/parisc/kernel/syscall.S 1.5 vs edited =====
--- 1.5/arch/parisc/kernel/syscall.S	Fri Nov 29 04:31:54 2002
+++ edited/arch/parisc/kernel/syscall.S	Fri Dec 20 15:46:40 2002
@@ -94,6 +94,7 @@
 	mtsp	%r0,%sr7			/* get kernel space into sr7 */
 	STREG	%r1,0(%r30)			/* Stick r1 (usp) here for now */
+	ldo	16(%r30),%r30
 	mfctl	%cr30,%r1			/*  get task ptr in %r1 */
 	LDREG	TI_TASK(%r1),%r1
@@ -104,7 +105,8 @@
 	   PSW value is stored.  This is needed for gdb and sys_ptrace. */
 	STREG	%r0,  TASK_PT_PSW(%r1)
 	STREG	%r2,  TASK_PT_GR2(%r1)		/* preserve rp */
-	LDREG	0(%r30), %r2			/* get users sp back */
+	LDREG	-16(%r30), %r2			/* get users sp back */
+	ldo	-16(%r30), %r30
 	STREG	%r2,  TASK_PT_GR30(%r1)		/* ... and save it */
 	STREG	%r19, TASK_PT_GR19(%r1)
 	STREG	%r20, TASK_PT_GR20(%r1)