
From: Martin Schwidefsky <schwidefsky@de.ibm.com>

This patch adds support for 6 system call arguments on s390.  The first
exploiter of this will be the sys_futex system call for the
FUTEX_CMP_REQUEUE operation.  The idea is simple: use register %r7 for the
6th argument.  This can be extended to 7/8/9/...  arguments if there ever
will be the need for it.  To call the system call function in the kernel
the additional arguments needs to get stored on the stack.  8 bytes are
added to the head of struct pt_regs.  %r7 is stored to the additional field
for all system calls.  The store is hidden in a
address-generation-interlock slot, it doesn't slow down the system call
path.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/s390/kernel/asm-offsets.c    |    1 +
 25-akpm/arch/s390/kernel/compat_wrapper.S |    2 ++
 25-akpm/arch/s390/kernel/entry.S          |   10 +++++++---
 25-akpm/arch/s390/kernel/entry64.S        |   10 +++++++---
 25-akpm/arch/s390/kernel/ptrace.c         |   10 +++++-----
 25-akpm/include/asm-s390/ptrace.h         |    1 +
 6 files changed, 23 insertions(+), 11 deletions(-)

diff -puN arch/s390/kernel/asm-offsets.c~s390-add-support-for-6-system-call-arguments arch/s390/kernel/asm-offsets.c
--- 25/arch/s390/kernel/asm-offsets.c~s390-add-support-for-6-system-call-arguments	2004-06-07 22:06:52.869018800 -0700
+++ 25-akpm/arch/s390/kernel/asm-offsets.c	2004-06-07 22:06:52.886016216 -0700
@@ -32,6 +32,7 @@ int main(void)
 	DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),);
 	DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),);
 	BLANK();
+	DEFINE(__PT_ARGS, offsetof(struct pt_regs, args),);
 	DEFINE(__PT_PSW, offsetof(struct pt_regs, psw),);
 	DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs),);
 	DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2),);
diff -puN arch/s390/kernel/compat_wrapper.S~s390-add-support-for-6-system-call-arguments arch/s390/kernel/compat_wrapper.S
--- 25/arch/s390/kernel/compat_wrapper.S~s390-add-support-for-6-system-call-arguments	2004-06-07 22:06:52.870018648 -0700
+++ 25-akpm/arch/s390/kernel/compat_wrapper.S	2004-06-07 22:06:52.887016064 -0700
@@ -1097,6 +1097,8 @@ compat_sys_futex_wrapper:
 	lgfr	%r4,%r4			# int
 	llgtr	%r5,%r5			# struct compat_timespec *
 	llgtr	%r6,%r6			# u32 *
+	lgf	%r0,164(%r15)		# int
+	stg	%r0,160(%r15)
 	jg	compat_sys_futex	# branch to system call
 
 	.globl	sys32_setxattr_wrapper
diff -puN arch/s390/kernel/entry64.S~s390-add-support-for-6-system-call-arguments arch/s390/kernel/entry64.S
--- 25/arch/s390/kernel/entry64.S~s390-add-support-for-6-system-call-arguments	2004-06-07 22:06:52.872018344 -0700
+++ 25-akpm/arch/s390/kernel/entry64.S	2004-06-07 22:06:52.888015912 -0700
@@ -24,7 +24,8 @@
  * Stack layout for the system_call stack entry.
  * The first few entries are identical to the user_regs_struct.
  */
-SP_PTREGS    =  STACK_FRAME_OVERHEAD 
+SP_PTREGS    =  STACK_FRAME_OVERHEAD
+SP_ARGS      =  STACK_FRAME_OVERHEAD + __PT_ARGS
 SP_PSW       =  STACK_FRAME_OVERHEAD + __PT_PSW
 SP_R0        =  STACK_FRAME_OVERHEAD + __PT_GPRS
 SP_R1        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 8
@@ -214,13 +215,15 @@ system_call:
 sysc_enter:
         GET_THREAD_INFO           # load pointer to task_struct to R9
         slag    %r7,%r7,2         # *4 and test for svc 0
-	jnz	sysc_do_restart
+	jnz	sysc_nr_ok
 	# svc 0: system call number in %r1
 	lghi	%r0,NR_syscalls
 	clr	%r1,%r0
-	jnl	sysc_do_restart
+	jnl	sysc_nr_ok
 	lgfr	%r7,%r1           # clear high word in r1
 	slag    %r7,%r7,2         # svc 0: system call number in %r1
+sysc_nr_ok:
+	mvc	SP_ARGS(8,%r15),SP_R7(%r15)
 sysc_do_restart:
 	larl    %r10,sys_call_table
 #ifdef CONFIG_S390_SUPPORT
@@ -542,6 +545,7 @@ pgm_svcper:
 	clr	%r1,%r0
 	slag	%r7,%r1,2
 pgm_svcstd:
+	mvc	SP_ARGS(8,%r15),SP_R7(%r15)
 	larl    %r10,sys_call_table
 #ifdef CONFIG_S390_SUPPORT
         tm      SP_PSW+3(%r15),0x01  # are we running in 31 bit mode ?
