Message ID | 1305677682-21158-1-git-send-email-vapier@gentoo.org |
---|---|
State | New |
Headers | show |
On 05/18/2011 03:14 AM, Mike Frysinger wrote: > Some architectures (like Blackfin) only implement pselect6 (and skip > select/newselect). So add support for it using existing newselect code. There is a blackfin qemu? Anyways, with this patch pselect01 ltp testcase starts failing. Looks like (at least on arm), arg6 is set and valid pointer, but arg7[0] is 0, which quite doesn't work as lock_user read target... Checking if arg7==0 and setting sig_ptr to null in that case makes the testcase to work, but is that correct? Riku > > Signed-off-by: Mike Frysinger<vapier@gentoo.org> > --- > linux-user/syscall.c | 145 +++++++++++++++++++++++++++++++++++++++++++------- > 1 files changed, 126 insertions(+), 19 deletions(-) > > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index 6e7d88e..b35c437 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -550,6 +550,15 @@ _syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds, > size_t, sigsetsize) > #endif > > +#if defined(TARGET_NR_pselect6) > +#ifndef __NR_pselect6 > +# define __NR_pselect6 -1 > +#endif > +#define __NR_sys_pselect6 __NR_pselect6 > +_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, > + fd_set *, exceptfds, struct timespec *, timeout, void *, sig); > +#endif > + > extern int personality(int); > extern int flock(int, int); > extern int setfsuid(int); > @@ -787,6 +796,20 @@ static inline abi_long copy_from_user_fdset(fd_set *fds, > return 0; > } > > +static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr, > + abi_ulong target_fds_addr, > + int n) > +{ > + if (target_fds_addr) { > + if (copy_from_user_fdset(fds, target_fds_addr, n)) > + return -TARGET_EFAULT; > + *fds_ptr = fds; > + } else { > + *fds_ptr = NULL; > + } > + return 0; > +} > + > static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr, > const fd_set *fds, > int n) > @@ -952,6 +975,7 @@ static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr, > } > #endif > > +#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) > /* do_select() must return target values and target errnos. */ > static abi_long do_select(int n, > abi_ulong rfd_addr, abi_ulong wfd_addr, > @@ -962,26 +986,17 @@ static abi_long do_select(int n, > struct timeval tv, *tv_ptr; > abi_long ret; > > - if (rfd_addr) { > - if (copy_from_user_fdset(&rfds, rfd_addr, n)) > - return -TARGET_EFAULT; > - rfds_ptr =&rfds; > - } else { > - rfds_ptr = NULL; > + ret = copy_from_user_fdset_ptr(&rfds,&rfds_ptr, rfd_addr, n); > + if (ret) { > + return ret; > } > - if (wfd_addr) { > - if (copy_from_user_fdset(&wfds, wfd_addr, n)) > - return -TARGET_EFAULT; > - wfds_ptr =&wfds; > - } else { > - wfds_ptr = NULL; > + ret = copy_from_user_fdset_ptr(&wfds,&wfds_ptr, wfd_addr, n); > + if (ret) { > + return ret; > } > - if (efd_addr) { > - if (copy_from_user_fdset(&efds, efd_addr, n)) > - return -TARGET_EFAULT; > - efds_ptr =&efds; > - } else { > - efds_ptr = NULL; > + ret = copy_from_user_fdset_ptr(&efds,&efds_ptr, efd_addr, n); > + if (ret) { > + return ret; > } > > if (target_tv_addr) { > @@ -1008,6 +1023,7 @@ static abi_long do_select(int n, > > return ret; > } > +#endif > > static abi_long do_pipe2(int host_pipe[], int flags) > { > @@ -5569,7 +5585,98 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, > #endif > #ifdef TARGET_NR_pselect6 > case TARGET_NR_pselect6: > - goto unimplemented_nowarn; > + { > + abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr; > + fd_set rfds, wfds, efds; > + fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; > + struct timespec ts, *ts_ptr; > + > + /* > + * The 6th arg is actually two args smashed together, > + * so we cannot use the C library. > + */ > + sigset_t set; > + struct { > + sigset_t *set; > + size_t size; > + } sig, *sig_ptr; > + > + abi_ulong arg_sigset, arg_sigsize, *arg7; > + target_sigset_t *target_sigset; > + > + n = arg1; > + rfd_addr = arg2; > + wfd_addr = arg3; > + efd_addr = arg4; > + ts_addr = arg5; > + > + ret = copy_from_user_fdset_ptr(&rfds,&rfds_ptr, rfd_addr, n); > + if (ret) { > + goto fail; > + } > + ret = copy_from_user_fdset_ptr(&wfds,&wfds_ptr, wfd_addr, n); > + if (ret) { > + goto fail; > + } > + ret = copy_from_user_fdset_ptr(&efds,&efds_ptr, efd_addr, n); > + if (ret) { > + goto fail; > + } > + > + /* > + * This takes a timespec, and not a timeval, so we cannot > + * the do_select() helper ... > + */ > + if (ts_addr) { > + if (target_to_host_timespec(&ts, ts_addr)) { > + goto efault; > + } > + ts_ptr =&ts; > + } else { > + ts_ptr = NULL; > + } > + > + /* Extract the two packed args for the sigset */ > + if (arg6) { > + sig_ptr =&sig; > + sig.set =&set; > + sig.size = _NSIG / 8; > + > + arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1); > + if (!arg7) { > + goto efault; > + } > + arg_sigset = tswapl(arg7[0]); > + arg_sigsize = tswapl(arg7[1]); > + unlock_user(arg7, arg6, 0); > + > + target_sigset = lock_user(VERIFY_READ, arg_sigset, > + sizeof(*target_sigset), 1); > + if (!target_sigset) { > + goto efault; > + } > + target_to_host_sigset(&set, target_sigset); > + unlock_user(target_sigset, arg_sigset, 0); > + } else { > + sig_ptr = NULL; > + } > + > + ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr, > + ts_ptr, sig_ptr)); > + > + if (!is_error(ret)) { > + if (rfd_addr&& copy_to_user_fdset(rfd_addr,&rfds, n)) > + goto efault; > + if (wfd_addr&& copy_to_user_fdset(wfd_addr,&wfds, n)) > + goto efault; > + if (efd_addr&& copy_to_user_fdset(efd_addr,&efds, n)) > + goto efault; > + > + if (ts_addr&& host_to_target_timespec(ts_addr,&ts)) > + goto efault; > + } > + } > + break; > #endif > case TARGET_NR_symlink: > {
On Fri, Jun 3, 2011 at 14:10, riku voipio wrote: > On 05/18/2011 03:14 AM, Mike Frysinger wrote: >> Some architectures (like Blackfin) only implement pselect6 (and skip >> select/newselect). So add support for it using existing newselect code. > > There is a blackfin qemu? i posted it to the list for feedback, but i havent followed up since > Anyways, with this patch pselect01 ltp testcase > starts failing. Looks like (at least on arm), arg6 is set and valid pointer, > but arg7[0] is 0, which quite doesn't work as lock_user read target... > > Checking if arg7==0 and setting sig_ptr to null in that case makes the > testcase to work, but is that correct? looking at the kernel code, it accepts a 6th arg which contains a NULL pointer (and then just ignores it), so i'll do the same -mike
Am 03.06.2011 um 20:10 schrieb Riku Voipio: > On 05/18/2011 03:14 AM, Mike Frysinger wrote: >> Some architectures (like Blackfin) only implement pselect6 (and skip >> select/newselect). So add support for it using existing newselect >> code. > > There is a blackfin qemu? http://blackfin.uclinux.org/git/?p=users/vapier/qemu.git;a=summary Mike, you should add a feature page for your target: http://wiki.qemu.org/Contribute/StartHere Andreas
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6e7d88e..b35c437 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -550,6 +550,15 @@ _syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds, size_t, sigsetsize) #endif +#if defined(TARGET_NR_pselect6) +#ifndef __NR_pselect6 +# define __NR_pselect6 -1 +#endif +#define __NR_sys_pselect6 __NR_pselect6 +_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, + fd_set *, exceptfds, struct timespec *, timeout, void *, sig); +#endif + extern int personality(int); extern int flock(int, int); extern int setfsuid(int); @@ -787,6 +796,20 @@ static inline abi_long copy_from_user_fdset(fd_set *fds, return 0; } +static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr, + abi_ulong target_fds_addr, + int n) +{ + if (target_fds_addr) { + if (copy_from_user_fdset(fds, target_fds_addr, n)) + return -TARGET_EFAULT; + *fds_ptr = fds; + } else { + *fds_ptr = NULL; + } + return 0; +} + static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, int n) @@ -952,6 +975,7 @@ static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr, } #endif +#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect) /* do_select() must return target values and target errnos. */ static abi_long do_select(int n, abi_ulong rfd_addr, abi_ulong wfd_addr, @@ -962,26 +986,17 @@ static abi_long do_select(int n, struct timeval tv, *tv_ptr; abi_long ret; - if (rfd_addr) { - if (copy_from_user_fdset(&rfds, rfd_addr, n)) - return -TARGET_EFAULT; - rfds_ptr = &rfds; - } else { - rfds_ptr = NULL; + ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n); + if (ret) { + return ret; } - if (wfd_addr) { - if (copy_from_user_fdset(&wfds, wfd_addr, n)) - return -TARGET_EFAULT; - wfds_ptr = &wfds; - } else { - wfds_ptr = NULL; + ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n); + if (ret) { + return ret; } - if (efd_addr) { - if (copy_from_user_fdset(&efds, efd_addr, n)) - return -TARGET_EFAULT; - efds_ptr = &efds; - } else { - efds_ptr = NULL; + ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n); + if (ret) { + return ret; } if (target_tv_addr) { @@ -1008,6 +1023,7 @@ static abi_long do_select(int n, return ret; } +#endif static abi_long do_pipe2(int host_pipe[], int flags) { @@ -5569,7 +5585,98 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_pselect6 case TARGET_NR_pselect6: - goto unimplemented_nowarn; + { + abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr; + fd_set rfds, wfds, efds; + fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; + struct timespec ts, *ts_ptr; + + /* + * The 6th arg is actually two args smashed together, + * so we cannot use the C library. + */ + sigset_t set; + struct { + sigset_t *set; + size_t size; + } sig, *sig_ptr; + + abi_ulong arg_sigset, arg_sigsize, *arg7; + target_sigset_t *target_sigset; + + n = arg1; + rfd_addr = arg2; + wfd_addr = arg3; + efd_addr = arg4; + ts_addr = arg5; + + ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n); + if (ret) { + goto fail; + } + ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n); + if (ret) { + goto fail; + } + ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n); + if (ret) { + goto fail; + } + + /* + * This takes a timespec, and not a timeval, so we cannot + * the do_select() helper ... + */ + if (ts_addr) { + if (target_to_host_timespec(&ts, ts_addr)) { + goto efault; + } + ts_ptr = &ts; + } else { + ts_ptr = NULL; + } + + /* Extract the two packed args for the sigset */ + if (arg6) { + sig_ptr = &sig; + sig.set = &set; + sig.size = _NSIG / 8; + + arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1); + if (!arg7) { + goto efault; + } + arg_sigset = tswapl(arg7[0]); + arg_sigsize = tswapl(arg7[1]); + unlock_user(arg7, arg6, 0); + + target_sigset = lock_user(VERIFY_READ, arg_sigset, + sizeof(*target_sigset), 1); + if (!target_sigset) { + goto efault; + } + target_to_host_sigset(&set, target_sigset); + unlock_user(target_sigset, arg_sigset, 0); + } else { + sig_ptr = NULL; + } + + ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr, + ts_ptr, sig_ptr)); + + if (!is_error(ret)) { + if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) + goto efault; + if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n)) + goto efault; + if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) + goto efault; + + if (ts_addr && host_to_target_timespec(ts_addr, &ts)) + goto efault; + } + } + break; #endif case TARGET_NR_symlink: {
Some architectures (like Blackfin) only implement pselect6 (and skip select/newselect). So add support for it using existing newselect code. Signed-off-by: Mike Frysinger <vapier@gentoo.org> --- linux-user/syscall.c | 145 +++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 126 insertions(+), 19 deletions(-)