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:
parent
d107e37573
commit
6ac03b2cac
@ -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:
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user