Add the first part of FreeBSD time support: nanosleep, clock_nanosleep, clock_gettime, clock_settime, clock_getres, gettimeofday, settimeofday, adjtime, ntp_adjtime, and ntp_gettime. Also add safe_syscall wrappers for nanosleep, clock_nanosleep, and kevent.
Signed-off-by: Stacey Son <[email protected]> Signed-off-by: Mikaƫl Urankar <[email protected]> Signed-off-by: Sean Bruno <[email protected]> Signed-off-by: Kyle Evans <[email protected]> Signed-off-by: Warner Losh <[email protected]> Assisted-by: Claude Opus 4.6 (1M context) --- bsd-user/freebsd/os-syscall.c | 9 ++ bsd-user/freebsd/os-time.h | 221 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 5d3a66e360..6fbd2da261 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -89,6 +89,15 @@ safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, int, safe_syscall3(ssize_t, recvmsg, int, s, struct msghdr *, msg, int, flags); safe_syscall3(ssize_t, sendmsg, int, s, const struct msghdr *, msg, int, flags); +/* used in os-time */ +safe_syscall2(int, nanosleep, const struct timespec *, rqtp, struct timespec *, + rmtp); +safe_syscall4(int, clock_nanosleep, clockid_t, clock_id, int, flags, + const struct timespec *, rqtp, struct timespec *, rmtp); +safe_syscall6(int, kevent, int, kq, const struct kevent *, changelist, + int, nchanges, struct kevent *, eventlist, int, nevents, + const struct timespec *, timeout); + /* used in os-proc */ safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options, struct rusage *, rusage); diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h new file mode 100644 index 0000000000..16b71e6234 --- /dev/null +++ b/bsd-user/freebsd/os-time.h @@ -0,0 +1,221 @@ +/* + * FreeBSD time related system call shims + * + * Copyright (c) 2013-2015 Stacey Son + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef FREEBSD_OS_TIME_H +#define FREEBSD_OS_TIME_H + +#include <sys/types.h> +#include <sys/event.h> +#include <sys/select.h> +#include <sys/timex.h> +#include <poll.h> +#include <signal.h> +#include <time.h> + +#include "qemu.h" +#include "qemu-os.h" + +#include "bsd-socket.h" + +int safe_clock_nanosleep(clockid_t clock_id, int flags, + const struct timespec *rqtp, struct timespec *rmtp); +int safe_nanosleep(const struct timespec *rqtp, struct timespec *rmtp); +int safe_kevent(int, const struct kevent *, int, struct kevent *, int, + const struct timespec *); + +int __sys_ktimer_create(clockid_t, struct sigevent *restrict, + int *restrict); +int __sys_ktimer_gettime(int, struct itimerspec *); +int __sys_ktimer_settime(int, int, const struct itimerspec *restrict, + struct itimerspec *restrict); +int __sys_ktimer_delete(int); + +/* 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(safe_nanosleep(&req, &rem)); + if (ret == -TARGET_EINTR && arg2) { + ret = h2t_freebsd_timespec(arg2, &rem); + } + } + + return ret; +} + +/* clock_nanosleep(2) */ +static inline abi_long do_freebsd_clock_nanosleep(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + struct timespec req, rem; + abi_long ret; + int clkid, flags; + + clkid = arg1; + /* XXX Translate? */ + flags = arg2; + ret = t2h_freebsd_timespec(&req, arg3); + if (!is_error(ret)) { + ret = get_errno(safe_clock_nanosleep(clkid, flags, &req, &rem)); + if (ret == -TARGET_EINTR && arg4) { + h2t_freebsd_timespec(arg4, &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_ulong arg1, abi_ulong 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 inline 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 inline 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 (!is_error(ret)) { + ret = h2t_freebsd_ntptimeval(target_ntv_addr, &host_ntv); + } + + return ret; +} + + + +#endif /* FREEBSD_OS_TIME_H */ -- 2.52.0
