linux-user: Add support for 'clock_nanosleep_time64()' and 'clock_adjtime64()'

This patch implements functionality for following time64 syscall:

*clock_nanosleep_time64()

    This is a year 2038 safe vairant of syscall:
    int clock_nanosleep(clockid_t clockid, int flags,
                        const struct timespec *request,
                        struct timespec *remain)
    --high-resolution sleep with specifiable clock--
    man page: https://man7.org/linux/man-pages/man2/clock_nanosleep.2.html

*clock_adjtime64()

    This is a year 2038 safe variant of syscall:
    int clock_adjtime(clockid_t clk_id, struct timex *buf)
    --tune kernel clock--
    man page: https://man7.org/linux/man-pages/man2/clock_adjtime.2.html

Implementation notes:

    Syscall 'clock_nanosleep_time64()' was implemented similarly
    to syscall 'clock_nanosleep()' except that 'host_to_target_timespec64()'
    and 'target_to_host_timespec64()' were used instead of the regular
    'host_to_target_timespec()' and 'target_to_host_timespec()'.

    For 'clock_adjtime64()' a 64-bit target kernel version of 'struct timex'
    was defined in 'syscall_defs.h': 'struct target__kernel_timex'.
    This type was used to convert the values of 64-bit timex type between
    host and target. For this purpose a 64-bit timex converting functions
    'target_to_host_timex64()' and 'host_to_target_timex64()'. An existing
    function 'copy_to_user_timeval64()' was used to convert the field
    'time' which if of type 'struct timeval' from host to target.
    Function 'copy_from_user_timveal64()' was added in this patch and
    used to convert the 'time' field from target to host.

Signed-off-by: Filip Bozuta <Filip.Bozuta@syrmia.com>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <20200824192116.65562-2-Filip.Bozuta@syrmia.com>
[lv: add missing ifdef's]
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
Filip Bozuta 2020-08-24 21:21:15 +02:00 committed by Laurent Vivier
parent d107e37573
commit 6ac03b2cac
2 changed files with 170 additions and 3 deletions

View File

@ -774,7 +774,8 @@ safe_syscall4(int, accept4, int, fd, struct sockaddr *, addr, socklen_t *, len,
safe_syscall2(int, nanosleep, const struct timespec *, req,
struct timespec *, rem)
#endif
#ifdef TARGET_NR_clock_nanosleep
#if defined(TARGET_NR_clock_nanosleep) || \
defined(TARGET_NR_clock_nanosleep_time64)
safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
const struct timespec *, req, struct timespec *, rem)
#endif
@ -1177,8 +1178,27 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
return 0;
}
#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME)
static inline abi_long copy_from_user_timeval64(struct timeval *tv,
abi_ulong target_tv_addr)
{
struct target__kernel_sock_timeval *target_tv;
if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) {
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, 0);
return 0;
}
#endif
static inline abi_long copy_to_user_timeval64(abi_ulong target_tv_addr,
const struct timeval *tv)
const struct timeval *tv)
{
struct target__kernel_sock_timeval *target_tv;
@ -1222,7 +1242,8 @@ static inline abi_long target_to_host_timespec(struct timespec *host_ts,
defined(TARGET_NR_timer_settime64) || \
defined(TARGET_NR_mq_timedsend_time64) || \
defined(TARGET_NR_mq_timedreceive_time64) || \
(defined(TARGET_NR_timerfd_settime64) && defined(CONFIG_TIMERFD))
(defined(TARGET_NR_timerfd_settime64) && defined(CONFIG_TIMERFD)) || \
defined(TARGET_NR_clock_nanosleep_time64)
static inline abi_long target_to_host_timespec64(struct timespec *host_ts,
abi_ulong target_addr)
{
@ -6953,6 +6974,87 @@ static inline abi_long host_to_target_timex(abi_long target_addr,
}
#endif
#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME)
static inline abi_long target_to_host_timex64(struct timex *host_tx,
abi_long target_addr)
{
struct target__kernel_timex *target_tx;
if (copy_from_user_timeval64(&host_tx->time, target_addr +
offsetof(struct target__kernel_timex,
time))) {
return -TARGET_EFAULT;
}
if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) {
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->tolerance, &target_tx->tolerance);
__get_user(host_tx->tick, &target_tx->tick);
__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);
__get_user(host_tx->tai, &target_tx->tai);
unlock_user_struct(target_tx, target_addr, 0);
return 0;
}
static inline abi_long host_to_target_timex64(abi_long target_addr,
struct timex *host_tx)
{
struct target__kernel_timex *target_tx;
if (copy_to_user_timeval64(target_addr +
offsetof(struct target__kernel_timex, time),
&host_tx->time)) {
return -TARGET_EFAULT;
}
if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) {
return -TARGET_EFAULT;
}
__put_user(host_tx->modes, &target_tx->modes);
__put_user(host_tx->offset, &target_tx->offset);
__put_user(host_tx->freq, &target_tx->freq);
__put_user(host_tx->maxerror, &target_tx->maxerror);
__put_user(host_tx->esterror, &target_tx->esterror);
__put_user(host_tx->status, &target_tx->status);
__put_user(host_tx->constant, &target_tx->constant);
__put_user(host_tx->precision, &target_tx->precision);
__put_user(host_tx->tolerance, &target_tx->tolerance);
__put_user(host_tx->tick, &target_tx->tick);
__put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
__put_user(host_tx->jitter, &target_tx->jitter);
__put_user(host_tx->shift, &target_tx->shift);
__put_user(host_tx->stabil, &target_tx->stabil);
__put_user(host_tx->jitcnt, &target_tx->jitcnt);
__put_user(host_tx->calcnt, &target_tx->calcnt);
__put_user(host_tx->errcnt, &target_tx->errcnt);
__put_user(host_tx->stbcnt, &target_tx->stbcnt);
__put_user(host_tx->tai, &target_tx->tai);
unlock_user_struct(target_tx, target_addr, 1);
return 0;
}
#endif
static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp,
abi_ulong target_addr)
{
@ -9940,6 +10042,21 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
}
}
return ret;
#endif
#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME)
case TARGET_NR_clock_adjtime64:
{
struct timex htx;
if (target_to_host_timex64(&htx, arg2) != 0) {
return -TARGET_EFAULT;
}
ret = get_errno(clock_adjtime(arg1, &htx));
if (!is_error(ret) && host_to_target_timex64(arg2, &htx)) {
return -TARGET_EFAULT;
}
}
return ret;
#endif
case TARGET_NR_getpgid:
return get_errno(getpgid(arg1));
@ -11911,6 +12028,25 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return ret;
}
#endif
#ifdef TARGET_NR_clock_nanosleep_time64
case TARGET_NR_clock_nanosleep_time64:
{
struct timespec ts;
if (target_to_host_timespec64(&ts, arg3)) {
return -TARGET_EFAULT;
}
ret = get_errno(safe_clock_nanosleep(arg1, arg2,
&ts, arg4 ? &ts : NULL));
if (ret == -TARGET_EINTR && arg4 && arg2 != TIMER_ABSTIME &&
host_to_target_timespec64(arg4, &ts)) {
return -TARGET_EFAULT;
}
return ret;
}
#endif
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
case TARGET_NR_set_tid_address:

