Commit f1b2f7ff authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: add support for 6 system call arguments (FUTEX_CMP_REQUEUE)

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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a57867c3
...@@ -32,6 +32,7 @@ int main(void) ...@@ -32,6 +32,7 @@ int main(void)
DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),); DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),);
DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),); DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),);
BLANK(); BLANK();
DEFINE(__PT_ARGS, offsetof(struct pt_regs, args),);
DEFINE(__PT_PSW, offsetof(struct pt_regs, psw),); DEFINE(__PT_PSW, offsetof(struct pt_regs, psw),);
DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs),); DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs),);
DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2),); DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2),);
......
...@@ -1097,6 +1097,8 @@ compat_sys_futex_wrapper: ...@@ -1097,6 +1097,8 @@ compat_sys_futex_wrapper:
lgfr %r4,%r4 # int lgfr %r4,%r4 # int
llgtr %r5,%r5 # struct compat_timespec * llgtr %r5,%r5 # struct compat_timespec *
llgtr %r6,%r6 # u32 * llgtr %r6,%r6 # u32 *
lgf %r0,164(%r15) # int
stg %r0,160(%r15)
jg compat_sys_futex # branch to system call jg compat_sys_futex # branch to system call
.globl sys32_setxattr_wrapper .globl sys32_setxattr_wrapper
......
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
* Stack layout for the system_call stack entry. * Stack layout for the system_call stack entry.
* The first few entries are identical to the user_regs_struct. * 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_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4 SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4
...@@ -230,12 +231,14 @@ system_call: ...@@ -230,12 +231,14 @@ system_call:
sysc_enter: sysc_enter:
GET_THREAD_INFO # load pointer to task_struct to R9 GET_THREAD_INFO # load pointer to task_struct to R9
sla %r7,2 # *4 and test for svc 0 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 # svc 0: system call number in %r1
cl %r1,BASED(.Lnr_syscalls) cl %r1,BASED(.Lnr_syscalls)
bnl BASED(sysc_do_restart) bnl BASED(sysc_nr_ok)
lr %r7,%r1 # copy svc number to %r7 lr %r7,%r1 # copy svc number to %r7
sla %r7,2 # *4 sla %r7,2 # *4
sysc_nr_ok:
mvc SP_ARGS(4,%r15),SP_R7(%r15)
sysc_do_restart: sysc_do_restart:
tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
l %r8,sys_call_table-system_call(%r7,%r13) # get system call addr. l %r8,sys_call_table-system_call(%r7,%r13) # get system call addr.
...@@ -510,6 +513,7 @@ pgm_svcper: ...@@ -510,6 +513,7 @@ pgm_svcper:
lr %r7,%r1 # copy svc number to %r7 lr %r7,%r1 # copy svc number to %r7
sla %r7,2 # *4 sla %r7,2 # *4
pgm_svcstd: pgm_svcstd:
mvc SP_ARGS(4,%r15),SP_R7(%r15)
tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
l %r8,sys_call_table-system_call(%r7,%r13) # get system call addr. l %r8,sys_call_table-system_call(%r7,%r13) # get system call addr.
bnz BASED(pgm_tracesys) bnz BASED(pgm_tracesys)
......
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
* Stack layout for the system_call stack entry. * Stack layout for the system_call stack entry.
* The first few entries are identical to the user_regs_struct. * 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_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8 SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
...@@ -214,13 +215,15 @@ system_call: ...@@ -214,13 +215,15 @@ system_call:
sysc_enter: sysc_enter:
GET_THREAD_INFO # load pointer to task_struct to R9 GET_THREAD_INFO # load pointer to task_struct to R9
slag %r7,%r7,2 # *4 and test for svc 0 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 # svc 0: system call number in %r1
lghi %r0,NR_syscalls lghi %r0,NR_syscalls
clr %r1,%r0 clr %r1,%r0
jnl sysc_do_restart jnl sysc_nr_ok
lgfr %r7,%r1 # clear high word in r1 lgfr %r7,%r1 # clear high word in r1
slag %r7,%r7,2 # svc 0: system call number 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: sysc_do_restart:
larl %r10,sys_call_table larl %r10,sys_call_table
#ifdef CONFIG_S390_SUPPORT #ifdef CONFIG_S390_SUPPORT
...@@ -542,6 +545,7 @@ pgm_svcper: ...@@ -542,6 +545,7 @@ pgm_svcper:
clr %r1,%r0 clr %r1,%r0
slag %r7,%r1,2 slag %r7,%r1,2
pgm_svcstd: pgm_svcstd:
mvc SP_ARGS(8,%r15),SP_R7(%r15)
larl %r10,sys_call_table larl %r10,sys_call_table
#ifdef CONFIG_S390_SUPPORT #ifdef CONFIG_S390_SUPPORT
tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ? tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ?
......
...@@ -141,7 +141,7 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) ...@@ -141,7 +141,7 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data)
/* /*
* psw and gprs are stored on the stack * 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) if (addr == (addr_t) &dummy->regs.psw.mask)
/* Remove per bit from user psw. */ /* Remove per bit from user psw. */
tmp &= ~PSW_MASK_PER; tmp &= ~PSW_MASK_PER;
...@@ -215,7 +215,7 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) ...@@ -215,7 +215,7 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
high order bit but older gdb's rely on it */ high order bit but older gdb's rely on it */
data |= PSW_ADDR_AMODE; data |= PSW_ADDR_AMODE;
#endif #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)) { } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {
/* /*
...@@ -360,7 +360,7 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) ...@@ -360,7 +360,7 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
PSW32_ADDR_AMODE31; PSW32_ADDR_AMODE31;
} else { } else {
/* gpr 0-15 */ /* gpr 0-15 */
tmp = *(__u32 *)((addr_t) __KSTK_PTREGS(child) + tmp = *(__u32 *)((addr_t) &__KSTK_PTREGS(child)->psw +
addr*2 + 4); addr*2 + 4);
} }
} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
...@@ -439,8 +439,8 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) ...@@ -439,8 +439,8 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
(__u64) tmp & PSW32_ADDR_INSN; (__u64) tmp & PSW32_ADDR_INSN;
} else { } else {
/* gpr 0-15 */ /* gpr 0-15 */
*(__u32*)((addr_t) __KSTK_PTREGS(child) + addr*2 + 4) = *(__u32*)((addr_t) &__KSTK_PTREGS(child)->psw
tmp; + addr*2 + 4) = tmp;
} }
} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
/* /*
......
...@@ -303,6 +303,7 @@ typedef struct ...@@ -303,6 +303,7 @@ typedef struct
*/ */
struct pt_regs struct pt_regs
{ {
unsigned long args[1];
psw_t psw; psw_t psw;
unsigned long gprs[NUM_GPRS]; unsigned long gprs[NUM_GPRS];
unsigned long orig_gpr2; unsigned long orig_gpr2;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment