From c3bbdb48653834d7c04f4eb06fbeb949d858fe36 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Tue, 28 May 2013 18:39:53 -0500 Subject: [PATCH 12/23] bsd-user: add shims for time related system calls. To: Cc: This change adds support for time related system calls that are largely FreeBSD dependent because time_t is inconsistly defined for the various *BSD's. On FreeBSD time_t is mostly defined as a 64-bit value. On some architectures like PPC32 it is defined as a 32-bit value, however. On NetBSD it is always defined as an int64_t. On OpenBSD it is defined as an int. This change also defines system call shim stubs for NetBSD/OpenBSD in case some whats to add code to emulate FreeBSD binaries on one of the other *BSD's. Signed-off-by: Stacey Son --- bsd-user/Makefile.objs | 2 +- bsd-user/freebsd/os-time.c | 205 +++++++++++++++ bsd-user/freebsd/os-time.h | 602 ++++++++++++++++++++++++++++++++++++++++++++ bsd-user/freebsd/qemu-os.h | 41 +++ bsd-user/netbsd/os-time.c | 1 + bsd-user/netbsd/os-time.h | 179 +++++++++++++ bsd-user/netbsd/qemu-os.h | 1 + bsd-user/openbsd/os-time.c | 1 + bsd-user/openbsd/os-time.h | 179 +++++++++++++ bsd-user/openbsd/qemu-os.h | 1 + bsd-user/syscall.c | 96 +++++++ bsd-user/syscall_defs.h | 76 ++++++ 12 files changed, 1383 insertions(+), 1 deletions(-) create mode 100644 bsd-user/freebsd/os-time.c create mode 100644 bsd-user/freebsd/os-time.h create mode 100644 bsd-user/freebsd/qemu-os.h create mode 100644 bsd-user/netbsd/os-time.c create mode 100644 bsd-user/netbsd/os-time.h create mode 100644 bsd-user/netbsd/qemu-os.h create mode 100644 bsd-user/openbsd/os-time.c create mode 100644 bsd-user/openbsd/os-time.h create mode 100644 bsd-user/openbsd/qemu-os.h diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs index d0cea36..4c6acb0 100644 --- a/bsd-user/Makefile.objs +++ b/bsd-user/Makefile.objs @@ -1,2 +1,2 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ - uaccess.o bsd-mem.o + uaccess.o bsd-mem.o $(TARGET_OS)/os-time.o diff --git a/bsd-user/freebsd/os-time.c b/bsd-user/freebsd/os-time.c new file mode 100644 index 0000000..7ac4397 --- /dev/null +++ b/bsd-user/freebsd/os-time.c @@ -0,0 +1,205 @@ +/* + * FreeBSD time related system call helpers + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include + +#include "qemu.h" +#include "qemu-os.h" + +/* + * FreeBSD time conversion functions + */ +abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr) +{ + struct target_freebsd_timeval *target_tv; + + if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 0)) { + return -TARGET_EFAULT; + } + __get_user(tv->tv_sec, &target_tv->tv_sec); + __get_user(tv->tv_usec, &target_tv->tv_usec); + unlock_user_struct(target_tv, target_tv_addr, 1); + + return 0; +} + +abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr) +{ + struct target_freebsd_timeval *target_tv; + + if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(tv->tv_sec, &target_tv->tv_sec); + __put_user(tv->tv_usec, &target_tv->tv_usec); + unlock_user_struct(target_tv, target_tv_addr, 1); + + return 0; +} + +abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr) +{ + struct target_freebsd_timespec *target_ts; + + if (!lock_user_struct(VERIFY_READ, target_ts, target_ts_addr, 0)) { + return -TARGET_EFAULT; + } + __get_user(ts->tv_sec, &target_ts->tv_sec); + __get_user(ts->tv_nsec, &target_ts->tv_nsec); + unlock_user_struct(target_ts, target_ts_addr, 1); + + return 0; +} + +abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts) +{ + struct target_freebsd_timespec *target_ts; + + if (!lock_user_struct(VERIFY_WRITE, target_ts, target_ts_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(ts->tv_sec, &target_ts->tv_sec); + __put_user(ts->tv_nsec, &target_ts->tv_nsec); + unlock_user_struct(target_ts, target_ts_addr, 1); + + return 0; +} + +abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr) +{ + struct target_freebsd_timex *target_tx; + + if (!lock_user_struct(VERIFY_READ, target_tx, target_tx_addr, 0)) { + return -TARGET_EFAULT; + } + __get_user(host_tx->modes, &target_tx->modes); + __get_user(host_tx->offset, &target_tx->offset); + __get_user(host_tx->freq, &target_tx->freq); + __get_user(host_tx->maxerror, &target_tx->maxerror); + __get_user(host_tx->esterror, &target_tx->esterror); + __get_user(host_tx->status, &target_tx->status); + __get_user(host_tx->constant, &target_tx->constant); + __get_user(host_tx->precision, &target_tx->precision); + __get_user(host_tx->ppsfreq, &target_tx->ppsfreq); + __get_user(host_tx->jitter, &target_tx->jitter); + __get_user(host_tx->shift, &target_tx->shift); + __get_user(host_tx->stabil, &target_tx->stabil); + __get_user(host_tx->jitcnt, &target_tx->jitcnt); + __get_user(host_tx->calcnt, &target_tx->calcnt); + __get_user(host_tx->errcnt, &target_tx->errcnt); + __get_user(host_tx->stbcnt, &target_tx->stbcnt); + unlock_user_struct(target_tx, target_tx_addr, 1); + + return 0; +} + +abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr, + struct ntptimeval *ntv) +{ + struct target_freebsd_ntptimeval *target_ntv; + + if (!lock_user_struct(VERIFY_WRITE, target_ntv, target_ntv_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(ntv->time.tv_sec, &target_ntv->time.tv_sec); + __put_user(ntv->time.tv_nsec, &target_ntv->time.tv_nsec); + __put_user(ntv->maxerror, &target_ntv->maxerror); + __put_user(ntv->esterror, &target_ntv->esterror); + __put_user(ntv->tai, &target_ntv->tai); + __put_user(ntv->time_state, &target_ntv->time_state); + + return 0; +} + +/* + * select(2) fdset copy functions + */ +abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n) +{ + int i, nw, j, k; + abi_ulong b, *target_fds; + + nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; + target_fds = lock_user(VERIFY_READ, target_fds_addr, + sizeof(abi_ulong) * nw, 1); + if (target_fds == NULL) { + return -TARGET_EFAULT; + } + FD_ZERO(fds); + k = 0; + for (i = 0; i < nw; i++) { + /* grab the abi_ulong */ + __get_user(b, &target_fds[i]); + for (j = 0; j < TARGET_ABI_BITS; j++) { + /* check the bit inside the abi_ulong */ + if ((b >> j) & 1) { + FD_SET(k, fds); + } + k++; + } + } + unlock_user(target_fds, target_fds_addr, 0); + + return 0; +} + +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; +} + +abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, int n) +{ + int i, nw, j, k; + abi_long v; + abi_ulong *target_fds; + + nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; + target_fds = lock_user(VERIFY_WRITE, target_fds_addr, + sizeof(abi_ulong) * nw, 0); + if (target_fds == NULL) { + return -TARGET_EFAULT; + } + k = 0; + for (i = 0; i < nw; i++) { + v = 0; + for (j = 0; j < TARGET_ABI_BITS; j++) { + v |= ((FD_ISSET(k, fds) != 0) << j); + k++; + } + __put_user(v, &target_fds[i]); + } + unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw); + + return 0; +} + diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h new file mode 100644 index 0000000..a607e06 --- /dev/null +++ b/bsd-user/freebsd/os-time.h @@ -0,0 +1,602 @@ +/* + * FreeBSD time related system call shims + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef __FREEBSD_OS_TIME_H_ +#define __FREEBSD_OS_TIME_H_ + +#include +#include +#include +#include +#include +#include + +#include "qemu-os.h" + +/* nanosleep(2) */ +static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2) +{ + abi_long ret; + struct timespec req, rem; + + ret = t2h_freebsd_timespec(&req, arg1); + if (!is_error(ret)) { + ret = get_errno(nanosleep(&req, &rem)); + if (!is_error(ret) && arg2) { + h2t_freebsd_timespec(arg2, &rem); + } + } + + return ret; +} + +/* clock_gettime(2) */ +static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2) +{ + abi_long ret; + struct timespec ts; + + ret = get_errno(clock_gettime(arg1, &ts)); + if (!is_error(ret)) { + if (h2t_freebsd_timespec(arg2, &ts)) { + return -TARGET_EFAULT; + } + } + + return ret; +} + +/* clock_settime(2) */ +static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2) +{ + struct timespec ts; + + if (t2h_freebsd_timespec(&ts, arg2) != 0) { + return -TARGET_EFAULT; + } + + return get_errno(clock_settime(arg1, &ts)); +} + +/* clock_getres(2) */ +static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2) +{ + abi_long ret; + struct timespec ts; + + ret = get_errno(clock_getres(arg1, &ts)); + if (!is_error(ret)) { + if (h2t_freebsd_timespec(arg2, &ts)) { + return -TARGET_EFAULT; + } + } + + return ret; +} + +/* gettimeofday(2) */ +static inline abi_long do_freebsd_gettimeofday(abi_long arg1, abi_long arg2) +{ + abi_long ret; + struct timeval tv; + struct timezone tz, *target_tz; /* XXX */ + + if (arg2 != 0) { + if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) { + return -TARGET_EFAULT; + } + __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest); + __get_user(tz.tz_dsttime, &target_tz->tz_dsttime); + unlock_user_struct(target_tz, arg2, 1); + } + ret = get_errno(gettimeofday(&tv, arg2 != 0 ? &tz : NULL)); + if (!is_error(ret)) { + if (h2t_freebsd_timeval(&tv, arg1)) { + return -TARGET_EFAULT; + } + } + + return ret; +} + +/* settimeofday(2) */ +static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2) +{ + struct timeval tv; + struct timezone tz, *target_tz; /* XXX */ + + if (arg2 != 0) { + if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) { + return -TARGET_EFAULT; + } + __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest); + __get_user(tz.tz_dsttime, &target_tz->tz_dsttime); + unlock_user_struct(target_tz, arg2, 1); + } + if (t2h_freebsd_timeval(&tv, arg1)) { + return -TARGET_EFAULT; + } + + return get_errno(settimeofday(&tv, arg2 != 0 ? &tz : NULL)); +} + +/* adjtime(2) */ +static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr, + abi_ulong target_old_addr) +{ + abi_long ret; + struct timeval host_delta, host_old; + + ret = t2h_freebsd_timeval(&host_delta, target_delta_addr); + if (is_error(ret)) { + return ret; + } + + if (target_old_addr) { + ret = get_errno(adjtime(&host_delta, &host_old)); + if (is_error(ret)) { + return ret; + } + ret = h2t_freebsd_timeval(&host_old, target_old_addr); + } else { + ret = get_errno(adjtime(&host_delta, NULL)); + } + + return ret; +} + +/* ntp_adjtime(2) */ +static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr) +{ + abi_long ret; + struct timex host_tx; + + ret = t2h_freebsd_timex(&host_tx, target_tx_addr); + if (ret == 0) { + ret = get_errno(ntp_adjtime(&host_tx)); + } + + return ret; +} + +/* ntp_gettime(2) */ +static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr) +{ + abi_long ret; + struct ntptimeval host_ntv; + + ret = get_errno(ntp_gettime(&host_ntv)); + if (ret == 0) { + ret = h2t_freebsd_ntptimeval(target_ntv_addr, &host_ntv); + } + + return ret; +} + + +/* utimes(2) */ +static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct timeval *tvp, tv[2]; + + if (arg2 != 0) { + if (t2h_freebsd_timeval(&tv[0], arg2) || + t2h_freebsd_timeval(&tv[1], arg2 + + sizeof(struct target_freebsd_timeval))) { + return -TARGET_EFAULT; + } + tvp = tv; + } else { + tvp = NULL; + } + p = lock_user_string(arg1); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(utimes(p, tvp)); + unlock_user(p, arg1, 0); + + return ret; +} + +/* lutimes(2) */ +static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct timeval *tvp, tv[2]; + + if (arg2 != 0) { + if (t2h_freebsd_timeval(&tv[0], arg2) || + t2h_freebsd_timeval(&tv[1], arg2 + + sizeof(struct target_freebsd_timeval))) { + return -TARGET_EFAULT; + } + tvp = tv; + } else { + tvp = NULL; + } + p = lock_user_string(arg1); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(lutimes(p, tvp)); + unlock_user(p, arg1, 0); + + return ret; +} + +/* futimes(2) */ +static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2) +{ + struct timeval *tvp, tv[2]; + + if (arg2 != 0) { + if (t2h_freebsd_timeval(&tv[0], arg2) || + t2h_freebsd_timeval(&tv[1], arg2 + + sizeof(struct target_freebsd_timeval))) { + return -TARGET_EFAULT; + } + tvp = tv; + } else { + tvp = NULL; + } + + return get_errno(futimes(arg1, tvp)); +} + +/* futimesat(2) */ +static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + abi_long ret; + void *p; + struct timeval *tvp, tv[2]; + + if (arg3 != 0) { + if (t2h_freebsd_timeval(&tv[0], arg3) || + t2h_freebsd_timeval(&tv[1], arg3 + + sizeof(struct target_freebsd_timeval))) { + return -TARGET_EFAULT; + } + tvp = tv; + } else { + tvp = NULL; + } + + p = lock_user_string(arg2); + if (p == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(futimesat(arg1, p, tvp)); + unlock_user(p, arg2, 0); + + return ret; +} + +/* + * undocumented ktimer_create(clockid_t clock_id, struct sigevent *evp, + * int *timerid) syscall + */ +static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + + qemu_log("qemu: Unsupported syscall ktimer_create()\n"); + return -TARGET_ENOSYS; +} + +/* undocumented ktimer_delete(int timerid) syscall */ +static inline abi_long do_freebsd_ktimer_delete(abi_long arg1) +{ + + qemu_log("qemu: Unsupported syscall ktimer_delete()\n"); + return -TARGET_ENOSYS; +} + +/* + * undocumented ktimer_settime(int timerid, int flags, + * const struct itimerspec *value, struct itimerspec *ovalue) syscall + */ +static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + + qemu_log("qemu: Unsupported syscall ktimer_settime()\n"); + return -TARGET_ENOSYS; +} + +/* + * undocumented ktimer_gettime(int timerid, struct itimerspec *value) + * syscall + */ +static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall ktimer_gettime()\n"); + return -TARGET_ENOSYS; +} + +/* + * undocumented ktimer_getoverrun(int timerid) syscall + */ +static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1) +{ + + qemu_log("qemu: Unsupported syscall ktimer_getoverrun()\n"); + return -TARGET_ENOSYS; +} + +/* select(2) */ +static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr, + abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr) +{ + fd_set rfds, wfds, efds; + fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; + struct timeval tv, *tv_ptr; + abi_long ret, error; + + ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n); + if (ret != 0) { + return ret; + } + ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n); + if (ret != 0) { + return ret; + } + ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n); + if (ret != 0) { + return ret; + } + + if (target_tv_addr != 0) { + if (t2h_freebsd_timeval(&tv, target_tv_addr)) { + return -TARGET_EFAULT; + } + tv_ptr = &tv; + } else { + tv_ptr = NULL; + } + + ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr)); + + if (!is_error(ret)) { + if (rfd_addr != 0) { + error = copy_to_user_fdset(rfd_addr, &rfds, n); + if (error != 0) { + return error; + } + } + if (wfd_addr != 0) { + error = copy_to_user_fdset(wfd_addr, &wfds, n); + if (error != 0) { + return error; + } + } + if (efd_addr != 0) { + error = copy_to_user_fdset(efd_addr, &efds, n); + if (error != 0) { + return error; + } + } + if (target_tv_addr != 0) { + error = h2t_freebsd_timeval(&tv, target_tv_addr); + if (is_error(error)) { + return error; + } + } + } + return ret; +} + +/* pselect(2) */ +static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr, + abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr, + abi_ulong set_addr) +{ + fd_set rfds, wfds, efds; + fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; + sigset_t set, *set_ptr; + struct timespec ts, *ts_ptr; + void *p; + abi_long ret; + + ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n); + if (is_error(ret)) { + return ret; + } + ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n); + if (is_error(ret)) { + return ret; + } + ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n); + if (is_error(ret)) { + return ret; + } + + /* Unlike select(), pselect() uses struct timespec instead of timeval */ + if (ts_addr) { + if (t2h_freebsd_timespec(&ts, ts_addr)) { + return -TARGET_EFAULT; + } + ts_ptr = &ts; + } else { + ts_ptr = NULL; + } + + if (set_addr != 0) { + p = lock_user(VERIFY_READ, set_addr, sizeof(target_sigset_t), 1); + if (p == NULL) { + return -TARGET_EFAULT; + } + target_to_host_sigset(&set, p); + unlock_user(p, set_addr, 0); + set_ptr = &set; + } else { + set_ptr = NULL; + } + + ret = get_errno(pselect(n, rfds_ptr, wfds_ptr, efds_ptr, ts_ptr, set_ptr)); + + if (!is_error(ret)) { + if (rfd_addr != 0) { + ret = copy_to_user_fdset(rfd_addr, &rfds, n); + if (is_error(ret)) { + return ret; + } + } + if (wfd_addr != 0) { + ret = copy_to_user_fdset(wfd_addr, &wfds, n); + if (is_error(ret)) { + return ret; + } + } + if (efd_addr != 0) { + ret = copy_to_user_fdset(efd_addr, &efds, n); + if (is_error(ret)) { + return ret; + } + } + if (ts_addr != 0) { + ret = h2t_freebsd_timespec(ts_addr, &ts); + if (is_error(ret)) { + return ret; + } + } + } + return ret; +} + +/* kqueue(2) */ +static inline abi_long do_freebsd_kqueue(void) +{ + + return get_errno(kqueue()); +} + +/* kevent(2) */ +static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2, + abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6) +{ + abi_long ret; + struct kevent *changelist = NULL, *eventlist = NULL; + struct target_freebsd_kevent *target_changelist, *target_eventlist; + struct timespec ts; + int i; + + if (arg3 != 0) { + target_changelist = lock_user(VERIFY_READ, arg2, + sizeof(struct target_freebsd_kevent) * arg3, 1); + if (target_changelist == NULL) { + return -TARGET_EFAULT; + } + + changelist = alloca(sizeof(struct kevent) * arg3); + for (i = 0; i < arg3; i++) { + __get_user(changelist[i].ident, &target_changelist[i].ident); + __get_user(changelist[i].filter, &target_changelist[i].filter); + __get_user(changelist[i].flags, &target_changelist[i].flags); + __get_user(changelist[i].fflags, &target_changelist[i].fflags); + __get_user(changelist[i].data, &target_changelist[i].data); + /* __get_user(changelist[i].udata, &target_changelist[i].udata); */ +#if TARGET_ABI_BITS == 32 + changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata; + tswap32s((uint32_t *)&changelist[i].udata); +#else + changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata; + tswap64s((uint64_t *)&changelist[i].udata); +#endif + } + unlock_user(target_changelist, arg2, 0); + } + + if (arg5 != 0) { + eventlist = alloca(sizeof(struct kevent) * arg5); + } + if (arg6 != 0) { + if (t2h_freebsd_timespec(&ts, arg6)) { + return -TARGET_EFAULT; + } + } + ret = get_errno(kevent(arg1, changelist, arg3, eventlist, arg5, + arg6 != 0 ? &ts : NULL)); + if (!is_error(ret)) { + target_eventlist = lock_user(VERIFY_WRITE, arg4, + sizeof(struct target_freebsd_kevent) * arg5, 0); + if (target_eventlist == NULL) { + return -TARGET_EFAULT; + } + for (i = 0; i < arg5; i++) { + __put_user(eventlist[i].ident, &target_eventlist[i].ident); + __put_user(eventlist[i].filter, &target_eventlist[i].filter); + __put_user(eventlist[i].flags, &target_eventlist[i].flags); + __put_user(eventlist[i].fflags, &target_eventlist[i].fflags); + __put_user(eventlist[i].data, &target_eventlist[i].data); + /* __put_user(eventlist[i].udata, &target_eventlist[i].udata);*/ +#if TARGET_ABI_BITS == 32 + tswap32s((uint32_t *)&eventlist[i].data); + target_eventlist[i].data = (uintptr_t)eventlist[i].data; +#else + tswap64s((uint64_t *)&eventlist[i].data); + target_eventlist[i].data = (uintptr_t)eventlist[i].data; +#endif + } + unlock_user(target_eventlist, arg4, + sizeof(struct target_freebsd_kevent) * arg5); + } + return ret; +} + +/* sigtimedwait(2) */ +static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2, + abi_ulong arg3) +{ + abi_long ret; + void *p; + sigset_t set; + struct timespec uts, *puts; + siginfo_t uinfo; + + p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1); + if (p == NULL) { + return -TARGET_EFAULT; + } + target_to_host_sigset(&set, p); + unlock_user(p, arg1, 0); + if (arg3) { + puts = &uts; + t2h_freebsd_timespec(puts, arg3); + } else { + puts = NULL; + } + ret = get_errno(sigtimedwait(&set, &uinfo, puts)); + if (!is_error(ret) && arg2) { + p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + host_to_target_siginfo(p, &uinfo); + unlock_user(p, arg2, sizeof(target_siginfo_t)); + } + return ret; +} + +#endif /* __FREEBSD_OS_TIME_H_ */ diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h new file mode 100644 index 0000000..7a1ed9c --- /dev/null +++ b/bsd-user/freebsd/qemu-os.h @@ -0,0 +1,41 @@ +/* + * FreeBSD conversion extern declarations + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef _QEMU_OS_H_ +#define _QEMU_OS_H_ + +/* os-time.c */ +abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr); +abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr); + +abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr); +abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts); + +abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr); + +abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr, + struct ntptimeval *ntv); + +abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n); +abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr, + abi_ulong target_fds_addr, int n); +abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, + int n); + +#endif /* !_QEMU_OS_H_ */ diff --git a/bsd-user/netbsd/os-time.c b/bsd-user/netbsd/os-time.c new file mode 100644 index 0000000..ee2c7a0 --- /dev/null +++ b/bsd-user/netbsd/os-time.c @@ -0,0 +1 @@ +/* XXX NetBSD time related helpers */ diff --git a/bsd-user/netbsd/os-time.h b/bsd-user/netbsd/os-time.h new file mode 100644 index 0000000..6d0f1de --- /dev/null +++ b/bsd-user/netbsd/os-time.h @@ -0,0 +1,179 @@ +#ifndef __NETBSD_OS_TIME_H_ +#define __NETBSD_OS_TIME_H_ + +/* + * XXX To support FreeBSD binaries on NetBSD these syscalls will need to + * be emulated. + */ +static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_gettimeofday(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr, + abi_ulong target_old_addr) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_ktimer_delete(abi_long arg1) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr, + abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + + +static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr, + abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr, + abi_ulong set_addr) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_kqueue(void) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2, + abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2, + abi_ulong arg3) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +#endif /* ! __NETBSD_OS_TIME_H_ */ diff --git a/bsd-user/netbsd/qemu-os.h b/bsd-user/netbsd/qemu-os.h new file mode 100644 index 0000000..016618b --- /dev/null +++ b/bsd-user/netbsd/qemu-os.h @@ -0,0 +1 @@ +/* NetBSD conversion extern declarations */ diff --git a/bsd-user/openbsd/os-time.c b/bsd-user/openbsd/os-time.c new file mode 100644 index 0000000..accd886 --- /dev/null +++ b/bsd-user/openbsd/os-time.c @@ -0,0 +1 @@ +/* XXX OpenBSD time related helpers */ diff --git a/bsd-user/openbsd/os-time.h b/bsd-user/openbsd/os-time.h new file mode 100644 index 0000000..fc444bb --- /dev/null +++ b/bsd-user/openbsd/os-time.h @@ -0,0 +1,179 @@ +#ifndef __OPENBSD_OS_TIME_H_ +#define __OPENBSD_OS_TIME_H_ + +/* + * XXX To support FreeBSD binaries on OpenBSD these syscalls will need to + * be emulated. + */ +static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_gettimeofday(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr, + abi_ulong target_old_addr) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_ktimer_delete(abi_long arg1) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_ktimer_getoverrun(abi_long arg1) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_select(int n, abi_ulong rfd_addr, + abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong target_tv_addr) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + + +static inline abi_long do_freebsd_pselect(int n, abi_ulong rfd_addr, + abi_ulong wfd_addr, abi_ulong efd_addr, abi_ulong ts_addr, + abi_ulong set_addr) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_kqueue(void) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2, + abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2, + abi_ulong arg3) +{ + + qemu_log("qemu: Unsupported syscall %s\n", __func__); + return -TARGET_ENOSYS; +} + +#endif /* ! __OPENBSD_OS_TIME_H_ */ diff --git a/bsd-user/openbsd/qemu-os.h b/bsd-user/openbsd/qemu-os.h new file mode 100644 index 0000000..f4ad3be --- /dev/null +++ b/bsd-user/openbsd/qemu-os.h @@ -0,0 +1 @@ +/* OpenBSD conversion extern declarations */ diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 2efa772..cbdd363 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -2,6 +2,7 @@ * BSD syscalls * * Copyright (c) 2003 - 2008 Fabrice Bellard + * Copyright (c) 2013 Stacey D. Son * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +37,8 @@ #include "bsd-file.h" #include "bsd-mem.h" +#include "os-time.h" + /* #define DEBUG */ #if defined(TARGET_I386) @@ -682,6 +685,99 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, break; + /* + * time related system calls. + */ + case TARGET_FREEBSD_NR_nanosleep: /* nanosleep(2) */ + ret = do_freebsd_nanosleep(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_clock_gettime: /* clock_gettime(2) */ + ret = do_freebsd_clock_gettime(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_clock_settime: /* clock_settime(2) */ + ret = do_freebsd_clock_settime(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_clock_getres: /* clock_getres(2) */ + ret = do_freebsd_clock_getres(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_gettimeofday: /* gettimeofday(2) */ + ret = do_freebsd_gettimeofday(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_settimeofday: /* settimeofday(2) */ + ret = do_freebsd_settimeofday(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_adjtime: /* adjtime(2) */ + ret = do_freebsd_adjtime(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_ntp_adjtime: /* ntp_adjtime(2) */ + ret = do_freebsd_ntp_adjtime(arg1); + break; + + case TARGET_FREEBSD_NR_ntp_gettime: /* ntp_gettime(2) */ + ret = do_freebsd_ntp_gettime(arg1); + break; + + case TARGET_FREEBSD_NR_utimes: /* utimes(2) */ + ret = do_freebsd_utimes(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_lutimes: /* lutimes(2) */ + ret = do_freebsd_lutimes(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_futimes: /* futimes(2) */ + ret = do_freebsd_futimes(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_futimesat: /* futimesat(2) */ + ret = do_freebsd_futimesat(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_ktimer_create: /* undocumented */ + ret = do_freebsd_ktimer_create(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_ktimer_delete: /* undocumented */ + ret = do_freebsd_ktimer_delete(arg1); + break; + + case TARGET_FREEBSD_NR_ktimer_settime: /* undocumented */ + ret = do_freebsd_ktimer_settime(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_ktimer_gettime: /* undocumented */ + ret = do_freebsd_ktimer_gettime(arg1, arg2); + break; + + + case TARGET_FREEBSD_NR_ktimer_getoverrun: /* undocumented */ + ret = do_freebsd_ktimer_getoverrun(arg1); + break; + + case TARGET_FREEBSD_NR_select: /* select(2) */ + ret = do_freebsd_select(arg1, arg2, arg3, arg4, arg5); + break; + + case TARGET_FREEBSD_NR_pselect: /* pselect(2) */ + ret = do_freebsd_pselect(arg1, arg2, arg3, arg4, arg5, arg6); + break; + + case TARGET_FREEBSD_NR_kqueue: /* kqueue(2) */ + ret = do_freebsd_kqueue(); + break; + + case TARGET_FREEBSD_NR_kevent: /* kevent(2) */ + ret = do_freebsd_kevent(arg1, arg2, arg3, arg4, arg5, arg6); + break; + + case TARGET_FREEBSD_NR_break: ret = do_obreak(arg1); break; diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index dea94ef..7b85835 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -83,4 +83,80 @@ struct bsd_shm_regions { /* XXX */ #define TARGET_BSD_MAP_FLAGMASK 0x3ff7 +/* + * sys/time.h + * sys/timex.h + */ + +/* + * time_t seems to be very inconsistly defined for the different *BSD's... + * + * FreeBSD/{arm, mips} uses a 64bits time_t, even in 32bits mode, + * so we have to add a special case here. + * + * On NetBSD time_t is always defined as an int64_t. On OpenBSD time_t + * is always defined as an int. + * + */ +#if (defined(TARGET_ARM) || defined(TARGET_MIPS)) +typedef int64_t target_freebsd_time_t; +#else +typedef abi_long target_freebsd_time_t; +#endif + +typedef abi_long target_freebsd_suseconds_t; + +/* compare to sys/timespec.h */ +struct target_freebsd_timespec { + target_freebsd_time_t tv_sec; /* seconds */ + abi_long tv_nsec; /* and nanoseconds */ +} __packed; + +struct target_freebsd_timeval { + target_freebsd_time_t tv_sec; /* seconds */ + target_freebsd_suseconds_t tv_usec;/* and microseconds */ +} __packed; + +/* compare to sys/timex.h */ +struct target_freebsd_ntptimeval { + struct target_freebsd_timespec time; + abi_long maxerror; + abi_long esterror; + abi_long tai; + int32_t time_state; +}; + +struct target_freebsd_timex { + uint32_t modes; + abi_long offset; + abi_long freq; + abi_long maxerror; + abi_long esterror; + int32_t status; + abi_long constant; + abi_long precision; + abi_long tolerance; + + abi_long ppsfreq; + abi_long jitter; + int32_t shift; + abi_long stabil; + abi_long jitcnt; + abi_long calcnt; + abi_long errcnt; + abi_long stbcnt; +}; + +/* + * sys/event.h + */ +struct target_freebsd_kevent { + abi_ulong ident; + int16_t filter; + uint16_t flags; + uint32_t fflags; + abi_long data; + abi_ulong udata; +} __packed; + #endif /* ! _SYSCALL_DEFS_H_ */ -- 1.7.8