diff -puN arch/s390/kernel/entry.S~s390-add-support-for-6-system-call-arguments arch/s390/kernel/entry.S
--- 25/arch/s390/kernel/entry.S~s390-add-support-for-6-system-call-arguments	2004-06-07 22:06:52.880017128 -0700
+++ 25-akpm/arch/s390/kernel/entry.S	2004-06-07 22:06:52.888015912 -0700
@@ -24,7 +24,8 @@
  * Stack layout for the system_call stack entry.
  * The first few entries are identical to the user_regs_struct.
  */
-SP_PTREGS    =  STACK_FRAME_OVERHEAD 
+SP_PTREGS    =  STACK_FRAME_OVERHEAD
+SP_ARGS      =  STACK_FRAME_OVERHEAD + __PT_ARGS
 SP_PSW       =  STACK_FRAME_OVERHEAD + __PT_PSW
 SP_R0        =  STACK_FRAME_OVERHEAD + __PT_GPRS
 SP_R1        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 4
@@ -230,12 +231,14 @@ system_call:
 sysc_enter:
         GET_THREAD_INFO           # load pointer to task_struct to R9
 	sla	%r7,2             # *4 and test for svc 0
-	bnz	BASED(sysc_do_restart)  # svc number > 0
+	bnz	BASED(sysc_nr_ok) # svc number > 0
 	# svc 0: system call number in %r1
 	cl	%r1,BASED(.Lnr_syscalls)
-	bnl	BASED(sysc_do_restart)
+	bnl	BASED(sysc_nr_ok)
 	lr	%r7,%r1           # copy svc number to %r7
 	sla	%r7,2             # *4
+sysc_nr_ok:
+	mvc	SP_ARGS(4,%r15),SP_R7(%r15)
 sysc_do_restart:
 	tm	__TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
         l       %r8,sys_call_table-system_call(%r7,%r13) # get system call addr.
@@ -510,6 +513,7 @@ pgm_svcper:
 	lr	%r7,%r1           # copy svc number to %r7
 	sla	%r7,2             # *4
 pgm_svcstd:
+	mvc	SP_ARGS(4,%r15),SP_R7(%r15)
 	tm	__TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
         l       %r8,sys_call_table-system_call(%r7,%r13) # get system call addr.
         bnz     BASED(pgm_tracesys)
diff -puN arch/s390/kernel/ptrace.c~s390-add-support-for-6-system-call-arguments arch/s390/kernel/ptrace.c
--- 25/arch/s390/kernel/ptrace.c~s390-add-support-for-6-system-call-arguments	2004-06-07 22:06:52.881016976 -0700
+++ 25-akpm/arch/s390/kernel/ptrace.c	2004-06-07 22:06:52.889015760 -0700
@@ -141,7 +141,7 @@ peek_user(struct task_struct *child, add
 		/*
 		 * psw and gprs are stored on the stack
 		 */
-		tmp = *(addr_t *)((addr_t) __KSTK_PTREGS(child) + addr);
+		tmp = *(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr);
 		if (addr == (addr_t) &dummy->regs.psw.mask)
 			/* Remove per bit from user psw. */
 			tmp &= ~PSW_MASK_PER;
@@ -215,7 +215,7 @@ poke_user(struct task_struct *child, add
 			   high order bit but older gdb's rely on it */
 			data |= PSW_ADDR_AMODE;
 #endif
-		*(addr_t *)((addr_t) __KSTK_PTREGS(child) + addr) = data;
+		*(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr) = data;
 
 	} else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {
 		/*
@@ -360,7 +360,7 @@ peek_user_emu31(struct task_struct *chil
 				PSW32_ADDR_AMODE31;
 		} else {
 			/* gpr 0-15 */
-			tmp = *(__u32 *)((addr_t) __KSTK_PTREGS(child) + 
+			tmp = *(__u32 *)((addr_t) &__KSTK_PTREGS(child)->psw +
 					 addr*2 + 4);
 		}
 	} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
@@ -439,8 +439,8 @@ poke_user_emu31(struct task_struct *chil
 				(__u64) tmp & PSW32_ADDR_INSN;
 		} else {
 			/* gpr 0-15 */
-			*(__u32*)((addr_t) __KSTK_PTREGS(child) + addr*2 + 4) =
-				tmp;
+			*(__u32*)((addr_t) &__KSTK_PTREGS(child)->psw
+				  + addr*2 + 4) = tmp;
 		}
 	} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
 		/*
diff -puN include/asm-s390/ptrace.h~s390-add-support-for-6-system-call-arguments include/asm-s390/ptrace.h
--- 25/include/asm-s390/ptrace.h~s390-add-support-for-6-system-call-arguments	2004-06-07 22:06:52.882016824 -0700
+++ 25-akpm/include/asm-s390/ptrace.h	2004-06-07 22:06:52.890015608 -0700
@@ -303,6 +303,7 @@ typedef struct
  */
 struct pt_regs 
 {
+	unsigned long args[1];
 	psw_t psw;
 	unsigned long gprs[NUM_GPRS];
 	unsigned long orig_gpr2;
_