View File

@ -294,6 +294,37 @@ struct target_timex {
abi_int:32; abi_int:32; abi_int:32;
};
struct target__kernel_timex {
abi_uint modes; /* Mode selector */
abi_int: 32; /* pad */
abi_llong offset; /* Time offset */
abi_llong freq; /* Frequency offset */
abi_llong maxerror; /* Maximum error (microseconds) */
abi_llong esterror; /* Estimated error (microseconds) */
abi_int status; /* Clock command/status */
abi_int: 32; /* pad */
abi_llong constant; /* PLL (phase-locked loop) time constant */
abi_llong precision; /* Clock precision (microseconds, ro) */
abi_llong tolerance; /* Clock freq. tolerance (ppm, ro) */
struct target__kernel_sock_timeval time; /* Current time */
abi_llong tick; /* Microseconds between clock ticks */
abi_llong ppsfreq; /* PPS (pulse per second) frequency */
abi_llong jitter; /* PPS jitter (ro); nanoseconds */
abi_int shift; /* PPS interval duration (seconds) */
abi_int: 32; /* pad */
abi_llong stabil; /* PPS stability */
abi_llong jitcnt; /* PPS jitter limit exceeded (ro) */
abi_llong calcnt; /* PPS calibration intervals */
abi_llong errcnt; /* PPS calibration errors */
abi_llong stbcnt; /* PPS stability limit exceeded */
abi_int tai; /* TAI offset */
/* Further padding bytes to allow for future expansion */
abi_int:32; abi_int:32; abi_int:32; abi_int:32;
abi_int:32; abi_int:32; abi_int:32; abi_int:32;
abi_int:32; abi_int:32; abi_int:32;
};
typedef abi_long target_clock_t;
#define TARGET_HZ 100