xref: /freebsd/sys/compat/linux/linux_vdso_gtod.inc (revision a129642ced9e6ceacf98c7663bc1178eb32a78be)
19931033bSDmitry Chagin/*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
39931033bSDmitry Chagin *
49931033bSDmitry Chagin * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
59931033bSDmitry Chagin * Copyright (c) 2021 Dmitry Chagin <dchagin@FreeBSD.org>
69931033bSDmitry Chagin *
79931033bSDmitry Chagin * Redistribution and use in source and binary forms, with or without
89931033bSDmitry Chagin * modification, are permitted provided that the following conditions
99931033bSDmitry Chagin * are met:
109931033bSDmitry Chagin * 1. Redistributions of source code must retain the above copyright
119931033bSDmitry Chagin *    notice, this list of conditions and the following disclaimer.
129931033bSDmitry Chagin * 2. Redistributions in binary form must reproduce the above copyright
139931033bSDmitry Chagin *    notice, this list of conditions and the following disclaimer in the
149931033bSDmitry Chagin *    documentation and/or other materials provided with the distribution.
159931033bSDmitry Chagin *
169931033bSDmitry Chagin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
179931033bSDmitry Chagin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
189931033bSDmitry Chagin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199931033bSDmitry Chagin * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
209931033bSDmitry Chagin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
219931033bSDmitry Chagin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
229931033bSDmitry Chagin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
239931033bSDmitry Chagin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
249931033bSDmitry Chagin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
259931033bSDmitry Chagin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
269931033bSDmitry Chagin * SUCH DAMAGE.
279931033bSDmitry Chagin */
289931033bSDmitry Chagin
29*a129642cSDmitry Chagin#if defined(__aarch64__)
30*a129642cSDmitry Chagin#define	__VDSO_PREFIX		__kernel
31*a129642cSDmitry Chagin#else
32*a129642cSDmitry Chagin#define	__VDSO_PREFIX		__vdso
33*a129642cSDmitry Chagin#endif
34*a129642cSDmitry Chagin
35*a129642cSDmitry Chagin#define	__vdsoN(x)	__CONCAT(__CONCAT(__VDSO_PREFIX,_),x)
36*a129642cSDmitry Chagin
37f3379401SDmitry Chaginstatic int
38f3379401SDmitry Chaginfls(int mask)
39f3379401SDmitry Chagin{
40f3379401SDmitry Chagin
41f3379401SDmitry Chagin	if (mask == 0)
42f3379401SDmitry Chagin		return (0);
43f3379401SDmitry Chagin	return ((__builtin_clz(mask) ^ 0x1f) + 1);
44f3379401SDmitry Chagin}
45f3379401SDmitry Chagin
46f3379401SDmitry Chagin#ifdef _LP64
47f3379401SDmitry Chaginstatic int
48c6df2176SDmitry Chaginflsl(long mask)
49f3379401SDmitry Chagin{
50f3379401SDmitry Chagin	int bit;
51f3379401SDmitry Chagin
52f3379401SDmitry Chagin	if (mask == 0)
53f3379401SDmitry Chagin		return (0);
54c6df2176SDmitry Chagin	for (bit = 1; mask != 1; bit++)
55f3379401SDmitry Chagin		mask = (unsigned long)mask >> 1;
56f3379401SDmitry Chagin	return (bit);
57f3379401SDmitry Chagin}
58f3379401SDmitry Chagin#else
59f3379401SDmitry Chaginstatic int
60c6df2176SDmitry Chaginflsll(long long mask)
61f3379401SDmitry Chagin{
62f3379401SDmitry Chagin	int bit;
63f3379401SDmitry Chagin
64f3379401SDmitry Chagin	if (mask == 0)
65f3379401SDmitry Chagin		return (0);
66c6df2176SDmitry Chagin	for (bit = 1; mask != 1; bit++)
67f3379401SDmitry Chagin		mask = (unsigned long long)mask >> 1;
68f3379401SDmitry Chagin	return (bit);
69f3379401SDmitry Chagin}
70f3379401SDmitry Chagin#endif
719931033bSDmitry Chagin
729931033bSDmitry Chaginstatic int
739931033bSDmitry Chagin__vdso_native_to_linux_timespec(struct l_timespec *lts,
749931033bSDmitry Chagin    struct timespec *nts)
759931033bSDmitry Chagin{
769931033bSDmitry Chagin
779931033bSDmitry Chagin#ifdef COMPAT_LINUX32
789931033bSDmitry Chagin	if (nts->tv_sec > INT_MAX || nts->tv_sec < INT_MIN)
799931033bSDmitry Chagin		return (LINUX_EOVERFLOW);
809931033bSDmitry Chagin#endif
819931033bSDmitry Chagin	lts->tv_sec = nts->tv_sec;
829931033bSDmitry Chagin	lts->tv_nsec = nts->tv_nsec;
839931033bSDmitry Chagin	return (0);
849931033bSDmitry Chagin}
859931033bSDmitry Chagin
869931033bSDmitry Chaginstatic int
879931033bSDmitry Chagin__vdso_native_to_linux_timeval(l_timeval *ltv,
889931033bSDmitry Chagin    struct timeval *ntv)
899931033bSDmitry Chagin{
909931033bSDmitry Chagin
919931033bSDmitry Chagin#ifdef COMPAT_LINUX32
929931033bSDmitry Chagin	if (ntv->tv_sec > INT_MAX || ntv->tv_sec < INT_MIN)
939931033bSDmitry Chagin		return (LINUX_EOVERFLOW);
949931033bSDmitry Chagin#endif
959931033bSDmitry Chagin	ltv->tv_sec = ntv->tv_sec;
969931033bSDmitry Chagin	ltv->tv_usec = ntv->tv_usec;
979931033bSDmitry Chagin	return (0);
989931033bSDmitry Chagin}
999931033bSDmitry Chagin
1009931033bSDmitry Chagin
1019931033bSDmitry Chagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1029931033bSDmitry Chaginstatic int
1039931033bSDmitry Chagin__vdso_native_to_linux_timespec64(struct l_timespec64 *lts,
1049931033bSDmitry Chagin    struct timespec *nts)
1059931033bSDmitry Chagin{
1069931033bSDmitry Chagin
1079931033bSDmitry Chagin	lts->tv_sec = nts->tv_sec;
1089931033bSDmitry Chagin	lts->tv_nsec = nts->tv_nsec;
1099931033bSDmitry Chagin	return (0);
1109931033bSDmitry Chagin}
1119931033bSDmitry Chagin#endif
1129931033bSDmitry Chagin
1139931033bSDmitry Chaginstatic int
1149931033bSDmitry Chagin__vdso_linux_to_native_clockid(clockid_t *n, clockid_t l)
1159931033bSDmitry Chagin{
1169931033bSDmitry Chagin
1179931033bSDmitry Chagin	switch (l) {
1189931033bSDmitry Chagin	case LINUX_CLOCK_REALTIME:
1199931033bSDmitry Chagin		*n = CLOCK_REALTIME;
1209931033bSDmitry Chagin		break;
1219931033bSDmitry Chagin	case LINUX_CLOCK_MONOTONIC:
1229931033bSDmitry Chagin		*n = CLOCK_MONOTONIC;
1239931033bSDmitry Chagin		break;
1249931033bSDmitry Chagin	case LINUX_CLOCK_REALTIME_COARSE:
1259931033bSDmitry Chagin		*n = CLOCK_REALTIME_FAST;
1269931033bSDmitry Chagin		break;
1279931033bSDmitry Chagin	case LINUX_CLOCK_MONOTONIC_COARSE:
1289931033bSDmitry Chagin	case LINUX_CLOCK_MONOTONIC_RAW:
1299931033bSDmitry Chagin		*n = CLOCK_MONOTONIC_FAST;
1309931033bSDmitry Chagin		break;
1319931033bSDmitry Chagin	case LINUX_CLOCK_BOOTTIME:
1329931033bSDmitry Chagin		*n = CLOCK_UPTIME;
1339931033bSDmitry Chagin		break;
1349931033bSDmitry Chagin	default:
1359931033bSDmitry Chagin		return (LINUX_EINVAL);
1369931033bSDmitry Chagin	}
1379931033bSDmitry Chagin	return (0);
1389931033bSDmitry Chagin}
1399931033bSDmitry Chagin
1409931033bSDmitry Chagin/*
1419931033bSDmitry Chagin * The code below adapted from
1429931033bSDmitry Chagin * lib/libc/sys/__vdso_gettimeofday.c
1439931033bSDmitry Chagin */
1449931033bSDmitry Chagin
1459931033bSDmitry Chaginstatic inline void
1469931033bSDmitry Chagin__vdso_gettimekeep(struct vdso_timekeep **tk)
1479931033bSDmitry Chagin{
1489931033bSDmitry Chagin
1499931033bSDmitry Chagin	*tk = (struct vdso_timekeep *)kern_timekeep_base;
1509931033bSDmitry Chagin}
1519931033bSDmitry Chagin
1529931033bSDmitry Chaginstatic int
1539931033bSDmitry Chagintc_delta(const struct vdso_timehands *th, u_int *delta)
1549931033bSDmitry Chagin{
1559931033bSDmitry Chagin	int error;
1569931033bSDmitry Chagin	u_int tc;
1579931033bSDmitry Chagin
1589931033bSDmitry Chagin	error = __vdso_gettc(th, &tc);
1599931033bSDmitry Chagin	if (error == 0)
1609931033bSDmitry Chagin		*delta = (tc - th->th_offset_count) & th->th_counter_mask;
1619931033bSDmitry Chagin	return (error);
1629931033bSDmitry Chagin}
1639931033bSDmitry Chagin
1649931033bSDmitry Chagin/*
1659931033bSDmitry Chagin * Calculate the absolute or boot-relative time from the
1669931033bSDmitry Chagin * machine-specific fast timecounter and the published timehands
1679931033bSDmitry Chagin * structure read from the shared page.
1689931033bSDmitry Chagin *
1699931033bSDmitry Chagin * The lockless reading scheme is similar to the one used to read the
1709931033bSDmitry Chagin * in-kernel timehands, see sys/kern/kern_tc.c:binuptime().  This code
1719931033bSDmitry Chagin * is based on the kernel implementation.
1729931033bSDmitry Chagin */
1739931033bSDmitry Chaginstatic int
1749931033bSDmitry Chaginfreebsd_binuptime(struct bintime *bt, struct vdso_timekeep *tk, bool abs)
1759931033bSDmitry Chagin{
1769931033bSDmitry Chagin	struct vdso_timehands *th;
1779931033bSDmitry Chagin	uint32_t curr, gen;
1789931033bSDmitry Chagin	uint64_t scale, x;
1799931033bSDmitry Chagin	u_int delta, scale_bits;
1809931033bSDmitry Chagin	int error;
1819931033bSDmitry Chagin
1829931033bSDmitry Chagin	do {
1839931033bSDmitry Chagin		if (!tk->tk_enabled)
1849931033bSDmitry Chagin			return (ENOSYS);
1859931033bSDmitry Chagin
1869931033bSDmitry Chagin		curr = atomic_load_acq_32(&tk->tk_current);
1879931033bSDmitry Chagin		th = &tk->tk_th[curr];
1889931033bSDmitry Chagin		gen = atomic_load_acq_32(&th->th_gen);
1899931033bSDmitry Chagin		*bt = th->th_offset;
1909931033bSDmitry Chagin		error = tc_delta(th, &delta);
1919931033bSDmitry Chagin		if (error == EAGAIN)
1929931033bSDmitry Chagin			continue;
1939931033bSDmitry Chagin		if (error != 0)
1949931033bSDmitry Chagin			return (error);
1959931033bSDmitry Chagin		scale = th->th_scale;
1969931033bSDmitry Chagin#ifdef _LP64
197c6df2176SDmitry Chagin		scale_bits = flsl(scale);
1989931033bSDmitry Chagin#else
199c6df2176SDmitry Chagin		scale_bits = flsll(scale);
2009931033bSDmitry Chagin#endif
2019931033bSDmitry Chagin		if (__predict_false(scale_bits + fls(delta) > 63)) {
2029931033bSDmitry Chagin			x = (scale >> 32) * delta;
2039931033bSDmitry Chagin			scale &= 0xffffffff;
2049931033bSDmitry Chagin			bt->sec += x >> 32;
2059931033bSDmitry Chagin			bintime_addx(bt, x << 32);
2069931033bSDmitry Chagin		}
2079931033bSDmitry Chagin		bintime_addx(bt, scale * delta);
2089931033bSDmitry Chagin		if (abs)
2099931033bSDmitry Chagin			bintime_add(bt, &th->th_boottime);
2109931033bSDmitry Chagin
2119931033bSDmitry Chagin		/*
2129931033bSDmitry Chagin		 * Ensure that the load of th_offset is completed
2139931033bSDmitry Chagin		 * before the load of th_gen.
2149931033bSDmitry Chagin		 */
2159931033bSDmitry Chagin		atomic_thread_fence_acq();
2169931033bSDmitry Chagin	} while (curr != tk->tk_current || gen == 0 || gen != th->th_gen);
2179931033bSDmitry Chagin	return (0);
2189931033bSDmitry Chagin}
2199931033bSDmitry Chagin
2209931033bSDmitry Chaginstatic int
2219931033bSDmitry Chaginfreebsd_getnanouptime(struct bintime *bt, struct vdso_timekeep *tk)
2229931033bSDmitry Chagin{
2239931033bSDmitry Chagin	struct vdso_timehands *th;
2249931033bSDmitry Chagin	uint32_t curr, gen;
2259931033bSDmitry Chagin
2269931033bSDmitry Chagin	do {
2279931033bSDmitry Chagin		if (!tk->tk_enabled)
2289931033bSDmitry Chagin			return (ENOSYS);
2299931033bSDmitry Chagin
2309931033bSDmitry Chagin		curr = atomic_load_acq_32(&tk->tk_current);
2319931033bSDmitry Chagin		th = &tk->tk_th[curr];
2329931033bSDmitry Chagin		gen = atomic_load_acq_32(&th->th_gen);
2339931033bSDmitry Chagin		*bt = th->th_offset;
2349931033bSDmitry Chagin
2359931033bSDmitry Chagin		/*
2369931033bSDmitry Chagin		 * Ensure that the load of th_offset is completed
2379931033bSDmitry Chagin		 * before the load of th_gen.
2389931033bSDmitry Chagin		 */
2399931033bSDmitry Chagin		atomic_thread_fence_acq();
2409931033bSDmitry Chagin	} while (curr != tk->tk_current || gen == 0 || gen != th->th_gen);
2419931033bSDmitry Chagin	return (0);
2429931033bSDmitry Chagin}
2439931033bSDmitry Chagin
2449931033bSDmitry Chaginstatic int
2459931033bSDmitry Chaginfreebsd_gettimeofday(struct timeval *tv, struct timezone *tz)
2469931033bSDmitry Chagin{
2479931033bSDmitry Chagin	struct vdso_timekeep *tk;
2489931033bSDmitry Chagin	struct bintime bt;
2499931033bSDmitry Chagin	int error;
2509931033bSDmitry Chagin
2519931033bSDmitry Chagin	if (tz != NULL)
2529931033bSDmitry Chagin		return (ENOSYS);
2539931033bSDmitry Chagin	__vdso_gettimekeep(&tk);
2549931033bSDmitry Chagin	if (tk == NULL)
2559931033bSDmitry Chagin		return (ENOSYS);
2569931033bSDmitry Chagin	if (tk->tk_ver != VDSO_TK_VER_CURR)
2579931033bSDmitry Chagin		return (ENOSYS);
2589931033bSDmitry Chagin	error = freebsd_binuptime(&bt, tk, true);
2599931033bSDmitry Chagin	if (error == 0)
2609931033bSDmitry Chagin		bintime2timeval(&bt, tv);
2619931033bSDmitry Chagin	return (error);
2629931033bSDmitry Chagin}
2639931033bSDmitry Chagin
2649931033bSDmitry Chaginstatic int
2659931033bSDmitry Chaginfreebsd_clock_gettime(clockid_t clock_id, struct timespec *ts)
2669931033bSDmitry Chagin{
2679931033bSDmitry Chagin	struct vdso_timekeep *tk;
2689931033bSDmitry Chagin	struct bintime bt;
2699931033bSDmitry Chagin	int error;
2709931033bSDmitry Chagin
2719931033bSDmitry Chagin	__vdso_gettimekeep(&tk);
2729931033bSDmitry Chagin	if (tk == NULL)
2739931033bSDmitry Chagin		return (ENOSYS);
2749931033bSDmitry Chagin	if (tk->tk_ver != VDSO_TK_VER_CURR)
2759931033bSDmitry Chagin		return (ENOSYS);
2769931033bSDmitry Chagin	switch (clock_id) {
2779931033bSDmitry Chagin	case CLOCK_REALTIME:
2789931033bSDmitry Chagin	case CLOCK_REALTIME_PRECISE:
2799931033bSDmitry Chagin	case CLOCK_REALTIME_FAST:
2809931033bSDmitry Chagin		error = freebsd_binuptime(&bt, tk, true);
2819931033bSDmitry Chagin		break;
2829931033bSDmitry Chagin	case CLOCK_MONOTONIC:
2839931033bSDmitry Chagin	case CLOCK_MONOTONIC_PRECISE:
2849931033bSDmitry Chagin	case CLOCK_UPTIME:
2859931033bSDmitry Chagin	case CLOCK_UPTIME_PRECISE:
2869931033bSDmitry Chagin		error = freebsd_binuptime(&bt, tk, false);
2879931033bSDmitry Chagin		break;
2889931033bSDmitry Chagin	case CLOCK_MONOTONIC_FAST:
2899931033bSDmitry Chagin	case CLOCK_UPTIME_FAST:
2909931033bSDmitry Chagin		error = freebsd_getnanouptime(&bt, tk);
2919931033bSDmitry Chagin		break;
2929931033bSDmitry Chagin	default:
2939931033bSDmitry Chagin		error = ENOSYS;
2949931033bSDmitry Chagin		break;
2959931033bSDmitry Chagin	}
2969931033bSDmitry Chagin	if (error == 0)
2979931033bSDmitry Chagin		bintime2timespec(&bt, ts);
2989931033bSDmitry Chagin	return (error);
2999931033bSDmitry Chagin}
3009931033bSDmitry Chagin
3019931033bSDmitry Chagin/*
3029931033bSDmitry Chagin * Linux vDSO interfaces
3039931033bSDmitry Chagin *
3049931033bSDmitry Chagin */
3059931033bSDmitry Chaginint
306*a129642cSDmitry Chagin__vdsoN(clock_gettime)(clockid_t clock_id, struct l_timespec *lts)
3079931033bSDmitry Chagin{
3089931033bSDmitry Chagin	struct timespec ts;
3099931033bSDmitry Chagin	clockid_t which;
3109931033bSDmitry Chagin	int error;
3119931033bSDmitry Chagin
3129931033bSDmitry Chagin	error = __vdso_linux_to_native_clockid(&which, clock_id);
3139931033bSDmitry Chagin	if (error != 0)
3149931033bSDmitry Chagin		return (__vdso_clock_gettime_fallback(clock_id, lts));
3159931033bSDmitry Chagin	error = freebsd_clock_gettime(which, &ts);
3169931033bSDmitry Chagin	if (error == 0)
3179931033bSDmitry Chagin		return (-__vdso_native_to_linux_timespec(lts, &ts));
3189931033bSDmitry Chagin	else
3199931033bSDmitry Chagin		return (__vdso_clock_gettime_fallback(clock_id, lts));
3209931033bSDmitry Chagin}
3219931033bSDmitry Chagin
3229931033bSDmitry Chaginint
323*a129642cSDmitry Chagin__vdsoN(gettimeofday)(l_timeval *ltv, struct timezone *tz)
3249931033bSDmitry Chagin{
3259931033bSDmitry Chagin	struct timeval tv;
3269931033bSDmitry Chagin	int error;
3279931033bSDmitry Chagin
3289931033bSDmitry Chagin	error = freebsd_gettimeofday(&tv, tz);
3299931033bSDmitry Chagin	if (error != 0)
3309931033bSDmitry Chagin		return (__vdso_gettimeofday_fallback(ltv, tz));
3319931033bSDmitry Chagin	return (-__vdso_native_to_linux_timeval(ltv, &tv));
3329931033bSDmitry Chagin}
3339931033bSDmitry Chagin
3349931033bSDmitry Chaginint
335*a129642cSDmitry Chagin__vdsoN(clock_getres)(clockid_t clock_id, struct l_timespec *lts)
3369931033bSDmitry Chagin{
3379931033bSDmitry Chagin
3389931033bSDmitry Chagin	return (__vdso_clock_getres_fallback(clock_id, lts));
3399931033bSDmitry Chagin}
3409931033bSDmitry Chagin
3419931033bSDmitry Chagin#if defined(__i386__) || defined(COMPAT_LINUX32)
3429931033bSDmitry Chaginint
3439931033bSDmitry Chagin__vdso_clock_gettime64(clockid_t clock_id, struct l_timespec64 *lts)
3449931033bSDmitry Chagin{
3459931033bSDmitry Chagin	struct timespec ts;
3469931033bSDmitry Chagin	clockid_t which;
3479931033bSDmitry Chagin	int error;
3489931033bSDmitry Chagin
3499931033bSDmitry Chagin	error = __vdso_linux_to_native_clockid(&which, clock_id);
3509931033bSDmitry Chagin	if (error != 0)
3519931033bSDmitry Chagin		return (__vdso_clock_gettime64_fallback(clock_id, lts));
3529931033bSDmitry Chagin	error = freebsd_clock_gettime(which, &ts);
3539931033bSDmitry Chagin	if (error == 0)
3549931033bSDmitry Chagin		return(-__vdso_native_to_linux_timespec64(lts, &ts));
3559931033bSDmitry Chagin	else
3569931033bSDmitry Chagin		return(__vdso_clock_gettime64_fallback(clock_id, lts));
3579931033bSDmitry Chagin}
3589931033bSDmitry Chagin
3599931033bSDmitry Chaginint clock_gettime64(clockid_t clock_id, struct l_timespec64 *lts)
3609931033bSDmitry Chagin    __attribute__((weak, alias("__vdso_clock_gettime64")));
3619931033bSDmitry Chagin#endif
3629931033bSDmitry Chagin
3635a6a4fb2SDmitry Chagin#if defined(__i386__) || defined(__amd64__)
3649931033bSDmitry Chaginint
3659931033bSDmitry Chagin__vdso_getcpu(uint32_t *cpu, uint32_t *node, void *cache)
3669931033bSDmitry Chagin{
3675a6a4fb2SDmitry Chagin	int ret;
3689931033bSDmitry Chagin
3695a6a4fb2SDmitry Chagin	if (node != NULL)
3709931033bSDmitry Chagin		return (__vdso_getcpu_fallback(cpu, node, cache));
3715a6a4fb2SDmitry Chagin	ret = __vdso_getcpu_try();
3725a6a4fb2SDmitry Chagin	if (ret < 0)
3735a6a4fb2SDmitry Chagin		return (__vdso_getcpu_fallback(cpu, node, cache));
3745a6a4fb2SDmitry Chagin	*cpu = ret;
3755a6a4fb2SDmitry Chagin	return (0);
3769931033bSDmitry Chagin}
3779931033bSDmitry Chagin#endif
3789931033bSDmitry Chagin
3799931033bSDmitry Chagin#if defined(__i386__) || defined(__amd64__)
3809931033bSDmitry Chaginint
3819931033bSDmitry Chagin__vdso_time(long *tm)
3829931033bSDmitry Chagin{
38342317e64SDmitry Chagin	struct timeval tv;
38442317e64SDmitry Chagin	int error;
3859931033bSDmitry Chagin
38642317e64SDmitry Chagin	error = freebsd_gettimeofday(&tv, NULL);
38742317e64SDmitry Chagin	if (error != 0)
3889931033bSDmitry Chagin		return (__vdso_time_fallback(tm));
38942317e64SDmitry Chagin	if (tm != NULL)
39042317e64SDmitry Chagin		*tm = tv.tv_sec;
39142317e64SDmitry Chagin	return (tv.tv_sec);
3929931033bSDmitry Chagin}
3939931033bSDmitry Chagin#endif
394