Commit 33c567a3 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: 32 bit emulation fixes.

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

 - Add emulation for sys_fadvise64 and sys_fadvise64_64.
 - Use common code wrapper for sys_sched_setaffinity and sys_sched_getaffinity.
 - Remove unused put_rusage.
 - Add ssize_t checks for iovec lengths in do_readv_writev32.
 - Add emulation for posix timer system calls.
parent f51320a5
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Gerhard Tonn (ton@de.ibm.com) * Gerhard Tonn (ton@de.ibm.com)
* Thomas Spatzier (tspat@de.ibm.com)
* *
* Conversion between 31bit and 64bit native syscalls. * Conversion between 31bit and 64bit native syscalls.
* *
...@@ -934,19 +935,32 @@ static long do_readv_writev32(int type, struct file *file, ...@@ -934,19 +935,32 @@ static long do_readv_writev32(int type, struct file *file,
tot_len = 0; tot_len = 0;
i = count; i = count;
ivp = iov; ivp = iov;
retval = -EINVAL;
while(i > 0) { while(i > 0) {
u32 len; compat_ssize_t tmp = tot_len;
compat_ssize_t len;
u32 buf; u32 buf;
__get_user(len, &vector->iov_len); if (__get_user(len, &vector->iov_len) ||
__get_user(buf, &vector->iov_base); __get_user(buf, &vector->iov_base)) {
retval = -EFAULT;
goto out;
}
if (len < 0) /* size_t not fitting an ssize_t32 .. */
goto out;
tot_len += len; tot_len += len;
if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
goto out;
ivp->iov_base = (void *)A(buf); ivp->iov_base = (void *)A(buf);
ivp->iov_len = (__kernel_size_t) len; ivp->iov_len = (__kernel_size_t) len;
vector++; vector++;
ivp++; ivp++;
i--; i--;
} }
if (tot_len == 0) {
retval = 0;
goto out;
}
inode = file->f_dentry->d_inode; inode = file->f_dentry->d_inode;
/* VERIFY_WRITE actually means a read, as we write to user space */ /* VERIFY_WRITE actually means a read, as we write to user space */
...@@ -1500,50 +1514,6 @@ asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned ...@@ -1500,50 +1514,6 @@ asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned
return err; return err;
} }
struct rusage32 {
struct compat_timeval ru_utime;
struct compat_timeval ru_stime;
s32 ru_maxrss;
s32 ru_ixrss;
s32 ru_idrss;
s32 ru_isrss;
s32 ru_minflt;
s32 ru_majflt;
s32 ru_nswap;
s32 ru_inblock;
s32 ru_oublock;
s32 ru_msgsnd;
s32 ru_msgrcv;
s32 ru_nsignals;
s32 ru_nvcsw;
s32 ru_nivcsw;
};
static int put_rusage (struct rusage32 *ru, struct rusage *r)
{
int err;
err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
err |= __put_user (r->ru_maxrss, &ru->ru_maxrss);
err |= __put_user (r->ru_ixrss, &ru->ru_ixrss);
err |= __put_user (r->ru_idrss, &ru->ru_idrss);
err |= __put_user (r->ru_isrss, &ru->ru_isrss);
err |= __put_user (r->ru_minflt, &ru->ru_minflt);
err |= __put_user (r->ru_majflt, &ru->ru_majflt);
err |= __put_user (r->ru_nswap, &ru->ru_nswap);
err |= __put_user (r->ru_inblock, &ru->ru_inblock);
err |= __put_user (r->ru_oublock, &ru->ru_oublock);
err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd);
err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv);
err |= __put_user (r->ru_nsignals, &ru->ru_nsignals);
err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw);
err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw);
return err;
}
struct sysinfo32 { struct sysinfo32 {
s32 uptime; s32 uptime;
u32 loads[3]; u32 loads[3];
...@@ -2706,56 +2676,6 @@ sys32_mmap2(struct mmap_arg_struct_emu31 *arg) ...@@ -2706,56 +2676,6 @@ sys32_mmap2(struct mmap_arg_struct_emu31 *arg)
return error; return error;
} }
extern asmlinkage int sys_sched_setaffinity(pid_t pid, unsigned int len,
unsigned long *user_mask_ptr);
asmlinkage int sys32_sched_setaffinity(compat_pid_t pid, unsigned int len,
u32 *user_mask_ptr)
{
unsigned long kernel_mask;
mm_segment_t old_fs;
int ret;
if (get_user(kernel_mask, user_mask_ptr))
return -EFAULT;
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_sched_setaffinity(pid,
/* XXX Nice api... */
sizeof(kernel_mask),
&kernel_mask);
set_fs(old_fs);
return ret;
}
extern asmlinkage int sys_sched_getaffinity(pid_t pid, unsigned int len,
unsigned long *user_mask_ptr);
asmlinkage int sys32_sched_getaffinity(compat_pid_t pid, unsigned int len,
u32 *user_mask_ptr)
{
unsigned long kernel_mask;
mm_segment_t old_fs;
int ret;
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_sched_getaffinity(pid,
/* XXX Nice api... */
sizeof(kernel_mask),
&kernel_mask);
set_fs(old_fs);
if (ret == 0) {
if (put_user(kernel_mask, user_mask_ptr))
ret = -EFAULT;
}
return ret;
}
asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count); asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count);
asmlinkage compat_ssize_t sys32_read(unsigned int fd, char * buf, size_t count) asmlinkage compat_ssize_t sys32_read(unsigned int fd, char * buf, size_t count)
...@@ -2792,4 +2712,43 @@ asmlinkage int sys32_clone(struct pt_regs regs) ...@@ -2792,4 +2712,43 @@ asmlinkage int sys32_clone(struct pt_regs regs)
parent_tidptr, child_tidptr); parent_tidptr, child_tidptr);
} }
/*
* Wrapper function for sys_timer_create.
*/
extern asmlinkage long
sys_timer_create(clockid_t, struct sigevent *, timer_t *);
asmlinkage long
sys32_timer_create(clockid_t which_clock, struct sigevent32 *se32,
timer_t *timer_id)
{
struct sigevent se;
timer_t ktimer_id;
mm_segment_t old_fs;
long ret;
if (se32 == NULL)
return sys_timer_create(which_clock, NULL, timer_id);
/* XXX: converting se32 to se is filthy because of the
* two union members. For now it is ok, because the pointers
* are not touched in kernel.
*/
memset(&se, 0, sizeof(se));
if (get_user(se.sigev_value.sival_int, &se32->sigev_value.sival_int) ||
get_user(se.sigev_signo, &se32->sigev_signo) ||
get_user(se.sigev_notify, &se32->sigev_notify) ||
copy_from_user(&se._sigev_un._pad, &se32->_sigev_un._pad,
sizeof(se._sigev_un._pad)))
return -EFAULT;
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_timer_create(which_clock, &se, &ktimer_id);
set_fs(old_fs);
if (!ret)
ret = put_user (ktimer_id, timer_id);
return ret;
}
...@@ -190,4 +190,22 @@ struct ucontext32 { ...@@ -190,4 +190,22 @@ struct ucontext32 {
compat_sigset_t uc_sigmask; /* mask last for extensibility */ compat_sigset_t uc_sigmask; /* mask last for extensibility */
}; };
#define SIGEV_PAD_SIZE32 ((SIGEV_MAX_SIZE/sizeof(int)) - 3)
struct sigevent32 {
union {
int sival_int;
u32 sival_ptr;
} sigev_value;
int sigev_signo;
int sigev_notify;
union {
int _pad[SIGEV_PAD_SIZE32];
int _tid;
struct {
u32 *_function;
u32 *_attribute;
} _sigev_thread;
} _sigev_un;
};
#endif /* _ASM_S390X_S390_H */ #endif /* _ASM_S390X_S390_H */
...@@ -314,6 +314,9 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) ...@@ -314,6 +314,9 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs)
_s390_regs_common32 regs32; _s390_regs_common32 regs32;
int err, i; int err, i;
/* Alwys make any pending restarted system call return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32)); err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
if (err) if (err)
return err; return err;
......
...@@ -135,7 +135,7 @@ sys32_alarm_wrapper: ...@@ -135,7 +135,7 @@ sys32_alarm_wrapper:
compat_sys_utime_wrapper: compat_sys_utime_wrapper:
llgtr %r2,%r2 # char * llgtr %r2,%r2 # char *
llgtr %r3,%r3 # struct compat_utimbuf * llgtr %r3,%r3 # struct compat_utimbuf *
jg compat_sys_utime # branch to system call jg compat_sys_utime # branch to system call
.globl sys32_access_wrapper .globl sys32_access_wrapper
sys32_access_wrapper: sys32_access_wrapper:
...@@ -1192,14 +1192,14 @@ sys32_sched_setaffinity_wrapper: ...@@ -1192,14 +1192,14 @@ sys32_sched_setaffinity_wrapper:
lgfr %r2,%r2 # int lgfr %r2,%r2 # int
llgfr %r3,%r3 # unsigned int llgfr %r3,%r3 # unsigned int
llgtr %r4,%r4 # unsigned long * llgtr %r4,%r4 # unsigned long *
jg sys32_sched_setaffinity jg compat_sys_sched_setaffinity
.globl sys32_sched_getaffinity_wrapper .globl sys32_sched_getaffinity_wrapper
sys32_sched_getaffinity_wrapper: sys32_sched_getaffinity_wrapper:
lgfr %r2,%r2 # int lgfr %r2,%r2 # int
llgfr %r3,%r3 # unsigned int llgfr %r3,%r3 # unsigned int
llgtr %r4,%r4 # unsigned long * llgtr %r4,%r4 # unsigned long *
jg sys32_sched_getaffinity jg compat_sys_sched_getaffinity
.globl sys32_exit_group_wrapper .globl sys32_exit_group_wrapper
sys32_exit_group_wrapper: sys32_exit_group_wrapper:
...@@ -1232,6 +1232,77 @@ sys_epoll_wait_wrapper: ...@@ -1232,6 +1232,77 @@ sys_epoll_wait_wrapper:
lgfr %r5,%r5 # int lgfr %r5,%r5 # int
jg sys_epoll_wait # branch to system call jg sys_epoll_wait # branch to system call
.globl sys32_fadvise64_wrapper
sys32_fadvise64_wrapper:
lgfr %r2,%r2 # int
sllg %r3,%r3,32 # get high word of 64bit loff_t
or %r3,%r4 # get low word of 64bit loff_t
llgfr %r4,%r5 # size_t (unsigned long)
lgfr %r5,%r6 # int
jg sys_fadvise64
.globl sys32_fadvise64_64_wrapper
sys32_fadvise64_64_wrapper:
llgtr %r2,%r2 # struct fadvise64_64_args *
jg s390_fadvise64_64
.globl sys32_clock_settime_wrapper
sys32_clock_settime_wrapper:
lgfr %r2,%r2 # clockid_t (int)
llgtr %r3,%r3 # struct compat_timespec *
jg compat_clock_settime
.globl sys32_clock_gettime_wrapper
sys32_clock_gettime_wrapper:
lgfr %r2,%r2 # clockid_t (int)
llgtr %r3,%r3 # struct compat_timespec *
jg compat_clock_gettime
.globl sys32_clock_getres_wrapper
sys32_clock_getres_wrapper:
lgfr %r2,%r2 # clockid_t (int)
llgtr %r3,%r3 # struct compat_timespec *
jg compat_clock_getres
.globl sys32_clock_nanosleep_wrapper
sys32_clock_nanosleep_wrapper:
lgfr %r2,%r2 # clockid_t (int)
lgfr %r3,%r3 # int
llgtr %r4,%r4 # struct compat_timespec *
llgtr %r5,%r5 # struct compat_timespec *
jg compat_clock_nanosleep
.globl sys32_timer_create_wrapper
sys32_timer_create_wrapper:
lgfr %r2,%r2 # timer_t (int)
llgtr %r3,%r3 # struct compat_sigevent *
llgtr %r4,%r4 # timer_t *
jg sys32_timer_create
.globl sys32_timer_settime_wrapper
sys32_timer_settime_wrapper:
lgfr %r2,%r2 # timer_t (int)
lgfr %r3,%r3 # int
llgtr %r4,%r4 # struct compat_itimerspec *
llgtr %r5,%r5 # struct compat_itimerspec *
jg compat_timer_settime
.globl sys32_timer_gettime_wrapper
sys32_timer_gettime_wrapper:
lgfr %r2,%r2 # timer_t (int)
llgtr %r3,%r3 # struct compat_itimerspec *
jg compat_timer_gettime
.globl sys32_timer_getoverrun_wrapper
sys32_timer_getoverrun_wrapper:
lgfr %r2,%r2 # timer_t (int)
jg sys_timer_getoverrun
.globl sys32_timer_delete_wrapper
sys32_timer_delete_wrapper:
lgfr %r2,%r2 # timer_t (int)
jg sys_timer_delete
.globl sys32_io_setup_wrapper .globl sys32_io_setup_wrapper
sys32_io_setup_wrapper: sys32_io_setup_wrapper:
llgfr %r2,%r2 # unsigned int llgfr %r2,%r2 # unsigned int
......
...@@ -261,15 +261,15 @@ SYSCALL(sys_epoll_create,sys_epoll_create,sys_epoll_create_wrapper) ...@@ -261,15 +261,15 @@ SYSCALL(sys_epoll_create,sys_epoll_create,sys_epoll_create_wrapper)
SYSCALL(sys_epoll_ctl,sys_epoll_ctl,sys_epoll_ctl_wrapper) /* 250 */ SYSCALL(sys_epoll_ctl,sys_epoll_ctl,sys_epoll_ctl_wrapper) /* 250 */
SYSCALL(sys_epoll_wait,sys_epoll_wait,sys_epoll_wait_wrapper) SYSCALL(sys_epoll_wait,sys_epoll_wait,sys_epoll_wait_wrapper)
SYSCALL(sys_set_tid_address,sys_set_tid_address,sys32_set_tid_address_wrapper) SYSCALL(sys_set_tid_address,sys_set_tid_address,sys32_set_tid_address_wrapper)
SYSCALL(s390_fadvise64,sys_fadvise64_64,sys_ni_syscall) SYSCALL(s390_fadvise64,sys_fadvise64_64,sys32_fadvise64_wrapper)
SYSCALL(sys_timer_create,sys_timer_create,sys_ni_syscall) SYSCALL(sys_timer_create,sys_timer_create,sys32_timer_create_wrapper)
SYSCALL(sys_timer_settime,sys_timer_settime,sys_ni_syscall) /* 255 */ SYSCALL(sys_timer_settime,sys_timer_settime,sys32_timer_settime_wrapper) /* 255 */
SYSCALL(sys_timer_gettime,sys_timer_gettime,sys_ni_syscall) SYSCALL(sys_timer_gettime,sys_timer_gettime,sys32_timer_gettime_wrapper)
SYSCALL(sys_timer_getoverrun,sys_timer_getoverrun,sys_ni_syscall) SYSCALL(sys_timer_getoverrun,sys_timer_getoverrun,sys32_timer_getoverrun_wrapper)
SYSCALL(sys_timer_delete,sys_timer_delete,sys_ni_syscall) SYSCALL(sys_timer_delete,sys_timer_delete,sys32_timer_delete_wrapper)
SYSCALL(sys_clock_settime,sys_clock_settime,sys_ni_syscall) SYSCALL(sys_clock_settime,sys_clock_settime,sys32_clock_settime_wrapper)
SYSCALL(sys_clock_gettime,sys_clock_gettime,sys_ni_syscall) /* 260 */ SYSCALL(sys_clock_gettime,sys_clock_gettime,sys32_clock_gettime_wrapper) /* 260 */
SYSCALL(sys_clock_getres,sys_clock_getres,sys_ni_syscall) SYSCALL(sys_clock_getres,sys_clock_getres,sys32_clock_getres_wrapper)
SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys_ni_syscall) SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper)
NI_SYSCALL /* reserved for vserver */ NI_SYSCALL /* reserved for vserver */
SYSCALL(s390_fadvise64_64,sys_ni_syscall,sys_ni_syscall) SYSCALL(s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper)
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