userland clock_gettime proof of concept

classic Classic list List threaded Threaded
203 messages Options
12345678 ... 11
Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Mark Kettenis
> Date: Fri, 5 Jun 2020 01:33:16 +0300
> From: Paul Irofti <[hidden email]>
>
> On Wed, Jun 03, 2020 at 05:13:42PM +0300, Paul Irofti wrote:
> > On 2020-05-31 20:46, Mark Kettenis wrote:
> > > Forget about all that for a moment.  Here is an alternative suggestion:
> > >
> > > On sparc64 we need to support both tick_timecounter and
> > > sys_tick_timecounter.  So we need some sort of clockid value to
> > > distnguish between those two.  I already suggested to use the tc_user
> > > field of the timecounter for that.  0 means that a timecounter is not
> > > usable in userland, a (small) positive integer means a specific
> > > timecounter type.  The code in libc will need to know whether a
> > > particular timecounter type can be supported.  My proposal would be to
> > > implement a function*on all architecture*  that takes the clockid as
> > > an argument and returns a pointer to the function that implements
> > > support for that timecounter.  On architectures without support, ir
> > > when called with a clockid that isn't supported, that function would
> > > simply return NULL.
> >
> > I am sorry, but the more I try to implement this in a sane way, the more
> > obvious it is that it is not possible. I would rather have a define sausage
> > than something like this.
> >
> > I will try to think of something else that avoids the defines, but I do not
> > think that your proposal is a valid solution.
>
> OK. I think I found an elegant way around this using the Makefile
> system: if usertc.c is not present in the arch/${MACHINE}/gen, then a
> stub gen/usertc.c file is built that just sets the function pointer to
> NULL. This avoids the need for the define checks in dlfcn/init.c and I
> think fixes the rest of the issues discussed around this bit.
>
> Also included in the diff are a few other fixes and regression tests.
> I left the rdtsc and acpihpet example (with no functional acpihpet
> support) just to show-case how we can handle multiple clocks on
> architectures that have them.

You're still using tk_user unconditionally.  If the kernel returns a
tk_user value that is larger than what's supported by libc you have an
out-of-bounds array access.

Also if the machine switches to a timecounter that has tk_user == 0
you have an out-of-bounds array access.  If that happens you need to
detect this and fall back on the system call.

> I could not add support for other architectures as I still do not have
> access to my machines.

arm64 can be done; I'm waiting with sparc64 until you have worked out
how to handle the multiple clocks properly...

> Is the Makefile approach good enough?

Not sure.  Others should judge that.

> diff --git lib/libc/arch/amd64/gen/Makefile.inc lib/libc/arch/amd64/gen/Makefile.inc
> index e995309ed71..f6349e2b974 100644
> --- lib/libc/arch/amd64/gen/Makefile.inc
> +++ lib/libc/arch/amd64/gen/Makefile.inc
> @@ -2,6 +2,7 @@
>  
>  SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.S nan.c setjmp.S \
>   sigsetjmp.S
> -SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
> +SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c \
> + usertc.c
>  SRCS+= flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S \
>   fpsetround.S fpsetsticky.S
> diff --git lib/libc/arch/amd64/gen/usertc.c lib/libc/arch/amd64/gen/usertc.c
> new file mode 100644
> index 00000000000..cec1b484865
> --- /dev/null
> +++ lib/libc/arch/amd64/gen/usertc.c
> @@ -0,0 +1,46 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +static uint64_t
> +rdtsc()
> +{
> + uint32_t hi, lo;
> + asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
> + return ((uint64_t)lo)|(((uint64_t)hi)<<32);
> +}
> +
> +static uint64_t
> +acpihpet()
> +{
> + return rdtsc(); /* JUST TO COMPILE */
> +}
> +
> +static uint64_t (*get_tc[])(void) =
> +{
> + rdtsc,
> + acpihpet,
> +};
> +
> +uint64_t
> +tc_get_timecount(struct timekeep *tk)
> +{
> + return (*get_tc[tk->tk_user - 1])();
> +}
> +uint64_t (*const _tc_get_timecount)(struct timekeep *tk) = tc_get_timecount;
> diff --git lib/libc/asr/asr.c lib/libc/asr/asr.c
> index cd056c85719..2b25d49f32a 100644
> --- lib/libc/asr/asr.c
> +++ lib/libc/asr/asr.c
> @@ -196,11 +196,11 @@ poll_intrsafe(struct pollfd *fds, nfds_t nfds, int timeout)
>   struct timespec pollstart, pollend, elapsed;
>   int r;
>  
> - if (clock_gettime(CLOCK_MONOTONIC, &pollstart))
> + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollstart))
>   return -1;
>  
>   while ((r = poll(fds, 1, timeout)) == -1 && errno == EINTR) {
> - if (clock_gettime(CLOCK_MONOTONIC, &pollend))
> + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollend))
>   return -1;
>   timespecsub(&pollend, &pollstart, &elapsed);
>   timeout -= elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000;
> @@ -418,7 +418,7 @@ asr_check_reload(struct asr *asr)
>   asr->a_rtime = 0;
>   }
>  
> - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
> + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1)
>   return;
>  
>   if ((ts.tv_sec - asr->a_rtime) < RELOAD_DELAY && asr->a_rtime != 0)
> diff --git lib/libc/crypt/bcrypt.c lib/libc/crypt/bcrypt.c
> index 82de8fa33b7..02fd3013cc1 100644
> --- lib/libc/crypt/bcrypt.c
> +++ lib/libc/crypt/bcrypt.c
> @@ -248,9 +248,9 @@ _bcrypt_autorounds(void)
>   char buf[_PASSWORD_LEN];
>   int duration;
>  
> - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &before);
> + WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &before);
>   bcrypt_newhash("testpassword", r, buf, sizeof(buf));
> - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &after);
> + WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &after);
>  
>   duration = after.tv_sec - before.tv_sec;
>   duration *= 1000000;
> diff --git lib/libc/dlfcn/init.c lib/libc/dlfcn/init.c
> index 270f54aada5..19d0a2c3ad6 100644
> --- lib/libc/dlfcn/init.c
> +++ lib/libc/dlfcn/init.c
> @@ -20,6 +20,7 @@
>  
>  #include <sys/types.h>
>  #include <sys/syscall.h>
> +#include <sys/timetc.h> /* timekeep */
>  
>  #ifndef PIC
>  #include <sys/mman.h>
> @@ -45,8 +46,9 @@
>  /* XXX should be in an include file shared with csu */
>  char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void));
>  
> -/* provide definition for this */
> +/* provide definitions for these */
>  int _pagesize = 0;
> +void *_timekeep = NULL;
>  
>  /*
>   * In dynamicly linked binaries environ and __progname are overriden by
> @@ -105,6 +107,10 @@ _libc_preinit(int argc, char **argv, char **envp, dl_cb_cb *cb)
>   phnum = aux->au_v;
>   break;
>  #endif /* !PIC */
> + case AUX_openbsd_timekeep:
> + if (_tc_get_timecount)
> + _timekeep = (void *)aux->au_v;
> + break;
>   }
>   }
>  
> diff --git lib/libc/gen/Makefile.inc lib/libc/gen/Makefile.inc
> index cf36ead40e9..da52d9fbb13 100644
> --- lib/libc/gen/Makefile.inc
> +++ lib/libc/gen/Makefile.inc
> @@ -27,6 +27,10 @@ SRCS+=  alarm.c assert.c auth_subr.c authenticate.c \
>          utime.c valloc.c vis.c wait.c wait3.c waitpid.c warn.c \
>          warnc.c warnx.c vwarn.c vwarnc.c vwarnx.c verr.c verrc.c verrx.c
>  
> +.if !exists (${LIBCSRCDIR}/arch/${MACHINE_CPU}/gen/usertc.c)
> +SRCS+=  usertc.c
> +.endif
> +
>  # machine-dependent gen sources
>  # m-d Makefile.inc must include sources for:
>  # _setjmp() fabs() frexp() infinity ldexp() modf() __nan
> diff --git lib/libc/gen/auth_subr.c lib/libc/gen/auth_subr.c
> index 1286a96fe40..32f86eda50f 100644
> --- lib/libc/gen/auth_subr.c
> +++ lib/libc/gen/auth_subr.c
> @@ -752,7 +752,7 @@ auth_check_expire(auth_session_t *as)
>  
>   if (as->pwd && (quad_t)as->pwd->pw_expire != 0) {
>   if (as->now.tv_sec == 0)
> - gettimeofday(&as->now, NULL);
> + WRAP(gettimeofday)(&as->now, NULL);
>   if ((quad_t)as->now.tv_sec >= (quad_t)as->pwd->pw_expire) {
>   as->state &= ~AUTH_ALLOW;
>   as->state |= AUTH_EXPIRED;
> @@ -779,7 +779,7 @@ auth_check_change(auth_session_t *as)
>  
>   if (as->pwd && (quad_t)as->pwd->pw_change) {
>   if (as->now.tv_sec == 0)
> - gettimeofday(&as->now, NULL);
> + WRAP(gettimeofday)(&as->now, NULL);
>   if (as->now.tv_sec >= (quad_t)as->pwd->pw_change) {
>   as->state &= ~AUTH_ALLOW;
>   as->state |= AUTH_PWEXPIRED;
> diff --git lib/libc/gen/time.c lib/libc/gen/time.c
> index 3bbd0d733d1..b3ce9a800f1 100644
> --- lib/libc/gen/time.c
> +++ lib/libc/gen/time.c
> @@ -36,7 +36,7 @@ time(time_t *t)
>  {
>   struct timeval tt;
>  
> - if (gettimeofday(&tt, NULL) == -1)
> + if (WRAP(gettimeofday)(&tt, NULL) == -1)
>   return (-1);
>   if (t)
>   *t = (time_t)tt.tv_sec;
> diff --git lib/libc/gen/times.c lib/libc/gen/times.c
> index 02e4dd44b5c..36841810d1b 100644
> --- lib/libc/gen/times.c
> +++ lib/libc/gen/times.c
> @@ -52,7 +52,7 @@ times(struct tms *tp)
>   return ((clock_t)-1);
>   tp->tms_cutime = CONVTCK(ru.ru_utime);
>   tp->tms_cstime = CONVTCK(ru.ru_stime);
> - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
> + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1)
>   return ((clock_t)-1);
>   return (ts.tv_sec * CLK_TCK + ts.tv_nsec / (1000000000 / CLK_TCK));
>  }
> diff --git lib/libc/gen/timespec_get.c lib/libc/gen/timespec_get.c
> index 520a5954025..845cbe80356 100644
> --- lib/libc/gen/timespec_get.c
> +++ lib/libc/gen/timespec_get.c
> @@ -37,7 +37,7 @@ timespec_get(struct timespec *ts, int base)
>  {
>   switch (base) {
>   case TIME_UTC:
> - if (clock_gettime(CLOCK_REALTIME, ts) == -1)
> + if (WRAP(clock_gettime)(CLOCK_REALTIME, ts) == -1)
>   return 0;
>   break;
>   default:
> diff --git lib/libc/gen/usertc.c lib/libc/gen/usertc.c
> new file mode 100644
> index 00000000000..43fa1728361
> --- /dev/null
> +++ lib/libc/gen/usertc.c
> @@ -0,0 +1,24 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +/*
> + * Stub. Add implementation in arch/${MACHINE_CPU}/gen/usertc.c.
> + */
> +uint64_t (*const _tc_get_timecount)(struct timekeep *tk) = NULL;
> diff --git lib/libc/hidden/sys/time.h lib/libc/hidden/sys/time.h
> index ed112320fa2..df717021cab 100644
> --- lib/libc/hidden/sys/time.h
> +++ lib/libc/hidden/sys/time.h
> @@ -24,7 +24,7 @@ PROTO_NORMAL(adjfreq);
>  PROTO_NORMAL(adjtime);
>  PROTO_NORMAL(futimes);
>  PROTO_NORMAL(getitimer);
> -PROTO_NORMAL(gettimeofday);
> +PROTO_WRAP(gettimeofday);
>  PROTO_NORMAL(setitimer);
>  PROTO_NORMAL(settimeofday);
>  PROTO_NORMAL(utimes);
> diff --git lib/libc/hidden/sys/timetc.h lib/libc/hidden/sys/timetc.h
> new file mode 100644
> index 00000000000..b0c982ebe57
> --- /dev/null
> +++ lib/libc/hidden/sys/timetc.h
> @@ -0,0 +1,38 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#ifndef _LIBC_SYS_TIMETC_H_
> +#define _LIBC_SYS_TIMETC_H_
> +
> +#define _LIBC
> +#include <sys/types.h>
> +#include <sys/time.h>
> +
> +#include_next <sys/timetc.h>
> +
> +__BEGIN_HIDDEN_DECLS
> +extern void *_timekeep;
> +
> +extern uint64_t (*const _tc_get_timecount)(struct timekeep *tk);
> +
> +void _microtime(struct timeval *tvp, struct timekeep *tk);
> +void _nanotime(struct timespec *tsp, struct timekeep *tk);
> +void _nanoruntime(struct timespec *ts, struct timekeep *tk);
> +void _nanouptime(struct timespec *tsp, struct timekeep *tk);
> +__END_HIDDEN_DECLS
> +
> +#endif /* !_LIBC_SYS_TIMETC_H_ */
> diff --git lib/libc/hidden/time.h lib/libc/hidden/time.h
> index 18c49f8fcb9..d8e1e0caf64 100644
> --- lib/libc/hidden/time.h
> +++ lib/libc/hidden/time.h
> @@ -29,7 +29,7 @@ PROTO_NORMAL(asctime_r);
>  PROTO_STD_DEPRECATED(clock);
>  PROTO_DEPRECATED(clock_getcpuclockid);
>  PROTO_NORMAL(clock_getres);
> -PROTO_NORMAL(clock_gettime);
> +PROTO_WRAP(clock_gettime);
>  PROTO_NORMAL(clock_settime);
>  PROTO_STD_DEPRECATED(ctime);
>  PROTO_DEPRECATED(ctime_r);
> diff --git lib/libc/net/res_random.c lib/libc/net/res_random.c
> index 763e420bb88..9babb28470a 100644
> --- lib/libc/net/res_random.c
> +++ lib/libc/net/res_random.c
> @@ -219,7 +219,7 @@ res_initid(void)
>   if (ru_prf != NULL)
>   arc4random_buf(ru_prf, sizeof(*ru_prf));
>  
> - clock_gettime(CLOCK_MONOTONIC, &ts);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts);
>   ru_reseed = ts.tv_sec + RU_OUT;
>   ru_msb = ru_msb == 0x8000 ? 0 : 0x8000;
>  }
> @@ -232,7 +232,7 @@ __res_randomid(void)
>   u_int r;
>   static void *randomid_mutex;
>  
> - clock_gettime(CLOCK_MONOTONIC, &ts);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts);
>   pid = getpid();
>  
>   _MUTEX_LOCK(&randomid_mutex);
> diff --git lib/libc/rpc/auth_unix.c lib/libc/rpc/auth_unix.c
> index 402d98cede4..917a6d42b8a 100644
> --- lib/libc/rpc/auth_unix.c
> +++ lib/libc/rpc/auth_unix.c
> @@ -121,7 +121,7 @@ authunix_create(char *machname, int uid, int gid, int len, int *aup_gids)
>   /*
>   * fill in param struct from the given params
>   */
> - (void)gettimeofday(&now,  NULL);
> + (void)WRAP(gettimeofday)(&now,  NULL);
>   aup.aup_time = now.tv_sec;
>   aup.aup_machname = machname;
>   aup.aup_uid = uid;
> @@ -274,7 +274,7 @@ authunix_refresh(AUTH *auth)
>   goto done;
>  
>   /* update the time and serialize in place */
> - (void)gettimeofday(&now, NULL);
> + (void)WRAP(gettimeofday)(&now, NULL);
>   aup.aup_time = now.tv_sec;
>   xdrs.x_op = XDR_ENCODE;
>   XDR_SETPOS(&xdrs, 0);
> diff --git lib/libc/rpc/clnt_tcp.c lib/libc/rpc/clnt_tcp.c
> index 8e6ef515b0e..927b4bf2028 100644
> --- lib/libc/rpc/clnt_tcp.c
> +++ lib/libc/rpc/clnt_tcp.c
> @@ -393,12 +393,12 @@ readtcp(struct ct_data *ct, caddr_t buf, int len)
>   pfd[0].events = POLLIN;
>   TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &wait);
>   delta = wait;
> - clock_gettime(CLOCK_MONOTONIC, &start);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
>   for (;;) {
>   r = ppoll(pfd, 1, &delta, NULL);
>   save_errno = errno;
>  
> - clock_gettime(CLOCK_MONOTONIC, &after);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
>   timespecsub(&start, &after, &duration);
>   timespecsub(&wait, &duration, &delta);
>   if (delta.tv_sec < 0 || !timespecisset(&delta))
> diff --git lib/libc/rpc/clnt_udp.c lib/libc/rpc/clnt_udp.c
> index 68d01674410..92e1d5c350d 100644
> --- lib/libc/rpc/clnt_udp.c
> +++ lib/libc/rpc/clnt_udp.c
> @@ -265,7 +265,7 @@ send_again:
>   reply_msg.acpted_rply.ar_results.where = resultsp;
>   reply_msg.acpted_rply.ar_results.proc = xresults;
>  
> - clock_gettime(CLOCK_MONOTONIC, &start);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
>   for (;;) {
>   switch (ppoll(pfd, 1, &wait, NULL)) {
>   case 0:
> @@ -283,7 +283,7 @@ send_again:
>   /* FALLTHROUGH */
>   case -1:
>   if (errno == EINTR) {
> - clock_gettime(CLOCK_MONOTONIC, &after);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
>   timespecsub(&after, &start, &duration);
>   timespecadd(&time_waited, &duration, &time_waited);
>   if (timespeccmp(&time_waited, &timeout, <))
> diff --git lib/libc/rpc/svc_tcp.c lib/libc/rpc/svc_tcp.c
> index f9d7a70938f..6c99db84359 100644
> --- lib/libc/rpc/svc_tcp.c
> +++ lib/libc/rpc/svc_tcp.c
> @@ -342,7 +342,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len)
>   * A timeout is fatal for the connection.
>   */
>   delta = wait_per_try;
> - clock_gettime(CLOCK_MONOTONIC, &start);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
>   pfd[0].fd = sock;
>   pfd[0].events = POLLIN;
>   do {
> @@ -351,7 +351,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len)
>   case -1:
>   if (errno != EINTR)
>   goto fatal_err;
> - clock_gettime(CLOCK_MONOTONIC, &after);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
>   timespecsub(&after, &start, &duration);
>   timespecsub(&wait_per_try, &duration, &delta);
>   if (delta.tv_sec < 0 || !timespecisset(&delta))
> diff --git lib/libc/sys/Makefile.inc lib/libc/sys/Makefile.inc
> index 34769576ced..d57418d81bf 100644
> --- lib/libc/sys/Makefile.inc
> +++ lib/libc/sys/Makefile.inc
> @@ -12,7 +12,8 @@ SRCS+= Ovfork.S brk.S ${CERROR} \
>  
>  # glue to offer userland wrappers for some syscalls
>  SRCS+= posix_madvise.c pthread_sigmask.c \
> - w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c
> + w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c \
> + w_clock_gettime.c w_gettimeofday.c microtime.c
>  
>  # glue for compat with old syscall interfaces.
>  SRCS+= ftruncate.c lseek.c mquery.c mmap.c ptrace.c semctl.c truncate.c \
> @@ -43,7 +44,7 @@ SRCS+= ${CANCEL:%=w_%.c} w_pread.c w_preadv.c w_pwrite.c w_pwritev.c
>  ASM= __semctl.o __syscall.o __thrsigdivert.o \
>   access.o acct.o adjfreq.o adjtime.o \
>   bind.o chdir.o chflags.o chflagsat.o chmod.o chown.o chroot.o \
> - clock_getres.o clock_gettime.o clock_settime.o \
> + clock_getres.o clock_settime.o \
>   dup.o dup2.o dup3.o \
>   execve.o \
>   faccessat.o fchdir.o fchflags.o fchmod.o fchmodat.o fchown.o \
> @@ -54,7 +55,7 @@ ASM= __semctl.o __syscall.o __thrsigdivert.o \
>   getgroups.o getitimer.o getpeername.o getpgid.o \
>   getpriority.o getresgid.o getresuid.o \
>   getrlimit.o getrusage.o getsid.o getsockname.o \
> - getsockopt.o gettimeofday.o ioctl.o \
> + getsockopt.o ioctl.o \
>   kevent.o kill.o kqueue.o ktrace.o lchown.o \
>   link.o linkat.o listen.o lstat.o madvise.o \
>   minherit.o mkdir.o mkdirat.o mkfifo.o mkfifoat.o \
> @@ -109,7 +110,8 @@ PPSEUDO_NOERR=${PSEUDO_NOERR:.o=.po}
>  SPSEUDO_NOERR=${PSEUDO_NOERR:.o=.so}
>  DPSEUDO_NOERR=${PSEUDO_NOERR:.o=.do}
>  
> -HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o}
> +HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o} \
> + clock_gettime.o gettimeofday.o
>  PHIDDEN=${HIDDEN:.o=.po}
>  SHIDDEN=${HIDDEN:.o=.so}
>  DHIDDEN=${HIDDEN:.o=.do}
> diff --git lib/libc/sys/microtime.c lib/libc/sys/microtime.c
> new file mode 100644
> index 00000000000..6eb3cd40d28
> --- /dev/null
> +++ lib/libc/sys/microtime.c
> @@ -0,0 +1,157 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2000 Poul-Henning Kamp <[hidden email]>
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/atomic.h>
> +#include <sys/timetc.h>
> +
> +#include <time.h>
> +
> +/*
> + * Return the difference between the timehands' counter value now and what
> + * was when we copied it to the timehands' offset_count.
> + */
> +static inline u_int
> +tc_delta(struct timekeep *tk)
> +{
> + return ((_tc_get_timecount(tk) - tk->tk_offset_count) &
> +    tk->tk_counter_mask);
> +}
> +
> +static inline void
> +bintimeaddfrac(const struct bintime *bt, uint64_t x, struct bintime *ct)
> +{
> + ct->sec = bt->sec;
> + if (bt->frac > bt->frac + x)
> + ct->sec++;
> + ct->frac = bt->frac + x;
> +}
> +
> +static inline void
> +BINTIME_TO_TIMESPEC(const struct bintime *bt, struct timespec *ts)
> +{
> + ts->tv_sec = bt->sec;
> + ts->tv_nsec = (long)(((uint64_t)1000000000 * (uint32_t)(bt->frac >> 32)) >> 32);
> +}
> +
> +static inline void
> +BINTIME_TO_TIMEVAL(const struct bintime *bt, struct timeval *tv)
> +{
> + tv->tv_sec = bt->sec;
> + tv->tv_usec = (long)(((uint64_t)1000000 * (uint32_t)(bt->frac >> 32)) >> 32);
> +}
> +
> +static void
> +binuptime(struct bintime *bt, struct timekeep *tk)
> +{
> + u_int gen;
> +
> + do {
> + gen = tk->tk_generation;
> + membar_consumer();
> + *bt = tk->tk_offset;
> + bintimeaddfrac(bt, tk->tk_scale * tc_delta(tk), bt);
> + membar_consumer();
> + } while (gen == 0 || gen != tk->tk_generation);
> +}
> +
> +static inline void
> +bintimeadd(const struct bintime *bt, const struct bintime *ct,
> +    struct bintime *dt)
> +{
> + dt->sec = bt->sec + ct->sec;
> + if (bt->frac > bt->frac + ct->frac)
> + dt->sec++;
> + dt->frac = bt->frac + ct->frac;
> +}
> +
> +static inline void
> +bintimesub(const struct bintime *bt, const struct bintime *ct,
> +    struct bintime *dt)
> +{
> + dt->sec = bt->sec - ct->sec;
> + if (bt->frac < bt->frac - ct->frac)
> + dt->sec--;
> + dt->frac = bt->frac - ct->frac;
> +}
> +
> +static void
> +binruntime(struct bintime *bt, struct timekeep *tk)
> +{
> + u_int gen;
> +
> + do {
> + gen = tk->tk_generation;
> + membar_consumer();
> + bintimeaddfrac(&tk->tk_offset, tk->tk_scale * tc_delta(tk), bt);
> + bintimesub(bt, &tk->tk_naptime, bt);
> + membar_consumer();
> + } while (gen == 0 || gen != tk->tk_generation);
> +}
> +
> +static void
> +bintime(struct bintime *bt, struct timekeep *tk)
> +{
> + u_int gen;
> +
> + do {
> + gen = tk->tk_generation;
> + membar_consumer();
> + *bt = tk->tk_offset;
> + bintimeaddfrac(bt, tk->tk_scale * tc_delta(tk), bt);
> + bintimeadd(bt, &tk->tk_boottime, bt);
> + membar_consumer();
> + } while (gen == 0 || gen != tk->tk_generation);
> +}
> +
> +void
> +_microtime(struct timeval *tvp, struct timekeep *tk)
> +{
> + struct bintime bt;
> +
> + bintime(&bt, tk);
> + BINTIME_TO_TIMEVAL(&bt, tvp);
> +}
> +
> +void
> +_nanotime(struct timespec *tsp, struct timekeep *tk)
> +{
> + struct bintime bt;
> +
> + bintime(&bt, tk);
> + BINTIME_TO_TIMESPEC(&bt, tsp);
> +}
> +
> +void
> +_nanoruntime(struct timespec *ts, struct timekeep *tk)
> +{
> + struct bintime bt;
> +
> + binruntime(&bt, tk);
> + BINTIME_TO_TIMESPEC(&bt, ts);
> +}
> +
> +
> +void
> +_nanouptime(struct timespec *tsp, struct timekeep *tk)
> +{
> + struct bintime bt;
> +
> + binuptime(&bt, tk);
> + BINTIME_TO_TIMESPEC(&bt, tsp);
> +}
> diff --git lib/libc/sys/w_clock_gettime.c lib/libc/sys/w_clock_gettime.c
> new file mode 100644
> index 00000000000..ff72c9fb64d
> --- /dev/null
> +++ lib/libc/sys/w_clock_gettime.c
> @@ -0,0 +1,46 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/timetc.h>
> +
> +#include <time.h>
> +
> +int
> +WRAP(clock_gettime)(clockid_t clock_id, struct timespec *tp)
> +{
> + struct timekeep *timekeep = _timekeep;
> +
> + if (timekeep == NULL || timekeep->tk_user == 0)
> + return clock_gettime(clock_id, tp);
> +
> + switch (clock_id) {
> + case CLOCK_REALTIME:
> + _nanotime(tp, timekeep);
> + break;
> + case CLOCK_UPTIME:
> + _nanoruntime(tp, timekeep);
> + break;
> + case CLOCK_MONOTONIC:
> + case CLOCK_BOOTTIME:
> + _nanouptime(tp, timekeep);
> + break;
> + default:
> + return clock_gettime(clock_id, tp);
> + }
> + return 0;
> +}
> +DEF_WRAP(clock_gettime);
> diff --git lib/libc/sys/w_gettimeofday.c lib/libc/sys/w_gettimeofday.c
> new file mode 100644
> index 00000000000..0b198190485
> --- /dev/null
> +++ lib/libc/sys/w_gettimeofday.c
> @@ -0,0 +1,37 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Robert Nagy <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/timetc.h>
> +
> +int
> +WRAP(gettimeofday)(struct timeval *tp, struct timezone *tzp)
> +{
> + struct timekeep *timekeep = _timekeep;
> + static struct timezone zerotz = { 0, 0 };
> +
> + if (timekeep == NULL || timekeep->tk_user == 0)
> + return gettimeofday(tp, tzp);
> +
> + if (tp)
> + _microtime(tp, timekeep);
> +
> + if (tzp)
> + tzp = &zerotz;
> +
> + return 0;
> +}
> +DEF_WRAP(gettimeofday);
> diff --git lib/libc/thread/synch.h lib/libc/thread/synch.h
> index 788890add89..df2239438d2 100644
> --- lib/libc/thread/synch.h
> +++ lib/libc/thread/synch.h
> @@ -33,7 +33,7 @@ _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *
>   if (abs == NULL)
>   return futex(p, FUTEX_WAIT_PRIVATE, val, NULL, NULL);
>  
> - if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel))
> + if (abs->tv_nsec >= 1000000000 || WRAP(clock_gettime)(clockid, &rel))
>   return (EINVAL);
>  
>   rel.tv_sec = abs->tv_sec - rel.tv_sec;
> diff --git regress/lib/libc/timekeep/Makefile regress/lib/libc/timekeep/Makefile
> new file mode 100644
> index 00000000000..a7f3080290d
> --- /dev/null
> +++ regress/lib/libc/timekeep/Makefile
> @@ -0,0 +1,5 @@
> +# $OpenBSD$
> +
> +PROGS= test_clock_gettime test_time_skew test_gettimeofday
> +
> +.include <bsd.regress.mk>
> diff --git regress/lib/libc/timekeep/test_clock_gettime.c regress/lib/libc/timekeep/test_clock_gettime.c
> new file mode 100644
> index 00000000000..859ec368215
> --- /dev/null
> +++ regress/lib/libc/timekeep/test_clock_gettime.c
> @@ -0,0 +1,43 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <assert.h>
> +#include <time.h>
> +
> +#define ASSERT_EQ(a, b) assert((a) == (b))
> +
> +void
> +check()
> +{
> + struct timespec tp = {0};
> +
> + ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp));
> + ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp));
> + ASSERT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &tp));
> + ASSERT_EQ(0, clock_gettime(CLOCK_UPTIME, &tp));
> +
> +
> + ASSERT_EQ(0, clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp));
> + ASSERT_EQ(0, clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp));
> +
> +}
> +
> +int main()
> +{
> + check();
> + return 0;
> +}
> diff --git regress/lib/libc/timekeep/test_gettimeofday.c regress/lib/libc/timekeep/test_gettimeofday.c
> new file mode 100644
> index 00000000000..ea90a1be7e0
> --- /dev/null
> +++ regress/lib/libc/timekeep/test_gettimeofday.c
> @@ -0,0 +1,37 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <assert.h>
> +#include <sys/time.h>
> +
> +#define ASSERT_EQ(a, b) assert((a) == (b))
> +
> +void
> +check()
> +{
> + struct timeval tv = {0};
> + struct timezone tzp;
> +
> + ASSERT_EQ(0, gettimeofday(&tv, NULL));
> + ASSERT_EQ(0, gettimeofday(&tv, &tzp));
> +}
> +
> +int main()
> +{
> + check();
> + return 0;
> +}
> diff --git regress/lib/libc/timekeep/test_time_skew.c regress/lib/libc/timekeep/test_time_skew.c
> new file mode 100644
> index 00000000000..dfa9481c091
> --- /dev/null
> +++ regress/lib/libc/timekeep/test_time_skew.c
> @@ -0,0 +1,55 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/time.h>
> +
> +#include <assert.h>
> +#include <time.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +#define ASSERT_EQ(a, b) assert((a) == (b))
> +#define ASSERT_NE(a, b) assert((a) != (b))
> +
> +void
> +check()
> +{
> +         struct timespec tp1, tp2, tout;
> +
> +         tout.tv_sec = 0;
> +         tout.tv_nsec = 100000;
> +
> +         ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp1));
> +
> +         nanosleep(&tout, NULL);
> +
> +         ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp2));
> +
> +         /* tp1 should never be larger than tp2 */
> +         ASSERT_NE(1, timespeccmp(&tp1, &tp2, >));
> +}
> +
> +int
> +main(void)
> +{
> + int i;
> +
> + for (i = 0; i < 1000; i++)
> + check();
> +
> + return 0;
> +}
> diff --git sys/arch/alpha/alpha/clock.c sys/arch/alpha/alpha/clock.c
> index 3f5f2c5b42b..6eaf8b107c6 100644
> --- sys/arch/alpha/alpha/clock.c
> +++ sys/arch/alpha/alpha/clock.c
> @@ -64,7 +64,7 @@ int clk_irq = 0;
>  
>  u_int rpcc_get_timecount(struct timecounter *);
>  struct timecounter rpcc_timecounter = {
> - rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL
> + rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL, 0
>  };
>  
>  extern todr_chip_handle_t todr_handle;
> diff --git sys/arch/amd64/amd64/tsc.c sys/arch/amd64/amd64/tsc.c
> index 7a1dcb4ad75..3db93d88dec 100644
> --- sys/arch/amd64/amd64/tsc.c
> +++ sys/arch/amd64/amd64/tsc.c
> @@ -50,7 +50,7 @@ extern u_int32_t lapic_per_second;
>  #endif
>  
>  struct timecounter tsc_timecounter = {
> - tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL
> + tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL, 1
>  };
>  
>  uint64_t
> diff --git sys/arch/amd64/isa/clock.c sys/arch/amd64/isa/clock.c
> index 613f7ee0e0f..00da0c6a8d0 100644
> --- sys/arch/amd64/isa/clock.c
> +++ sys/arch/amd64/isa/clock.c
> @@ -116,7 +116,7 @@ u_int i8254_get_timecount(struct timecounter *tc);
>  u_int i8254_simple_get_timecount(struct timecounter *tc);
>  
>  static struct timecounter i8254_timecounter = {
> - i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
> + i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0
>  };
>  
>  int clockintr(void *);
> diff --git sys/arch/arm64/dev/agtimer.c sys/arch/arm64/dev/agtimer.c
> index 29394141ad5..6b7c6db862f 100644
> --- sys/arch/arm64/dev/agtimer.c
> +++ sys/arch/arm64/dev/agtimer.c
> @@ -43,7 +43,7 @@ int32_t agtimer_frequency = TIMER_FREQUENCY;
>  u_int agtimer_get_timecount(struct timecounter *);
>  
>  static struct timecounter agtimer_timecounter = {
> - agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL
> + agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL, 0
>  };
>  
>  struct agtimer_pcpu_softc {
> diff --git sys/arch/armv7/omap/gptimer.c sys/arch/armv7/omap/gptimer.c
> index 7605845d5e2..061542d532f 100644
> --- sys/arch/armv7/omap/gptimer.c
> +++ sys/arch/armv7/omap/gptimer.c
> @@ -117,7 +117,7 @@ int gptimer_irq = 0;
>  u_int gptimer_get_timecount(struct timecounter *);
>  
>  static struct timecounter gptimer_timecounter = {
> - gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL
> + gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL, 0
>  };
>  
>  volatile u_int32_t nexttickevent;
> diff --git sys/arch/armv7/sunxi/sxitimer.c sys/arch/armv7/sunxi/sxitimer.c
> index 14a243c78d0..41028f9a602 100644
> --- sys/arch/armv7/sunxi/sxitimer.c
> +++ sys/arch/armv7/sunxi/sxitimer.c
> @@ -89,7 +89,7 @@ void sxitimer_delay(u_int);
>  u_int sxitimer_get_timecount(struct timecounter *);
>  
>  static struct timecounter sxitimer_timecounter = {
> - sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL
> + sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL, 0
>  };
>  
>  bus_space_tag_t sxitimer_iot;
> diff --git sys/arch/hppa/dev/clock.c sys/arch/hppa/dev/clock.c
> index 4c594ab5ec7..8cce6c3a893 100644
> --- sys/arch/hppa/dev/clock.c
> +++ sys/arch/hppa/dev/clock.c
> @@ -47,7 +47,7 @@ int cpu_hardclock(void *);
>  u_int itmr_get_timecount(struct timecounter *);
>  
>  struct timecounter itmr_timecounter = {
> - itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL
> + itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL, 0
>  };
>  
>  extern todr_chip_handle_t todr_handle;
> diff --git sys/arch/i386/isa/clock.c sys/arch/i386/isa/clock.c
> index 09a6db983f2..dd74bd425ad 100644
> --- sys/arch/i386/isa/clock.c
> +++ sys/arch/i386/isa/clock.c
> @@ -129,7 +129,7 @@ u_int i8254_get_timecount(struct timecounter *tc);
>  u_int i8254_simple_get_timecount(struct timecounter *tc);
>  
>  static struct timecounter i8254_timecounter = {
> - i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
> + i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0
>  };
>  struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH);
>  u_long rtclock_tval;
> diff --git sys/arch/i386/pci/geodesc.c sys/arch/i386/pci/geodesc.c
> index 9d9f061eef9..bb8e4c7f9ae 100644
> --- sys/arch/i386/pci/geodesc.c
> +++ sys/arch/i386/pci/geodesc.c
> @@ -65,7 +65,9 @@ struct timecounter geodesc_timecounter = {
>   0xffffffff, /* counter_mask */
>   27000000, /* frequency */
>   "GEOTSC", /* name */
> - 2000 /* quality */
> + 2000, /* quality */
> + NULL, /* private bits */
> + 0 /* expose to user */
>  };
>  
>  int
> diff --git sys/arch/i386/pci/gscpm.c sys/arch/i386/pci/gscpm.c
> index 8b8aa4ac430..a6f324e66f3 100644
> --- sys/arch/i386/pci/gscpm.c
> +++ sys/arch/i386/pci/gscpm.c
> @@ -55,7 +55,9 @@ struct timecounter gscpm_timecounter = {
>   0xffffff, /* counter_mask */
>   3579545, /* frequency */
>   "GSCPM", /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0 /* expose to user */
>  };
>  
>  struct cfattach gscpm_ca = {
> diff --git sys/arch/i386/pci/ichpcib.c sys/arch/i386/pci/ichpcib.c
> index 6abf1627de2..629a86a14ff 100644
> --- sys/arch/i386/pci/ichpcib.c
> +++ sys/arch/i386/pci/ichpcib.c
> @@ -63,7 +63,9 @@ struct timecounter ichpcib_timecounter = {
>   0xffffff, /* counter_mask */
>   3579545, /* frequency */
>   "ICHPM", /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0 /* expose to user */
>  };
>  
>  struct cfattach ichpcib_ca = {
> diff --git sys/arch/loongson/loongson/generic3a_machdep.c sys/arch/loongson/loongson/generic3a_machdep.c
> index ac3f1db6ccd..53489b07549 100644
> --- sys/arch/loongson/loongson/generic3a_machdep.c
> +++ sys/arch/loongson/loongson/generic3a_machdep.c
> @@ -98,7 +98,9 @@ struct timecounter rs780e_timecounter = {
>   .tc_counter_mask = 0xffffffffu, /* truncated to 32 bits */
>   .tc_frequency = HPET_FREQ,
>   .tc_name = "hpet",
> - .tc_quality = 100
> + .tc_quality = 100,
> + .tc_priv = NULL,
> + .tc_user = 0,
>  };
>  
>  /* Firmware entry points */
> diff --git sys/arch/luna88k/luna88k/clock.c sys/arch/luna88k/luna88k/clock.c
> index a04120987e0..6580a4a46bf 100644
> --- sys/arch/luna88k/luna88k/clock.c
> +++ sys/arch/luna88k/luna88k/clock.c
> @@ -112,7 +112,9 @@ struct timecounter clock_tc = {
>   .tc_counter_mask = 0xffffffff,
>   .tc_frequency = 0, /* will be filled in */
>   .tc_name = "clock",
> - .tc_quality = 0
> + .tc_quality = 0,
> + .tc_priv = NULL,
> + .tc_user = 0,
>  };
>  
>  /*
> diff --git sys/arch/macppc/macppc/clock.c sys/arch/macppc/macppc/clock.c
> index 4a44a92cfc0..8c3ad620be8 100644
> --- sys/arch/macppc/macppc/clock.c
> +++ sys/arch/macppc/macppc/clock.c
> @@ -57,7 +57,7 @@ u_int32_t ns_per_tick = 320;
>  static int32_t ticks_per_intr;
>  
>  static struct timecounter tb_timecounter = {
> - tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL
> + tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL, 0
>  };
>  
>  /* calibrate the timecounter frequency for the listed models */
> diff --git sys/arch/mips64/mips64/mips64_machdep.c sys/arch/mips64/mips64/mips64_machdep.c
> index d4a42ed5acc..5c4dbadb5bb 100644
> --- sys/arch/mips64/mips64/mips64_machdep.c
> +++ sys/arch/mips64/mips64/mips64_machdep.c
> @@ -327,7 +327,9 @@ struct timecounter cp0_timecounter = {
>   0xffffffff, /* counter_mask */
>   0, /* frequency */
>   "CP0", /* name */
> - 0 /* quality */
> + 0, /* quality */
> + NULL, /* private bits */
> + 0, /* expose to user */
>  };
>  
>  u_int
> diff --git sys/arch/octeon/octeon/machdep.c sys/arch/octeon/octeon/machdep.c
> index 1387af284ca..2b22a9e942c 100644
> --- sys/arch/octeon/octeon/machdep.c
> +++ sys/arch/octeon/octeon/machdep.c
> @@ -151,8 +151,9 @@ struct timecounter ioclock_timecounter = {
>   .tc_name = "ioclock",
>   .tc_quality = 0, /* ioclock can be overridden
>   * by cp0 counter */
> - .tc_priv = 0 /* clock register,
> + .tc_priv = 0, /* clock register,
>   * determined at runtime */
> + .tc_user = 0, /* expose to user */
>  };
>  
>  static int
> diff --git sys/arch/sgi/sgi/ip27_machdep.c sys/arch/sgi/sgi/ip27_machdep.c
> index ba7fa558b96..2a2cc144242 100644
> --- sys/arch/sgi/sgi/ip27_machdep.c
> +++ sys/arch/sgi/sgi/ip27_machdep.c
> @@ -111,7 +111,9 @@ struct timecounter ip27_hub_timecounter = {
>   .tc_counter_mask = 0xffffffff, /* truncated to 32 bits. */
>   .tc_frequency = 1250000,
>   .tc_name = "hubrt",
> - .tc_quality = 100
> + .tc_quality = 100,
> + .tc_priv = 0,
> + .tc_user = 0,
>  };
>  
>  volatile uint64_t ip27_spinup_a0;
> diff --git sys/arch/sgi/xbow/xheart.c sys/arch/sgi/xbow/xheart.c
> index 56b29915c70..827775512ac 100644
> --- sys/arch/sgi/xbow/xheart.c
> +++ sys/arch/sgi/xbow/xheart.c
> @@ -83,7 +83,9 @@ struct timecounter xheart_timecounter = {
>   .tc_counter_mask = 0xffffffff, /* truncate 52-bit counter to 32-bit */
>   .tc_frequency = 12500000,
>   .tc_name = "heart",
> - .tc_quality = 100
> + .tc_quality = 100,
> + .tc_priv = NULL,
> + .tc_user = 0,
>  };
>  
>  extern uint32_t ip30_lights_frob(uint32_t, struct trapframe *);
> diff --git sys/arch/sparc64/dev/psycho.c sys/arch/sparc64/dev/psycho.c
> index e24f804dff6..1a7a1afa8c2 100644
> --- sys/arch/sparc64/dev/psycho.c
> +++ sys/arch/sparc64/dev/psycho.c
> @@ -127,7 +127,7 @@ extern struct sparc_pci_chipset _sparc_pci_chipset;
>  u_int stick_get_timecount(struct timecounter *);
>  
>  struct timecounter stick_timecounter = {
> - stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL
> + stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL, 0
>  };
>  
>  /*
> diff --git sys/arch/sparc64/sparc64/clock.c sys/arch/sparc64/sparc64/clock.c
> index fd5e8a9c15b..5c2e47d386b 100644
> --- sys/arch/sparc64/sparc64/clock.c
> +++ sys/arch/sparc64/sparc64/clock.c
> @@ -109,13 +109,13 @@ struct cfdriver clock_cd = {
>  u_int tick_get_timecount(struct timecounter *);
>  
>  struct timecounter tick_timecounter = {
> - tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL
> + tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL, 0
>  };
>  
>  u_int sys_tick_get_timecount(struct timecounter *);
>  
>  struct timecounter sys_tick_timecounter = {
> - sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL
> + sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL, 0
>  };
>  
>  /*
> diff --git sys/dev/acpi/acpihpet.c sys/dev/acpi/acpihpet.c
> index d0ee72cec9b..13177a909da 100644
> --- sys/dev/acpi/acpihpet.c
> +++ sys/dev/acpi/acpihpet.c
> @@ -45,7 +45,9 @@ static struct timecounter hpet_timecounter = {
>   0xffffffff, /* counter_mask (32 bits) */
>   0, /* frequency */
>   0, /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0, /* expose to user */
>  };
>  
>  #define HPET_TIMERS 3
> diff --git sys/dev/acpi/acpitimer.c sys/dev/acpi/acpitimer.c
> index cdc8c99a17a..89b5a397e47 100644
> --- sys/dev/acpi/acpitimer.c
> +++ sys/dev/acpi/acpitimer.c
> @@ -36,7 +36,9 @@ static struct timecounter acpi_timecounter = {
>   0x00ffffff, /* counter_mask (24 bits) */
>   ACPI_FREQUENCY, /* frequency */
>   0, /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0, /* expose to user */
>  };
>  
>  struct acpitimer_softc {
> diff --git sys/dev/pci/amdpm.c sys/dev/pci/amdpm.c
> index 6df82858016..9610d5bc1f0 100644
> --- sys/dev/pci/amdpm.c
> +++ sys/dev/pci/amdpm.c
> @@ -82,7 +82,9 @@ static struct timecounter amdpm_timecounter = {
>   0xffffff, /* counter_mask */
>   AMDPM_FREQUENCY, /* frequency */
>   "AMDPM", /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0, /* expose to user */
>  };
>  
>  #define AMDPM_CONFREG 0x40
> diff --git sys/dev/pci/viapm.c sys/dev/pci/viapm.c
> index db806eedf80..ce33cd175e6 100644
> --- sys/dev/pci/viapm.c
> +++ sys/dev/pci/viapm.c
> @@ -177,7 +177,9 @@ static struct timecounter viapm_timecounter = {
>   0xffffff, /* counter_mask */
>   VIAPM_FREQUENCY, /* frequency */
>   "VIAPM", /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0, /* expose to user */
>  };
>  
>  struct timeout viapm_timeout;
> diff --git sys/dev/pv/hyperv.c sys/dev/pv/hyperv.c
> index b32facdacb1..b9ee2feec4c 100644
> --- sys/dev/pv/hyperv.c
> +++ sys/dev/pv/hyperv.c
> @@ -141,7 +141,7 @@ struct {
>  };
>  
>  struct timecounter hv_timecounter = {
> - hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001
> + hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001, NULL, 0
>  };
>  
>  struct cfdriver hyperv_cd = {
> diff --git sys/dev/pv/pvclock.c sys/dev/pv/pvclock.c
> index 6b242f7448d..b80e4d2a484 100644
> --- sys/dev/pv/pvclock.c
> +++ sys/dev/pv/pvclock.c
> @@ -74,7 +74,7 @@ struct cfdriver pvclock_cd = {
>  };
>  
>  struct timecounter pvclock_timecounter = {
> - pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL
> + pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL, 0
>  };
>  
>  int
> diff --git sys/kern/exec_elf.c sys/kern/exec_elf.c
> index 9b5b8eb3acf..59bc923a6fb 100644
> --- sys/kern/exec_elf.c
> +++ sys/kern/exec_elf.c
> @@ -124,7 +124,7 @@ extern char *syscallnames[];
>  /*
>   * How many entries are in the AuxInfo array we pass to the process?
>   */
> -#define ELF_AUX_ENTRIES 8
> +#define ELF_AUX_ENTRIES 9
>  
>  /*
>   * This is the OpenBSD ELF emul
> @@ -860,6 +860,10 @@ exec_elf_fixup(struct proc *p, struct exec_package *epp)
>   a->au_v = ap->arg_entry;
>   a++;
>  
> + a->au_id = AUX_openbsd_timekeep;
> + a->au_v = p->p_p->ps_timekeep;
> + a++;
> +
>   a->au_id = AUX_null;
>   a->au_v = 0;
>   a++;
> diff --git sys/kern/kern_exec.c sys/kern/kern_exec.c
> index 20480c2fc28..8869f1fb89f 100644
> --- sys/kern/kern_exec.c
> +++ sys/kern/kern_exec.c
> @@ -64,6 +64,11 @@
>  #include <uvm/uvm_extern.h>
>  #include <machine/tcb.h>
>  
> +#include <sys/timetc.h>
> +
> +struct uvm_object *timekeep_object;
> +struct timekeep* timekeep;
> +
>  void unveil_destroy(struct process *ps);
>  
>  const struct kmem_va_mode kv_exec = {
> @@ -76,6 +81,11 @@ const struct kmem_va_mode kv_exec = {
>   */
>  int exec_sigcode_map(struct process *, struct emul *);
>  
> +/*
> + * Map the shared timekeep page.
> + */
> +int exec_timekeep_map(struct process *);
> +
>  /*
>   * If non-zero, stackgap_random specifies the upper limit of the random gap size
>   * added to the fixed stack position. Must be n^2.
> @@ -684,6 +694,9 @@ sys_execve(struct proc *p, void *v, register_t *retval)
>   /* map the process's signal trampoline code */
>   if (exec_sigcode_map(pr, pack.ep_emul))
>   goto free_pack_abort;
> + /* map the process's timekeep page */
> + if (exec_timekeep_map(pr))
> + goto free_pack_abort;
>  
>  #ifdef __HAVE_EXEC_MD_MAP
>   /* perform md specific mappings that process might need */
> @@ -863,3 +876,41 @@ exec_sigcode_map(struct process *pr, struct emul *e)
>  
>   return (0);
>  }
> +
> +int
> +exec_timekeep_map(struct process *pr)
> +{
> + size_t timekeep_sz = sizeof(struct timekeep);
> +
> + /*
> + * Similar to the sigcode object, except that there is a single timekeep
> + * object, and not one per emulation.
> + */
> + if (timekeep_object == NULL) {
> + vaddr_t va;
> +
> + timekeep_object = uao_create(timekeep_sz, 0);
> + uao_reference(timekeep_object);
> +
> + if (uvm_map(kernel_map, &va, round_page(timekeep_sz), timekeep_object,
> +    0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
> +    MAP_INHERIT_SHARE, MADV_RANDOM, 0))) {
> + uao_detach(timekeep_object);
> + return (ENOMEM);
> + }
> +
> + timekeep = (struct timekeep *)va;
> + timekeep->tk_major = 0;
> + timekeep->tk_minor = 0;
> + }
> +
> + uao_reference(timekeep_object);
> + if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_timekeep, round_page(timekeep_sz),
> +    timekeep_object, 0, 0, UVM_MAPFLAG(PROT_READ, PROT_READ,
> +    MAP_INHERIT_COPY, MADV_RANDOM, 0))) {
> + uao_detach(timekeep_object);
> + return (ENOMEM);
> + }
> +
> + return (0);
> +}
> diff --git sys/kern/kern_tc.c sys/kern/kern_tc.c
> index 88d4a3379f9..47efbdd0b78 100644
> --- sys/kern/kern_tc.c
> +++ sys/kern/kern_tc.c
> @@ -63,7 +63,7 @@ dummy_get_timecount(struct timecounter *tc)
>  }
>  
>  static struct timecounter dummy_timecounter = {
> - dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000
> + dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000, NULL, 0
>  };
>  
>  /*
> @@ -479,6 +479,34 @@ tc_setclock(const struct timespec *ts)
>  #endif
>  }
>  
> +void
> +tc_update_timekeep(void)
> +{
> + static struct timecounter *last_tc = NULL;
> + struct timehands *th;
> +
> + if (timekeep == NULL)
> + return;
> +
> + th = timehands;
> + timekeep->tk_generation = 0;
> + membar_producer();
> + timekeep->tk_scale = th->th_scale;
> + timekeep->tk_offset_count = th->th_offset_count;
> + timekeep->tk_offset = th->th_offset;
> + timekeep->tk_naptime = th->th_naptime;
> + timekeep->tk_boottime = th->th_boottime;
> + if (last_tc != th->th_counter) {
> + timekeep->tk_counter_mask = th->th_counter->tc_counter_mask;
> + timekeep->tk_user = th->th_counter->tc_user;
> + last_tc = th->th_counter;
> + }
> + membar_producer();
> + timekeep->tk_generation = th->th_generation;
> +
> + return;
> +}
> +
>  /*
>   * Initialize the next struct timehands in the ring and make
>   * it the active timehands.  Along the way we might switch to a different
> @@ -631,6 +659,8 @@ tc_windup(struct bintime *new_boottime, struct bintime *new_offset,
>   time_uptime = th->th_offset.sec;
>   membar_producer();
>   timehands = th;
> +
> + tc_update_timekeep();
>  }
>  
>  /* Report or change the active timecounter hardware. */
> diff --git sys/sys/exec_elf.h sys/sys/exec_elf.h
> index a40e0510273..3084ed595a6 100644
> --- sys/sys/exec_elf.h
> +++ sys/sys/exec_elf.h
> @@ -691,7 +691,8 @@ enum AuxID {
>   AUX_sun_uid = 2000, /* euid */
>   AUX_sun_ruid = 2001, /* ruid */
>   AUX_sun_gid = 2002, /* egid */
> - AUX_sun_rgid = 2003 /* rgid */
> + AUX_sun_rgid = 2003, /* rgid */
> + AUX_openbsd_timekeep = 4000, /* userland clock_gettime */
>  };
>  
>  struct elf_args {
> diff --git sys/sys/proc.h sys/sys/proc.h
> index 357c0c0d52c..c6d54572bdd 100644
> --- sys/sys/proc.h
> +++ sys/sys/proc.h
> @@ -242,6 +242,7 @@ struct process {
>   char ps_comm[MAXCOMLEN+1];
>  
>   vaddr_t ps_strings; /* User pointers to argv/env */
> + vaddr_t ps_timekeep; /* User pointer to timekeep */
>   vaddr_t ps_sigcode; /* User pointer to the signal code */
>   vaddr_t ps_sigcoderet; /* User pointer to sigreturn retPC */
>   u_long ps_sigcookie;
> diff --git sys/sys/time.h sys/sys/time.h
> index e758a64ce07..bcd3acd034d 100644
> --- sys/sys/time.h
> +++ sys/sys/time.h
> @@ -163,7 +163,7 @@ struct clockinfo {
>  };
>  #endif /* __BSD_VISIBLE */
>  
> -#if defined(_KERNEL) || defined(_STANDALONE)
> +#if defined(_KERNEL) || defined(_STANDALONE) || defined (_LIBC)
>  #include <sys/_time.h>
>  
>  /* Time expressed as seconds and fractions of a second + operations on it. */
> @@ -171,6 +171,9 @@ struct bintime {
>   time_t sec;
>   uint64_t frac;
>  };
> +#endif
> +
> +#if defined(_KERNEL) || defined(_STANDALONE)
>  
>  #define bintimecmp(btp, ctp, cmp) \
>   ((btp)->sec == (ctp)->sec ? \
> diff --git sys/sys/timetc.h sys/sys/timetc.h
> index ce81c3475a0..22658b00da2 100644
> --- sys/sys/timetc.h
> +++ sys/sys/timetc.h
> @@ -24,7 +24,7 @@
>  #ifndef _SYS_TIMETC_H_
>  #define _SYS_TIMETC_H_
>  
> -#ifndef _KERNEL
> +#if !defined(_KERNEL) && !defined(_LIBC)
>  #error "no user-serviceable parts inside"
>  #endif
>  
> @@ -80,6 +80,8 @@ struct timecounter {
>   */
>   void *tc_priv; /* [I] */
>   /* Pointer to the timecounter's private parts. */
> + int tc_user; /* [I] */
> + /* Expose this timecounter to userland. */
>   SLIST_ENTRY(timecounter) tc_next; /* [I] */
>   /* Pointer to the next timecounter. */
>   int64_t tc_freq_adj; /* [tw] */
> @@ -88,11 +90,31 @@ struct timecounter {
>   /* Precision of the counter.  Computed in tc_init(). */
>  };
>  
> +struct timekeep {
> + uint32_t tk_major; /* version major number */
> + uint32_t tk_minor; /* version minor number */
> +
> + /* timehands members */
> + uint64_t tk_scale;
> + u_int tk_offset_count;
> + struct bintime tk_offset;
> + struct bintime tk_naptime;
> + struct bintime tk_boottime;
> + volatile u_int tk_generation;
> +
> + /* timecounter members */
> + int tk_user;
> + u_int tk_counter_mask;
> +};
> +
>  struct rwlock;
>  extern struct rwlock tc_lock;
>  
>  extern struct timecounter *timecounter;
>  
> +extern struct uvm_object *timekeep_object;
> +extern struct timekeep *timekeep;
> +
>  u_int64_t tc_getfrequency(void);
>  u_int64_t tc_getprecision(void);
>  void tc_init(struct timecounter *tc);
>

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Theo de Raadt-2
> > Is the Makefile approach good enough?
>
> Not sure.  Others should judge that.

I don't know why the complexity of Makefile hackery is needed.

Give all the other architectures a MD file.  Some contain code and
array handling, others contain fewer lines of code marking it NULL.

And that would be the end of the story.

Why do you need a .if !exists point at a different
file, confusing all of it.

Is cp(1) of a file with 1 line of code some deep-seated attack on OOP or
something?

Is there going to be a bug found in this years from now, and all of them
will get fixed except someone will forget to fix the powerpc file
leading to a massive security hole?

This type of complexity is *WORSE*.

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Paul Irofti-4
In reply to this post by Mark Kettenis
On 05.06.2020 20:25, Mark Kettenis wrote:

>> Date: Fri, 5 Jun 2020 01:33:16 +0300
>> From: Paul Irofti <[hidden email]>
>>
>> On Wed, Jun 03, 2020 at 05:13:42PM +0300, Paul Irofti wrote:
>>> On 2020-05-31 20:46, Mark Kettenis wrote:
>>>> Forget about all that for a moment.  Here is an alternative suggestion:
>>>>
>>>> On sparc64 we need to support both tick_timecounter and
>>>> sys_tick_timecounter.  So we need some sort of clockid value to
>>>> distnguish between those two.  I already suggested to use the tc_user
>>>> field of the timecounter for that.  0 means that a timecounter is not
>>>> usable in userland, a (small) positive integer means a specific
>>>> timecounter type.  The code in libc will need to know whether a
>>>> particular timecounter type can be supported.  My proposal would be to
>>>> implement a function*on all architecture*  that takes the clockid as
>>>> an argument and returns a pointer to the function that implements
>>>> support for that timecounter.  On architectures without support, ir
>>>> when called with a clockid that isn't supported, that function would
>>>> simply return NULL.
>>>
>>> I am sorry, but the more I try to implement this in a sane way, the more
>>> obvious it is that it is not possible. I would rather have a define sausage
>>> than something like this.
>>>
>>> I will try to think of something else that avoids the defines, but I do not
>>> think that your proposal is a valid solution.
>>
>> OK. I think I found an elegant way around this using the Makefile
>> system: if usertc.c is not present in the arch/${MACHINE}/gen, then a
>> stub gen/usertc.c file is built that just sets the function pointer to
>> NULL. This avoids the need for the define checks in dlfcn/init.c and I
>> think fixes the rest of the issues discussed around this bit.
>>
>> Also included in the diff are a few other fixes and regression tests.
>> I left the rdtsc and acpihpet example (with no functional acpihpet
>> support) just to show-case how we can handle multiple clocks on
>> architectures that have them.
>
> You're still using tk_user unconditionally.  If the kernel returns a
> tk_user value that is larger than what's supported by libc you have an
> out-of-bounds array access.
>
> Also if the machine switches to a timecounter that has tk_user == 0
> you have an out-of-bounds array access.  If that happens you need to
> detect this and fall back on the system call.

Right. Even though we test in the beginning for tk_user=0 it might
change until the access to tc_get_timecount(). I will fix this in my
next diff. Thanks!

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Paul Irofti-4
On Fri, Jun 05, 2020 at 08:34:12PM +0300, Paul Irofti wrote:

> On 05.06.2020 20:25, Mark Kettenis wrote:
> > > Date: Fri, 5 Jun 2020 01:33:16 +0300
> > > From: Paul Irofti <[hidden email]>
> > >
> > > On Wed, Jun 03, 2020 at 05:13:42PM +0300, Paul Irofti wrote:
> > > > On 2020-05-31 20:46, Mark Kettenis wrote:
> > > > > Forget about all that for a moment.  Here is an alternative suggestion:
> > > > >
> > > > > On sparc64 we need to support both tick_timecounter and
> > > > > sys_tick_timecounter.  So we need some sort of clockid value to
> > > > > distnguish between those two.  I already suggested to use the tc_user
> > > > > field of the timecounter for that.  0 means that a timecounter is not
> > > > > usable in userland, a (small) positive integer means a specific
> > > > > timecounter type.  The code in libc will need to know whether a
> > > > > particular timecounter type can be supported.  My proposal would be to
> > > > > implement a function*on all architecture*  that takes the clockid as
> > > > > an argument and returns a pointer to the function that implements
> > > > > support for that timecounter.  On architectures without support, ir
> > > > > when called with a clockid that isn't supported, that function would
> > > > > simply return NULL.
> > > >
> > > > I am sorry, but the more I try to implement this in a sane way, the more
> > > > obvious it is that it is not possible. I would rather have a define sausage
> > > > than something like this.
> > > >
> > > > I will try to think of something else that avoids the defines, but I do not
> > > > think that your proposal is a valid solution.
> > >
> > > OK. I think I found an elegant way around this using the Makefile
> > > system: if usertc.c is not present in the arch/${MACHINE}/gen, then a
> > > stub gen/usertc.c file is built that just sets the function pointer to
> > > NULL. This avoids the need for the define checks in dlfcn/init.c and I
> > > think fixes the rest of the issues discussed around this bit.
> > >
> > > Also included in the diff are a few other fixes and regression tests.
> > > I left the rdtsc and acpihpet example (with no functional acpihpet
> > > support) just to show-case how we can handle multiple clocks on
> > > architectures that have them.
> >
> > You're still using tk_user unconditionally.  If the kernel returns a
> > tk_user value that is larger than what's supported by libc you have an
> > out-of-bounds array access.
> >
> > Also if the machine switches to a timecounter that has tk_user == 0
> > you have an out-of-bounds array access.  If that happens you need to
> > detect this and fall back on the system call.
>
> Right. Even though we test in the beginning for tk_user=0 it might change
> until the access to tc_get_timecount(). I will fix this in my next diff.
> Thanks!

Hi,

This iteration of the diff adds bounds checking for tk_user and moves
the usertc.c stub to every arch in libc as recommanded by deraadt@.
It also fixes a gettimeofday issue reported by cheloha@ and tb@.

The acpihpet stub is still there, but it will be removed in the final
diff.

Paul


diff --git lib/libc/arch/aarch64/gen/Makefile.inc lib/libc/arch/aarch64/gen/Makefile.inc
index a7b1b73f3ef..ee198f5d611 100644
--- lib/libc/arch/aarch64/gen/Makefile.inc
+++ lib/libc/arch/aarch64/gen/Makefile.inc
@@ -9,4 +9,4 @@ SRCS+= fpgetmask.c fpgetround.c fpgetsticky.c
 SRCS+= fpsetmask.c fpsetround.c fpsetsticky.c
 SRCS+= fpclassifyl.c
 SRCS+= isfinitel.c isinfl.c isnanl.c isnormall.c
-SRCS+= signbitl.c
+SRCS+= signbitl.c usertc.c
diff --git lib/libc/arch/aarch64/gen/usertc.c lib/libc/arch/aarch64/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/aarch64/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/alpha/gen/Makefile.inc lib/libc/arch/alpha/gen/Makefile.inc
index a44599d2cab..2a8abd32b61 100644
--- lib/libc/arch/alpha/gen/Makefile.inc
+++ lib/libc/arch/alpha/gen/Makefile.inc
@@ -3,5 +3,5 @@
 
 SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c setjmp.S
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
- fpsetround.c fpsetsticky.c
+ fpsetround.c fpsetsticky.c usertc.c
 SRCS+= sigsetjmp.S
diff --git lib/libc/arch/alpha/gen/usertc.c lib/libc/arch/alpha/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/alpha/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/amd64/gen/Makefile.inc lib/libc/arch/amd64/gen/Makefile.inc
index e995309ed71..f6349e2b974 100644
--- lib/libc/arch/amd64/gen/Makefile.inc
+++ lib/libc/arch/amd64/gen/Makefile.inc
@@ -2,6 +2,7 @@
 
 SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.S nan.c setjmp.S \
  sigsetjmp.S
-SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
+SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c \
+ usertc.c
 SRCS+= flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S \
  fpsetround.S fpsetsticky.S
diff --git lib/libc/arch/amd64/gen/usertc.c lib/libc/arch/amd64/gen/usertc.c
new file mode 100644
index 00000000000..3f3052445cf
--- /dev/null
+++ lib/libc/arch/amd64/gen/usertc.c
@@ -0,0 +1,53 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+static uint64_t
+rdtsc()
+{
+ uint32_t hi, lo;
+ asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
+ return ((uint64_t)lo)|(((uint64_t)hi)<<32);
+}
+
+static uint64_t
+acpihpet()
+{
+ return rdtsc(); /* JUST TO COMPILE */
+}
+
+static uint64_t (*get_tc[])(void) =
+{
+ rdtsc,
+ acpihpet,
+};
+
+int
+tc_get_timecount(struct timekeep *tk, uint64_t *tc)
+{
+ int tk_user = tk->tk_user;
+
+ if (tc == NULL || tk_user < 1 || tk_user > tk->tk_nclocks)
+ return -1;
+
+ *tc = (*get_tc[tk_user - 1])();
+ return 0;
+}
+int (*const _tc_get_timecount)(struct timekeep *tk, uint64_t *tc)
+ = tc_get_timecount;
diff --git lib/libc/arch/arm/gen/Makefile.inc lib/libc/arch/arm/gen/Makefile.inc
index 1b4ab2f3ae7..27090a0d9dc 100644
--- lib/libc/arch/arm/gen/Makefile.inc
+++ lib/libc/arch/arm/gen/Makefile.inc
@@ -2,5 +2,5 @@
 # $NetBSD: Makefile.inc,v 1.6 2003/08/01 17:03:47 lukem Exp $
 
 SRCS+= byte_swap_2.S byte_swap_4.S divsi3.S fabs.c flt_rounds.c infinity.c
-SRCS+= ldexp.c modf.c nan.c
+SRCS+= ldexp.c modf.c nan.c usertc.c
 SRCS+= setjmp.S _setjmp.S sigsetjmp.S
diff --git lib/libc/arch/arm/gen/usertc.c lib/libc/arch/arm/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/arm/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/hppa/gen/Makefile.inc lib/libc/arch/hppa/gen/Makefile.inc
index e0c864242fe..1fde24670f1 100644
--- lib/libc/arch/hppa/gen/Makefile.inc
+++ lib/libc/arch/hppa/gen/Makefile.inc
@@ -2,6 +2,6 @@
 
 SRCS+= setjmp.S
 SRCS+= fabs.c
-SRCS+= infinity.c ldexp.c modf.c nan.c
+SRCS+= infinity.c ldexp.c modf.c nan.c usertc.c
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c
diff --git lib/libc/arch/hppa/gen/usertc.c lib/libc/arch/hppa/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/hppa/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/i386/gen/Makefile.inc lib/libc/arch/i386/gen/Makefile.inc
index 4c18e059581..b7dd30adccd 100644
--- lib/libc/arch/i386/gen/Makefile.inc
+++ lib/libc/arch/i386/gen/Makefile.inc
@@ -1,6 +1,6 @@
 # $OpenBSD: Makefile.inc,v 1.14 2012/04/19 19:14:56 deraadt Exp $
 
-SRCS+= _setjmp.S fabs.S infinity.c ldexp.c \
+SRCS+= _setjmp.S fabs.S infinity.c ldexp.c usertc.c \
  modf.S nan.c setjmp.S sigsetjmp.S
 SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
 SRCS+= flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S \
diff --git lib/libc/arch/i386/gen/usertc.c lib/libc/arch/i386/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/i386/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/m88k/gen/Makefile.inc lib/libc/arch/m88k/gen/Makefile.inc
index cff75b8d425..d66f66af4af 100644
--- lib/libc/arch/m88k/gen/Makefile.inc
+++ lib/libc/arch/m88k/gen/Makefile.inc
@@ -1,7 +1,7 @@
 # $OpenBSD: Makefile.inc,v 1.16 2013/06/05 22:06:30 miod Exp $
 # $NetBSD: Makefile.inc,v 1.3 1995/04/10 21:09:06 jtc Exp $
 
-SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c
+SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c usertc.c
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c
 SRCS+= setjmp.S sigsetjmp.S
diff --git lib/libc/arch/m88k/gen/usertc.c lib/libc/arch/m88k/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/m88k/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/mips64/gen/Makefile.inc lib/libc/arch/mips64/gen/Makefile.inc
index 8cf1fc2d28a..839241a2069 100644
--- lib/libc/arch/mips64/gen/Makefile.inc
+++ lib/libc/arch/mips64/gen/Makefile.inc
@@ -1,6 +1,6 @@
 # $OpenBSD: Makefile.inc,v 1.12 2012/04/12 16:14:09 deraadt Exp $
 
-SRCS+= _setjmp.S fabs.S infinity.c ldexp.S modf.S nan.c
+SRCS+= _setjmp.S fabs.S infinity.c ldexp.S modf.S nan.c usertc.c
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c
 SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
diff --git lib/libc/arch/mips64/gen/usertc.c lib/libc/arch/mips64/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/mips64/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/powerpc/gen/Makefile.inc lib/libc/arch/powerpc/gen/Makefile.inc
index 6b2e4613ee8..d4d7b00bff7 100644
--- lib/libc/arch/powerpc/gen/Makefile.inc
+++ lib/libc/arch/powerpc/gen/Makefile.inc
@@ -1,5 +1,5 @@
 SRCS+= infinity.c setjmp.S sigsetjmp.S flt_rounds.c ldexp.c modf.c nan.c
-SRCS+= fabs.c
+SRCS+= fabs.c usertc.c
 SRCS+= fpgetmask.c fpsetmask.c
 SRCS+= fpgetround.c fpsetround.c
 SRCS+= fpgetsticky.c fpsetsticky.c
diff --git lib/libc/arch/powerpc/gen/usertc.c lib/libc/arch/powerpc/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/powerpc/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/sh/gen/Makefile.inc lib/libc/arch/sh/gen/Makefile.inc
index 55de1973b30..4724fb3a6a8 100644
--- lib/libc/arch/sh/gen/Makefile.inc
+++ lib/libc/arch/sh/gen/Makefile.inc
@@ -3,4 +3,4 @@
 SRCS+= flt_rounds.c infinity.c ldexp.c modf.c nan.c setjmp.S _setjmp.S
 SRCS+= sigsetjmp.S
 SRCS+= fabs.c fpgetmask.c fpgetround.c fpgetsticky.c \
- fpsetmask.c fpsetround.c fpsetsticky.c
+ fpsetmask.c fpsetround.c fpsetsticky.c usertc.c
diff --git lib/libc/arch/sh/gen/usertc.c lib/libc/arch/sh/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/sh/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/sparc64/gen/Makefile.inc lib/libc/arch/sparc64/gen/Makefile.inc
index 58259cedef6..a908e022954 100644
--- lib/libc/arch/sparc64/gen/Makefile.inc
+++ lib/libc/arch/sparc64/gen/Makefile.inc
@@ -3,5 +3,5 @@
 SRCS+= _setjmp.S fabs.S fixunsdfsi.S flt_rounds.c fpclassifyl.c \
  fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c infinity.c isfinitel.c \
- isinfl.c isnanl.c isnormall.c ldexp.c modf.S \
+ isinfl.c isnanl.c isnormall.c ldexp.c usertc.c modf.S \
  mul.S nan.c setjmp.S signbitl.c sigsetjmp.S umul.S
diff --git lib/libc/arch/sparc64/gen/usertc.c lib/libc/arch/sparc64/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/sparc64/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/asr/asr.c lib/libc/asr/asr.c
index cd056c85719..2b25d49f32a 100644
--- lib/libc/asr/asr.c
+++ lib/libc/asr/asr.c
@@ -196,11 +196,11 @@ poll_intrsafe(struct pollfd *fds, nfds_t nfds, int timeout)
  struct timespec pollstart, pollend, elapsed;
  int r;
 
- if (clock_gettime(CLOCK_MONOTONIC, &pollstart))
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollstart))
  return -1;
 
  while ((r = poll(fds, 1, timeout)) == -1 && errno == EINTR) {
- if (clock_gettime(CLOCK_MONOTONIC, &pollend))
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollend))
  return -1;
  timespecsub(&pollend, &pollstart, &elapsed);
  timeout -= elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000;
@@ -418,7 +418,7 @@ asr_check_reload(struct asr *asr)
  asr->a_rtime = 0;
  }
 
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1)
  return;
 
  if ((ts.tv_sec - asr->a_rtime) < RELOAD_DELAY && asr->a_rtime != 0)
diff --git lib/libc/crypt/bcrypt.c lib/libc/crypt/bcrypt.c
index 82de8fa33b7..02fd3013cc1 100644
--- lib/libc/crypt/bcrypt.c
+++ lib/libc/crypt/bcrypt.c
@@ -248,9 +248,9 @@ _bcrypt_autorounds(void)
  char buf[_PASSWORD_LEN];
  int duration;
 
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &before);
+ WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &before);
  bcrypt_newhash("testpassword", r, buf, sizeof(buf));
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &after);
+ WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &after);
 
  duration = after.tv_sec - before.tv_sec;
  duration *= 1000000;
diff --git lib/libc/dlfcn/init.c lib/libc/dlfcn/init.c
index 270f54aada5..19d0a2c3ad6 100644
--- lib/libc/dlfcn/init.c
+++ lib/libc/dlfcn/init.c
@@ -20,6 +20,7 @@
 
 #include <sys/types.h>
 #include <sys/syscall.h>
+#include <sys/timetc.h> /* timekeep */
 
 #ifndef PIC
 #include <sys/mman.h>
@@ -45,8 +46,9 @@
 /* XXX should be in an include file shared with csu */
 char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void));
 
-/* provide definition for this */
+/* provide definitions for these */
 int _pagesize = 0;
+void *_timekeep = NULL;
 
 /*
  * In dynamicly linked binaries environ and __progname are overriden by
@@ -105,6 +107,10 @@ _libc_preinit(int argc, char **argv, char **envp, dl_cb_cb *cb)
  phnum = aux->au_v;
  break;
 #endif /* !PIC */
+ case AUX_openbsd_timekeep:
+ if (_tc_get_timecount)
+ _timekeep = (void *)aux->au_v;
+ break;
  }
  }
 
diff --git lib/libc/gen/auth_subr.c lib/libc/gen/auth_subr.c
index 1286a96fe40..32f86eda50f 100644
--- lib/libc/gen/auth_subr.c
+++ lib/libc/gen/auth_subr.c
@@ -752,7 +752,7 @@ auth_check_expire(auth_session_t *as)
 
  if (as->pwd && (quad_t)as->pwd->pw_expire != 0) {
  if (as->now.tv_sec == 0)
- gettimeofday(&as->now, NULL);
+ WRAP(gettimeofday)(&as->now, NULL);
  if ((quad_t)as->now.tv_sec >= (quad_t)as->pwd->pw_expire) {
  as->state &= ~AUTH_ALLOW;
  as->state |= AUTH_EXPIRED;
@@ -779,7 +779,7 @@ auth_check_change(auth_session_t *as)
 
  if (as->pwd && (quad_t)as->pwd->pw_change) {
  if (as->now.tv_sec == 0)
- gettimeofday(&as->now, NULL);
+ WRAP(gettimeofday)(&as->now, NULL);
  if (as->now.tv_sec >= (quad_t)as->pwd->pw_change) {
  as->state &= ~AUTH_ALLOW;
  as->state |= AUTH_PWEXPIRED;
diff --git lib/libc/gen/time.c lib/libc/gen/time.c
index 3bbd0d733d1..b3ce9a800f1 100644
--- lib/libc/gen/time.c
+++ lib/libc/gen/time.c
@@ -36,7 +36,7 @@ time(time_t *t)
 {
  struct timeval tt;
 
- if (gettimeofday(&tt, NULL) == -1)
+ if (WRAP(gettimeofday)(&tt, NULL) == -1)
  return (-1);
  if (t)
  *t = (time_t)tt.tv_sec;
diff --git lib/libc/gen/times.c lib/libc/gen/times.c
index 02e4dd44b5c..36841810d1b 100644
--- lib/libc/gen/times.c
+++ lib/libc/gen/times.c
@@ -52,7 +52,7 @@ times(struct tms *tp)
  return ((clock_t)-1);
  tp->tms_cutime = CONVTCK(ru.ru_utime);
  tp->tms_cstime = CONVTCK(ru.ru_stime);
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1)
  return ((clock_t)-1);
  return (ts.tv_sec * CLK_TCK + ts.tv_nsec / (1000000000 / CLK_TCK));
 }
diff --git lib/libc/gen/timespec_get.c lib/libc/gen/timespec_get.c
index 520a5954025..845cbe80356 100644
--- lib/libc/gen/timespec_get.c
+++ lib/libc/gen/timespec_get.c
@@ -37,7 +37,7 @@ timespec_get(struct timespec *ts, int base)
 {
  switch (base) {
  case TIME_UTC:
- if (clock_gettime(CLOCK_REALTIME, ts) == -1)
+ if (WRAP(clock_gettime)(CLOCK_REALTIME, ts) == -1)
  return 0;
  break;
  default:
diff --git lib/libc/hidden/sys/time.h lib/libc/hidden/sys/time.h
index ed112320fa2..df717021cab 100644
--- lib/libc/hidden/sys/time.h
+++ lib/libc/hidden/sys/time.h
@@ -24,7 +24,7 @@ PROTO_NORMAL(adjfreq);
 PROTO_NORMAL(adjtime);
 PROTO_NORMAL(futimes);
 PROTO_NORMAL(getitimer);
-PROTO_NORMAL(gettimeofday);
+PROTO_WRAP(gettimeofday);
 PROTO_NORMAL(setitimer);
 PROTO_NORMAL(settimeofday);
 PROTO_NORMAL(utimes);
diff --git lib/libc/hidden/sys/timetc.h lib/libc/hidden/sys/timetc.h
new file mode 100644
index 00000000000..d86b31e0d86
--- /dev/null
+++ lib/libc/hidden/sys/timetc.h
@@ -0,0 +1,38 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LIBC_SYS_TIMETC_H_
+#define _LIBC_SYS_TIMETC_H_
+
+#define _LIBC
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include_next <sys/timetc.h>
+
+__BEGIN_HIDDEN_DECLS
+extern void *_timekeep;
+
+extern int (*const _tc_get_timecount)(struct timekeep *, uint64_t *);
+
+int _microtime(struct timeval *, struct timekeep *);
+int _nanotime(struct timespec *, struct timekeep *);
+int _nanoruntime(struct timespec *, struct timekeep *);
+int _nanouptime(struct timespec *, struct timekeep *);
+__END_HIDDEN_DECLS
+
+#endif /* !_LIBC_SYS_TIMETC_H_ */
diff --git lib/libc/hidden/time.h lib/libc/hidden/time.h
index 18c49f8fcb9..d8e1e0caf64 100644
--- lib/libc/hidden/time.h
+++ lib/libc/hidden/time.h
@@ -29,7 +29,7 @@ PROTO_NORMAL(asctime_r);
 PROTO_STD_DEPRECATED(clock);
 PROTO_DEPRECATED(clock_getcpuclockid);
 PROTO_NORMAL(clock_getres);
-PROTO_NORMAL(clock_gettime);
+PROTO_WRAP(clock_gettime);
 PROTO_NORMAL(clock_settime);
 PROTO_STD_DEPRECATED(ctime);
 PROTO_DEPRECATED(ctime_r);
diff --git lib/libc/net/res_random.c lib/libc/net/res_random.c
index 763e420bb88..9babb28470a 100644
--- lib/libc/net/res_random.c
+++ lib/libc/net/res_random.c
@@ -219,7 +219,7 @@ res_initid(void)
  if (ru_prf != NULL)
  arc4random_buf(ru_prf, sizeof(*ru_prf));
 
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts);
  ru_reseed = ts.tv_sec + RU_OUT;
  ru_msb = ru_msb == 0x8000 ? 0 : 0x8000;
 }
@@ -232,7 +232,7 @@ __res_randomid(void)
  u_int r;
  static void *randomid_mutex;
 
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts);
  pid = getpid();
 
  _MUTEX_LOCK(&randomid_mutex);
diff --git lib/libc/rpc/auth_unix.c lib/libc/rpc/auth_unix.c
index 402d98cede4..917a6d42b8a 100644
--- lib/libc/rpc/auth_unix.c
+++ lib/libc/rpc/auth_unix.c
@@ -121,7 +121,7 @@ authunix_create(char *machname, int uid, int gid, int len, int *aup_gids)
  /*
  * fill in param struct from the given params
  */
- (void)gettimeofday(&now,  NULL);
+ (void)WRAP(gettimeofday)(&now,  NULL);
  aup.aup_time = now.tv_sec;
  aup.aup_machname = machname;
  aup.aup_uid = uid;
@@ -274,7 +274,7 @@ authunix_refresh(AUTH *auth)
  goto done;
 
  /* update the time and serialize in place */
- (void)gettimeofday(&now, NULL);
+ (void)WRAP(gettimeofday)(&now, NULL);
  aup.aup_time = now.tv_sec;
  xdrs.x_op = XDR_ENCODE;
  XDR_SETPOS(&xdrs, 0);
diff --git lib/libc/rpc/clnt_tcp.c lib/libc/rpc/clnt_tcp.c
index 8e6ef515b0e..927b4bf2028 100644
--- lib/libc/rpc/clnt_tcp.c
+++ lib/libc/rpc/clnt_tcp.c
@@ -393,12 +393,12 @@ readtcp(struct ct_data *ct, caddr_t buf, int len)
  pfd[0].events = POLLIN;
  TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &wait);
  delta = wait;
- clock_gettime(CLOCK_MONOTONIC, &start);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
  for (;;) {
  r = ppoll(pfd, 1, &delta, NULL);
  save_errno = errno;
 
- clock_gettime(CLOCK_MONOTONIC, &after);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
  timespecsub(&start, &after, &duration);
  timespecsub(&wait, &duration, &delta);
  if (delta.tv_sec < 0 || !timespecisset(&delta))
diff --git lib/libc/rpc/clnt_udp.c lib/libc/rpc/clnt_udp.c
index 68d01674410..92e1d5c350d 100644
--- lib/libc/rpc/clnt_udp.c
+++ lib/libc/rpc/clnt_udp.c
@@ -265,7 +265,7 @@ send_again:
  reply_msg.acpted_rply.ar_results.where = resultsp;
  reply_msg.acpted_rply.ar_results.proc = xresults;
 
- clock_gettime(CLOCK_MONOTONIC, &start);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
  for (;;) {
  switch (ppoll(pfd, 1, &wait, NULL)) {
  case 0:
@@ -283,7 +283,7 @@ send_again:
  /* FALLTHROUGH */
  case -1:
  if (errno == EINTR) {
- clock_gettime(CLOCK_MONOTONIC, &after);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
  timespecsub(&after, &start, &duration);
  timespecadd(&time_waited, &duration, &time_waited);
  if (timespeccmp(&time_waited, &timeout, <))
diff --git lib/libc/rpc/svc_tcp.c lib/libc/rpc/svc_tcp.c
index f9d7a70938f..6c99db84359 100644
--- lib/libc/rpc/svc_tcp.c
+++ lib/libc/rpc/svc_tcp.c
@@ -342,7 +342,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len)
  * A timeout is fatal for the connection.
  */
  delta = wait_per_try;
- clock_gettime(CLOCK_MONOTONIC, &start);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
  pfd[0].fd = sock;
  pfd[0].events = POLLIN;
  do {
@@ -351,7 +351,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len)
  case -1:
  if (errno != EINTR)
  goto fatal_err;
- clock_gettime(CLOCK_MONOTONIC, &after);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
  timespecsub(&after, &start, &duration);
  timespecsub(&wait_per_try, &duration, &delta);
  if (delta.tv_sec < 0 || !timespecisset(&delta))
diff --git lib/libc/sys/Makefile.inc lib/libc/sys/Makefile.inc
index 34769576ced..d57418d81bf 100644
--- lib/libc/sys/Makefile.inc
+++ lib/libc/sys/Makefile.inc
@@ -12,7 +12,8 @@ SRCS+= Ovfork.S brk.S ${CERROR} \
 
 # glue to offer userland wrappers for some syscalls
 SRCS+= posix_madvise.c pthread_sigmask.c \
- w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c
+ w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c \
+ w_clock_gettime.c w_gettimeofday.c microtime.c
 
 # glue for compat with old syscall interfaces.
 SRCS+= ftruncate.c lseek.c mquery.c mmap.c ptrace.c semctl.c truncate.c \
@@ -43,7 +44,7 @@ SRCS+= ${CANCEL:%=w_%.c} w_pread.c w_preadv.c w_pwrite.c w_pwritev.c
 ASM= __semctl.o __syscall.o __thrsigdivert.o \
  access.o acct.o adjfreq.o adjtime.o \
  bind.o chdir.o chflags.o chflagsat.o chmod.o chown.o chroot.o \
- clock_getres.o clock_gettime.o clock_settime.o \
+ clock_getres.o clock_settime.o \
  dup.o dup2.o dup3.o \
  execve.o \
  faccessat.o fchdir.o fchflags.o fchmod.o fchmodat.o fchown.o \
@@ -54,7 +55,7 @@ ASM= __semctl.o __syscall.o __thrsigdivert.o \
  getgroups.o getitimer.o getpeername.o getpgid.o \
  getpriority.o getresgid.o getresuid.o \
  getrlimit.o getrusage.o getsid.o getsockname.o \
- getsockopt.o gettimeofday.o ioctl.o \
+ getsockopt.o ioctl.o \
  kevent.o kill.o kqueue.o ktrace.o lchown.o \
  link.o linkat.o listen.o lstat.o madvise.o \
  minherit.o mkdir.o mkdirat.o mkfifo.o mkfifoat.o \
@@ -109,7 +110,8 @@ PPSEUDO_NOERR=${PSEUDO_NOERR:.o=.po}
 SPSEUDO_NOERR=${PSEUDO_NOERR:.o=.so}
 DPSEUDO_NOERR=${PSEUDO_NOERR:.o=.do}
 
-HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o}
+HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o} \
+ clock_gettime.o gettimeofday.o
 PHIDDEN=${HIDDEN:.o=.po}
 SHIDDEN=${HIDDEN:.o=.so}
 DHIDDEN=${HIDDEN:.o=.do}
diff --git lib/libc/sys/microtime.c lib/libc/sys/microtime.c
new file mode 100644
index 00000000000..fc023e8452f
--- /dev/null
+++ lib/libc/sys/microtime.c
@@ -0,0 +1,180 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2000 Poul-Henning Kamp <[hidden email]>
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/timetc.h>
+
+#include <time.h>
+
+/*
+ * Return the difference between the timehands' counter value now and what
+ * was when we copied it to the timehands' offset_count.
+ */
+static inline int
+tc_delta(struct timekeep *tk, u_int *delta)
+{
+ uint64_t tc;
+ if (delta == NULL || _tc_get_timecount(tk, &tc))
+ return -1;
+ *delta = (tc - tk->tk_offset_count) & tk->tk_counter_mask;
+ return 0;
+}
+
+static inline void
+bintimeaddfrac(const struct bintime *bt, uint64_t x, struct bintime *ct)
+{
+ ct->sec = bt->sec;
+ if (bt->frac > bt->frac + x)
+ ct->sec++;
+ ct->frac = bt->frac + x;
+}
+
+static inline void
+BINTIME_TO_TIMESPEC(const struct bintime *bt, struct timespec *ts)
+{
+ ts->tv_sec = bt->sec;
+ ts->tv_nsec = (long)(((uint64_t)1000000000 * (uint32_t)(bt->frac >> 32)) >> 32);
+}
+
+static inline void
+BINTIME_TO_TIMEVAL(const struct bintime *bt, struct timeval *tv)
+{
+ tv->tv_sec = bt->sec;
+ tv->tv_usec = (long)(((uint64_t)1000000 * (uint32_t)(bt->frac >> 32)) >> 32);
+}
+
+static int
+binuptime(struct bintime *bt, struct timekeep *tk)
+{
+ u_int gen, delta;
+
+ do {
+ gen = tk->tk_generation;
+ membar_consumer();
+ *bt = tk->tk_offset;
+ if (tc_delta(tk, &delta))
+ return -1;
+ bintimeaddfrac(bt, tk->tk_scale * delta, bt);
+ membar_consumer();
+ } while (gen == 0 || gen != tk->tk_generation);
+
+ return 0;
+}
+
+static inline void
+bintimeadd(const struct bintime *bt, const struct bintime *ct,
+    struct bintime *dt)
+{
+ dt->sec = bt->sec + ct->sec;
+ if (bt->frac > bt->frac + ct->frac)
+ dt->sec++;
+ dt->frac = bt->frac + ct->frac;
+}
+
+static inline void
+bintimesub(const struct bintime *bt, const struct bintime *ct,
+    struct bintime *dt)
+{
+ dt->sec = bt->sec - ct->sec;
+ if (bt->frac < bt->frac - ct->frac)
+ dt->sec--;
+ dt->frac = bt->frac - ct->frac;
+}
+
+static int
+binruntime(struct bintime *bt, struct timekeep *tk)
+{
+ u_int gen, delta;
+
+ do {
+ gen = tk->tk_generation;
+ membar_consumer();
+ if (tc_delta(tk, &delta))
+ return -1;
+ bintimeaddfrac(&tk->tk_offset, tk->tk_scale * delta, bt);
+ bintimesub(bt, &tk->tk_naptime, bt);
+ membar_consumer();
+ } while (gen == 0 || gen != tk->tk_generation);
+
+ return 0;
+}
+
+static int
+bintime(struct bintime *bt, struct timekeep *tk)
+{
+ u_int gen, delta;
+
+ do {
+ gen = tk->tk_generation;
+ membar_consumer();
+ *bt = tk->tk_offset;
+ if (tc_delta(tk, &delta))
+ return -1;
+ bintimeaddfrac(bt, tk->tk_scale * delta, bt);
+ bintimeadd(bt, &tk->tk_boottime, bt);
+ membar_consumer();
+ } while (gen == 0 || gen != tk->tk_generation);
+
+ return 0;
+}
+
+int
+_microtime(struct timeval *tvp, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (bintime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMEVAL(&bt, tvp);
+ return 0;
+}
+
+int
+_nanotime(struct timespec *tsp, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (bintime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMESPEC(&bt, tsp);
+ return 0;
+}
+
+int
+_nanoruntime(struct timespec *ts, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (binruntime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMESPEC(&bt, ts);
+ return 0;
+}
+
+
+int
+_nanouptime(struct timespec *tsp, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (binuptime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMESPEC(&bt, tsp);
+ return 0;
+}
diff --git lib/libc/sys/w_clock_gettime.c lib/libc/sys/w_clock_gettime.c
new file mode 100644
index 00000000000..6e6478bd131
--- /dev/null
+++ lib/libc/sys/w_clock_gettime.c
@@ -0,0 +1,51 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/timetc.h>
+
+#include <time.h>
+
+int
+WRAP(clock_gettime)(clockid_t clock_id, struct timespec *tp)
+{
+ int rc = 0;
+ struct timekeep *timekeep = _timekeep;
+
+ if (timekeep == NULL || timekeep->tk_user == 0)
+ return clock_gettime(clock_id, tp);
+
+ switch (clock_id) {
+ case CLOCK_REALTIME:
+ rc = _nanotime(tp, timekeep);
+ break;
+ case CLOCK_UPTIME:
+ rc = _nanoruntime(tp, timekeep);
+ break;
+ case CLOCK_MONOTONIC:
+ case CLOCK_BOOTTIME:
+ rc = _nanouptime(tp, timekeep);
+ break;
+ default:
+ return clock_gettime(clock_id, tp);
+ }
+
+ if (rc)
+ return clock_gettime(clock_id, tp);
+
+ return 0;
+}
+DEF_WRAP(clock_gettime);
diff --git lib/libc/sys/w_gettimeofday.c lib/libc/sys/w_gettimeofday.c
new file mode 100644
index 00000000000..f44edfbb1ad
--- /dev/null
+++ lib/libc/sys/w_gettimeofday.c
@@ -0,0 +1,40 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Robert Nagy <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/timetc.h>
+
+int
+WRAP(gettimeofday)(struct timeval *tp, struct timezone *tzp)
+{
+ int rc = 0;
+ struct timekeep *timekeep = _timekeep;
+ static struct timezone zerotz = { 0, 0 };
+
+ if (timekeep == NULL || timekeep->tk_user == 0)
+ return gettimeofday(tp, tzp);
+
+ if (tp)
+ rc = _microtime(tp, timekeep);
+ if (rc)
+ return gettimeofday(tp, tzp);
+
+ if (tzp)
+ *tzp = zerotz;
+
+ return 0;
+}
+DEF_WRAP(gettimeofday);
diff --git lib/libc/thread/synch.h lib/libc/thread/synch.h
index 788890add89..df2239438d2 100644
--- lib/libc/thread/synch.h
+++ lib/libc/thread/synch.h
@@ -33,7 +33,7 @@ _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *
  if (abs == NULL)
  return futex(p, FUTEX_WAIT_PRIVATE, val, NULL, NULL);
 
- if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel))
+ if (abs->tv_nsec >= 1000000000 || WRAP(clock_gettime)(clockid, &rel))
  return (EINVAL);
 
  rel.tv_sec = abs->tv_sec - rel.tv_sec;
diff --git regress/lib/libc/timekeep/Makefile regress/lib/libc/timekeep/Makefile
new file mode 100644
index 00000000000..a7f3080290d
--- /dev/null
+++ regress/lib/libc/timekeep/Makefile
@@ -0,0 +1,5 @@
+# $OpenBSD$
+
+PROGS= test_clock_gettime test_time_skew test_gettimeofday
+
+.include <bsd.regress.mk>
diff --git regress/lib/libc/timekeep/test_clock_gettime.c regress/lib/libc/timekeep/test_clock_gettime.c
new file mode 100644
index 00000000000..859ec368215
--- /dev/null
+++ regress/lib/libc/timekeep/test_clock_gettime.c
@@ -0,0 +1,43 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <time.h>
+
+#define ASSERT_EQ(a, b) assert((a) == (b))
+
+void
+check()
+{
+ struct timespec tp = {0};
+
+ ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_UPTIME, &tp));
+
+
+ ASSERT_EQ(0, clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp));
+
+}
+
+int main()
+{
+ check();
+ return 0;
+}
diff --git regress/lib/libc/timekeep/test_gettimeofday.c regress/lib/libc/timekeep/test_gettimeofday.c
new file mode 100644
index 00000000000..ea90a1be7e0
--- /dev/null
+++ regress/lib/libc/timekeep/test_gettimeofday.c
@@ -0,0 +1,37 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <sys/time.h>
+
+#define ASSERT_EQ(a, b) assert((a) == (b))
+
+void
+check()
+{
+ struct timeval tv = {0};
+ struct timezone tzp;
+
+ ASSERT_EQ(0, gettimeofday(&tv, NULL));
+ ASSERT_EQ(0, gettimeofday(&tv, &tzp));
+}
+
+int main()
+{
+ check();
+ return 0;
+}
diff --git regress/lib/libc/timekeep/test_time_skew.c regress/lib/libc/timekeep/test_time_skew.c
new file mode 100644
index 00000000000..dfa9481c091
--- /dev/null
+++ regress/lib/libc/timekeep/test_time_skew.c
@@ -0,0 +1,55 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/time.h>
+
+#include <assert.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define ASSERT_EQ(a, b) assert((a) == (b))
+#define ASSERT_NE(a, b) assert((a) != (b))
+
+void
+check()
+{
+         struct timespec tp1, tp2, tout;
+
+         tout.tv_sec = 0;
+         tout.tv_nsec = 100000;
+
+         ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp1));
+
+         nanosleep(&tout, NULL);
+
+         ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp2));
+
+         /* tp1 should never be larger than tp2 */
+         ASSERT_NE(1, timespeccmp(&tp1, &tp2, >));
+}
+
+int
+main(void)
+{
+ int i;
+
+ for (i = 0; i < 1000; i++)
+ check();
+
+ return 0;
+}
diff --git sys/arch/alpha/alpha/clock.c sys/arch/alpha/alpha/clock.c
index 3f5f2c5b42b..6eaf8b107c6 100644
--- sys/arch/alpha/alpha/clock.c
+++ sys/arch/alpha/alpha/clock.c
@@ -64,7 +64,7 @@ int clk_irq = 0;
 
 u_int rpcc_get_timecount(struct timecounter *);
 struct timecounter rpcc_timecounter = {
- rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL
+ rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL, 0
 };
 
 extern todr_chip_handle_t todr_handle;
diff --git sys/arch/alpha/alpha/machdep.c sys/arch/alpha/alpha/machdep.c
index 09dc7e9cba5..9e43723959f 100644
--- sys/arch/alpha/alpha/machdep.c
+++ sys/arch/alpha/alpha/machdep.c
@@ -139,6 +139,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
 struct vm_map *exec_map = NULL;
 struct vm_map *phys_map = NULL;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/amd64/amd64/machdep.c sys/arch/amd64/amd64/machdep.c
index 9dab8947af0..f58ab1a345c 100644
--- sys/arch/amd64/amd64/machdep.c
+++ sys/arch/amd64/amd64/machdep.c
@@ -193,6 +193,9 @@ int lid_action = 1;
 int pwr_action = 1;
 int forceukbd;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 1;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/amd64/amd64/tsc.c sys/arch/amd64/amd64/tsc.c
index 7a1dcb4ad75..3db93d88dec 100644
--- sys/arch/amd64/amd64/tsc.c
+++ sys/arch/amd64/amd64/tsc.c
@@ -50,7 +50,7 @@ extern u_int32_t lapic_per_second;
 #endif
 
 struct timecounter tsc_timecounter = {
- tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL
+ tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL, 1
 };
 
 uint64_t
diff --git sys/arch/amd64/isa/clock.c sys/arch/amd64/isa/clock.c
index 613f7ee0e0f..00da0c6a8d0 100644
--- sys/arch/amd64/isa/clock.c
+++ sys/arch/amd64/isa/clock.c
@@ -116,7 +116,7 @@ u_int i8254_get_timecount(struct timecounter *tc);
 u_int i8254_simple_get_timecount(struct timecounter *tc);
 
 static struct timecounter i8254_timecounter = {
- i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
+ i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0
 };
 
 int clockintr(void *);
diff --git sys/arch/arm64/arm64/machdep.c sys/arch/arm64/arm64/machdep.c
index 4e292479233..2b6165800ca 100644
--- sys/arch/arm64/arm64/machdep.c
+++ sys/arch/arm64/arm64/machdep.c
@@ -90,6 +90,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
 /* the following is used externally (sysctl_hw) */
 char    machine[] = MACHINE;            /* from <machine/param.h> */
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 int safepri = 0;
 
 struct cpu_info cpu_info_primary;
diff --git sys/arch/arm64/dev/agtimer.c sys/arch/arm64/dev/agtimer.c
index 29394141ad5..6b7c6db862f 100644
--- sys/arch/arm64/dev/agtimer.c
+++ sys/arch/arm64/dev/agtimer.c
@@ -43,7 +43,7 @@ int32_t agtimer_frequency = TIMER_FREQUENCY;
 u_int agtimer_get_timecount(struct timecounter *);
 
 static struct timecounter agtimer_timecounter = {
- agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL
+ agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL, 0
 };
 
 struct agtimer_pcpu_softc {
diff --git sys/arch/armv7/omap/gptimer.c sys/arch/armv7/omap/gptimer.c
index 7605845d5e2..061542d532f 100644
--- sys/arch/armv7/omap/gptimer.c
+++ sys/arch/armv7/omap/gptimer.c
@@ -117,7 +117,7 @@ int gptimer_irq = 0;
 u_int gptimer_get_timecount(struct timecounter *);
 
 static struct timecounter gptimer_timecounter = {
- gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL
+ gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL, 0
 };
 
 volatile u_int32_t nexttickevent;
diff --git sys/arch/armv7/sunxi/sxitimer.c sys/arch/armv7/sunxi/sxitimer.c
index 14a243c78d0..41028f9a602 100644
--- sys/arch/armv7/sunxi/sxitimer.c
+++ sys/arch/armv7/sunxi/sxitimer.c
@@ -89,7 +89,7 @@ void sxitimer_delay(u_int);
 u_int sxitimer_get_timecount(struct timecounter *);
 
 static struct timecounter sxitimer_timecounter = {
- sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL
+ sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL, 0
 };
 
 bus_space_tag_t sxitimer_iot;
diff --git sys/arch/hppa/dev/clock.c sys/arch/hppa/dev/clock.c
index 4c594ab5ec7..8cce6c3a893 100644
--- sys/arch/hppa/dev/clock.c
+++ sys/arch/hppa/dev/clock.c
@@ -47,7 +47,7 @@ int cpu_hardclock(void *);
 u_int itmr_get_timecount(struct timecounter *);
 
 struct timecounter itmr_timecounter = {
- itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL
+ itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL, 0
 };
 
 extern todr_chip_handle_t todr_handle;
diff --git sys/arch/hppa/hppa/machdep.c sys/arch/hppa/hppa/machdep.c
index f7bb998d53e..df356e5202f 100644
--- sys/arch/hppa/hppa/machdep.c
+++ sys/arch/hppa/hppa/machdep.c
@@ -152,6 +152,9 @@ void hpmc_dump(void);
 void cpuid(void);
 void blink_led_timeout(void *);
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/i386/i386/machdep.c sys/arch/i386/i386/machdep.c
index 0d392c75802..c22eb22bafe 100644
--- sys/arch/i386/i386/machdep.c
+++ sys/arch/i386/i386/machdep.c
@@ -235,6 +235,9 @@ int lid_action = 1;
 int pwr_action = 1;
 int forceukbd;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/i386/isa/clock.c sys/arch/i386/isa/clock.c
index 09a6db983f2..dd74bd425ad 100644
--- sys/arch/i386/isa/clock.c
+++ sys/arch/i386/isa/clock.c
@@ -129,7 +129,7 @@ u_int i8254_get_timecount(struct timecounter *tc);
 u_int i8254_simple_get_timecount(struct timecounter *tc);
 
 static struct timecounter i8254_timecounter = {
- i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
+ i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0
 };
 struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH);
 u_long rtclock_tval;
diff --git sys/arch/i386/pci/geodesc.c sys/arch/i386/pci/geodesc.c
index 9d9f061eef9..bb8e4c7f9ae 100644
--- sys/arch/i386/pci/geodesc.c
+++ sys/arch/i386/pci/geodesc.c
@@ -65,7 +65,9 @@ struct timecounter geodesc_timecounter = {
  0xffffffff, /* counter_mask */
  27000000, /* frequency */
  "GEOTSC", /* name */
- 2000 /* quality */
+ 2000, /* quality */
+ NULL, /* private bits */
+ 0 /* expose to user */
 };
 
 int
diff --git sys/arch/i386/pci/gscpm.c sys/arch/i386/pci/gscpm.c
index 8b8aa4ac430..a6f324e66f3 100644
--- sys/arch/i386/pci/gscpm.c
+++ sys/arch/i386/pci/gscpm.c
@@ -55,7 +55,9 @@ struct timecounter gscpm_timecounter = {
  0xffffff, /* counter_mask */
  3579545, /* frequency */
  "GSCPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0 /* expose to user */
 };
 
 struct cfattach gscpm_ca = {
diff --git sys/arch/i386/pci/ichpcib.c sys/arch/i386/pci/ichpcib.c
index 6abf1627de2..629a86a14ff 100644
--- sys/arch/i386/pci/ichpcib.c
+++ sys/arch/i386/pci/ichpcib.c
@@ -63,7 +63,9 @@ struct timecounter ichpcib_timecounter = {
  0xffffff, /* counter_mask */
  3579545, /* frequency */
  "ICHPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0 /* expose to user */
 };
 
 struct cfattach ichpcib_ca = {
diff --git sys/arch/landisk/landisk/machdep.c sys/arch/landisk/landisk/machdep.c
index d5ea8df1740..3b515d191c9 100644
--- sys/arch/landisk/landisk/machdep.c
+++ sys/arch/landisk/landisk/machdep.c
@@ -119,6 +119,9 @@ extern u_int32_t getramsize(void);
 struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
 struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/loongson/loongson/generic3a_machdep.c sys/arch/loongson/loongson/generic3a_machdep.c
index ac3f1db6ccd..53489b07549 100644
--- sys/arch/loongson/loongson/generic3a_machdep.c
+++ sys/arch/loongson/loongson/generic3a_machdep.c
@@ -98,7 +98,9 @@ struct timecounter rs780e_timecounter = {
  .tc_counter_mask = 0xffffffffu, /* truncated to 32 bits */
  .tc_frequency = HPET_FREQ,
  .tc_name = "hpet",
- .tc_quality = 100
+ .tc_quality = 100,
+ .tc_priv = NULL,
+ .tc_user = 0,
 };
 
 /* Firmware entry points */
diff --git sys/arch/loongson/loongson/machdep.c sys/arch/loongson/loongson/machdep.c
index aaceb54bea8..9c66faa4b50 100644
--- sys/arch/loongson/loongson/machdep.c
+++ sys/arch/loongson/loongson/machdep.c
@@ -103,6 +103,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
 vm_map_t exec_map;
 vm_map_t phys_map;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/luna88k/luna88k/clock.c sys/arch/luna88k/luna88k/clock.c
index a04120987e0..6580a4a46bf 100644
--- sys/arch/luna88k/luna88k/clock.c
+++ sys/arch/luna88k/luna88k/clock.c
@@ -112,7 +112,9 @@ struct timecounter clock_tc = {
  .tc_counter_mask = 0xffffffff,
  .tc_frequency = 0, /* will be filled in */
  .tc_name = "clock",
- .tc_quality = 0
+ .tc_quality = 0,
+ .tc_priv = NULL,
+ .tc_user = 0,
 };
 
 /*
diff --git sys/arch/luna88k/luna88k/machdep.c sys/arch/luna88k/luna88k/machdep.c
index 9501ad85210..41bbe6793d4 100644
--- sys/arch/luna88k/luna88k/machdep.c
+++ sys/arch/luna88k/luna88k/machdep.c
@@ -193,6 +193,9 @@ int sysconsole = 1; /* 0 = ttya, 1 = keyboard/mouse, used in dev/sio.c */
 u_int16_t dipswitch = 0; /* set in locore.S */
 int hwplanebits; /* set in locore.S */
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 extern struct consdev syscons; /* in dev/siotty.c */
 
 extern void syscnattach(int); /* in dev/siotty.c */
diff --git sys/arch/macppc/macppc/clock.c sys/arch/macppc/macppc/clock.c
index 4a44a92cfc0..8c3ad620be8 100644
--- sys/arch/macppc/macppc/clock.c
+++ sys/arch/macppc/macppc/clock.c
@@ -57,7 +57,7 @@ u_int32_t ns_per_tick = 320;
 static int32_t ticks_per_intr;
 
 static struct timecounter tb_timecounter = {
- tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL
+ tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL, 0
 };
 
 /* calibrate the timecounter frequency for the listed models */
diff --git sys/arch/macppc/macppc/machdep.c sys/arch/macppc/macppc/machdep.c
index 178fe0995da..af4f68ed1d6 100644
--- sys/arch/macppc/macppc/machdep.c
+++ sys/arch/macppc/macppc/machdep.c
@@ -350,6 +350,9 @@ install_extint(void (*handler)(void))
  ppc_mtmsr(omsr);
 }
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/mips64/mips64/mips64_machdep.c sys/arch/mips64/mips64/mips64_machdep.c
index d4a42ed5acc..5c4dbadb5bb 100644
--- sys/arch/mips64/mips64/mips64_machdep.c
+++ sys/arch/mips64/mips64/mips64_machdep.c
@@ -327,7 +327,9 @@ struct timecounter cp0_timecounter = {
  0xffffffff, /* counter_mask */
  0, /* frequency */
  "CP0", /* name */
- 0 /* quality */
+ 0, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 u_int
diff --git sys/arch/octeon/octeon/machdep.c sys/arch/octeon/octeon/machdep.c
index 1387af284ca..0cfabfc642a 100644
--- sys/arch/octeon/octeon/machdep.c
+++ sys/arch/octeon/octeon/machdep.c
@@ -107,6 +107,9 @@ struct boot_info *octeon_boot_info;
 void *octeon_fdt;
 unsigned int octeon_ver;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
@@ -151,8 +154,9 @@ struct timecounter ioclock_timecounter = {
  .tc_name = "ioclock",
  .tc_quality = 0, /* ioclock can be overridden
  * by cp0 counter */
- .tc_priv = 0 /* clock register,
+ .tc_priv = 0, /* clock register,
  * determined at runtime */
+ .tc_user = 0, /* expose to user */
 };
 
 static int
diff --git sys/arch/powerpc64/powerpc64/machdep.c sys/arch/powerpc64/powerpc64/machdep.c
index bae64a1f297..b00bf682b76 100644
--- sys/arch/powerpc64/powerpc64/machdep.c
+++ sys/arch/powerpc64/powerpc64/machdep.c
@@ -43,6 +43,9 @@ int cacheline_size = 128;
 struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
 struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 int cold = 1;
 int safepri = 0;
 int physmem;
diff --git sys/arch/sgi/sgi/ip27_machdep.c sys/arch/sgi/sgi/ip27_machdep.c
index ba7fa558b96..2a2cc144242 100644
--- sys/arch/sgi/sgi/ip27_machdep.c
+++ sys/arch/sgi/sgi/ip27_machdep.c
@@ -111,7 +111,9 @@ struct timecounter ip27_hub_timecounter = {
  .tc_counter_mask = 0xffffffff, /* truncated to 32 bits. */
  .tc_frequency = 1250000,
  .tc_name = "hubrt",
- .tc_quality = 100
+ .tc_quality = 100,
+ .tc_priv = 0,
+ .tc_user = 0,
 };
 
 volatile uint64_t ip27_spinup_a0;
diff --git sys/arch/sgi/sgi/machdep.c sys/arch/sgi/sgi/machdep.c
index d251c15fc01..9b73112addf 100644
--- sys/arch/sgi/sgi/machdep.c
+++ sys/arch/sgi/sgi/machdep.c
@@ -93,6 +93,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
 vm_map_t exec_map;
 vm_map_t phys_map;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/sgi/xbow/xheart.c sys/arch/sgi/xbow/xheart.c
index 56b29915c70..827775512ac 100644
--- sys/arch/sgi/xbow/xheart.c
+++ sys/arch/sgi/xbow/xheart.c
@@ -83,7 +83,9 @@ struct timecounter xheart_timecounter = {
  .tc_counter_mask = 0xffffffff, /* truncate 52-bit counter to 32-bit */
  .tc_frequency = 12500000,
  .tc_name = "heart",
- .tc_quality = 100
+ .tc_quality = 100,
+ .tc_priv = NULL,
+ .tc_user = 0,
 };
 
 extern uint32_t ip30_lights_frob(uint32_t, struct trapframe *);
diff --git sys/arch/sparc64/dev/psycho.c sys/arch/sparc64/dev/psycho.c
index e24f804dff6..1a7a1afa8c2 100644
--- sys/arch/sparc64/dev/psycho.c
+++ sys/arch/sparc64/dev/psycho.c
@@ -127,7 +127,7 @@ extern struct sparc_pci_chipset _sparc_pci_chipset;
 u_int stick_get_timecount(struct timecounter *);
 
 struct timecounter stick_timecounter = {
- stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL
+ stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL, 0
 };
 
 /*
diff --git sys/arch/sparc64/sparc64/clock.c sys/arch/sparc64/sparc64/clock.c
index fd5e8a9c15b..5c2e47d386b 100644
--- sys/arch/sparc64/sparc64/clock.c
+++ sys/arch/sparc64/sparc64/clock.c
@@ -109,13 +109,13 @@ struct cfdriver clock_cd = {
 u_int tick_get_timecount(struct timecounter *);
 
 struct timecounter tick_timecounter = {
- tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL
+ tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL, 0
 };
 
 u_int sys_tick_get_timecount(struct timecounter *);
 
 struct timecounter sys_tick_timecounter = {
- sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL
+ sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL, 0
 };
 
 /*
diff --git sys/arch/sparc64/sparc64/machdep.c sys/arch/sparc64/sparc64/machdep.c
index 05aa4342943..0ee7ff3b802 100644
--- sys/arch/sparc64/sparc64/machdep.c
+++ sys/arch/sparc64/sparc64/machdep.c
@@ -183,6 +183,9 @@ extern int64_t cecclast;
 #define MAX_DMA_SEGS 20
 #endif
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/dev/acpi/acpihpet.c sys/dev/acpi/acpihpet.c
index d0ee72cec9b..13177a909da 100644
--- sys/dev/acpi/acpihpet.c
+++ sys/dev/acpi/acpihpet.c
@@ -45,7 +45,9 @@ static struct timecounter hpet_timecounter = {
  0xffffffff, /* counter_mask (32 bits) */
  0, /* frequency */
  0, /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 #define HPET_TIMERS 3
diff --git sys/dev/acpi/acpitimer.c sys/dev/acpi/acpitimer.c
index cdc8c99a17a..89b5a397e47 100644
--- sys/dev/acpi/acpitimer.c
+++ sys/dev/acpi/acpitimer.c
@@ -36,7 +36,9 @@ static struct timecounter acpi_timecounter = {
  0x00ffffff, /* counter_mask (24 bits) */
  ACPI_FREQUENCY, /* frequency */
  0, /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 struct acpitimer_softc {
diff --git sys/dev/pci/amdpm.c sys/dev/pci/amdpm.c
index 6df82858016..9610d5bc1f0 100644
--- sys/dev/pci/amdpm.c
+++ sys/dev/pci/amdpm.c
@@ -82,7 +82,9 @@ static struct timecounter amdpm_timecounter = {
  0xffffff, /* counter_mask */
  AMDPM_FREQUENCY, /* frequency */
  "AMDPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 #define AMDPM_CONFREG 0x40
diff --git sys/dev/pci/viapm.c sys/dev/pci/viapm.c
index db806eedf80..ce33cd175e6 100644
--- sys/dev/pci/viapm.c
+++ sys/dev/pci/viapm.c
@@ -177,7 +177,9 @@ static struct timecounter viapm_timecounter = {
  0xffffff, /* counter_mask */
  VIAPM_FREQUENCY, /* frequency */
  "VIAPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 struct timeout viapm_timeout;
diff --git sys/dev/pv/hyperv.c sys/dev/pv/hyperv.c
index b32facdacb1..b9ee2feec4c 100644
--- sys/dev/pv/hyperv.c
+++ sys/dev/pv/hyperv.c
@@ -141,7 +141,7 @@ struct {
 };
 
 struct timecounter hv_timecounter = {
- hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001
+ hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001, NULL, 0
 };
 
 struct cfdriver hyperv_cd = {
diff --git sys/dev/pv/pvclock.c sys/dev/pv/pvclock.c
index 6b242f7448d..b80e4d2a484 100644
--- sys/dev/pv/pvclock.c
+++ sys/dev/pv/pvclock.c
@@ -74,7 +74,7 @@ struct cfdriver pvclock_cd = {
 };
 
 struct timecounter pvclock_timecounter = {
- pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL
+ pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL, 0
 };
 
 int
diff --git sys/kern/exec_elf.c sys/kern/exec_elf.c
index 9b5b8eb3acf..59bc923a6fb 100644
--- sys/kern/exec_elf.c
+++ sys/kern/exec_elf.c
@@ -124,7 +124,7 @@ extern char *syscallnames[];
 /*
  * How many entries are in the AuxInfo array we pass to the process?
  */
-#define ELF_AUX_ENTRIES 8
+#define ELF_AUX_ENTRIES 9
 
 /*
  * This is the OpenBSD ELF emul
@@ -860,6 +860,10 @@ exec_elf_fixup(struct proc *p, struct exec_package *epp)
  a->au_v = ap->arg_entry;
  a++;
 
+ a->au_id = AUX_openbsd_timekeep;
+ a->au_v = p->p_p->ps_timekeep;
+ a++;
+
  a->au_id = AUX_null;
  a->au_v = 0;
  a++;
diff --git sys/kern/kern_exec.c sys/kern/kern_exec.c
index 20480c2fc28..9d6a3d9c910 100644
--- sys/kern/kern_exec.c
+++ sys/kern/kern_exec.c
@@ -64,6 +64,11 @@
 #include <uvm/uvm_extern.h>
 #include <machine/tcb.h>
 
+#include <sys/timetc.h>
+
+struct uvm_object *timekeep_object;
+struct timekeep* timekeep;
+
 void unveil_destroy(struct process *ps);
 
 const struct kmem_va_mode kv_exec = {
@@ -76,6 +81,11 @@ const struct kmem_va_mode kv_exec = {
  */
 int exec_sigcode_map(struct process *, struct emul *);
 
+/*
+ * Map the shared timekeep page.
+ */
+int exec_timekeep_map(struct process *);
+
 /*
  * If non-zero, stackgap_random specifies the upper limit of the random gap size
  * added to the fixed stack position. Must be n^2.
@@ -684,6 +694,9 @@ sys_execve(struct proc *p, void *v, register_t *retval)
  /* map the process's signal trampoline code */
  if (exec_sigcode_map(pr, pack.ep_emul))
  goto free_pack_abort;
+ /* map the process's timekeep page */
+ if (exec_timekeep_map(pr))
+ goto free_pack_abort;
 
 #ifdef __HAVE_EXEC_MD_MAP
  /* perform md specific mappings that process might need */
@@ -863,3 +876,42 @@ exec_sigcode_map(struct process *pr, struct emul *e)
 
  return (0);
 }
+
+int
+exec_timekeep_map(struct process *pr)
+{
+ size_t timekeep_sz = sizeof(struct timekeep);
+
+ /*
+ * Similar to the sigcode object, except that there is a single timekeep
+ * object, and not one per emulation.
+ */
+ if (timekeep_object == NULL) {
+ vaddr_t va;
+
+ timekeep_object = uao_create(timekeep_sz, 0);
+ uao_reference(timekeep_object);
+
+ if (uvm_map(kernel_map, &va, round_page(timekeep_sz), timekeep_object,
+    0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
+    MAP_INHERIT_SHARE, MADV_RANDOM, 0))) {
+ uao_detach(timekeep_object);
+ return (ENOMEM);
+ }
+
+ timekeep = (struct timekeep *)va;
+ timekeep->tk_major = 0;
+ timekeep->tk_minor = 0;
+ timekeep->tk_nclocks = tk_nclocks;
+ }
+
+ uao_reference(timekeep_object);
+ if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_timekeep, round_page(timekeep_sz),
+    timekeep_object, 0, 0, UVM_MAPFLAG(PROT_READ, PROT_READ,
+    MAP_INHERIT_COPY, MADV_RANDOM, 0))) {
+ uao_detach(timekeep_object);
+ return (ENOMEM);
+ }
+
+ return (0);
+}
diff --git sys/kern/kern_tc.c sys/kern/kern_tc.c
index 88d4a3379f9..47efbdd0b78 100644
--- sys/kern/kern_tc.c
+++ sys/kern/kern_tc.c
@@ -63,7 +63,7 @@ dummy_get_timecount(struct timecounter *tc)
 }
 
 static struct timecounter dummy_timecounter = {
- dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000
+ dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000, NULL, 0
 };
 
 /*
@@ -479,6 +479,34 @@ tc_setclock(const struct timespec *ts)
 #endif
 }
 
+void
+tc_update_timekeep(void)
+{
+ static struct timecounter *last_tc = NULL;
+ struct timehands *th;
+
+ if (timekeep == NULL)
+ return;
+
+ th = timehands;
+ timekeep->tk_generation = 0;
+ membar_producer();
+ timekeep->tk_scale = th->th_scale;
+ timekeep->tk_offset_count = th->th_offset_count;
+ timekeep->tk_offset = th->th_offset;
+ timekeep->tk_naptime = th->th_naptime;
+ timekeep->tk_boottime = th->th_boottime;
+ if (last_tc != th->th_counter) {
+ timekeep->tk_counter_mask = th->th_counter->tc_counter_mask;
+ timekeep->tk_user = th->th_counter->tc_user;
+ last_tc = th->th_counter;
+ }
+ membar_producer();
+ timekeep->tk_generation = th->th_generation;
+
+ return;
+}
+
 /*
  * Initialize the next struct timehands in the ring and make
  * it the active timehands.  Along the way we might switch to a different
@@ -631,6 +659,8 @@ tc_windup(struct bintime *new_boottime, struct bintime *new_offset,
  time_uptime = th->th_offset.sec;
  membar_producer();
  timehands = th;
+
+ tc_update_timekeep();
 }
 
 /* Report or change the active timecounter hardware. */
diff --git sys/sys/exec_elf.h sys/sys/exec_elf.h
index a40e0510273..3084ed595a6 100644
--- sys/sys/exec_elf.h
+++ sys/sys/exec_elf.h
@@ -691,7 +691,8 @@ enum AuxID {
  AUX_sun_uid = 2000, /* euid */
  AUX_sun_ruid = 2001, /* ruid */
  AUX_sun_gid = 2002, /* egid */
- AUX_sun_rgid = 2003 /* rgid */
+ AUX_sun_rgid = 2003, /* rgid */
+ AUX_openbsd_timekeep = 4000, /* userland clock_gettime */
 };
 
 struct elf_args {
diff --git sys/sys/proc.h sys/sys/proc.h
index 357c0c0d52c..c6d54572bdd 100644
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -242,6 +242,7 @@ struct process {
  char ps_comm[MAXCOMLEN+1];
 
  vaddr_t ps_strings; /* User pointers to argv/env */
+ vaddr_t ps_timekeep; /* User pointer to timekeep */
  vaddr_t ps_sigcode; /* User pointer to the signal code */
  vaddr_t ps_sigcoderet; /* User pointer to sigreturn retPC */
  u_long ps_sigcookie;
diff --git sys/sys/time.h sys/sys/time.h
index e758a64ce07..bcd3acd034d 100644
--- sys/sys/time.h
+++ sys/sys/time.h
@@ -163,7 +163,7 @@ struct clockinfo {
 };
 #endif /* __BSD_VISIBLE */
 
-#if defined(_KERNEL) || defined(_STANDALONE)
+#if defined(_KERNEL) || defined(_STANDALONE) || defined (_LIBC)
 #include <sys/_time.h>
 
 /* Time expressed as seconds and fractions of a second + operations on it. */
@@ -171,6 +171,9 @@ struct bintime {
  time_t sec;
  uint64_t frac;
 };
+#endif
+
+#if defined(_KERNEL) || defined(_STANDALONE)
 
 #define bintimecmp(btp, ctp, cmp) \
  ((btp)->sec == (ctp)->sec ? \
diff --git sys/sys/timetc.h sys/sys/timetc.h
index ce81c3475a0..a4a80eecff1 100644
--- sys/sys/timetc.h
+++ sys/sys/timetc.h
@@ -24,7 +24,7 @@
 #ifndef _SYS_TIMETC_H_
 #define _SYS_TIMETC_H_
 
-#ifndef _KERNEL
+#if !defined(_KERNEL) && !defined(_LIBC)
 #error "no user-serviceable parts inside"
 #endif
 
@@ -80,6 +80,8 @@ struct timecounter {
  */
  void *tc_priv; /* [I] */
  /* Pointer to the timecounter's private parts. */
+ int tc_user; /* [I] */
+ /* Expose this timecounter to userland. */
  SLIST_ENTRY(timecounter) tc_next; /* [I] */
  /* Pointer to the next timecounter. */
  int64_t tc_freq_adj; /* [tw] */
@@ -88,11 +90,34 @@ struct timecounter {
  /* Precision of the counter.  Computed in tc_init(). */
 };
 
+struct timekeep {
+ /* set at initialization */
+ uint32_t tk_major; /* version major number */
+ uint32_t tk_minor; /* version minor number */
+ int tk_nclocks; /* number of arch user clocks */
+
+ /* timehands members */
+ uint64_t tk_scale;
+ u_int tk_offset_count;
+ struct bintime tk_offset;
+ struct bintime tk_naptime;
+ struct bintime tk_boottime;
+ volatile u_int tk_generation;
+
+ /* timecounter members */
+ int tk_user;
+ u_int tk_counter_mask;
+};
+extern int tk_nclocks;
+
 struct rwlock;
 extern struct rwlock tc_lock;
 
 extern struct timecounter *timecounter;
 
+extern struct uvm_object *timekeep_object;
+extern struct timekeep *timekeep;
+
 u_int64_t tc_getfrequency(void);
 u_int64_t tc_getprecision(void);
 void tc_init(struct timecounter *tc);

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Stuart Henderson
On 2020/06/08 12:59, Paul Irofti wrote:
> This iteration of the diff adds bounds checking for tk_user and moves
> the usertc.c stub to every arch in libc as recommanded by deraadt@.
> It also fixes a gettimeofday issue reported by cheloha@ and tb@.
>
> The acpihpet stub is still there, but it will be removed in the final
> diff.

Good timing as I wanted to update my kernel for the DRM update anyway
now that I don't have to pick that out of git :)

FWIW it's still working as expected on my uninteresting amd64.

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Paul Irofti-4
In reply to this post by Paul Irofti-4
> This iteration of the diff adds bounds checking for tk_user and moves
> the usertc.c stub to every arch in libc as recommanded by deraadt@.
> It also fixes a gettimeofday issue reported by cheloha@ and tb@.

Forgot to add armv7 tk_nclock entries. Noticed by benno@, thanks!


diff --git lib/libc/arch/aarch64/gen/Makefile.inc lib/libc/arch/aarch64/gen/Makefile.inc
index a7b1b73f3ef..ee198f5d611 100644
--- lib/libc/arch/aarch64/gen/Makefile.inc
+++ lib/libc/arch/aarch64/gen/Makefile.inc
@@ -9,4 +9,4 @@ SRCS+= fpgetmask.c fpgetround.c fpgetsticky.c
 SRCS+= fpsetmask.c fpsetround.c fpsetsticky.c
 SRCS+= fpclassifyl.c
 SRCS+= isfinitel.c isinfl.c isnanl.c isnormall.c
-SRCS+= signbitl.c
+SRCS+= signbitl.c usertc.c
diff --git lib/libc/arch/aarch64/gen/usertc.c lib/libc/arch/aarch64/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/aarch64/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/alpha/gen/Makefile.inc lib/libc/arch/alpha/gen/Makefile.inc
index a44599d2cab..2a8abd32b61 100644
--- lib/libc/arch/alpha/gen/Makefile.inc
+++ lib/libc/arch/alpha/gen/Makefile.inc
@@ -3,5 +3,5 @@
 
 SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c setjmp.S
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
- fpsetround.c fpsetsticky.c
+ fpsetround.c fpsetsticky.c usertc.c
 SRCS+= sigsetjmp.S
diff --git lib/libc/arch/alpha/gen/usertc.c lib/libc/arch/alpha/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/alpha/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/amd64/gen/Makefile.inc lib/libc/arch/amd64/gen/Makefile.inc
index e995309ed71..f6349e2b974 100644
--- lib/libc/arch/amd64/gen/Makefile.inc
+++ lib/libc/arch/amd64/gen/Makefile.inc
@@ -2,6 +2,7 @@
 
 SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.S nan.c setjmp.S \
  sigsetjmp.S
-SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
+SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c \
+ usertc.c
 SRCS+= flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S \
  fpsetround.S fpsetsticky.S
diff --git lib/libc/arch/amd64/gen/usertc.c lib/libc/arch/amd64/gen/usertc.c
new file mode 100644
index 00000000000..3f3052445cf
--- /dev/null
+++ lib/libc/arch/amd64/gen/usertc.c
@@ -0,0 +1,53 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+static uint64_t
+rdtsc()
+{
+ uint32_t hi, lo;
+ asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
+ return ((uint64_t)lo)|(((uint64_t)hi)<<32);
+}
+
+static uint64_t
+acpihpet()
+{
+ return rdtsc(); /* JUST TO COMPILE */
+}
+
+static uint64_t (*get_tc[])(void) =
+{
+ rdtsc,
+ acpihpet,
+};
+
+int
+tc_get_timecount(struct timekeep *tk, uint64_t *tc)
+{
+ int tk_user = tk->tk_user;
+
+ if (tc == NULL || tk_user < 1 || tk_user > tk->tk_nclocks)
+ return -1;
+
+ *tc = (*get_tc[tk_user - 1])();
+ return 0;
+}
+int (*const _tc_get_timecount)(struct timekeep *tk, uint64_t *tc)
+ = tc_get_timecount;
diff --git lib/libc/arch/arm/gen/Makefile.inc lib/libc/arch/arm/gen/Makefile.inc
index 1b4ab2f3ae7..27090a0d9dc 100644
--- lib/libc/arch/arm/gen/Makefile.inc
+++ lib/libc/arch/arm/gen/Makefile.inc
@@ -2,5 +2,5 @@
 # $NetBSD: Makefile.inc,v 1.6 2003/08/01 17:03:47 lukem Exp $
 
 SRCS+= byte_swap_2.S byte_swap_4.S divsi3.S fabs.c flt_rounds.c infinity.c
-SRCS+= ldexp.c modf.c nan.c
+SRCS+= ldexp.c modf.c nan.c usertc.c
 SRCS+= setjmp.S _setjmp.S sigsetjmp.S
diff --git lib/libc/arch/arm/gen/usertc.c lib/libc/arch/arm/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/arm/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/hppa/gen/Makefile.inc lib/libc/arch/hppa/gen/Makefile.inc
index e0c864242fe..1fde24670f1 100644
--- lib/libc/arch/hppa/gen/Makefile.inc
+++ lib/libc/arch/hppa/gen/Makefile.inc
@@ -2,6 +2,6 @@
 
 SRCS+= setjmp.S
 SRCS+= fabs.c
-SRCS+= infinity.c ldexp.c modf.c nan.c
+SRCS+= infinity.c ldexp.c modf.c nan.c usertc.c
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c
diff --git lib/libc/arch/hppa/gen/usertc.c lib/libc/arch/hppa/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/hppa/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/i386/gen/Makefile.inc lib/libc/arch/i386/gen/Makefile.inc
index 4c18e059581..b7dd30adccd 100644
--- lib/libc/arch/i386/gen/Makefile.inc
+++ lib/libc/arch/i386/gen/Makefile.inc
@@ -1,6 +1,6 @@
 # $OpenBSD: Makefile.inc,v 1.14 2012/04/19 19:14:56 deraadt Exp $
 
-SRCS+= _setjmp.S fabs.S infinity.c ldexp.c \
+SRCS+= _setjmp.S fabs.S infinity.c ldexp.c usertc.c \
  modf.S nan.c setjmp.S sigsetjmp.S
 SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
 SRCS+= flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S \
diff --git lib/libc/arch/i386/gen/usertc.c lib/libc/arch/i386/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/i386/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/m88k/gen/Makefile.inc lib/libc/arch/m88k/gen/Makefile.inc
index cff75b8d425..d66f66af4af 100644
--- lib/libc/arch/m88k/gen/Makefile.inc
+++ lib/libc/arch/m88k/gen/Makefile.inc
@@ -1,7 +1,7 @@
 # $OpenBSD: Makefile.inc,v 1.16 2013/06/05 22:06:30 miod Exp $
 # $NetBSD: Makefile.inc,v 1.3 1995/04/10 21:09:06 jtc Exp $
 
-SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c
+SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c usertc.c
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c
 SRCS+= setjmp.S sigsetjmp.S
diff --git lib/libc/arch/m88k/gen/usertc.c lib/libc/arch/m88k/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/m88k/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/mips64/gen/Makefile.inc lib/libc/arch/mips64/gen/Makefile.inc
index 8cf1fc2d28a..839241a2069 100644
--- lib/libc/arch/mips64/gen/Makefile.inc
+++ lib/libc/arch/mips64/gen/Makefile.inc
@@ -1,6 +1,6 @@
 # $OpenBSD: Makefile.inc,v 1.12 2012/04/12 16:14:09 deraadt Exp $
 
-SRCS+= _setjmp.S fabs.S infinity.c ldexp.S modf.S nan.c
+SRCS+= _setjmp.S fabs.S infinity.c ldexp.S modf.S nan.c usertc.c
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c
 SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
diff --git lib/libc/arch/mips64/gen/usertc.c lib/libc/arch/mips64/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/mips64/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/powerpc/gen/Makefile.inc lib/libc/arch/powerpc/gen/Makefile.inc
index 6b2e4613ee8..d4d7b00bff7 100644
--- lib/libc/arch/powerpc/gen/Makefile.inc
+++ lib/libc/arch/powerpc/gen/Makefile.inc
@@ -1,5 +1,5 @@
 SRCS+= infinity.c setjmp.S sigsetjmp.S flt_rounds.c ldexp.c modf.c nan.c
-SRCS+= fabs.c
+SRCS+= fabs.c usertc.c
 SRCS+= fpgetmask.c fpsetmask.c
 SRCS+= fpgetround.c fpsetround.c
 SRCS+= fpgetsticky.c fpsetsticky.c
diff --git lib/libc/arch/powerpc/gen/usertc.c lib/libc/arch/powerpc/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/powerpc/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/sh/gen/Makefile.inc lib/libc/arch/sh/gen/Makefile.inc
index 55de1973b30..4724fb3a6a8 100644
--- lib/libc/arch/sh/gen/Makefile.inc
+++ lib/libc/arch/sh/gen/Makefile.inc
@@ -3,4 +3,4 @@
 SRCS+= flt_rounds.c infinity.c ldexp.c modf.c nan.c setjmp.S _setjmp.S
 SRCS+= sigsetjmp.S
 SRCS+= fabs.c fpgetmask.c fpgetround.c fpgetsticky.c \
- fpsetmask.c fpsetround.c fpsetsticky.c
+ fpsetmask.c fpsetround.c fpsetsticky.c usertc.c
diff --git lib/libc/arch/sh/gen/usertc.c lib/libc/arch/sh/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/sh/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/sparc64/gen/Makefile.inc lib/libc/arch/sparc64/gen/Makefile.inc
index 58259cedef6..a908e022954 100644
--- lib/libc/arch/sparc64/gen/Makefile.inc
+++ lib/libc/arch/sparc64/gen/Makefile.inc
@@ -3,5 +3,5 @@
 SRCS+= _setjmp.S fabs.S fixunsdfsi.S flt_rounds.c fpclassifyl.c \
  fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c infinity.c isfinitel.c \
- isinfl.c isnanl.c isnormall.c ldexp.c modf.S \
+ isinfl.c isnanl.c isnormall.c ldexp.c usertc.c modf.S \
  mul.S nan.c setjmp.S signbitl.c sigsetjmp.S umul.S
diff --git lib/libc/arch/sparc64/gen/usertc.c lib/libc/arch/sparc64/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/sparc64/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/asr/asr.c lib/libc/asr/asr.c
index cd056c85719..2b25d49f32a 100644
--- lib/libc/asr/asr.c
+++ lib/libc/asr/asr.c
@@ -196,11 +196,11 @@ poll_intrsafe(struct pollfd *fds, nfds_t nfds, int timeout)
  struct timespec pollstart, pollend, elapsed;
  int r;
 
- if (clock_gettime(CLOCK_MONOTONIC, &pollstart))
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollstart))
  return -1;
 
  while ((r = poll(fds, 1, timeout)) == -1 && errno == EINTR) {
- if (clock_gettime(CLOCK_MONOTONIC, &pollend))
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollend))
  return -1;
  timespecsub(&pollend, &pollstart, &elapsed);
  timeout -= elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000;
@@ -418,7 +418,7 @@ asr_check_reload(struct asr *asr)
  asr->a_rtime = 0;
  }
 
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1)
  return;
 
  if ((ts.tv_sec - asr->a_rtime) < RELOAD_DELAY && asr->a_rtime != 0)
diff --git lib/libc/crypt/bcrypt.c lib/libc/crypt/bcrypt.c
index 82de8fa33b7..02fd3013cc1 100644
--- lib/libc/crypt/bcrypt.c
+++ lib/libc/crypt/bcrypt.c
@@ -248,9 +248,9 @@ _bcrypt_autorounds(void)
  char buf[_PASSWORD_LEN];
  int duration;
 
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &before);
+ WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &before);
  bcrypt_newhash("testpassword", r, buf, sizeof(buf));
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &after);
+ WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &after);
 
  duration = after.tv_sec - before.tv_sec;
  duration *= 1000000;
diff --git lib/libc/dlfcn/init.c lib/libc/dlfcn/init.c
index 270f54aada5..19d0a2c3ad6 100644
--- lib/libc/dlfcn/init.c
+++ lib/libc/dlfcn/init.c
@@ -20,6 +20,7 @@
 
 #include <sys/types.h>
 #include <sys/syscall.h>
+#include <sys/timetc.h> /* timekeep */
 
 #ifndef PIC
 #include <sys/mman.h>
@@ -45,8 +46,9 @@
 /* XXX should be in an include file shared with csu */
 char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void));
 
-/* provide definition for this */
+/* provide definitions for these */
 int _pagesize = 0;
+void *_timekeep = NULL;
 
 /*
  * In dynamicly linked binaries environ and __progname are overriden by
@@ -105,6 +107,10 @@ _libc_preinit(int argc, char **argv, char **envp, dl_cb_cb *cb)
  phnum = aux->au_v;
  break;
 #endif /* !PIC */
+ case AUX_openbsd_timekeep:
+ if (_tc_get_timecount)
+ _timekeep = (void *)aux->au_v;
+ break;
  }
  }
 
diff --git lib/libc/gen/auth_subr.c lib/libc/gen/auth_subr.c
index 1286a96fe40..32f86eda50f 100644
--- lib/libc/gen/auth_subr.c
+++ lib/libc/gen/auth_subr.c
@@ -752,7 +752,7 @@ auth_check_expire(auth_session_t *as)
 
  if (as->pwd && (quad_t)as->pwd->pw_expire != 0) {
  if (as->now.tv_sec == 0)
- gettimeofday(&as->now, NULL);
+ WRAP(gettimeofday)(&as->now, NULL);
  if ((quad_t)as->now.tv_sec >= (quad_t)as->pwd->pw_expire) {
  as->state &= ~AUTH_ALLOW;
  as->state |= AUTH_EXPIRED;
@@ -779,7 +779,7 @@ auth_check_change(auth_session_t *as)
 
  if (as->pwd && (quad_t)as->pwd->pw_change) {
  if (as->now.tv_sec == 0)
- gettimeofday(&as->now, NULL);
+ WRAP(gettimeofday)(&as->now, NULL);
  if (as->now.tv_sec >= (quad_t)as->pwd->pw_change) {
  as->state &= ~AUTH_ALLOW;
  as->state |= AUTH_PWEXPIRED;
diff --git lib/libc/gen/time.c lib/libc/gen/time.c
index 3bbd0d733d1..b3ce9a800f1 100644
--- lib/libc/gen/time.c
+++ lib/libc/gen/time.c
@@ -36,7 +36,7 @@ time(time_t *t)
 {
  struct timeval tt;
 
- if (gettimeofday(&tt, NULL) == -1)
+ if (WRAP(gettimeofday)(&tt, NULL) == -1)
  return (-1);
  if (t)
  *t = (time_t)tt.tv_sec;
diff --git lib/libc/gen/times.c lib/libc/gen/times.c
index 02e4dd44b5c..36841810d1b 100644
--- lib/libc/gen/times.c
+++ lib/libc/gen/times.c
@@ -52,7 +52,7 @@ times(struct tms *tp)
  return ((clock_t)-1);
  tp->tms_cutime = CONVTCK(ru.ru_utime);
  tp->tms_cstime = CONVTCK(ru.ru_stime);
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1)
  return ((clock_t)-1);
  return (ts.tv_sec * CLK_TCK + ts.tv_nsec / (1000000000 / CLK_TCK));
 }
diff --git lib/libc/gen/timespec_get.c lib/libc/gen/timespec_get.c
index 520a5954025..845cbe80356 100644
--- lib/libc/gen/timespec_get.c
+++ lib/libc/gen/timespec_get.c
@@ -37,7 +37,7 @@ timespec_get(struct timespec *ts, int base)
 {
  switch (base) {
  case TIME_UTC:
- if (clock_gettime(CLOCK_REALTIME, ts) == -1)
+ if (WRAP(clock_gettime)(CLOCK_REALTIME, ts) == -1)
  return 0;
  break;
  default:
diff --git lib/libc/hidden/sys/time.h lib/libc/hidden/sys/time.h
index ed112320fa2..df717021cab 100644
--- lib/libc/hidden/sys/time.h
+++ lib/libc/hidden/sys/time.h
@@ -24,7 +24,7 @@ PROTO_NORMAL(adjfreq);
 PROTO_NORMAL(adjtime);
 PROTO_NORMAL(futimes);
 PROTO_NORMAL(getitimer);
-PROTO_NORMAL(gettimeofday);
+PROTO_WRAP(gettimeofday);
 PROTO_NORMAL(setitimer);
 PROTO_NORMAL(settimeofday);
 PROTO_NORMAL(utimes);
diff --git lib/libc/hidden/sys/timetc.h lib/libc/hidden/sys/timetc.h
new file mode 100644
index 00000000000..d86b31e0d86
--- /dev/null
+++ lib/libc/hidden/sys/timetc.h
@@ -0,0 +1,38 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LIBC_SYS_TIMETC_H_
+#define _LIBC_SYS_TIMETC_H_
+
+#define _LIBC
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include_next <sys/timetc.h>
+
+__BEGIN_HIDDEN_DECLS
+extern void *_timekeep;
+
+extern int (*const _tc_get_timecount)(struct timekeep *, uint64_t *);
+
+int _microtime(struct timeval *, struct timekeep *);
+int _nanotime(struct timespec *, struct timekeep *);
+int _nanoruntime(struct timespec *, struct timekeep *);
+int _nanouptime(struct timespec *, struct timekeep *);
+__END_HIDDEN_DECLS
+
+#endif /* !_LIBC_SYS_TIMETC_H_ */
diff --git lib/libc/hidden/time.h lib/libc/hidden/time.h
index 18c49f8fcb9..d8e1e0caf64 100644
--- lib/libc/hidden/time.h
+++ lib/libc/hidden/time.h
@@ -29,7 +29,7 @@ PROTO_NORMAL(asctime_r);
 PROTO_STD_DEPRECATED(clock);
 PROTO_DEPRECATED(clock_getcpuclockid);
 PROTO_NORMAL(clock_getres);
-PROTO_NORMAL(clock_gettime);
+PROTO_WRAP(clock_gettime);
 PROTO_NORMAL(clock_settime);
 PROTO_STD_DEPRECATED(ctime);
 PROTO_DEPRECATED(ctime_r);
diff --git lib/libc/net/res_random.c lib/libc/net/res_random.c
index 763e420bb88..9babb28470a 100644
--- lib/libc/net/res_random.c
+++ lib/libc/net/res_random.c
@@ -219,7 +219,7 @@ res_initid(void)
  if (ru_prf != NULL)
  arc4random_buf(ru_prf, sizeof(*ru_prf));
 
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts);
  ru_reseed = ts.tv_sec + RU_OUT;
  ru_msb = ru_msb == 0x8000 ? 0 : 0x8000;
 }
@@ -232,7 +232,7 @@ __res_randomid(void)
  u_int r;
  static void *randomid_mutex;
 
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts);
  pid = getpid();
 
  _MUTEX_LOCK(&randomid_mutex);
diff --git lib/libc/rpc/auth_unix.c lib/libc/rpc/auth_unix.c
index 402d98cede4..917a6d42b8a 100644
--- lib/libc/rpc/auth_unix.c
+++ lib/libc/rpc/auth_unix.c
@@ -121,7 +121,7 @@ authunix_create(char *machname, int uid, int gid, int len, int *aup_gids)
  /*
  * fill in param struct from the given params
  */
- (void)gettimeofday(&now,  NULL);
+ (void)WRAP(gettimeofday)(&now,  NULL);
  aup.aup_time = now.tv_sec;
  aup.aup_machname = machname;
  aup.aup_uid = uid;
@@ -274,7 +274,7 @@ authunix_refresh(AUTH *auth)
  goto done;
 
  /* update the time and serialize in place */
- (void)gettimeofday(&now, NULL);
+ (void)WRAP(gettimeofday)(&now, NULL);
  aup.aup_time = now.tv_sec;
  xdrs.x_op = XDR_ENCODE;
  XDR_SETPOS(&xdrs, 0);
diff --git lib/libc/rpc/clnt_tcp.c lib/libc/rpc/clnt_tcp.c
index 8e6ef515b0e..927b4bf2028 100644
--- lib/libc/rpc/clnt_tcp.c
+++ lib/libc/rpc/clnt_tcp.c
@@ -393,12 +393,12 @@ readtcp(struct ct_data *ct, caddr_t buf, int len)
  pfd[0].events = POLLIN;
  TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &wait);
  delta = wait;
- clock_gettime(CLOCK_MONOTONIC, &start);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
  for (;;) {
  r = ppoll(pfd, 1, &delta, NULL);
  save_errno = errno;
 
- clock_gettime(CLOCK_MONOTONIC, &after);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
  timespecsub(&start, &after, &duration);
  timespecsub(&wait, &duration, &delta);
  if (delta.tv_sec < 0 || !timespecisset(&delta))
diff --git lib/libc/rpc/clnt_udp.c lib/libc/rpc/clnt_udp.c
index 68d01674410..92e1d5c350d 100644
--- lib/libc/rpc/clnt_udp.c
+++ lib/libc/rpc/clnt_udp.c
@@ -265,7 +265,7 @@ send_again:
  reply_msg.acpted_rply.ar_results.where = resultsp;
  reply_msg.acpted_rply.ar_results.proc = xresults;
 
- clock_gettime(CLOCK_MONOTONIC, &start);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
  for (;;) {
  switch (ppoll(pfd, 1, &wait, NULL)) {
  case 0:
@@ -283,7 +283,7 @@ send_again:
  /* FALLTHROUGH */
  case -1:
  if (errno == EINTR) {
- clock_gettime(CLOCK_MONOTONIC, &after);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
  timespecsub(&after, &start, &duration);
  timespecadd(&time_waited, &duration, &time_waited);
  if (timespeccmp(&time_waited, &timeout, <))
diff --git lib/libc/rpc/svc_tcp.c lib/libc/rpc/svc_tcp.c
index f9d7a70938f..6c99db84359 100644
--- lib/libc/rpc/svc_tcp.c
+++ lib/libc/rpc/svc_tcp.c
@@ -342,7 +342,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len)
  * A timeout is fatal for the connection.
  */
  delta = wait_per_try;
- clock_gettime(CLOCK_MONOTONIC, &start);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
  pfd[0].fd = sock;
  pfd[0].events = POLLIN;
  do {
@@ -351,7 +351,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len)
  case -1:
  if (errno != EINTR)
  goto fatal_err;
- clock_gettime(CLOCK_MONOTONIC, &after);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
  timespecsub(&after, &start, &duration);
  timespecsub(&wait_per_try, &duration, &delta);
  if (delta.tv_sec < 0 || !timespecisset(&delta))
diff --git lib/libc/sys/Makefile.inc lib/libc/sys/Makefile.inc
index 34769576ced..d57418d81bf 100644
--- lib/libc/sys/Makefile.inc
+++ lib/libc/sys/Makefile.inc
@@ -12,7 +12,8 @@ SRCS+= Ovfork.S brk.S ${CERROR} \
 
 # glue to offer userland wrappers for some syscalls
 SRCS+= posix_madvise.c pthread_sigmask.c \
- w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c
+ w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c \
+ w_clock_gettime.c w_gettimeofday.c microtime.c
 
 # glue for compat with old syscall interfaces.
 SRCS+= ftruncate.c lseek.c mquery.c mmap.c ptrace.c semctl.c truncate.c \
@@ -43,7 +44,7 @@ SRCS+= ${CANCEL:%=w_%.c} w_pread.c w_preadv.c w_pwrite.c w_pwritev.c
 ASM= __semctl.o __syscall.o __thrsigdivert.o \
  access.o acct.o adjfreq.o adjtime.o \
  bind.o chdir.o chflags.o chflagsat.o chmod.o chown.o chroot.o \
- clock_getres.o clock_gettime.o clock_settime.o \
+ clock_getres.o clock_settime.o \
  dup.o dup2.o dup3.o \
  execve.o \
  faccessat.o fchdir.o fchflags.o fchmod.o fchmodat.o fchown.o \
@@ -54,7 +55,7 @@ ASM= __semctl.o __syscall.o __thrsigdivert.o \
  getgroups.o getitimer.o getpeername.o getpgid.o \
  getpriority.o getresgid.o getresuid.o \
  getrlimit.o getrusage.o getsid.o getsockname.o \
- getsockopt.o gettimeofday.o ioctl.o \
+ getsockopt.o ioctl.o \
  kevent.o kill.o kqueue.o ktrace.o lchown.o \
  link.o linkat.o listen.o lstat.o madvise.o \
  minherit.o mkdir.o mkdirat.o mkfifo.o mkfifoat.o \
@@ -109,7 +110,8 @@ PPSEUDO_NOERR=${PSEUDO_NOERR:.o=.po}
 SPSEUDO_NOERR=${PSEUDO_NOERR:.o=.so}
 DPSEUDO_NOERR=${PSEUDO_NOERR:.o=.do}
 
-HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o}
+HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o} \
+ clock_gettime.o gettimeofday.o
 PHIDDEN=${HIDDEN:.o=.po}
 SHIDDEN=${HIDDEN:.o=.so}
 DHIDDEN=${HIDDEN:.o=.do}
diff --git lib/libc/sys/microtime.c lib/libc/sys/microtime.c
new file mode 100644
index 00000000000..fc023e8452f
--- /dev/null
+++ lib/libc/sys/microtime.c
@@ -0,0 +1,180 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2000 Poul-Henning Kamp <[hidden email]>
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/timetc.h>
+
+#include <time.h>
+
+/*
+ * Return the difference between the timehands' counter value now and what
+ * was when we copied it to the timehands' offset_count.
+ */
+static inline int
+tc_delta(struct timekeep *tk, u_int *delta)
+{
+ uint64_t tc;
+ if (delta == NULL || _tc_get_timecount(tk, &tc))
+ return -1;
+ *delta = (tc - tk->tk_offset_count) & tk->tk_counter_mask;
+ return 0;
+}
+
+static inline void
+bintimeaddfrac(const struct bintime *bt, uint64_t x, struct bintime *ct)
+{
+ ct->sec = bt->sec;
+ if (bt->frac > bt->frac + x)
+ ct->sec++;
+ ct->frac = bt->frac + x;
+}
+
+static inline void
+BINTIME_TO_TIMESPEC(const struct bintime *bt, struct timespec *ts)
+{
+ ts->tv_sec = bt->sec;
+ ts->tv_nsec = (long)(((uint64_t)1000000000 * (uint32_t)(bt->frac >> 32)) >> 32);
+}
+
+static inline void
+BINTIME_TO_TIMEVAL(const struct bintime *bt, struct timeval *tv)
+{
+ tv->tv_sec = bt->sec;
+ tv->tv_usec = (long)(((uint64_t)1000000 * (uint32_t)(bt->frac >> 32)) >> 32);
+}
+
+static int
+binuptime(struct bintime *bt, struct timekeep *tk)
+{
+ u_int gen, delta;
+
+ do {
+ gen = tk->tk_generation;
+ membar_consumer();
+ *bt = tk->tk_offset;
+ if (tc_delta(tk, &delta))
+ return -1;
+ bintimeaddfrac(bt, tk->tk_scale * delta, bt);
+ membar_consumer();
+ } while (gen == 0 || gen != tk->tk_generation);
+
+ return 0;
+}
+
+static inline void
+bintimeadd(const struct bintime *bt, const struct bintime *ct,
+    struct bintime *dt)
+{
+ dt->sec = bt->sec + ct->sec;
+ if (bt->frac > bt->frac + ct->frac)
+ dt->sec++;
+ dt->frac = bt->frac + ct->frac;
+}
+
+static inline void
+bintimesub(const struct bintime *bt, const struct bintime *ct,
+    struct bintime *dt)
+{
+ dt->sec = bt->sec - ct->sec;
+ if (bt->frac < bt->frac - ct->frac)
+ dt->sec--;
+ dt->frac = bt->frac - ct->frac;
+}
+
+static int
+binruntime(struct bintime *bt, struct timekeep *tk)
+{
+ u_int gen, delta;
+
+ do {
+ gen = tk->tk_generation;
+ membar_consumer();
+ if (tc_delta(tk, &delta))
+ return -1;
+ bintimeaddfrac(&tk->tk_offset, tk->tk_scale * delta, bt);
+ bintimesub(bt, &tk->tk_naptime, bt);
+ membar_consumer();
+ } while (gen == 0 || gen != tk->tk_generation);
+
+ return 0;
+}
+
+static int
+bintime(struct bintime *bt, struct timekeep *tk)
+{
+ u_int gen, delta;
+
+ do {
+ gen = tk->tk_generation;
+ membar_consumer();
+ *bt = tk->tk_offset;
+ if (tc_delta(tk, &delta))
+ return -1;
+ bintimeaddfrac(bt, tk->tk_scale * delta, bt);
+ bintimeadd(bt, &tk->tk_boottime, bt);
+ membar_consumer();
+ } while (gen == 0 || gen != tk->tk_generation);
+
+ return 0;
+}
+
+int
+_microtime(struct timeval *tvp, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (bintime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMEVAL(&bt, tvp);
+ return 0;
+}
+
+int
+_nanotime(struct timespec *tsp, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (bintime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMESPEC(&bt, tsp);
+ return 0;
+}
+
+int
+_nanoruntime(struct timespec *ts, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (binruntime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMESPEC(&bt, ts);
+ return 0;
+}
+
+
+int
+_nanouptime(struct timespec *tsp, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (binuptime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMESPEC(&bt, tsp);
+ return 0;
+}
diff --git lib/libc/sys/w_clock_gettime.c lib/libc/sys/w_clock_gettime.c
new file mode 100644
index 00000000000..6e6478bd131
--- /dev/null
+++ lib/libc/sys/w_clock_gettime.c
@@ -0,0 +1,51 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/timetc.h>
+
+#include <time.h>
+
+int
+WRAP(clock_gettime)(clockid_t clock_id, struct timespec *tp)
+{
+ int rc = 0;
+ struct timekeep *timekeep = _timekeep;
+
+ if (timekeep == NULL || timekeep->tk_user == 0)
+ return clock_gettime(clock_id, tp);
+
+ switch (clock_id) {
+ case CLOCK_REALTIME:
+ rc = _nanotime(tp, timekeep);
+ break;
+ case CLOCK_UPTIME:
+ rc = _nanoruntime(tp, timekeep);
+ break;
+ case CLOCK_MONOTONIC:
+ case CLOCK_BOOTTIME:
+ rc = _nanouptime(tp, timekeep);
+ break;
+ default:
+ return clock_gettime(clock_id, tp);
+ }
+
+ if (rc)
+ return clock_gettime(clock_id, tp);
+
+ return 0;
+}
+DEF_WRAP(clock_gettime);
diff --git lib/libc/sys/w_gettimeofday.c lib/libc/sys/w_gettimeofday.c
new file mode 100644
index 00000000000..f44edfbb1ad
--- /dev/null
+++ lib/libc/sys/w_gettimeofday.c
@@ -0,0 +1,40 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Robert Nagy <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/timetc.h>
+
+int
+WRAP(gettimeofday)(struct timeval *tp, struct timezone *tzp)
+{
+ int rc = 0;
+ struct timekeep *timekeep = _timekeep;
+ static struct timezone zerotz = { 0, 0 };
+
+ if (timekeep == NULL || timekeep->tk_user == 0)
+ return gettimeofday(tp, tzp);
+
+ if (tp)
+ rc = _microtime(tp, timekeep);
+ if (rc)
+ return gettimeofday(tp, tzp);
+
+ if (tzp)
+ *tzp = zerotz;
+
+ return 0;
+}
+DEF_WRAP(gettimeofday);
diff --git lib/libc/thread/synch.h lib/libc/thread/synch.h
index 788890add89..df2239438d2 100644
--- lib/libc/thread/synch.h
+++ lib/libc/thread/synch.h
@@ -33,7 +33,7 @@ _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *
  if (abs == NULL)
  return futex(p, FUTEX_WAIT_PRIVATE, val, NULL, NULL);
 
- if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel))
+ if (abs->tv_nsec >= 1000000000 || WRAP(clock_gettime)(clockid, &rel))
  return (EINVAL);
 
  rel.tv_sec = abs->tv_sec - rel.tv_sec;
diff --git regress/lib/libc/timekeep/Makefile regress/lib/libc/timekeep/Makefile
new file mode 100644
index 00000000000..a7f3080290d
--- /dev/null
+++ regress/lib/libc/timekeep/Makefile
@@ -0,0 +1,5 @@
+# $OpenBSD$
+
+PROGS= test_clock_gettime test_time_skew test_gettimeofday
+
+.include <bsd.regress.mk>
diff --git regress/lib/libc/timekeep/test_clock_gettime.c regress/lib/libc/timekeep/test_clock_gettime.c
new file mode 100644
index 00000000000..859ec368215
--- /dev/null
+++ regress/lib/libc/timekeep/test_clock_gettime.c
@@ -0,0 +1,43 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <time.h>
+
+#define ASSERT_EQ(a, b) assert((a) == (b))
+
+void
+check()
+{
+ struct timespec tp = {0};
+
+ ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_UPTIME, &tp));
+
+
+ ASSERT_EQ(0, clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp));
+
+}
+
+int main()
+{
+ check();
+ return 0;
+}
diff --git regress/lib/libc/timekeep/test_gettimeofday.c regress/lib/libc/timekeep/test_gettimeofday.c
new file mode 100644
index 00000000000..ea90a1be7e0
--- /dev/null
+++ regress/lib/libc/timekeep/test_gettimeofday.c
@@ -0,0 +1,37 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <sys/time.h>
+
+#define ASSERT_EQ(a, b) assert((a) == (b))
+
+void
+check()
+{
+ struct timeval tv = {0};
+ struct timezone tzp;
+
+ ASSERT_EQ(0, gettimeofday(&tv, NULL));
+ ASSERT_EQ(0, gettimeofday(&tv, &tzp));
+}
+
+int main()
+{
+ check();
+ return 0;
+}
diff --git regress/lib/libc/timekeep/test_time_skew.c regress/lib/libc/timekeep/test_time_skew.c
new file mode 100644
index 00000000000..dfa9481c091
--- /dev/null
+++ regress/lib/libc/timekeep/test_time_skew.c
@@ -0,0 +1,55 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/time.h>
+
+#include <assert.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define ASSERT_EQ(a, b) assert((a) == (b))
+#define ASSERT_NE(a, b) assert((a) != (b))
+
+void
+check()
+{
+         struct timespec tp1, tp2, tout;
+
+         tout.tv_sec = 0;
+         tout.tv_nsec = 100000;
+
+         ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp1));
+
+         nanosleep(&tout, NULL);
+
+         ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp2));
+
+         /* tp1 should never be larger than tp2 */
+         ASSERT_NE(1, timespeccmp(&tp1, &tp2, >));
+}
+
+int
+main(void)
+{
+ int i;
+
+ for (i = 0; i < 1000; i++)
+ check();
+
+ return 0;
+}
diff --git sys/arch/alpha/alpha/clock.c sys/arch/alpha/alpha/clock.c
index 3f5f2c5b42b..6eaf8b107c6 100644
--- sys/arch/alpha/alpha/clock.c
+++ sys/arch/alpha/alpha/clock.c
@@ -64,7 +64,7 @@ int clk_irq = 0;
 
 u_int rpcc_get_timecount(struct timecounter *);
 struct timecounter rpcc_timecounter = {
- rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL
+ rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL, 0
 };
 
 extern todr_chip_handle_t todr_handle;
diff --git sys/arch/alpha/alpha/machdep.c sys/arch/alpha/alpha/machdep.c
index 09dc7e9cba5..9e43723959f 100644
--- sys/arch/alpha/alpha/machdep.c
+++ sys/arch/alpha/alpha/machdep.c
@@ -139,6 +139,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
 struct vm_map *exec_map = NULL;
 struct vm_map *phys_map = NULL;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/amd64/amd64/machdep.c sys/arch/amd64/amd64/machdep.c
index 9dab8947af0..f58ab1a345c 100644
--- sys/arch/amd64/amd64/machdep.c
+++ sys/arch/amd64/amd64/machdep.c
@@ -193,6 +193,9 @@ int lid_action = 1;
 int pwr_action = 1;
 int forceukbd;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 1;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/amd64/amd64/tsc.c sys/arch/amd64/amd64/tsc.c
index 7a1dcb4ad75..3db93d88dec 100644
--- sys/arch/amd64/amd64/tsc.c
+++ sys/arch/amd64/amd64/tsc.c
@@ -50,7 +50,7 @@ extern u_int32_t lapic_per_second;
 #endif
 
 struct timecounter tsc_timecounter = {
- tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL
+ tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL, 1
 };
 
 uint64_t
diff --git sys/arch/amd64/isa/clock.c sys/arch/amd64/isa/clock.c
index 613f7ee0e0f..00da0c6a8d0 100644
--- sys/arch/amd64/isa/clock.c
+++ sys/arch/amd64/isa/clock.c
@@ -116,7 +116,7 @@ u_int i8254_get_timecount(struct timecounter *tc);
 u_int i8254_simple_get_timecount(struct timecounter *tc);
 
 static struct timecounter i8254_timecounter = {
- i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
+ i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0
 };
 
 int clockintr(void *);
diff --git sys/arch/arm64/arm64/machdep.c sys/arch/arm64/arm64/machdep.c
index 4e292479233..2b6165800ca 100644
--- sys/arch/arm64/arm64/machdep.c
+++ sys/arch/arm64/arm64/machdep.c
@@ -90,6 +90,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
 /* the following is used externally (sysctl_hw) */
 char    machine[] = MACHINE;            /* from <machine/param.h> */
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 int safepri = 0;
 
 struct cpu_info cpu_info_primary;
diff --git sys/arch/arm64/dev/agtimer.c sys/arch/arm64/dev/agtimer.c
index 29394141ad5..6b7c6db862f 100644
--- sys/arch/arm64/dev/agtimer.c
+++ sys/arch/arm64/dev/agtimer.c
@@ -43,7 +43,7 @@ int32_t agtimer_frequency = TIMER_FREQUENCY;
 u_int agtimer_get_timecount(struct timecounter *);
 
 static struct timecounter agtimer_timecounter = {
- agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL
+ agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL, 0
 };
 
 struct agtimer_pcpu_softc {
diff --git sys/arch/armv7/armv7/armv7_machdep.c sys/arch/armv7/armv7/armv7_machdep.c
index 1a5418cbf58..8b347ce86fd 100644
--- sys/arch/armv7/armv7/armv7_machdep.c
+++ sys/arch/armv7/armv7/armv7_machdep.c
@@ -186,6 +186,9 @@ pv_addr_t kernel_pt_table[NUM_KERNEL_PTS];
 
 extern struct user *proc0paddr;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/armv7/omap/gptimer.c sys/arch/armv7/omap/gptimer.c
index 7605845d5e2..061542d532f 100644
--- sys/arch/armv7/omap/gptimer.c
+++ sys/arch/armv7/omap/gptimer.c
@@ -117,7 +117,7 @@ int gptimer_irq = 0;
 u_int gptimer_get_timecount(struct timecounter *);
 
 static struct timecounter gptimer_timecounter = {
- gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL
+ gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL, 0
 };
 
 volatile u_int32_t nexttickevent;
diff --git sys/arch/armv7/omap/omap_machdep.c sys/arch/armv7/omap/omap_machdep.c
index f62178f04a4..a36229a427c 100644
--- sys/arch/armv7/omap/omap_machdep.c
+++ sys/arch/armv7/omap/omap_machdep.c
@@ -32,6 +32,9 @@
 #include <armv7/armv7/armv7var.h>
 #include <armv7/armv7/armv7_machdep.h>
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 extern void omap4_smc_call(uint32_t, uint32_t);
 extern void omdog_reset(void);
 extern struct board_dev *omap_board_devs(void);
diff --git sys/arch/armv7/sunxi/sxitimer.c sys/arch/armv7/sunxi/sxitimer.c
index 14a243c78d0..41028f9a602 100644
--- sys/arch/armv7/sunxi/sxitimer.c
+++ sys/arch/armv7/sunxi/sxitimer.c
@@ -89,7 +89,7 @@ void sxitimer_delay(u_int);
 u_int sxitimer_get_timecount(struct timecounter *);
 
 static struct timecounter sxitimer_timecounter = {
- sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL
+ sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL, 0
 };
 
 bus_space_tag_t sxitimer_iot;
diff --git sys/arch/hppa/dev/clock.c sys/arch/hppa/dev/clock.c
index 4c594ab5ec7..8cce6c3a893 100644
--- sys/arch/hppa/dev/clock.c
+++ sys/arch/hppa/dev/clock.c
@@ -47,7 +47,7 @@ int cpu_hardclock(void *);
 u_int itmr_get_timecount(struct timecounter *);
 
 struct timecounter itmr_timecounter = {
- itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL
+ itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL, 0
 };
 
 extern todr_chip_handle_t todr_handle;
diff --git sys/arch/hppa/hppa/machdep.c sys/arch/hppa/hppa/machdep.c
index f7bb998d53e..df356e5202f 100644
--- sys/arch/hppa/hppa/machdep.c
+++ sys/arch/hppa/hppa/machdep.c
@@ -152,6 +152,9 @@ void hpmc_dump(void);
 void cpuid(void);
 void blink_led_timeout(void *);
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/i386/i386/machdep.c sys/arch/i386/i386/machdep.c
index 0d392c75802..c22eb22bafe 100644
--- sys/arch/i386/i386/machdep.c
+++ sys/arch/i386/i386/machdep.c
@@ -235,6 +235,9 @@ int lid_action = 1;
 int pwr_action = 1;
 int forceukbd;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/i386/isa/clock.c sys/arch/i386/isa/clock.c
index 09a6db983f2..dd74bd425ad 100644
--- sys/arch/i386/isa/clock.c
+++ sys/arch/i386/isa/clock.c
@@ -129,7 +129,7 @@ u_int i8254_get_timecount(struct timecounter *tc);
 u_int i8254_simple_get_timecount(struct timecounter *tc);
 
 static struct timecounter i8254_timecounter = {
- i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
+ i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0
 };
 struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH);
 u_long rtclock_tval;
diff --git sys/arch/i386/pci/geodesc.c sys/arch/i386/pci/geodesc.c
index 9d9f061eef9..bb8e4c7f9ae 100644
--- sys/arch/i386/pci/geodesc.c
+++ sys/arch/i386/pci/geodesc.c
@@ -65,7 +65,9 @@ struct timecounter geodesc_timecounter = {
  0xffffffff, /* counter_mask */
  27000000, /* frequency */
  "GEOTSC", /* name */
- 2000 /* quality */
+ 2000, /* quality */
+ NULL, /* private bits */
+ 0 /* expose to user */
 };
 
 int
diff --git sys/arch/i386/pci/gscpm.c sys/arch/i386/pci/gscpm.c
index 8b8aa4ac430..a6f324e66f3 100644
--- sys/arch/i386/pci/gscpm.c
+++ sys/arch/i386/pci/gscpm.c
@@ -55,7 +55,9 @@ struct timecounter gscpm_timecounter = {
  0xffffff, /* counter_mask */
  3579545, /* frequency */
  "GSCPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0 /* expose to user */
 };
 
 struct cfattach gscpm_ca = {
diff --git sys/arch/i386/pci/ichpcib.c sys/arch/i386/pci/ichpcib.c
index 6abf1627de2..629a86a14ff 100644
--- sys/arch/i386/pci/ichpcib.c
+++ sys/arch/i386/pci/ichpcib.c
@@ -63,7 +63,9 @@ struct timecounter ichpcib_timecounter = {
  0xffffff, /* counter_mask */
  3579545, /* frequency */
  "ICHPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0 /* expose to user */
 };
 
 struct cfattach ichpcib_ca = {
diff --git sys/arch/landisk/landisk/machdep.c sys/arch/landisk/landisk/machdep.c
index d5ea8df1740..3b515d191c9 100644
--- sys/arch/landisk/landisk/machdep.c
+++ sys/arch/landisk/landisk/machdep.c
@@ -119,6 +119,9 @@ extern u_int32_t getramsize(void);
 struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
 struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/loongson/loongson/generic3a_machdep.c sys/arch/loongson/loongson/generic3a_machdep.c
index ac3f1db6ccd..53489b07549 100644
--- sys/arch/loongson/loongson/generic3a_machdep.c
+++ sys/arch/loongson/loongson/generic3a_machdep.c
@@ -98,7 +98,9 @@ struct timecounter rs780e_timecounter = {
  .tc_counter_mask = 0xffffffffu, /* truncated to 32 bits */
  .tc_frequency = HPET_FREQ,
  .tc_name = "hpet",
- .tc_quality = 100
+ .tc_quality = 100,
+ .tc_priv = NULL,
+ .tc_user = 0,
 };
 
 /* Firmware entry points */
diff --git sys/arch/loongson/loongson/machdep.c sys/arch/loongson/loongson/machdep.c
index aaceb54bea8..9c66faa4b50 100644
--- sys/arch/loongson/loongson/machdep.c
+++ sys/arch/loongson/loongson/machdep.c
@@ -103,6 +103,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
 vm_map_t exec_map;
 vm_map_t phys_map;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/luna88k/luna88k/clock.c sys/arch/luna88k/luna88k/clock.c
index a04120987e0..6580a4a46bf 100644
--- sys/arch/luna88k/luna88k/clock.c
+++ sys/arch/luna88k/luna88k/clock.c
@@ -112,7 +112,9 @@ struct timecounter clock_tc = {
  .tc_counter_mask = 0xffffffff,
  .tc_frequency = 0, /* will be filled in */
  .tc_name = "clock",
- .tc_quality = 0
+ .tc_quality = 0,
+ .tc_priv = NULL,
+ .tc_user = 0,
 };
 
 /*
diff --git sys/arch/luna88k/luna88k/machdep.c sys/arch/luna88k/luna88k/machdep.c
index 9501ad85210..41bbe6793d4 100644
--- sys/arch/luna88k/luna88k/machdep.c
+++ sys/arch/luna88k/luna88k/machdep.c
@@ -193,6 +193,9 @@ int sysconsole = 1; /* 0 = ttya, 1 = keyboard/mouse, used in dev/sio.c */
 u_int16_t dipswitch = 0; /* set in locore.S */
 int hwplanebits; /* set in locore.S */
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 extern struct consdev syscons; /* in dev/siotty.c */
 
 extern void syscnattach(int); /* in dev/siotty.c */
diff --git sys/arch/macppc/macppc/clock.c sys/arch/macppc/macppc/clock.c
index 4a44a92cfc0..8c3ad620be8 100644
--- sys/arch/macppc/macppc/clock.c
+++ sys/arch/macppc/macppc/clock.c
@@ -57,7 +57,7 @@ u_int32_t ns_per_tick = 320;
 static int32_t ticks_per_intr;
 
 static struct timecounter tb_timecounter = {
- tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL
+ tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL, 0
 };
 
 /* calibrate the timecounter frequency for the listed models */
diff --git sys/arch/macppc/macppc/machdep.c sys/arch/macppc/macppc/machdep.c
index 178fe0995da..af4f68ed1d6 100644
--- sys/arch/macppc/macppc/machdep.c
+++ sys/arch/macppc/macppc/machdep.c
@@ -350,6 +350,9 @@ install_extint(void (*handler)(void))
  ppc_mtmsr(omsr);
 }
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/mips64/mips64/mips64_machdep.c sys/arch/mips64/mips64/mips64_machdep.c
index d4a42ed5acc..5c4dbadb5bb 100644
--- sys/arch/mips64/mips64/mips64_machdep.c
+++ sys/arch/mips64/mips64/mips64_machdep.c
@@ -327,7 +327,9 @@ struct timecounter cp0_timecounter = {
  0xffffffff, /* counter_mask */
  0, /* frequency */
  "CP0", /* name */
- 0 /* quality */
+ 0, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 u_int
diff --git sys/arch/octeon/octeon/machdep.c sys/arch/octeon/octeon/machdep.c
index 1387af284ca..0cfabfc642a 100644
--- sys/arch/octeon/octeon/machdep.c
+++ sys/arch/octeon/octeon/machdep.c
@@ -107,6 +107,9 @@ struct boot_info *octeon_boot_info;
 void *octeon_fdt;
 unsigned int octeon_ver;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
@@ -151,8 +154,9 @@ struct timecounter ioclock_timecounter = {
  .tc_name = "ioclock",
  .tc_quality = 0, /* ioclock can be overridden
  * by cp0 counter */
- .tc_priv = 0 /* clock register,
+ .tc_priv = 0, /* clock register,
  * determined at runtime */
+ .tc_user = 0, /* expose to user */
 };
 
 static int
diff --git sys/arch/powerpc64/powerpc64/machdep.c sys/arch/powerpc64/powerpc64/machdep.c
index bae64a1f297..b00bf682b76 100644
--- sys/arch/powerpc64/powerpc64/machdep.c
+++ sys/arch/powerpc64/powerpc64/machdep.c
@@ -43,6 +43,9 @@ int cacheline_size = 128;
 struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
 struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 int cold = 1;
 int safepri = 0;
 int physmem;
diff --git sys/arch/sgi/sgi/ip27_machdep.c sys/arch/sgi/sgi/ip27_machdep.c
index ba7fa558b96..2a2cc144242 100644
--- sys/arch/sgi/sgi/ip27_machdep.c
+++ sys/arch/sgi/sgi/ip27_machdep.c
@@ -111,7 +111,9 @@ struct timecounter ip27_hub_timecounter = {
  .tc_counter_mask = 0xffffffff, /* truncated to 32 bits. */
  .tc_frequency = 1250000,
  .tc_name = "hubrt",
- .tc_quality = 100
+ .tc_quality = 100,
+ .tc_priv = 0,
+ .tc_user = 0,
 };
 
 volatile uint64_t ip27_spinup_a0;
diff --git sys/arch/sgi/sgi/machdep.c sys/arch/sgi/sgi/machdep.c
index d251c15fc01..9b73112addf 100644
--- sys/arch/sgi/sgi/machdep.c
+++ sys/arch/sgi/sgi/machdep.c
@@ -93,6 +93,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
 vm_map_t exec_map;
 vm_map_t phys_map;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/sgi/xbow/xheart.c sys/arch/sgi/xbow/xheart.c
index 56b29915c70..827775512ac 100644
--- sys/arch/sgi/xbow/xheart.c
+++ sys/arch/sgi/xbow/xheart.c
@@ -83,7 +83,9 @@ struct timecounter xheart_timecounter = {
  .tc_counter_mask = 0xffffffff, /* truncate 52-bit counter to 32-bit */
  .tc_frequency = 12500000,
  .tc_name = "heart",
- .tc_quality = 100
+ .tc_quality = 100,
+ .tc_priv = NULL,
+ .tc_user = 0,
 };
 
 extern uint32_t ip30_lights_frob(uint32_t, struct trapframe *);
diff --git sys/arch/sparc64/dev/psycho.c sys/arch/sparc64/dev/psycho.c
index e24f804dff6..1a7a1afa8c2 100644
--- sys/arch/sparc64/dev/psycho.c
+++ sys/arch/sparc64/dev/psycho.c
@@ -127,7 +127,7 @@ extern struct sparc_pci_chipset _sparc_pci_chipset;
 u_int stick_get_timecount(struct timecounter *);
 
 struct timecounter stick_timecounter = {
- stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL
+ stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL, 0
 };
 
 /*
diff --git sys/arch/sparc64/sparc64/clock.c sys/arch/sparc64/sparc64/clock.c
index fd5e8a9c15b..5c2e47d386b 100644
--- sys/arch/sparc64/sparc64/clock.c
+++ sys/arch/sparc64/sparc64/clock.c
@@ -109,13 +109,13 @@ struct cfdriver clock_cd = {
 u_int tick_get_timecount(struct timecounter *);
 
 struct timecounter tick_timecounter = {
- tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL
+ tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL, 0
 };
 
 u_int sys_tick_get_timecount(struct timecounter *);
 
 struct timecounter sys_tick_timecounter = {
- sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL
+ sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL, 0
 };
 
 /*
diff --git sys/arch/sparc64/sparc64/machdep.c sys/arch/sparc64/sparc64/machdep.c
index 05aa4342943..0ee7ff3b802 100644
--- sys/arch/sparc64/sparc64/machdep.c
+++ sys/arch/sparc64/sparc64/machdep.c
@@ -183,6 +183,9 @@ extern int64_t cecclast;
 #define MAX_DMA_SEGS 20
 #endif
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/dev/acpi/acpihpet.c sys/dev/acpi/acpihpet.c
index d0ee72cec9b..13177a909da 100644
--- sys/dev/acpi/acpihpet.c
+++ sys/dev/acpi/acpihpet.c
@@ -45,7 +45,9 @@ static struct timecounter hpet_timecounter = {
  0xffffffff, /* counter_mask (32 bits) */
  0, /* frequency */
  0, /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 #define HPET_TIMERS 3
diff --git sys/dev/acpi/acpitimer.c sys/dev/acpi/acpitimer.c
index cdc8c99a17a..89b5a397e47 100644
--- sys/dev/acpi/acpitimer.c
+++ sys/dev/acpi/acpitimer.c
@@ -36,7 +36,9 @@ static struct timecounter acpi_timecounter = {
  0x00ffffff, /* counter_mask (24 bits) */
  ACPI_FREQUENCY, /* frequency */
  0, /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 struct acpitimer_softc {
diff --git sys/dev/pci/amdpm.c sys/dev/pci/amdpm.c
index 6df82858016..9610d5bc1f0 100644
--- sys/dev/pci/amdpm.c
+++ sys/dev/pci/amdpm.c
@@ -82,7 +82,9 @@ static struct timecounter amdpm_timecounter = {
  0xffffff, /* counter_mask */
  AMDPM_FREQUENCY, /* frequency */
  "AMDPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 #define AMDPM_CONFREG 0x40
diff --git sys/dev/pci/viapm.c sys/dev/pci/viapm.c
index db806eedf80..ce33cd175e6 100644
--- sys/dev/pci/viapm.c
+++ sys/dev/pci/viapm.c
@@ -177,7 +177,9 @@ static struct timecounter viapm_timecounter = {
  0xffffff, /* counter_mask */
  VIAPM_FREQUENCY, /* frequency */
  "VIAPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 struct timeout viapm_timeout;
diff --git sys/dev/pv/hyperv.c sys/dev/pv/hyperv.c
index b32facdacb1..b9ee2feec4c 100644
--- sys/dev/pv/hyperv.c
+++ sys/dev/pv/hyperv.c
@@ -141,7 +141,7 @@ struct {
 };
 
 struct timecounter hv_timecounter = {
- hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001
+ hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001, NULL, 0
 };
 
 struct cfdriver hyperv_cd = {
diff --git sys/dev/pv/pvclock.c sys/dev/pv/pvclock.c
index 6b242f7448d..b80e4d2a484 100644
--- sys/dev/pv/pvclock.c
+++ sys/dev/pv/pvclock.c
@@ -74,7 +74,7 @@ struct cfdriver pvclock_cd = {
 };
 
 struct timecounter pvclock_timecounter = {
- pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL
+ pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL, 0
 };
 
 int
diff --git sys/kern/exec_elf.c sys/kern/exec_elf.c
index 9b5b8eb3acf..59bc923a6fb 100644
--- sys/kern/exec_elf.c
+++ sys/kern/exec_elf.c
@@ -124,7 +124,7 @@ extern char *syscallnames[];
 /*
  * How many entries are in the AuxInfo array we pass to the process?
  */
-#define ELF_AUX_ENTRIES 8
+#define ELF_AUX_ENTRIES 9
 
 /*
  * This is the OpenBSD ELF emul
@@ -860,6 +860,10 @@ exec_elf_fixup(struct proc *p, struct exec_package *epp)
  a->au_v = ap->arg_entry;
  a++;
 
+ a->au_id = AUX_openbsd_timekeep;
+ a->au_v = p->p_p->ps_timekeep;
+ a++;
+
  a->au_id = AUX_null;
  a->au_v = 0;
  a++;
diff --git sys/kern/kern_exec.c sys/kern/kern_exec.c
index 20480c2fc28..9d6a3d9c910 100644
--- sys/kern/kern_exec.c
+++ sys/kern/kern_exec.c
@@ -64,6 +64,11 @@
 #include <uvm/uvm_extern.h>
 #include <machine/tcb.h>
 
+#include <sys/timetc.h>
+
+struct uvm_object *timekeep_object;
+struct timekeep* timekeep;
+
 void unveil_destroy(struct process *ps);
 
 const struct kmem_va_mode kv_exec = {
@@ -76,6 +81,11 @@ const struct kmem_va_mode kv_exec = {
  */
 int exec_sigcode_map(struct process *, struct emul *);
 
+/*
+ * Map the shared timekeep page.
+ */
+int exec_timekeep_map(struct process *);
+
 /*
  * If non-zero, stackgap_random specifies the upper limit of the random gap size
  * added to the fixed stack position. Must be n^2.
@@ -684,6 +694,9 @@ sys_execve(struct proc *p, void *v, register_t *retval)
  /* map the process's signal trampoline code */
  if (exec_sigcode_map(pr, pack.ep_emul))
  goto free_pack_abort;
+ /* map the process's timekeep page */
+ if (exec_timekeep_map(pr))
+ goto free_pack_abort;
 
 #ifdef __HAVE_EXEC_MD_MAP
  /* perform md specific mappings that process might need */
@@ -863,3 +876,42 @@ exec_sigcode_map(struct process *pr, struct emul *e)
 
  return (0);
 }
+
+int
+exec_timekeep_map(struct process *pr)
+{
+ size_t timekeep_sz = sizeof(struct timekeep);
+
+ /*
+ * Similar to the sigcode object, except that there is a single timekeep
+ * object, and not one per emulation.
+ */
+ if (timekeep_object == NULL) {
+ vaddr_t va;
+
+ timekeep_object = uao_create(timekeep_sz, 0);
+ uao_reference(timekeep_object);
+
+ if (uvm_map(kernel_map, &va, round_page(timekeep_sz), timekeep_object,
+    0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
+    MAP_INHERIT_SHARE, MADV_RANDOM, 0))) {
+ uao_detach(timekeep_object);
+ return (ENOMEM);
+ }
+
+ timekeep = (struct timekeep *)va;
+ timekeep->tk_major = 0;
+ timekeep->tk_minor = 0;
+ timekeep->tk_nclocks = tk_nclocks;
+ }
+
+ uao_reference(timekeep_object);
+ if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_timekeep, round_page(timekeep_sz),
+    timekeep_object, 0, 0, UVM_MAPFLAG(PROT_READ, PROT_READ,
+    MAP_INHERIT_COPY, MADV_RANDOM, 0))) {
+ uao_detach(timekeep_object);
+ return (ENOMEM);
+ }
+
+ return (0);
+}
diff --git sys/kern/kern_tc.c sys/kern/kern_tc.c
index 88d4a3379f9..47efbdd0b78 100644
--- sys/kern/kern_tc.c
+++ sys/kern/kern_tc.c
@@ -63,7 +63,7 @@ dummy_get_timecount(struct timecounter *tc)
 }
 
 static struct timecounter dummy_timecounter = {
- dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000
+ dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000, NULL, 0
 };
 
 /*
@@ -479,6 +479,34 @@ tc_setclock(const struct timespec *ts)
 #endif
 }
 
+void
+tc_update_timekeep(void)
+{
+ static struct timecounter *last_tc = NULL;
+ struct timehands *th;
+
+ if (timekeep == NULL)
+ return;
+
+ th = timehands;
+ timekeep->tk_generation = 0;
+ membar_producer();
+ timekeep->tk_scale = th->th_scale;
+ timekeep->tk_offset_count = th->th_offset_count;
+ timekeep->tk_offset = th->th_offset;
+ timekeep->tk_naptime = th->th_naptime;
+ timekeep->tk_boottime = th->th_boottime;
+ if (last_tc != th->th_counter) {
+ timekeep->tk_counter_mask = th->th_counter->tc_counter_mask;
+ timekeep->tk_user = th->th_counter->tc_user;
+ last_tc = th->th_counter;
+ }
+ membar_producer();
+ timekeep->tk_generation = th->th_generation;
+
+ return;
+}
+
 /*
  * Initialize the next struct timehands in the ring and make
  * it the active timehands.  Along the way we might switch to a different
@@ -631,6 +659,8 @@ tc_windup(struct bintime *new_boottime, struct bintime *new_offset,
  time_uptime = th->th_offset.sec;
  membar_producer();
  timehands = th;
+
+ tc_update_timekeep();
 }
 
 /* Report or change the active timecounter hardware. */
diff --git sys/sys/exec_elf.h sys/sys/exec_elf.h
index a40e0510273..3084ed595a6 100644
--- sys/sys/exec_elf.h
+++ sys/sys/exec_elf.h
@@ -691,7 +691,8 @@ enum AuxID {
  AUX_sun_uid = 2000, /* euid */
  AUX_sun_ruid = 2001, /* ruid */
  AUX_sun_gid = 2002, /* egid */
- AUX_sun_rgid = 2003 /* rgid */
+ AUX_sun_rgid = 2003, /* rgid */
+ AUX_openbsd_timekeep = 4000, /* userland clock_gettime */
 };
 
 struct elf_args {
diff --git sys/sys/proc.h sys/sys/proc.h
index 357c0c0d52c..c6d54572bdd 100644
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -242,6 +242,7 @@ struct process {
  char ps_comm[MAXCOMLEN+1];
 
  vaddr_t ps_strings; /* User pointers to argv/env */
+ vaddr_t ps_timekeep; /* User pointer to timekeep */
  vaddr_t ps_sigcode; /* User pointer to the signal code */
  vaddr_t ps_sigcoderet; /* User pointer to sigreturn retPC */
  u_long ps_sigcookie;
diff --git sys/sys/time.h sys/sys/time.h
index e758a64ce07..bcd3acd034d 100644
--- sys/sys/time.h
+++ sys/sys/time.h
@@ -163,7 +163,7 @@ struct clockinfo {
 };
 #endif /* __BSD_VISIBLE */
 
-#if defined(_KERNEL) || defined(_STANDALONE)
+#if defined(_KERNEL) || defined(_STANDALONE) || defined (_LIBC)
 #include <sys/_time.h>
 
 /* Time expressed as seconds and fractions of a second + operations on it. */
@@ -171,6 +171,9 @@ struct bintime {
  time_t sec;
  uint64_t frac;
 };
+#endif
+
+#if defined(_KERNEL) || defined(_STANDALONE)
 
 #define bintimecmp(btp, ctp, cmp) \
  ((btp)->sec == (ctp)->sec ? \
diff --git sys/sys/timetc.h sys/sys/timetc.h
index ce81c3475a0..a4a80eecff1 100644
--- sys/sys/timetc.h
+++ sys/sys/timetc.h
@@ -24,7 +24,7 @@
 #ifndef _SYS_TIMETC_H_
 #define _SYS_TIMETC_H_
 
-#ifndef _KERNEL
+#if !defined(_KERNEL) && !defined(_LIBC)
 #error "no user-serviceable parts inside"
 #endif
 
@@ -80,6 +80,8 @@ struct timecounter {
  */
  void *tc_priv; /* [I] */
  /* Pointer to the timecounter's private parts. */
+ int tc_user; /* [I] */
+ /* Expose this timecounter to userland. */
  SLIST_ENTRY(timecounter) tc_next; /* [I] */
  /* Pointer to the next timecounter. */
  int64_t tc_freq_adj; /* [tw] */
@@ -88,11 +90,34 @@ struct timecounter {
  /* Precision of the counter.  Computed in tc_init(). */
 };
 
+struct timekeep {
+ /* set at initialization */
+ uint32_t tk_major; /* version major number */
+ uint32_t tk_minor; /* version minor number */
+ int tk_nclocks; /* number of arch user clocks */
+
+ /* timehands members */
+ uint64_t tk_scale;
+ u_int tk_offset_count;
+ struct bintime tk_offset;
+ struct bintime tk_naptime;
+ struct bintime tk_boottime;
+ volatile u_int tk_generation;
+
+ /* timecounter members */
+ int tk_user;
+ u_int tk_counter_mask;
+};
+extern int tk_nclocks;
+
 struct rwlock;
 extern struct rwlock tc_lock;
 
 extern struct timecounter *timecounter;
 
+extern struct uvm_object *timekeep_object;
+extern struct timekeep *timekeep;
+
 u_int64_t tc_getfrequency(void);
 u_int64_t tc_getprecision(void);
 void tc_init(struct timecounter *tc);

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Christian Weisgerber
Paul Irofti:

> > This iteration of the diff adds bounds checking for tk_user and moves
> > the usertc.c stub to every arch in libc as recommanded by deraadt@.
> > It also fixes a gettimeofday issue reported by cheloha@ and tb@.
>
> Forgot to add armv7 tk_nclock entries. Noticed by benno@, thanks!

One blemish I see is that tk_user is a magic number.

For example, sparc64 will have two timecounters: tick and stick.
They will be assigned magic numbers 1 and 2...

    struct timecounter tick_timecounter = {
            tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL, 1
    };
    struct timecounter stick_timecounter = {
            stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL, 2
    };

... and sparc64 usertc.c will need the corresponding magic array order:

    static uint64_t (*get_tc[])(void) =
    {
            rdtick,
            rdstick,
    };

I don't know if we want to go through the effort to make this
prettier.  We would need an MD header, say, <machine/timetc.h>
that gets picked up by <sys/timetc.h>, with something like

    #define TC_TICK         1
    #define TC_STICK        2

The symbolic values could then be used in the kernel timecounter
definitions...

    struct timecounter tick_timecounter = {
            tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL, TC_TICK
    };
    struct timecounter stick_timecounter = {
            stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL, TC_STICK
    };

... and in libc usertc.c:

    static uint64_t (*get_tc[])(void) =
    {
            [TC_TICK] = rdtick,
            [TC_STICK] = rdstick,
    };
    ...
    *tc = (*get_tc[tk_user])();

The cost would be yet another header file per arch.
Thoughts?

--
Christian "naddy" Weisgerber                          [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Christian Weisgerber
In reply to this post by Paul Irofti-4
Paul Irofti:

> This iteration of the diff adds bounds checking for tk_user and moves
> the usertc.c stub to every arch in libc as recommanded by deraadt@.
> It also fixes a gettimeofday issue reported by cheloha@ and tb@.

Additionally, it changes struct timekeep in an incompatible way. ;-)
A userland built before the addition of tk_nclocks is very unhappy
with a kernel built afterwards.  There is no way to compile across
this.  You have to (U)pgrade from boot media to install a ftp.openbsd.org
userland, and then you can re-compile with the new diff.

Should we already bump major while the diff matures?

--
Christian "naddy" Weisgerber                          [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Theo de Raadt-2
Christian Weisgerber <[hidden email]> wrote:

> Paul Irofti:
>
> > This iteration of the diff adds bounds checking for tk_user and moves
> > the usertc.c stub to every arch in libc as recommanded by deraadt@.
> > It also fixes a gettimeofday issue reported by cheloha@ and tb@.
>
> Additionally, it changes struct timekeep in an incompatible way. ;-)
> A userland built before the addition of tk_nclocks is very unhappy
> with a kernel built afterwards.  There is no way to compile across
> this.  You have to (U)pgrade from boot media to install a ftp.openbsd.org
> userland, and then you can re-compile with the new diff.
>
> Should we already bump major while the diff matures?

See, I told everyone this shouldn't be commited, and then iterated in-tree!
Imagine if this was in-tree.  Such compatibility is a nightmare.

I'd say the easiest way is to backtrack to a snapshot, then forward again.

I want to see this diff support 3-4 architectures before commit.

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Paul Irofti-4
In reply to this post by Christian Weisgerber
On 2020-06-11 01:16, Christian Weisgerber wrote:

> Paul Irofti:
>
>>> This iteration of the diff adds bounds checking for tk_user and moves
>>> the usertc.c stub to every arch in libc as recommanded by deraadt@.
>>> It also fixes a gettimeofday issue reported by cheloha@ and tb@.
>>
>> Forgot to add armv7 tk_nclock entries. Noticed by benno@, thanks!
>
> One blemish I see is that tk_user is a magic number.
>
> For example, sparc64 will have two timecounters: tick and stick.
> They will be assigned magic numbers 1 and 2...
>
>      struct timecounter tick_timecounter = {
>              tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL, 1
>      };
>      struct timecounter stick_timecounter = {
>              stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL, 2
>      };
>
> ... and sparc64 usertc.c will need the corresponding magic array order:
>
>      static uint64_t (*get_tc[])(void) =
>      {
>              rdtick,
>              rdstick,
>      };
>
> I don't know if we want to go through the effort to make this
> prettier.  We would need an MD header, say, <machine/timetc.h>
> that gets picked up by <sys/timetc.h>, with something like
>
>      #define TC_TICK         1
>      #define TC_STICK        2
>
> The symbolic values could then be used in the kernel timecounter
> definitions...
>
>      struct timecounter tick_timecounter = {
>              tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL, TC_TICK
>      };
>      struct timecounter stick_timecounter = {
>              stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL, TC_STICK
>      };
>
> ... and in libc usertc.c:
>
>      static uint64_t (*get_tc[])(void) =
>      {
>              [TC_TICK] = rdtick,
>              [TC_STICK] = rdstick,
>      };
>      ...
>      *tc = (*get_tc[tk_user])();
>
> The cost would be yet another header file per arch.
> Thoughts?

I think this not a functional change and it can also be done afterwards
by you or somebody else that has the energy to go through the
bikesheding. I will definitely need a break after this.

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Paul Irofti-4
In reply to this post by Christian Weisgerber
On 2020-06-11 02:46, Christian Weisgerber wrote:

> Paul Irofti:
>
>> This iteration of the diff adds bounds checking for tk_user and moves
>> the usertc.c stub to every arch in libc as recommanded by deraadt@.
>> It also fixes a gettimeofday issue reported by cheloha@ and tb@.
>
> Additionally, it changes struct timekeep in an incompatible way. ;-)
> A userland built before the addition of tk_nclocks is very unhappy
> with a kernel built afterwards.  There is no way to compile across
> this.  You have to (U)pgrade from boot media to install a ftp.openbsd.org
> userland, and then you can re-compile with the new diff.

I have not seen this problem and have not built a snapshot to update or
go back. What do you mean by very unhappy? Can you show me the exact
steps you have done?

> Should we already bump major while the diff matures?

I am not a fan of this. I don't like bumping something before it is
actually used. It is like an errata before a release.

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Paul Irofti-4
In reply to this post by Theo de Raadt-2
On 2020-06-11 03:42, Theo de Raadt wrote:

> Christian Weisgerber <[hidden email]> wrote:
>
>> Paul Irofti:
>>
>>> This iteration of the diff adds bounds checking for tk_user and moves
>>> the usertc.c stub to every arch in libc as recommanded by deraadt@.
>>> It also fixes a gettimeofday issue reported by cheloha@ and tb@.
>>
>> Additionally, it changes struct timekeep in an incompatible way. ;-)
>> A userland built before the addition of tk_nclocks is very unhappy
>> with a kernel built afterwards.  There is no way to compile across
>> this.  You have to (U)pgrade from boot media to install a ftp.openbsd.org
>> userland, and then you can re-compile with the new diff.
>>
>> Should we already bump major while the diff matures?
>
> See, I told everyone this shouldn't be commited, and then iterated in-tree!
> Imagine if this was in-tree.  Such compatibility is a nightmare.
>
> I'd say the easiest way is to backtrack to a snapshot, then forward again.
>
> I want to see this diff support 3-4 architectures before commit.

Sure. Whenever you feel confident. As I said numerous times now here,
nobody is pressuring this with a commit.

I think we support already 3 architectures: amd64, macppc, sparc64
(kettenis?).

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Marc Espie-2
In reply to this post by Paul Irofti-4
On Thu, Jun 11, 2020 at 01:13:07PM +0300, Paul Irofti wrote:

> On 2020-06-11 02:46, Christian Weisgerber wrote:
> > Paul Irofti:
> >
> > > This iteration of the diff adds bounds checking for tk_user and moves
> > > the usertc.c stub to every arch in libc as recommanded by deraadt@.
> > > It also fixes a gettimeofday issue reported by cheloha@ and tb@.
> >
> > Additionally, it changes struct timekeep in an incompatible way. ;-)
> > A userland built before the addition of tk_nclocks is very unhappy
> > with a kernel built afterwards.  There is no way to compile across
> > this.  You have to (U)pgrade from boot media to install a ftp.openbsd.org
> > userland, and then you can re-compile with the new diff.
>
> I have not seen this problem and have not built a snapshot to update or go
> back. What do you mean by very unhappy? Can you show me the exact steps you
> have done?
>
> > Should we already bump major while the diff matures?
>
> I am not a fan of this. I don't like bumping something before it is actually
> used. It is like an errata before a release.

So what if we end at version 200 ?

we've got a full uint32_t for crying out loud, you're not going to run out
of numbers.

Besides, it's something that's entirely invisible to users, even more so
than library major/minors.

Remember the porters motto "when in doubt, bump"

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Paul Irofti-4
On Thu, Jun 11, 2020 at 02:05:44PM +0200, Marc Espie wrote:

> On Thu, Jun 11, 2020 at 01:13:07PM +0300, Paul Irofti wrote:
> > On 2020-06-11 02:46, Christian Weisgerber wrote:
> > > Paul Irofti:
> > >
> > > > This iteration of the diff adds bounds checking for tk_user and moves
> > > > the usertc.c stub to every arch in libc as recommanded by deraadt@.
> > > > It also fixes a gettimeofday issue reported by cheloha@ and tb@.
> > >
> > > Additionally, it changes struct timekeep in an incompatible way. ;-)
> > > A userland built before the addition of tk_nclocks is very unhappy
> > > with a kernel built afterwards.  There is no way to compile across
> > > this.  You have to (U)pgrade from boot media to install a ftp.openbsd.org
> > > userland, and then you can re-compile with the new diff.
> >
> > I have not seen this problem and have not built a snapshot to update or go
> > back. What do you mean by very unhappy? Can you show me the exact steps you
> > have done?
> >
> > > Should we already bump major while the diff matures?
> >
> > I am not a fan of this. I don't like bumping something before it is actually
> > used. It is like an errata before a release.
>
> So what if we end at version 200 ?
>
> we've got a full uint32_t for crying out loud, you're not going to run out
> of numbers.
>
> Besides, it's something that's entirely invisible to users, even more so
> than library major/minors.

This is not about the range available to us.

If I bump then I will have to also add checks for the revision.
Otherwise what is the point of the bump?  And then what? Keep old and
new code around for both revisions? And then, if this endless mail
thread is ever going to be added to the OpenBSD tree, it will contain
workarounds for something that was never in the tree to begin with.

That is what I am not a fan of. Not the fact that I have to do major=1.

> Remember the porters motto "when in doubt, bump"

Fine. If this turns out to be a real problem, I doubt it is and I think
this might be due to some other patches naddy@ has around in his tree,
then I will send a new diff with the above and with major bumped to 1.

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Marc Espie-2
On Thu, Jun 11, 2020 at 03:42:27PM +0300, Paul Irofti wrote:

> On Thu, Jun 11, 2020 at 02:05:44PM +0200, Marc Espie wrote:
> > On Thu, Jun 11, 2020 at 01:13:07PM +0300, Paul Irofti wrote:
> > > On 2020-06-11 02:46, Christian Weisgerber wrote:
> > > > Paul Irofti:
> > > >
> > > > > This iteration of the diff adds bounds checking for tk_user and moves
> > > > > the usertc.c stub to every arch in libc as recommanded by deraadt@.
> > > > > It also fixes a gettimeofday issue reported by cheloha@ and tb@.
> > > >
> > > > Additionally, it changes struct timekeep in an incompatible way. ;-)
> > > > A userland built before the addition of tk_nclocks is very unhappy
> > > > with a kernel built afterwards.  There is no way to compile across
> > > > this.  You have to (U)pgrade from boot media to install a ftp.openbsd.org
> > > > userland, and then you can re-compile with the new diff.
> > >
> > > I have not seen this problem and have not built a snapshot to update or go
> > > back. What do you mean by very unhappy? Can you show me the exact steps you
> > > have done?
> > >
> > > > Should we already bump major while the diff matures?
> > >
> > > I am not a fan of this. I don't like bumping something before it is actually
> > > used. It is like an errata before a release.
> >
> > So what if we end at version 200 ?
> >
> > we've got a full uint32_t for crying out loud, you're not going to run out
> > of numbers.
> >
> > Besides, it's something that's entirely invisible to users, even more so
> > than library major/minors.
>
> This is not about the range available to us.
>
> If I bump then I will have to also add checks for the revision.
> Otherwise what is the point of the bump?  And then what? Keep old and
> new code around for both revisions? And then, if this endless mail
> thread is ever going to be added to the OpenBSD tree, it will contain
> workarounds for something that was never in the tree to begin with.

Yeah, you do check for the revision, if it's the same, then you use
the timecounter. If it's not, you revert to the syscall.

End of story.

Right now, you can't even bump it if you need, because there is no code
that checks it in the libc, thus is you tweak kernel parts, things *will*
break.

You'd better have the version check in libc  before you even consider
committing this!

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Mark Kettenis
> Date: Thu, 11 Jun 2020 14:49:54 +0200
> From: Marc Espie <[hidden email]>
>
> On Thu, Jun 11, 2020 at 03:42:27PM +0300, Paul Irofti wrote:
> > On Thu, Jun 11, 2020 at 02:05:44PM +0200, Marc Espie wrote:
> > > On Thu, Jun 11, 2020 at 01:13:07PM +0300, Paul Irofti wrote:
> > > > On 2020-06-11 02:46, Christian Weisgerber wrote:
> > > > > Paul Irofti:
> > > > >
> > > > > > This iteration of the diff adds bounds checking for tk_user and moves
> > > > > > the usertc.c stub to every arch in libc as recommanded by deraadt@.
> > > > > > It also fixes a gettimeofday issue reported by cheloha@ and tb@.
> > > > >
> > > > > Additionally, it changes struct timekeep in an incompatible way. ;-)
> > > > > A userland built before the addition of tk_nclocks is very unhappy
> > > > > with a kernel built afterwards.  There is no way to compile across
> > > > > this.  You have to (U)pgrade from boot media to install a ftp.openbsd.org
> > > > > userland, and then you can re-compile with the new diff.
> > > >
> > > > I have not seen this problem and have not built a snapshot to update or go
> > > > back. What do you mean by very unhappy? Can you show me the exact steps you
> > > > have done?
> > > >
> > > > > Should we already bump major while the diff matures?
> > > >
> > > > I am not a fan of this. I don't like bumping something before it is actually
> > > > used. It is like an errata before a release.
> > >
> > > So what if we end at version 200 ?
> > >
> > > we've got a full uint32_t for crying out loud, you're not going to run out
> > > of numbers.
> > >
> > > Besides, it's something that's entirely invisible to users, even more so
> > > than library major/minors.
> >
> > This is not about the range available to us.
> >
> > If I bump then I will have to also add checks for the revision.
> > Otherwise what is the point of the bump?  And then what? Keep old and
> > new code around for both revisions? And then, if this endless mail
> > thread is ever going to be added to the OpenBSD tree, it will contain
> > workarounds for something that was never in the tree to begin with.
>
> Yeah, you do check for the revision, if it's the same, then you use
> the timecounter. If it's not, you revert to the syscall.
>
> End of story.
>
> Right now, you can't even bump it if you need, because there is no code
> that checks it in the libc, thus is you tweak kernel parts, things *will*
> break.
>
> You'd better have the version check in libc  before you even consider
> committing this!

Yup.

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Paul Irofti-4
In reply to this post by Marc Espie-2
On Thu, Jun 11, 2020 at 02:49:54PM +0200, Marc Espie wrote:

> On Thu, Jun 11, 2020 at 03:42:27PM +0300, Paul Irofti wrote:
> > On Thu, Jun 11, 2020 at 02:05:44PM +0200, Marc Espie wrote:
> > > On Thu, Jun 11, 2020 at 01:13:07PM +0300, Paul Irofti wrote:
> > > > On 2020-06-11 02:46, Christian Weisgerber wrote:
> > > > > Paul Irofti:
> > > > >
> > > > > > This iteration of the diff adds bounds checking for tk_user and moves
> > > > > > the usertc.c stub to every arch in libc as recommanded by deraadt@.
> > > > > > It also fixes a gettimeofday issue reported by cheloha@ and tb@.
> > > > >
> > > > > Additionally, it changes struct timekeep in an incompatible way. ;-)
> > > > > A userland built before the addition of tk_nclocks is very unhappy
> > > > > with a kernel built afterwards.  There is no way to compile across
> > > > > this.  You have to (U)pgrade from boot media to install a ftp.openbsd.org
> > > > > userland, and then you can re-compile with the new diff.
> > > >
> > > > I have not seen this problem and have not built a snapshot to update or go
> > > > back. What do you mean by very unhappy? Can you show me the exact steps you
> > > > have done?
> > > >
> > > > > Should we already bump major while the diff matures?
> > > >
> > > > I am not a fan of this. I don't like bumping something before it is actually
> > > > used. It is like an errata before a release.
> > >
> > > So what if we end at version 200 ?
> > >
> > > we've got a full uint32_t for crying out loud, you're not going to run out
> > > of numbers.
> > >
> > > Besides, it's something that's entirely invisible to users, even more so
> > > than library major/minors.
> >
> > This is not about the range available to us.
> >
> > If I bump then I will have to also add checks for the revision.
> > Otherwise what is the point of the bump?  And then what? Keep old and
> > new code around for both revisions? And then, if this endless mail
> > thread is ever going to be added to the OpenBSD tree, it will contain
> > workarounds for something that was never in the tree to begin with.
>
> Yeah, you do check for the revision, if it's the same, then you use
> the timecounter. If it's not, you revert to the syscall.
>
> End of story.
>
> Right now, you can't even bump it if you need, because there is no code
> that checks it in the libc, thus is you tweak kernel parts, things *will*
> break.
>
> You'd better have the version check in libc  before you even consider
> committing this!


diff --git lib/libc/arch/aarch64/gen/Makefile.inc lib/libc/arch/aarch64/gen/Makefile.inc
index a7b1b73f3ef..ee198f5d611 100644
--- lib/libc/arch/aarch64/gen/Makefile.inc
+++ lib/libc/arch/aarch64/gen/Makefile.inc
@@ -9,4 +9,4 @@ SRCS+= fpgetmask.c fpgetround.c fpgetsticky.c
 SRCS+= fpsetmask.c fpsetround.c fpsetsticky.c
 SRCS+= fpclassifyl.c
 SRCS+= isfinitel.c isinfl.c isnanl.c isnormall.c
-SRCS+= signbitl.c
+SRCS+= signbitl.c usertc.c
diff --git lib/libc/arch/aarch64/gen/usertc.c lib/libc/arch/aarch64/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/aarch64/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/alpha/gen/Makefile.inc lib/libc/arch/alpha/gen/Makefile.inc
index a44599d2cab..2a8abd32b61 100644
--- lib/libc/arch/alpha/gen/Makefile.inc
+++ lib/libc/arch/alpha/gen/Makefile.inc
@@ -3,5 +3,5 @@
 
 SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c setjmp.S
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
- fpsetround.c fpsetsticky.c
+ fpsetround.c fpsetsticky.c usertc.c
 SRCS+= sigsetjmp.S
diff --git lib/libc/arch/alpha/gen/usertc.c lib/libc/arch/alpha/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/alpha/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/amd64/gen/Makefile.inc lib/libc/arch/amd64/gen/Makefile.inc
index e995309ed71..f6349e2b974 100644
--- lib/libc/arch/amd64/gen/Makefile.inc
+++ lib/libc/arch/amd64/gen/Makefile.inc
@@ -2,6 +2,7 @@
 
 SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.S nan.c setjmp.S \
  sigsetjmp.S
-SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
+SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c \
+ usertc.c
 SRCS+= flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S \
  fpsetround.S fpsetsticky.S
diff --git lib/libc/arch/amd64/gen/usertc.c lib/libc/arch/amd64/gen/usertc.c
new file mode 100644
index 00000000000..3f3052445cf
--- /dev/null
+++ lib/libc/arch/amd64/gen/usertc.c
@@ -0,0 +1,53 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+static uint64_t
+rdtsc()
+{
+ uint32_t hi, lo;
+ asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
+ return ((uint64_t)lo)|(((uint64_t)hi)<<32);
+}
+
+static uint64_t
+acpihpet()
+{
+ return rdtsc(); /* JUST TO COMPILE */
+}
+
+static uint64_t (*get_tc[])(void) =
+{
+ rdtsc,
+ acpihpet,
+};
+
+int
+tc_get_timecount(struct timekeep *tk, uint64_t *tc)
+{
+ int tk_user = tk->tk_user;
+
+ if (tc == NULL || tk_user < 1 || tk_user > tk->tk_nclocks)
+ return -1;
+
+ *tc = (*get_tc[tk_user - 1])();
+ return 0;
+}
+int (*const _tc_get_timecount)(struct timekeep *tk, uint64_t *tc)
+ = tc_get_timecount;
diff --git lib/libc/arch/arm/gen/Makefile.inc lib/libc/arch/arm/gen/Makefile.inc
index 1b4ab2f3ae7..27090a0d9dc 100644
--- lib/libc/arch/arm/gen/Makefile.inc
+++ lib/libc/arch/arm/gen/Makefile.inc
@@ -2,5 +2,5 @@
 # $NetBSD: Makefile.inc,v 1.6 2003/08/01 17:03:47 lukem Exp $
 
 SRCS+= byte_swap_2.S byte_swap_4.S divsi3.S fabs.c flt_rounds.c infinity.c
-SRCS+= ldexp.c modf.c nan.c
+SRCS+= ldexp.c modf.c nan.c usertc.c
 SRCS+= setjmp.S _setjmp.S sigsetjmp.S
diff --git lib/libc/arch/arm/gen/usertc.c lib/libc/arch/arm/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/arm/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/hppa/gen/Makefile.inc lib/libc/arch/hppa/gen/Makefile.inc
index e0c864242fe..1fde24670f1 100644
--- lib/libc/arch/hppa/gen/Makefile.inc
+++ lib/libc/arch/hppa/gen/Makefile.inc
@@ -2,6 +2,6 @@
 
 SRCS+= setjmp.S
 SRCS+= fabs.c
-SRCS+= infinity.c ldexp.c modf.c nan.c
+SRCS+= infinity.c ldexp.c modf.c nan.c usertc.c
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c
diff --git lib/libc/arch/hppa/gen/usertc.c lib/libc/arch/hppa/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/hppa/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/i386/gen/Makefile.inc lib/libc/arch/i386/gen/Makefile.inc
index 4c18e059581..b7dd30adccd 100644
--- lib/libc/arch/i386/gen/Makefile.inc
+++ lib/libc/arch/i386/gen/Makefile.inc
@@ -1,6 +1,6 @@
 # $OpenBSD: Makefile.inc,v 1.14 2012/04/19 19:14:56 deraadt Exp $
 
-SRCS+= _setjmp.S fabs.S infinity.c ldexp.c \
+SRCS+= _setjmp.S fabs.S infinity.c ldexp.c usertc.c \
  modf.S nan.c setjmp.S sigsetjmp.S
 SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
 SRCS+= flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S \
diff --git lib/libc/arch/i386/gen/usertc.c lib/libc/arch/i386/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/i386/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/m88k/gen/Makefile.inc lib/libc/arch/m88k/gen/Makefile.inc
index cff75b8d425..d66f66af4af 100644
--- lib/libc/arch/m88k/gen/Makefile.inc
+++ lib/libc/arch/m88k/gen/Makefile.inc
@@ -1,7 +1,7 @@
 # $OpenBSD: Makefile.inc,v 1.16 2013/06/05 22:06:30 miod Exp $
 # $NetBSD: Makefile.inc,v 1.3 1995/04/10 21:09:06 jtc Exp $
 
-SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c
+SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c usertc.c
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c
 SRCS+= setjmp.S sigsetjmp.S
diff --git lib/libc/arch/m88k/gen/usertc.c lib/libc/arch/m88k/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/m88k/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/mips64/gen/Makefile.inc lib/libc/arch/mips64/gen/Makefile.inc
index 8cf1fc2d28a..839241a2069 100644
--- lib/libc/arch/mips64/gen/Makefile.inc
+++ lib/libc/arch/mips64/gen/Makefile.inc
@@ -1,6 +1,6 @@
 # $OpenBSD: Makefile.inc,v 1.12 2012/04/12 16:14:09 deraadt Exp $
 
-SRCS+= _setjmp.S fabs.S infinity.c ldexp.S modf.S nan.c
+SRCS+= _setjmp.S fabs.S infinity.c ldexp.S modf.S nan.c usertc.c
 SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c
 SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
diff --git lib/libc/arch/mips64/gen/usertc.c lib/libc/arch/mips64/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/mips64/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/powerpc/gen/Makefile.inc lib/libc/arch/powerpc/gen/Makefile.inc
index 6b2e4613ee8..d4d7b00bff7 100644
--- lib/libc/arch/powerpc/gen/Makefile.inc
+++ lib/libc/arch/powerpc/gen/Makefile.inc
@@ -1,5 +1,5 @@
 SRCS+= infinity.c setjmp.S sigsetjmp.S flt_rounds.c ldexp.c modf.c nan.c
-SRCS+= fabs.c
+SRCS+= fabs.c usertc.c
 SRCS+= fpgetmask.c fpsetmask.c
 SRCS+= fpgetround.c fpsetround.c
 SRCS+= fpgetsticky.c fpsetsticky.c
diff --git lib/libc/arch/powerpc/gen/usertc.c lib/libc/arch/powerpc/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/powerpc/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/sh/gen/Makefile.inc lib/libc/arch/sh/gen/Makefile.inc
index 55de1973b30..4724fb3a6a8 100644
--- lib/libc/arch/sh/gen/Makefile.inc
+++ lib/libc/arch/sh/gen/Makefile.inc
@@ -3,4 +3,4 @@
 SRCS+= flt_rounds.c infinity.c ldexp.c modf.c nan.c setjmp.S _setjmp.S
 SRCS+= sigsetjmp.S
 SRCS+= fabs.c fpgetmask.c fpgetround.c fpgetsticky.c \
- fpsetmask.c fpsetround.c fpsetsticky.c
+ fpsetmask.c fpsetround.c fpsetsticky.c usertc.c
diff --git lib/libc/arch/sh/gen/usertc.c lib/libc/arch/sh/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/sh/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/arch/sparc64/gen/Makefile.inc lib/libc/arch/sparc64/gen/Makefile.inc
index 58259cedef6..a908e022954 100644
--- lib/libc/arch/sparc64/gen/Makefile.inc
+++ lib/libc/arch/sparc64/gen/Makefile.inc
@@ -3,5 +3,5 @@
 SRCS+= _setjmp.S fabs.S fixunsdfsi.S flt_rounds.c fpclassifyl.c \
  fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
  fpsetround.c fpsetsticky.c infinity.c isfinitel.c \
- isinfl.c isnanl.c isnormall.c ldexp.c modf.S \
+ isinfl.c isnanl.c isnormall.c ldexp.c usertc.c modf.S \
  mul.S nan.c setjmp.S signbitl.c sigsetjmp.S umul.S
diff --git lib/libc/arch/sparc64/gen/usertc.c lib/libc/arch/sparc64/gen/usertc.c
new file mode 100644
index 00000000000..84a112c2ea3
--- /dev/null
+++ lib/libc/arch/sparc64/gen/usertc.c
@@ -0,0 +1,21 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/timetc.h>
+
+int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
diff --git lib/libc/asr/asr.c lib/libc/asr/asr.c
index cd056c85719..2b25d49f32a 100644
--- lib/libc/asr/asr.c
+++ lib/libc/asr/asr.c
@@ -196,11 +196,11 @@ poll_intrsafe(struct pollfd *fds, nfds_t nfds, int timeout)
  struct timespec pollstart, pollend, elapsed;
  int r;
 
- if (clock_gettime(CLOCK_MONOTONIC, &pollstart))
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollstart))
  return -1;
 
  while ((r = poll(fds, 1, timeout)) == -1 && errno == EINTR) {
- if (clock_gettime(CLOCK_MONOTONIC, &pollend))
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollend))
  return -1;
  timespecsub(&pollend, &pollstart, &elapsed);
  timeout -= elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000;
@@ -418,7 +418,7 @@ asr_check_reload(struct asr *asr)
  asr->a_rtime = 0;
  }
 
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1)
  return;
 
  if ((ts.tv_sec - asr->a_rtime) < RELOAD_DELAY && asr->a_rtime != 0)
diff --git lib/libc/crypt/bcrypt.c lib/libc/crypt/bcrypt.c
index 82de8fa33b7..02fd3013cc1 100644
--- lib/libc/crypt/bcrypt.c
+++ lib/libc/crypt/bcrypt.c
@@ -248,9 +248,9 @@ _bcrypt_autorounds(void)
  char buf[_PASSWORD_LEN];
  int duration;
 
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &before);
+ WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &before);
  bcrypt_newhash("testpassword", r, buf, sizeof(buf));
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &after);
+ WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &after);
 
  duration = after.tv_sec - before.tv_sec;
  duration *= 1000000;
diff --git lib/libc/dlfcn/init.c lib/libc/dlfcn/init.c
index 270f54aada5..19d0a2c3ad6 100644
--- lib/libc/dlfcn/init.c
+++ lib/libc/dlfcn/init.c
@@ -20,6 +20,7 @@
 
 #include <sys/types.h>
 #include <sys/syscall.h>
+#include <sys/timetc.h> /* timekeep */
 
 #ifndef PIC
 #include <sys/mman.h>
@@ -45,8 +46,9 @@
 /* XXX should be in an include file shared with csu */
 char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void));
 
-/* provide definition for this */
+/* provide definitions for these */
 int _pagesize = 0;
+void *_timekeep = NULL;
 
 /*
  * In dynamicly linked binaries environ and __progname are overriden by
@@ -105,6 +107,10 @@ _libc_preinit(int argc, char **argv, char **envp, dl_cb_cb *cb)
  phnum = aux->au_v;
  break;
 #endif /* !PIC */
+ case AUX_openbsd_timekeep:
+ if (_tc_get_timecount)
+ _timekeep = (void *)aux->au_v;
+ break;
  }
  }
 
diff --git lib/libc/gen/auth_subr.c lib/libc/gen/auth_subr.c
index 1286a96fe40..32f86eda50f 100644
--- lib/libc/gen/auth_subr.c
+++ lib/libc/gen/auth_subr.c
@@ -752,7 +752,7 @@ auth_check_expire(auth_session_t *as)
 
  if (as->pwd && (quad_t)as->pwd->pw_expire != 0) {
  if (as->now.tv_sec == 0)
- gettimeofday(&as->now, NULL);
+ WRAP(gettimeofday)(&as->now, NULL);
  if ((quad_t)as->now.tv_sec >= (quad_t)as->pwd->pw_expire) {
  as->state &= ~AUTH_ALLOW;
  as->state |= AUTH_EXPIRED;
@@ -779,7 +779,7 @@ auth_check_change(auth_session_t *as)
 
  if (as->pwd && (quad_t)as->pwd->pw_change) {
  if (as->now.tv_sec == 0)
- gettimeofday(&as->now, NULL);
+ WRAP(gettimeofday)(&as->now, NULL);
  if (as->now.tv_sec >= (quad_t)as->pwd->pw_change) {
  as->state &= ~AUTH_ALLOW;
  as->state |= AUTH_PWEXPIRED;
diff --git lib/libc/gen/time.c lib/libc/gen/time.c
index 3bbd0d733d1..b3ce9a800f1 100644
--- lib/libc/gen/time.c
+++ lib/libc/gen/time.c
@@ -36,7 +36,7 @@ time(time_t *t)
 {
  struct timeval tt;
 
- if (gettimeofday(&tt, NULL) == -1)
+ if (WRAP(gettimeofday)(&tt, NULL) == -1)
  return (-1);
  if (t)
  *t = (time_t)tt.tv_sec;
diff --git lib/libc/gen/times.c lib/libc/gen/times.c
index 02e4dd44b5c..36841810d1b 100644
--- lib/libc/gen/times.c
+++ lib/libc/gen/times.c
@@ -52,7 +52,7 @@ times(struct tms *tp)
  return ((clock_t)-1);
  tp->tms_cutime = CONVTCK(ru.ru_utime);
  tp->tms_cstime = CONVTCK(ru.ru_stime);
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1)
  return ((clock_t)-1);
  return (ts.tv_sec * CLK_TCK + ts.tv_nsec / (1000000000 / CLK_TCK));
 }
diff --git lib/libc/gen/timespec_get.c lib/libc/gen/timespec_get.c
index 520a5954025..845cbe80356 100644
--- lib/libc/gen/timespec_get.c
+++ lib/libc/gen/timespec_get.c
@@ -37,7 +37,7 @@ timespec_get(struct timespec *ts, int base)
 {
  switch (base) {
  case TIME_UTC:
- if (clock_gettime(CLOCK_REALTIME, ts) == -1)
+ if (WRAP(clock_gettime)(CLOCK_REALTIME, ts) == -1)
  return 0;
  break;
  default:
diff --git lib/libc/hidden/sys/time.h lib/libc/hidden/sys/time.h
index ed112320fa2..df717021cab 100644
--- lib/libc/hidden/sys/time.h
+++ lib/libc/hidden/sys/time.h
@@ -24,7 +24,7 @@ PROTO_NORMAL(adjfreq);
 PROTO_NORMAL(adjtime);
 PROTO_NORMAL(futimes);
 PROTO_NORMAL(getitimer);
-PROTO_NORMAL(gettimeofday);
+PROTO_WRAP(gettimeofday);
 PROTO_NORMAL(setitimer);
 PROTO_NORMAL(settimeofday);
 PROTO_NORMAL(utimes);
diff --git lib/libc/hidden/sys/timetc.h lib/libc/hidden/sys/timetc.h
new file mode 100644
index 00000000000..d86b31e0d86
--- /dev/null
+++ lib/libc/hidden/sys/timetc.h
@@ -0,0 +1,38 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LIBC_SYS_TIMETC_H_
+#define _LIBC_SYS_TIMETC_H_
+
+#define _LIBC
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include_next <sys/timetc.h>
+
+__BEGIN_HIDDEN_DECLS
+extern void *_timekeep;
+
+extern int (*const _tc_get_timecount)(struct timekeep *, uint64_t *);
+
+int _microtime(struct timeval *, struct timekeep *);
+int _nanotime(struct timespec *, struct timekeep *);
+int _nanoruntime(struct timespec *, struct timekeep *);
+int _nanouptime(struct timespec *, struct timekeep *);
+__END_HIDDEN_DECLS
+
+#endif /* !_LIBC_SYS_TIMETC_H_ */
diff --git lib/libc/hidden/time.h lib/libc/hidden/time.h
index 18c49f8fcb9..d8e1e0caf64 100644
--- lib/libc/hidden/time.h
+++ lib/libc/hidden/time.h
@@ -29,7 +29,7 @@ PROTO_NORMAL(asctime_r);
 PROTO_STD_DEPRECATED(clock);
 PROTO_DEPRECATED(clock_getcpuclockid);
 PROTO_NORMAL(clock_getres);
-PROTO_NORMAL(clock_gettime);
+PROTO_WRAP(clock_gettime);
 PROTO_NORMAL(clock_settime);
 PROTO_STD_DEPRECATED(ctime);
 PROTO_DEPRECATED(ctime_r);
diff --git lib/libc/net/res_random.c lib/libc/net/res_random.c
index 763e420bb88..9babb28470a 100644
--- lib/libc/net/res_random.c
+++ lib/libc/net/res_random.c
@@ -219,7 +219,7 @@ res_initid(void)
  if (ru_prf != NULL)
  arc4random_buf(ru_prf, sizeof(*ru_prf));
 
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts);
  ru_reseed = ts.tv_sec + RU_OUT;
  ru_msb = ru_msb == 0x8000 ? 0 : 0x8000;
 }
@@ -232,7 +232,7 @@ __res_randomid(void)
  u_int r;
  static void *randomid_mutex;
 
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts);
  pid = getpid();
 
  _MUTEX_LOCK(&randomid_mutex);
diff --git lib/libc/rpc/auth_unix.c lib/libc/rpc/auth_unix.c
index 402d98cede4..917a6d42b8a 100644
--- lib/libc/rpc/auth_unix.c
+++ lib/libc/rpc/auth_unix.c
@@ -121,7 +121,7 @@ authunix_create(char *machname, int uid, int gid, int len, int *aup_gids)
  /*
  * fill in param struct from the given params
  */
- (void)gettimeofday(&now,  NULL);
+ (void)WRAP(gettimeofday)(&now,  NULL);
  aup.aup_time = now.tv_sec;
  aup.aup_machname = machname;
  aup.aup_uid = uid;
@@ -274,7 +274,7 @@ authunix_refresh(AUTH *auth)
  goto done;
 
  /* update the time and serialize in place */
- (void)gettimeofday(&now, NULL);
+ (void)WRAP(gettimeofday)(&now, NULL);
  aup.aup_time = now.tv_sec;
  xdrs.x_op = XDR_ENCODE;
  XDR_SETPOS(&xdrs, 0);
diff --git lib/libc/rpc/clnt_tcp.c lib/libc/rpc/clnt_tcp.c
index 8e6ef515b0e..927b4bf2028 100644
--- lib/libc/rpc/clnt_tcp.c
+++ lib/libc/rpc/clnt_tcp.c
@@ -393,12 +393,12 @@ readtcp(struct ct_data *ct, caddr_t buf, int len)
  pfd[0].events = POLLIN;
  TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &wait);
  delta = wait;
- clock_gettime(CLOCK_MONOTONIC, &start);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
  for (;;) {
  r = ppoll(pfd, 1, &delta, NULL);
  save_errno = errno;
 
- clock_gettime(CLOCK_MONOTONIC, &after);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
  timespecsub(&start, &after, &duration);
  timespecsub(&wait, &duration, &delta);
  if (delta.tv_sec < 0 || !timespecisset(&delta))
diff --git lib/libc/rpc/clnt_udp.c lib/libc/rpc/clnt_udp.c
index 68d01674410..92e1d5c350d 100644
--- lib/libc/rpc/clnt_udp.c
+++ lib/libc/rpc/clnt_udp.c
@@ -265,7 +265,7 @@ send_again:
  reply_msg.acpted_rply.ar_results.where = resultsp;
  reply_msg.acpted_rply.ar_results.proc = xresults;
 
- clock_gettime(CLOCK_MONOTONIC, &start);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
  for (;;) {
  switch (ppoll(pfd, 1, &wait, NULL)) {
  case 0:
@@ -283,7 +283,7 @@ send_again:
  /* FALLTHROUGH */
  case -1:
  if (errno == EINTR) {
- clock_gettime(CLOCK_MONOTONIC, &after);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
  timespecsub(&after, &start, &duration);
  timespecadd(&time_waited, &duration, &time_waited);
  if (timespeccmp(&time_waited, &timeout, <))
diff --git lib/libc/rpc/svc_tcp.c lib/libc/rpc/svc_tcp.c
index f9d7a70938f..6c99db84359 100644
--- lib/libc/rpc/svc_tcp.c
+++ lib/libc/rpc/svc_tcp.c
@@ -342,7 +342,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len)
  * A timeout is fatal for the connection.
  */
  delta = wait_per_try;
- clock_gettime(CLOCK_MONOTONIC, &start);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
  pfd[0].fd = sock;
  pfd[0].events = POLLIN;
  do {
@@ -351,7 +351,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len)
  case -1:
  if (errno != EINTR)
  goto fatal_err;
- clock_gettime(CLOCK_MONOTONIC, &after);
+ WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
  timespecsub(&after, &start, &duration);
  timespecsub(&wait_per_try, &duration, &delta);
  if (delta.tv_sec < 0 || !timespecisset(&delta))
diff --git lib/libc/sys/Makefile.inc lib/libc/sys/Makefile.inc
index 34769576ced..d57418d81bf 100644
--- lib/libc/sys/Makefile.inc
+++ lib/libc/sys/Makefile.inc
@@ -12,7 +12,8 @@ SRCS+= Ovfork.S brk.S ${CERROR} \
 
 # glue to offer userland wrappers for some syscalls
 SRCS+= posix_madvise.c pthread_sigmask.c \
- w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c
+ w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c \
+ w_clock_gettime.c w_gettimeofday.c microtime.c
 
 # glue for compat with old syscall interfaces.
 SRCS+= ftruncate.c lseek.c mquery.c mmap.c ptrace.c semctl.c truncate.c \
@@ -43,7 +44,7 @@ SRCS+= ${CANCEL:%=w_%.c} w_pread.c w_preadv.c w_pwrite.c w_pwritev.c
 ASM= __semctl.o __syscall.o __thrsigdivert.o \
  access.o acct.o adjfreq.o adjtime.o \
  bind.o chdir.o chflags.o chflagsat.o chmod.o chown.o chroot.o \
- clock_getres.o clock_gettime.o clock_settime.o \
+ clock_getres.o clock_settime.o \
  dup.o dup2.o dup3.o \
  execve.o \
  faccessat.o fchdir.o fchflags.o fchmod.o fchmodat.o fchown.o \
@@ -54,7 +55,7 @@ ASM= __semctl.o __syscall.o __thrsigdivert.o \
  getgroups.o getitimer.o getpeername.o getpgid.o \
  getpriority.o getresgid.o getresuid.o \
  getrlimit.o getrusage.o getsid.o getsockname.o \
- getsockopt.o gettimeofday.o ioctl.o \
+ getsockopt.o ioctl.o \
  kevent.o kill.o kqueue.o ktrace.o lchown.o \
  link.o linkat.o listen.o lstat.o madvise.o \
  minherit.o mkdir.o mkdirat.o mkfifo.o mkfifoat.o \
@@ -109,7 +110,8 @@ PPSEUDO_NOERR=${PSEUDO_NOERR:.o=.po}
 SPSEUDO_NOERR=${PSEUDO_NOERR:.o=.so}
 DPSEUDO_NOERR=${PSEUDO_NOERR:.o=.do}
 
-HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o}
+HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o} \
+ clock_gettime.o gettimeofday.o
 PHIDDEN=${HIDDEN:.o=.po}
 SHIDDEN=${HIDDEN:.o=.so}
 DHIDDEN=${HIDDEN:.o=.do}
diff --git lib/libc/sys/microtime.c lib/libc/sys/microtime.c
new file mode 100644
index 00000000000..fc023e8452f
--- /dev/null
+++ lib/libc/sys/microtime.c
@@ -0,0 +1,180 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2000 Poul-Henning Kamp <[hidden email]>
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/timetc.h>
+
+#include <time.h>
+
+/*
+ * Return the difference between the timehands' counter value now and what
+ * was when we copied it to the timehands' offset_count.
+ */
+static inline int
+tc_delta(struct timekeep *tk, u_int *delta)
+{
+ uint64_t tc;
+ if (delta == NULL || _tc_get_timecount(tk, &tc))
+ return -1;
+ *delta = (tc - tk->tk_offset_count) & tk->tk_counter_mask;
+ return 0;
+}
+
+static inline void
+bintimeaddfrac(const struct bintime *bt, uint64_t x, struct bintime *ct)
+{
+ ct->sec = bt->sec;
+ if (bt->frac > bt->frac + x)
+ ct->sec++;
+ ct->frac = bt->frac + x;
+}
+
+static inline void
+BINTIME_TO_TIMESPEC(const struct bintime *bt, struct timespec *ts)
+{
+ ts->tv_sec = bt->sec;
+ ts->tv_nsec = (long)(((uint64_t)1000000000 * (uint32_t)(bt->frac >> 32)) >> 32);
+}
+
+static inline void
+BINTIME_TO_TIMEVAL(const struct bintime *bt, struct timeval *tv)
+{
+ tv->tv_sec = bt->sec;
+ tv->tv_usec = (long)(((uint64_t)1000000 * (uint32_t)(bt->frac >> 32)) >> 32);
+}
+
+static int
+binuptime(struct bintime *bt, struct timekeep *tk)
+{
+ u_int gen, delta;
+
+ do {
+ gen = tk->tk_generation;
+ membar_consumer();
+ *bt = tk->tk_offset;
+ if (tc_delta(tk, &delta))
+ return -1;
+ bintimeaddfrac(bt, tk->tk_scale * delta, bt);
+ membar_consumer();
+ } while (gen == 0 || gen != tk->tk_generation);
+
+ return 0;
+}
+
+static inline void
+bintimeadd(const struct bintime *bt, const struct bintime *ct,
+    struct bintime *dt)
+{
+ dt->sec = bt->sec + ct->sec;
+ if (bt->frac > bt->frac + ct->frac)
+ dt->sec++;
+ dt->frac = bt->frac + ct->frac;
+}
+
+static inline void
+bintimesub(const struct bintime *bt, const struct bintime *ct,
+    struct bintime *dt)
+{
+ dt->sec = bt->sec - ct->sec;
+ if (bt->frac < bt->frac - ct->frac)
+ dt->sec--;
+ dt->frac = bt->frac - ct->frac;
+}
+
+static int
+binruntime(struct bintime *bt, struct timekeep *tk)
+{
+ u_int gen, delta;
+
+ do {
+ gen = tk->tk_generation;
+ membar_consumer();
+ if (tc_delta(tk, &delta))
+ return -1;
+ bintimeaddfrac(&tk->tk_offset, tk->tk_scale * delta, bt);
+ bintimesub(bt, &tk->tk_naptime, bt);
+ membar_consumer();
+ } while (gen == 0 || gen != tk->tk_generation);
+
+ return 0;
+}
+
+static int
+bintime(struct bintime *bt, struct timekeep *tk)
+{
+ u_int gen, delta;
+
+ do {
+ gen = tk->tk_generation;
+ membar_consumer();
+ *bt = tk->tk_offset;
+ if (tc_delta(tk, &delta))
+ return -1;
+ bintimeaddfrac(bt, tk->tk_scale * delta, bt);
+ bintimeadd(bt, &tk->tk_boottime, bt);
+ membar_consumer();
+ } while (gen == 0 || gen != tk->tk_generation);
+
+ return 0;
+}
+
+int
+_microtime(struct timeval *tvp, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (bintime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMEVAL(&bt, tvp);
+ return 0;
+}
+
+int
+_nanotime(struct timespec *tsp, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (bintime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMESPEC(&bt, tsp);
+ return 0;
+}
+
+int
+_nanoruntime(struct timespec *ts, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (binruntime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMESPEC(&bt, ts);
+ return 0;
+}
+
+
+int
+_nanouptime(struct timespec *tsp, struct timekeep *tk)
+{
+ struct bintime bt;
+
+ if (binuptime(&bt, tk))
+ return -1;
+ BINTIME_TO_TIMESPEC(&bt, tsp);
+ return 0;
+}
diff --git lib/libc/sys/w_clock_gettime.c lib/libc/sys/w_clock_gettime.c
new file mode 100644
index 00000000000..decd3342d6d
--- /dev/null
+++ lib/libc/sys/w_clock_gettime.c
@@ -0,0 +1,54 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/timetc.h>
+
+#include <time.h>
+
+int
+WRAP(clock_gettime)(clockid_t clock_id, struct timespec *tp)
+{
+ int rc = 0;
+ struct timekeep *timekeep = _timekeep;
+
+ if (timekeep == NULL || timekeep->tk_user == 0)
+ return clock_gettime(clock_id, tp);
+
+ if (timekeep->tk_major != 1 || timekeep->tk_minor != 0)
+ return clock_gettime(clock_id, tp);
+
+ switch (clock_id) {
+ case CLOCK_REALTIME:
+ rc = _nanotime(tp, timekeep);
+ break;
+ case CLOCK_UPTIME:
+ rc = _nanoruntime(tp, timekeep);
+ break;
+ case CLOCK_MONOTONIC:
+ case CLOCK_BOOTTIME:
+ rc = _nanouptime(tp, timekeep);
+ break;
+ default:
+ return clock_gettime(clock_id, tp);
+ }
+
+ if (rc)
+ return clock_gettime(clock_id, tp);
+
+ return 0;
+}
+DEF_WRAP(clock_gettime);
diff --git lib/libc/sys/w_gettimeofday.c lib/libc/sys/w_gettimeofday.c
new file mode 100644
index 00000000000..2d9743e62bb
--- /dev/null
+++ lib/libc/sys/w_gettimeofday.c
@@ -0,0 +1,43 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Robert Nagy <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/timetc.h>
+
+int
+WRAP(gettimeofday)(struct timeval *tp, struct timezone *tzp)
+{
+ int rc = 0;
+ struct timekeep *timekeep = _timekeep;
+ static struct timezone zerotz = { 0, 0 };
+
+ if (timekeep == NULL || timekeep->tk_user == 0)
+ return gettimeofday(tp, tzp);
+
+ if (timekeep->tk_major != 1 || timekeep->tk_minor != 0)
+ return gettimeofday(tp, tzp);
+
+ if (tp)
+ rc = _microtime(tp, timekeep);
+ if (rc)
+ return gettimeofday(tp, tzp);
+
+ if (tzp)
+ *tzp = zerotz;
+
+ return 0;
+}
+DEF_WRAP(gettimeofday);
diff --git lib/libc/thread/synch.h lib/libc/thread/synch.h
index 788890add89..df2239438d2 100644
--- lib/libc/thread/synch.h
+++ lib/libc/thread/synch.h
@@ -33,7 +33,7 @@ _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *
  if (abs == NULL)
  return futex(p, FUTEX_WAIT_PRIVATE, val, NULL, NULL);
 
- if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel))
+ if (abs->tv_nsec >= 1000000000 || WRAP(clock_gettime)(clockid, &rel))
  return (EINVAL);
 
  rel.tv_sec = abs->tv_sec - rel.tv_sec;
diff --git regress/lib/libc/timekeep/Makefile regress/lib/libc/timekeep/Makefile
new file mode 100644
index 00000000000..a7f3080290d
--- /dev/null
+++ regress/lib/libc/timekeep/Makefile
@@ -0,0 +1,5 @@
+# $OpenBSD$
+
+PROGS= test_clock_gettime test_time_skew test_gettimeofday
+
+.include <bsd.regress.mk>
diff --git regress/lib/libc/timekeep/test_clock_gettime.c regress/lib/libc/timekeep/test_clock_gettime.c
new file mode 100644
index 00000000000..859ec368215
--- /dev/null
+++ regress/lib/libc/timekeep/test_clock_gettime.c
@@ -0,0 +1,43 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <time.h>
+
+#define ASSERT_EQ(a, b) assert((a) == (b))
+
+void
+check()
+{
+ struct timespec tp = {0};
+
+ ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_UPTIME, &tp));
+
+
+ ASSERT_EQ(0, clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp));
+ ASSERT_EQ(0, clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp));
+
+}
+
+int main()
+{
+ check();
+ return 0;
+}
diff --git regress/lib/libc/timekeep/test_gettimeofday.c regress/lib/libc/timekeep/test_gettimeofday.c
new file mode 100644
index 00000000000..ea90a1be7e0
--- /dev/null
+++ regress/lib/libc/timekeep/test_gettimeofday.c
@@ -0,0 +1,37 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <sys/time.h>
+
+#define ASSERT_EQ(a, b) assert((a) == (b))
+
+void
+check()
+{
+ struct timeval tv = {0};
+ struct timezone tzp;
+
+ ASSERT_EQ(0, gettimeofday(&tv, NULL));
+ ASSERT_EQ(0, gettimeofday(&tv, &tzp));
+}
+
+int main()
+{
+ check();
+ return 0;
+}
diff --git regress/lib/libc/timekeep/test_time_skew.c regress/lib/libc/timekeep/test_time_skew.c
new file mode 100644
index 00000000000..dfa9481c091
--- /dev/null
+++ regress/lib/libc/timekeep/test_time_skew.c
@@ -0,0 +1,55 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Paul Irofti <[hidden email]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/time.h>
+
+#include <assert.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define ASSERT_EQ(a, b) assert((a) == (b))
+#define ASSERT_NE(a, b) assert((a) != (b))
+
+void
+check()
+{
+         struct timespec tp1, tp2, tout;
+
+         tout.tv_sec = 0;
+         tout.tv_nsec = 100000;
+
+         ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp1));
+
+         nanosleep(&tout, NULL);
+
+         ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp2));
+
+         /* tp1 should never be larger than tp2 */
+         ASSERT_NE(1, timespeccmp(&tp1, &tp2, >));
+}
+
+int
+main(void)
+{
+ int i;
+
+ for (i = 0; i < 1000; i++)
+ check();
+
+ return 0;
+}
diff --git sys/arch/alpha/alpha/clock.c sys/arch/alpha/alpha/clock.c
index 3f5f2c5b42b..6eaf8b107c6 100644
--- sys/arch/alpha/alpha/clock.c
+++ sys/arch/alpha/alpha/clock.c
@@ -64,7 +64,7 @@ int clk_irq = 0;
 
 u_int rpcc_get_timecount(struct timecounter *);
 struct timecounter rpcc_timecounter = {
- rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL
+ rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL, 0
 };
 
 extern todr_chip_handle_t todr_handle;
diff --git sys/arch/alpha/alpha/machdep.c sys/arch/alpha/alpha/machdep.c
index 09dc7e9cba5..9e43723959f 100644
--- sys/arch/alpha/alpha/machdep.c
+++ sys/arch/alpha/alpha/machdep.c
@@ -139,6 +139,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
 struct vm_map *exec_map = NULL;
 struct vm_map *phys_map = NULL;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/amd64/amd64/machdep.c sys/arch/amd64/amd64/machdep.c
index 9dab8947af0..f58ab1a345c 100644
--- sys/arch/amd64/amd64/machdep.c
+++ sys/arch/amd64/amd64/machdep.c
@@ -193,6 +193,9 @@ int lid_action = 1;
 int pwr_action = 1;
 int forceukbd;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 1;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/amd64/amd64/tsc.c sys/arch/amd64/amd64/tsc.c
index 7a1dcb4ad75..3db93d88dec 100644
--- sys/arch/amd64/amd64/tsc.c
+++ sys/arch/amd64/amd64/tsc.c
@@ -50,7 +50,7 @@ extern u_int32_t lapic_per_second;
 #endif
 
 struct timecounter tsc_timecounter = {
- tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL
+ tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL, 1
 };
 
 uint64_t
diff --git sys/arch/amd64/isa/clock.c sys/arch/amd64/isa/clock.c
index 613f7ee0e0f..00da0c6a8d0 100644
--- sys/arch/amd64/isa/clock.c
+++ sys/arch/amd64/isa/clock.c
@@ -116,7 +116,7 @@ u_int i8254_get_timecount(struct timecounter *tc);
 u_int i8254_simple_get_timecount(struct timecounter *tc);
 
 static struct timecounter i8254_timecounter = {
- i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
+ i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0
 };
 
 int clockintr(void *);
diff --git sys/arch/arm64/arm64/machdep.c sys/arch/arm64/arm64/machdep.c
index 4e292479233..2b6165800ca 100644
--- sys/arch/arm64/arm64/machdep.c
+++ sys/arch/arm64/arm64/machdep.c
@@ -90,6 +90,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
 /* the following is used externally (sysctl_hw) */
 char    machine[] = MACHINE;            /* from <machine/param.h> */
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 int safepri = 0;
 
 struct cpu_info cpu_info_primary;
diff --git sys/arch/arm64/dev/agtimer.c sys/arch/arm64/dev/agtimer.c
index 29394141ad5..6b7c6db862f 100644
--- sys/arch/arm64/dev/agtimer.c
+++ sys/arch/arm64/dev/agtimer.c
@@ -43,7 +43,7 @@ int32_t agtimer_frequency = TIMER_FREQUENCY;
 u_int agtimer_get_timecount(struct timecounter *);
 
 static struct timecounter agtimer_timecounter = {
- agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL
+ agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL, 0
 };
 
 struct agtimer_pcpu_softc {
diff --git sys/arch/armv7/armv7/armv7_machdep.c sys/arch/armv7/armv7/armv7_machdep.c
index 1a5418cbf58..8b347ce86fd 100644
--- sys/arch/armv7/armv7/armv7_machdep.c
+++ sys/arch/armv7/armv7/armv7_machdep.c
@@ -186,6 +186,9 @@ pv_addr_t kernel_pt_table[NUM_KERNEL_PTS];
 
 extern struct user *proc0paddr;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/armv7/omap/gptimer.c sys/arch/armv7/omap/gptimer.c
index 7605845d5e2..061542d532f 100644
--- sys/arch/armv7/omap/gptimer.c
+++ sys/arch/armv7/omap/gptimer.c
@@ -117,7 +117,7 @@ int gptimer_irq = 0;
 u_int gptimer_get_timecount(struct timecounter *);
 
 static struct timecounter gptimer_timecounter = {
- gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL
+ gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL, 0
 };
 
 volatile u_int32_t nexttickevent;
diff --git sys/arch/armv7/omap/omap_machdep.c sys/arch/armv7/omap/omap_machdep.c
index f62178f04a4..a36229a427c 100644
--- sys/arch/armv7/omap/omap_machdep.c
+++ sys/arch/armv7/omap/omap_machdep.c
@@ -32,6 +32,9 @@
 #include <armv7/armv7/armv7var.h>
 #include <armv7/armv7/armv7_machdep.h>
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 extern void omap4_smc_call(uint32_t, uint32_t);
 extern void omdog_reset(void);
 extern struct board_dev *omap_board_devs(void);
diff --git sys/arch/armv7/sunxi/sxitimer.c sys/arch/armv7/sunxi/sxitimer.c
index 14a243c78d0..41028f9a602 100644
--- sys/arch/armv7/sunxi/sxitimer.c
+++ sys/arch/armv7/sunxi/sxitimer.c
@@ -89,7 +89,7 @@ void sxitimer_delay(u_int);
 u_int sxitimer_get_timecount(struct timecounter *);
 
 static struct timecounter sxitimer_timecounter = {
- sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL
+ sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL, 0
 };
 
 bus_space_tag_t sxitimer_iot;
diff --git sys/arch/hppa/dev/clock.c sys/arch/hppa/dev/clock.c
index 4c594ab5ec7..8cce6c3a893 100644
--- sys/arch/hppa/dev/clock.c
+++ sys/arch/hppa/dev/clock.c
@@ -47,7 +47,7 @@ int cpu_hardclock(void *);
 u_int itmr_get_timecount(struct timecounter *);
 
 struct timecounter itmr_timecounter = {
- itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL
+ itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL, 0
 };
 
 extern todr_chip_handle_t todr_handle;
diff --git sys/arch/hppa/hppa/machdep.c sys/arch/hppa/hppa/machdep.c
index f7bb998d53e..df356e5202f 100644
--- sys/arch/hppa/hppa/machdep.c
+++ sys/arch/hppa/hppa/machdep.c
@@ -152,6 +152,9 @@ void hpmc_dump(void);
 void cpuid(void);
 void blink_led_timeout(void *);
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/i386/i386/machdep.c sys/arch/i386/i386/machdep.c
index 0d392c75802..c22eb22bafe 100644
--- sys/arch/i386/i386/machdep.c
+++ sys/arch/i386/i386/machdep.c
@@ -235,6 +235,9 @@ int lid_action = 1;
 int pwr_action = 1;
 int forceukbd;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/i386/isa/clock.c sys/arch/i386/isa/clock.c
index 09a6db983f2..dd74bd425ad 100644
--- sys/arch/i386/isa/clock.c
+++ sys/arch/i386/isa/clock.c
@@ -129,7 +129,7 @@ u_int i8254_get_timecount(struct timecounter *tc);
 u_int i8254_simple_get_timecount(struct timecounter *tc);
 
 static struct timecounter i8254_timecounter = {
- i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
+ i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0
 };
 struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH);
 u_long rtclock_tval;
diff --git sys/arch/i386/pci/geodesc.c sys/arch/i386/pci/geodesc.c
index 9d9f061eef9..bb8e4c7f9ae 100644
--- sys/arch/i386/pci/geodesc.c
+++ sys/arch/i386/pci/geodesc.c
@@ -65,7 +65,9 @@ struct timecounter geodesc_timecounter = {
  0xffffffff, /* counter_mask */
  27000000, /* frequency */
  "GEOTSC", /* name */
- 2000 /* quality */
+ 2000, /* quality */
+ NULL, /* private bits */
+ 0 /* expose to user */
 };
 
 int
diff --git sys/arch/i386/pci/gscpm.c sys/arch/i386/pci/gscpm.c
index 8b8aa4ac430..a6f324e66f3 100644
--- sys/arch/i386/pci/gscpm.c
+++ sys/arch/i386/pci/gscpm.c
@@ -55,7 +55,9 @@ struct timecounter gscpm_timecounter = {
  0xffffff, /* counter_mask */
  3579545, /* frequency */
  "GSCPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0 /* expose to user */
 };
 
 struct cfattach gscpm_ca = {
diff --git sys/arch/i386/pci/ichpcib.c sys/arch/i386/pci/ichpcib.c
index 6abf1627de2..629a86a14ff 100644
--- sys/arch/i386/pci/ichpcib.c
+++ sys/arch/i386/pci/ichpcib.c
@@ -63,7 +63,9 @@ struct timecounter ichpcib_timecounter = {
  0xffffff, /* counter_mask */
  3579545, /* frequency */
  "ICHPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0 /* expose to user */
 };
 
 struct cfattach ichpcib_ca = {
diff --git sys/arch/landisk/landisk/machdep.c sys/arch/landisk/landisk/machdep.c
index d5ea8df1740..3b515d191c9 100644
--- sys/arch/landisk/landisk/machdep.c
+++ sys/arch/landisk/landisk/machdep.c
@@ -119,6 +119,9 @@ extern u_int32_t getramsize(void);
 struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
 struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/loongson/loongson/generic3a_machdep.c sys/arch/loongson/loongson/generic3a_machdep.c
index ac3f1db6ccd..53489b07549 100644
--- sys/arch/loongson/loongson/generic3a_machdep.c
+++ sys/arch/loongson/loongson/generic3a_machdep.c
@@ -98,7 +98,9 @@ struct timecounter rs780e_timecounter = {
  .tc_counter_mask = 0xffffffffu, /* truncated to 32 bits */
  .tc_frequency = HPET_FREQ,
  .tc_name = "hpet",
- .tc_quality = 100
+ .tc_quality = 100,
+ .tc_priv = NULL,
+ .tc_user = 0,
 };
 
 /* Firmware entry points */
diff --git sys/arch/loongson/loongson/machdep.c sys/arch/loongson/loongson/machdep.c
index aaceb54bea8..9c66faa4b50 100644
--- sys/arch/loongson/loongson/machdep.c
+++ sys/arch/loongson/loongson/machdep.c
@@ -103,6 +103,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
 vm_map_t exec_map;
 vm_map_t phys_map;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/luna88k/luna88k/clock.c sys/arch/luna88k/luna88k/clock.c
index a04120987e0..6580a4a46bf 100644
--- sys/arch/luna88k/luna88k/clock.c
+++ sys/arch/luna88k/luna88k/clock.c
@@ -112,7 +112,9 @@ struct timecounter clock_tc = {
  .tc_counter_mask = 0xffffffff,
  .tc_frequency = 0, /* will be filled in */
  .tc_name = "clock",
- .tc_quality = 0
+ .tc_quality = 0,
+ .tc_priv = NULL,
+ .tc_user = 0,
 };
 
 /*
diff --git sys/arch/luna88k/luna88k/machdep.c sys/arch/luna88k/luna88k/machdep.c
index 9501ad85210..41bbe6793d4 100644
--- sys/arch/luna88k/luna88k/machdep.c
+++ sys/arch/luna88k/luna88k/machdep.c
@@ -193,6 +193,9 @@ int sysconsole = 1; /* 0 = ttya, 1 = keyboard/mouse, used in dev/sio.c */
 u_int16_t dipswitch = 0; /* set in locore.S */
 int hwplanebits; /* set in locore.S */
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 extern struct consdev syscons; /* in dev/siotty.c */
 
 extern void syscnattach(int); /* in dev/siotty.c */
diff --git sys/arch/macppc/macppc/clock.c sys/arch/macppc/macppc/clock.c
index 4a44a92cfc0..8c3ad620be8 100644
--- sys/arch/macppc/macppc/clock.c
+++ sys/arch/macppc/macppc/clock.c
@@ -57,7 +57,7 @@ u_int32_t ns_per_tick = 320;
 static int32_t ticks_per_intr;
 
 static struct timecounter tb_timecounter = {
- tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL
+ tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL, 0
 };
 
 /* calibrate the timecounter frequency for the listed models */
diff --git sys/arch/macppc/macppc/machdep.c sys/arch/macppc/macppc/machdep.c
index 178fe0995da..af4f68ed1d6 100644
--- sys/arch/macppc/macppc/machdep.c
+++ sys/arch/macppc/macppc/machdep.c
@@ -350,6 +350,9 @@ install_extint(void (*handler)(void))
  ppc_mtmsr(omsr);
 }
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/mips64/mips64/mips64_machdep.c sys/arch/mips64/mips64/mips64_machdep.c
index d4a42ed5acc..5c4dbadb5bb 100644
--- sys/arch/mips64/mips64/mips64_machdep.c
+++ sys/arch/mips64/mips64/mips64_machdep.c
@@ -327,7 +327,9 @@ struct timecounter cp0_timecounter = {
  0xffffffff, /* counter_mask */
  0, /* frequency */
  "CP0", /* name */
- 0 /* quality */
+ 0, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 u_int
diff --git sys/arch/octeon/octeon/machdep.c sys/arch/octeon/octeon/machdep.c
index 1387af284ca..0cfabfc642a 100644
--- sys/arch/octeon/octeon/machdep.c
+++ sys/arch/octeon/octeon/machdep.c
@@ -107,6 +107,9 @@ struct boot_info *octeon_boot_info;
 void *octeon_fdt;
 unsigned int octeon_ver;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
@@ -151,8 +154,9 @@ struct timecounter ioclock_timecounter = {
  .tc_name = "ioclock",
  .tc_quality = 0, /* ioclock can be overridden
  * by cp0 counter */
- .tc_priv = 0 /* clock register,
+ .tc_priv = 0, /* clock register,
  * determined at runtime */
+ .tc_user = 0, /* expose to user */
 };
 
 static int
diff --git sys/arch/powerpc64/powerpc64/machdep.c sys/arch/powerpc64/powerpc64/machdep.c
index bae64a1f297..b00bf682b76 100644
--- sys/arch/powerpc64/powerpc64/machdep.c
+++ sys/arch/powerpc64/powerpc64/machdep.c
@@ -43,6 +43,9 @@ int cacheline_size = 128;
 struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
 struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 int cold = 1;
 int safepri = 0;
 int physmem;
diff --git sys/arch/sgi/sgi/ip27_machdep.c sys/arch/sgi/sgi/ip27_machdep.c
index ba7fa558b96..2a2cc144242 100644
--- sys/arch/sgi/sgi/ip27_machdep.c
+++ sys/arch/sgi/sgi/ip27_machdep.c
@@ -111,7 +111,9 @@ struct timecounter ip27_hub_timecounter = {
  .tc_counter_mask = 0xffffffff, /* truncated to 32 bits. */
  .tc_frequency = 1250000,
  .tc_name = "hubrt",
- .tc_quality = 100
+ .tc_quality = 100,
+ .tc_priv = 0,
+ .tc_user = 0,
 };
 
 volatile uint64_t ip27_spinup_a0;
diff --git sys/arch/sgi/sgi/machdep.c sys/arch/sgi/sgi/machdep.c
index d251c15fc01..9b73112addf 100644
--- sys/arch/sgi/sgi/machdep.c
+++ sys/arch/sgi/sgi/machdep.c
@@ -93,6 +93,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
 vm_map_t exec_map;
 vm_map_t phys_map;
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/arch/sgi/xbow/xheart.c sys/arch/sgi/xbow/xheart.c
index 56b29915c70..827775512ac 100644
--- sys/arch/sgi/xbow/xheart.c
+++ sys/arch/sgi/xbow/xheart.c
@@ -83,7 +83,9 @@ struct timecounter xheart_timecounter = {
  .tc_counter_mask = 0xffffffff, /* truncate 52-bit counter to 32-bit */
  .tc_frequency = 12500000,
  .tc_name = "heart",
- .tc_quality = 100
+ .tc_quality = 100,
+ .tc_priv = NULL,
+ .tc_user = 0,
 };
 
 extern uint32_t ip30_lights_frob(uint32_t, struct trapframe *);
diff --git sys/arch/sparc64/dev/psycho.c sys/arch/sparc64/dev/psycho.c
index e24f804dff6..1a7a1afa8c2 100644
--- sys/arch/sparc64/dev/psycho.c
+++ sys/arch/sparc64/dev/psycho.c
@@ -127,7 +127,7 @@ extern struct sparc_pci_chipset _sparc_pci_chipset;
 u_int stick_get_timecount(struct timecounter *);
 
 struct timecounter stick_timecounter = {
- stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL
+ stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL, 0
 };
 
 /*
diff --git sys/arch/sparc64/sparc64/clock.c sys/arch/sparc64/sparc64/clock.c
index fd5e8a9c15b..5c2e47d386b 100644
--- sys/arch/sparc64/sparc64/clock.c
+++ sys/arch/sparc64/sparc64/clock.c
@@ -109,13 +109,13 @@ struct cfdriver clock_cd = {
 u_int tick_get_timecount(struct timecounter *);
 
 struct timecounter tick_timecounter = {
- tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL
+ tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL, 0
 };
 
 u_int sys_tick_get_timecount(struct timecounter *);
 
 struct timecounter sys_tick_timecounter = {
- sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL
+ sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL, 0
 };
 
 /*
diff --git sys/arch/sparc64/sparc64/machdep.c sys/arch/sparc64/sparc64/machdep.c
index 05aa4342943..0ee7ff3b802 100644
--- sys/arch/sparc64/sparc64/machdep.c
+++ sys/arch/sparc64/sparc64/machdep.c
@@ -183,6 +183,9 @@ extern int64_t cecclast;
 #define MAX_DMA_SEGS 20
 #endif
 
+/* timekeep number of user accesible clocks */
+int tk_nclocks = 0;
+
 /*
  * safepri is a safe priority for sleep to set for a spin-wait
  * during autoconfiguration or after a panic.
diff --git sys/dev/acpi/acpihpet.c sys/dev/acpi/acpihpet.c
index d0ee72cec9b..13177a909da 100644
--- sys/dev/acpi/acpihpet.c
+++ sys/dev/acpi/acpihpet.c
@@ -45,7 +45,9 @@ static struct timecounter hpet_timecounter = {
  0xffffffff, /* counter_mask (32 bits) */
  0, /* frequency */
  0, /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 #define HPET_TIMERS 3
diff --git sys/dev/acpi/acpitimer.c sys/dev/acpi/acpitimer.c
index cdc8c99a17a..89b5a397e47 100644
--- sys/dev/acpi/acpitimer.c
+++ sys/dev/acpi/acpitimer.c
@@ -36,7 +36,9 @@ static struct timecounter acpi_timecounter = {
  0x00ffffff, /* counter_mask (24 bits) */
  ACPI_FREQUENCY, /* frequency */
  0, /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 struct acpitimer_softc {
diff --git sys/dev/pci/amdpm.c sys/dev/pci/amdpm.c
index 6df82858016..9610d5bc1f0 100644
--- sys/dev/pci/amdpm.c
+++ sys/dev/pci/amdpm.c
@@ -82,7 +82,9 @@ static struct timecounter amdpm_timecounter = {
  0xffffff, /* counter_mask */
  AMDPM_FREQUENCY, /* frequency */
  "AMDPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 #define AMDPM_CONFREG 0x40
diff --git sys/dev/pci/viapm.c sys/dev/pci/viapm.c
index db806eedf80..ce33cd175e6 100644
--- sys/dev/pci/viapm.c
+++ sys/dev/pci/viapm.c
@@ -177,7 +177,9 @@ static struct timecounter viapm_timecounter = {
  0xffffff, /* counter_mask */
  VIAPM_FREQUENCY, /* frequency */
  "VIAPM", /* name */
- 1000 /* quality */
+ 1000, /* quality */
+ NULL, /* private bits */
+ 0, /* expose to user */
 };
 
 struct timeout viapm_timeout;
diff --git sys/dev/pv/hyperv.c sys/dev/pv/hyperv.c
index b32facdacb1..b9ee2feec4c 100644
--- sys/dev/pv/hyperv.c
+++ sys/dev/pv/hyperv.c
@@ -141,7 +141,7 @@ struct {
 };
 
 struct timecounter hv_timecounter = {
- hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001
+ hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001, NULL, 0
 };
 
 struct cfdriver hyperv_cd = {
diff --git sys/dev/pv/pvclock.c sys/dev/pv/pvclock.c
index 6b242f7448d..b80e4d2a484 100644
--- sys/dev/pv/pvclock.c
+++ sys/dev/pv/pvclock.c
@@ -74,7 +74,7 @@ struct cfdriver pvclock_cd = {
 };
 
 struct timecounter pvclock_timecounter = {
- pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL
+ pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL, 0
 };
 
 int
diff --git sys/kern/exec_elf.c sys/kern/exec_elf.c
index 9b5b8eb3acf..59bc923a6fb 100644
--- sys/kern/exec_elf.c
+++ sys/kern/exec_elf.c
@@ -124,7 +124,7 @@ extern char *syscallnames[];
 /*
  * How many entries are in the AuxInfo array we pass to the process?
  */
-#define ELF_AUX_ENTRIES 8
+#define ELF_AUX_ENTRIES 9
 
 /*
  * This is the OpenBSD ELF emul
@@ -860,6 +860,10 @@ exec_elf_fixup(struct proc *p, struct exec_package *epp)
  a->au_v = ap->arg_entry;
  a++;
 
+ a->au_id = AUX_openbsd_timekeep;
+ a->au_v = p->p_p->ps_timekeep;
+ a++;
+
  a->au_id = AUX_null;
  a->au_v = 0;
  a++;
diff --git sys/kern/kern_exec.c sys/kern/kern_exec.c
index 20480c2fc28..215093a01da 100644
--- sys/kern/kern_exec.c
+++ sys/kern/kern_exec.c
@@ -64,6 +64,11 @@
 #include <uvm/uvm_extern.h>
 #include <machine/tcb.h>
 
+#include <sys/timetc.h>
+
+struct uvm_object *timekeep_object;
+struct timekeep* timekeep;
+
 void unveil_destroy(struct process *ps);
 
 const struct kmem_va_mode kv_exec = {
@@ -76,6 +81,11 @@ const struct kmem_va_mode kv_exec = {
  */
 int exec_sigcode_map(struct process *, struct emul *);
 
+/*
+ * Map the shared timekeep page.
+ */
+int exec_timekeep_map(struct process *);
+
 /*
  * If non-zero, stackgap_random specifies the upper limit of the random gap size
  * added to the fixed stack position. Must be n^2.
@@ -684,6 +694,9 @@ sys_execve(struct proc *p, void *v, register_t *retval)
  /* map the process's signal trampoline code */
  if (exec_sigcode_map(pr, pack.ep_emul))
  goto free_pack_abort;
+ /* map the process's timekeep page */
+ if (exec_timekeep_map(pr))
+ goto free_pack_abort;
 
 #ifdef __HAVE_EXEC_MD_MAP
  /* perform md specific mappings that process might need */
@@ -863,3 +876,42 @@ exec_sigcode_map(struct process *pr, struct emul *e)
 
  return (0);
 }
+
+int
+exec_timekeep_map(struct process *pr)
+{
+ size_t timekeep_sz = sizeof(struct timekeep);
+
+ /*
+ * Similar to the sigcode object, except that there is a single timekeep
+ * object, and not one per emulation.
+ */
+ if (timekeep_object == NULL) {
+ vaddr_t va;
+
+ timekeep_object = uao_create(timekeep_sz, 0);
+ uao_reference(timekeep_object);
+
+ if (uvm_map(kernel_map, &va, round_page(timekeep_sz), timekeep_object,
+    0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
+    MAP_INHERIT_SHARE, MADV_RANDOM, 0))) {
+ uao_detach(timekeep_object);
+ return (ENOMEM);
+ }
+
+ timekeep = (struct timekeep *)va;
+ timekeep->tk_major = 1;
+ timekeep->tk_minor = 0;
+ timekeep->tk_nclocks = tk_nclocks;
+ }
+
+ uao_reference(timekeep_object);
+ if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_timekeep, round_page(timekeep_sz),
+    timekeep_object, 0, 0, UVM_MAPFLAG(PROT_READ, PROT_READ,
+    MAP_INHERIT_COPY, MADV_RANDOM, 0))) {
+ uao_detach(timekeep_object);
+ return (ENOMEM);
+ }
+
+ return (0);
+}
diff --git sys/kern/kern_tc.c sys/kern/kern_tc.c
index 88d4a3379f9..47efbdd0b78 100644
--- sys/kern/kern_tc.c
+++ sys/kern/kern_tc.c
@@ -63,7 +63,7 @@ dummy_get_timecount(struct timecounter *tc)
 }
 
 static struct timecounter dummy_timecounter = {
- dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000
+ dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000, NULL, 0
 };
 
 /*
@@ -479,6 +479,34 @@ tc_setclock(const struct timespec *ts)
 #endif
 }
 
+void
+tc_update_timekeep(void)
+{
+ static struct timecounter *last_tc = NULL;
+ struct timehands *th;
+
+ if (timekeep == NULL)
+ return;
+
+ th = timehands;
+ timekeep->tk_generation = 0;
+ membar_producer();
+ timekeep->tk_scale = th->th_scale;
+ timekeep->tk_offset_count = th->th_offset_count;
+ timekeep->tk_offset = th->th_offset;
+ timekeep->tk_naptime = th->th_naptime;
+ timekeep->tk_boottime = th->th_boottime;
+ if (last_tc != th->th_counter) {
+ timekeep->tk_counter_mask = th->th_counter->tc_counter_mask;
+ timekeep->tk_user = th->th_counter->tc_user;
+ last_tc = th->th_counter;
+ }
+ membar_producer();
+ timekeep->tk_generation = th->th_generation;
+
+ return;
+}
+
 /*
  * Initialize the next struct timehands in the ring and make
  * it the active timehands.  Along the way we might switch to a different
@@ -631,6 +659,8 @@ tc_windup(struct bintime *new_boottime, struct bintime *new_offset,
  time_uptime = th->th_offset.sec;
  membar_producer();
  timehands = th;
+
+ tc_update_timekeep();
 }
 
 /* Report or change the active timecounter hardware. */
diff --git sys/sys/exec_elf.h sys/sys/exec_elf.h
index a40e0510273..3084ed595a6 100644
--- sys/sys/exec_elf.h
+++ sys/sys/exec_elf.h
@@ -691,7 +691,8 @@ enum AuxID {
  AUX_sun_uid = 2000, /* euid */
  AUX_sun_ruid = 2001, /* ruid */
  AUX_sun_gid = 2002, /* egid */
- AUX_sun_rgid = 2003 /* rgid */
+ AUX_sun_rgid = 2003, /* rgid */
+ AUX_openbsd_timekeep = 4000, /* userland clock_gettime */
 };
 
 struct elf_args {
diff --git sys/sys/proc.h sys/sys/proc.h
index 357c0c0d52c..c6d54572bdd 100644
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -242,6 +242,7 @@ struct process {
  char ps_comm[MAXCOMLEN+1];
 
  vaddr_t ps_strings; /* User pointers to argv/env */
+ vaddr_t ps_timekeep; /* User pointer to timekeep */
  vaddr_t ps_sigcode; /* User pointer to the signal code */
  vaddr_t ps_sigcoderet; /* User pointer to sigreturn retPC */
  u_long ps_sigcookie;
diff --git sys/sys/time.h sys/sys/time.h
index e758a64ce07..bcd3acd034d 100644
--- sys/sys/time.h
+++ sys/sys/time.h
@@ -163,7 +163,7 @@ struct clockinfo {
 };
 #endif /* __BSD_VISIBLE */
 
-#if defined(_KERNEL) || defined(_STANDALONE)
+#if defined(_KERNEL) || defined(_STANDALONE) || defined (_LIBC)
 #include <sys/_time.h>
 
 /* Time expressed as seconds and fractions of a second + operations on it. */
@@ -171,6 +171,9 @@ struct bintime {
  time_t sec;
  uint64_t frac;
 };
+#endif
+
+#if defined(_KERNEL) || defined(_STANDALONE)
 
 #define bintimecmp(btp, ctp, cmp) \
  ((btp)->sec == (ctp)->sec ? \
diff --git sys/sys/timetc.h sys/sys/timetc.h
index ce81c3475a0..a4a80eecff1 100644
--- sys/sys/timetc.h
+++ sys/sys/timetc.h
@@ -24,7 +24,7 @@
 #ifndef _SYS_TIMETC_H_
 #define _SYS_TIMETC_H_
 
-#ifndef _KERNEL
+#if !defined(_KERNEL) && !defined(_LIBC)
 #error "no user-serviceable parts inside"
 #endif
 
@@ -80,6 +80,8 @@ struct timecounter {
  */
  void *tc_priv; /* [I] */
  /* Pointer to the timecounter's private parts. */
+ int tc_user; /* [I] */
+ /* Expose this timecounter to userland. */
  SLIST_ENTRY(timecounter) tc_next; /* [I] */
  /* Pointer to the next timecounter. */
  int64_t tc_freq_adj; /* [tw] */
@@ -88,11 +90,34 @@ struct timecounter {
  /* Precision of the counter.  Computed in tc_init(). */
 };
 
+struct timekeep {
+ /* set at initialization */
+ uint32_t tk_major; /* version major number */
+ uint32_t tk_minor; /* version minor number */
+ int tk_nclocks; /* number of arch user clocks */
+
+ /* timehands members */
+ uint64_t tk_scale;
+ u_int tk_offset_count;
+ struct bintime tk_offset;
+ struct bintime tk_naptime;
+ struct bintime tk_boottime;
+ volatile u_int tk_generation;
+
+ /* timecounter members */
+ int tk_user;
+ u_int tk_counter_mask;
+};
+extern int tk_nclocks;
+
 struct rwlock;
 extern struct rwlock tc_lock;
 
 extern struct timecounter *timecounter;
 
+extern struct uvm_object *timekeep_object;
+extern struct timekeep *timekeep;
+
 u_int64_t tc_getfrequency(void);
 u_int64_t tc_getprecision(void);
 void tc_init(struct timecounter *tc);

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Christian Weisgerber
In reply to this post by Christian Weisgerber
Christian Weisgerber:

> Should we already bump major while the diff matures?

Oh, we can't quite bump yet.  tk_major und tk_minor are only set
in exec_timekeep_map(), but aren't checked anywhere.

+               timekeep->tk_major = 0;
+               timekeep->tk_minor = 0;

Those shouldn't be magic numbers but #defines in sys/timetc.h.

We only need to check those once at process startup.  In
libc/dlfcn/init.c, somewhere here:

+               case AUX_openbsd_timekeep:
+                       if (_tc_get_timecount)
+                               _timekeep = (void *)aux->au_v;
+                       break;

Something like this I think:

                case AUX_openbsd_timekeep:
                        if (_tc_get_timecount) {
                                struct timekeep *tk = (void *)aux->au_v;
                                if ((tk != NULL) &&
                                    (tk->tk_major == TK_MAJOR) &&
                                    (tk->tk_minor >= TK_MINOR))
                                        _timekeep = tk;
                        }
                        break;

--
Christian "naddy" Weisgerber                          [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Mark Kettenis
In reply to this post by Paul Irofti-4
> Date: Thu, 11 Jun 2020 16:27:03 +0300
> From: Paul Irofti <[hidden email]>
>
> On Thu, Jun 11, 2020 at 02:49:54PM +0200, Marc Espie wrote:
> > On Thu, Jun 11, 2020 at 03:42:27PM +0300, Paul Irofti wrote:
> > > On Thu, Jun 11, 2020 at 02:05:44PM +0200, Marc Espie wrote:
> > > > On Thu, Jun 11, 2020 at 01:13:07PM +0300, Paul Irofti wrote:
> > > > > On 2020-06-11 02:46, Christian Weisgerber wrote:
> > > > > > Paul Irofti:
> > > > > >
> > > > > > > This iteration of the diff adds bounds checking for tk_user and moves
> > > > > > > the usertc.c stub to every arch in libc as recommanded by deraadt@.
> > > > > > > It also fixes a gettimeofday issue reported by cheloha@ and tb@.
> > > > > >
> > > > > > Additionally, it changes struct timekeep in an incompatible way. ;-)
> > > > > > A userland built before the addition of tk_nclocks is very unhappy
> > > > > > with a kernel built afterwards.  There is no way to compile across
> > > > > > this.  You have to (U)pgrade from boot media to install a ftp.openbsd.org
> > > > > > userland, and then you can re-compile with the new diff.
> > > > >
> > > > > I have not seen this problem and have not built a snapshot to update or go
> > > > > back. What do you mean by very unhappy? Can you show me the exact steps you
> > > > > have done?
> > > > >
> > > > > > Should we already bump major while the diff matures?
> > > > >
> > > > > I am not a fan of this. I don't like bumping something before it is actually
> > > > > used. It is like an errata before a release.
> > > >
> > > > So what if we end at version 200 ?
> > > >
> > > > we've got a full uint32_t for crying out loud, you're not going to run out
> > > > of numbers.
> > > >
> > > > Besides, it's something that's entirely invisible to users, even more so
> > > > than library major/minors.
> > >
> > > This is not about the range available to us.
> > >
> > > If I bump then I will have to also add checks for the revision.
> > > Otherwise what is the point of the bump?  And then what? Keep old and
> > > new code around for both revisions? And then, if this endless mail
> > > thread is ever going to be added to the OpenBSD tree, it will contain
> > > workarounds for something that was never in the tree to begin with.
> >
> > Yeah, you do check for the revision, if it's the same, then you use
> > the timecounter. If it's not, you revert to the syscall.
> >
> > End of story.
> >
> > Right now, you can't even bump it if you need, because there is no code
> > that checks it in the libc, thus is you tweak kernel parts, things *will*
> > break.
> >
> > You'd better have the version check in libc  before you even consider
> > committing this!

Paul, that tk_nclocks addition isn't useful.  You need to do the
bounds checking against the number of clocks you have implemented in
libc.  How many clocks the kernel has implemented doesn't matter.

Cheers,

Mark

> diff --git lib/libc/arch/aarch64/gen/Makefile.inc lib/libc/arch/aarch64/gen/Makefile.inc
> index a7b1b73f3ef..ee198f5d611 100644
> --- lib/libc/arch/aarch64/gen/Makefile.inc
> +++ lib/libc/arch/aarch64/gen/Makefile.inc
> @@ -9,4 +9,4 @@ SRCS+= fpgetmask.c fpgetround.c fpgetsticky.c
>  SRCS+= fpsetmask.c fpsetround.c fpsetsticky.c
>  SRCS+= fpclassifyl.c
>  SRCS+= isfinitel.c isinfl.c isnanl.c isnormall.c
> -SRCS+= signbitl.c
> +SRCS+= signbitl.c usertc.c
> diff --git lib/libc/arch/aarch64/gen/usertc.c lib/libc/arch/aarch64/gen/usertc.c
> new file mode 100644
> index 00000000000..84a112c2ea3
> --- /dev/null
> +++ lib/libc/arch/aarch64/gen/usertc.c
> @@ -0,0 +1,21 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
> diff --git lib/libc/arch/alpha/gen/Makefile.inc lib/libc/arch/alpha/gen/Makefile.inc
> index a44599d2cab..2a8abd32b61 100644
> --- lib/libc/arch/alpha/gen/Makefile.inc
> +++ lib/libc/arch/alpha/gen/Makefile.inc
> @@ -3,5 +3,5 @@
>  
>  SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c setjmp.S
>  SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
> - fpsetround.c fpsetsticky.c
> + fpsetround.c fpsetsticky.c usertc.c
>  SRCS+= sigsetjmp.S
> diff --git lib/libc/arch/alpha/gen/usertc.c lib/libc/arch/alpha/gen/usertc.c
> new file mode 100644
> index 00000000000..84a112c2ea3
> --- /dev/null
> +++ lib/libc/arch/alpha/gen/usertc.c
> @@ -0,0 +1,21 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
> diff --git lib/libc/arch/amd64/gen/Makefile.inc lib/libc/arch/amd64/gen/Makefile.inc
> index e995309ed71..f6349e2b974 100644
> --- lib/libc/arch/amd64/gen/Makefile.inc
> +++ lib/libc/arch/amd64/gen/Makefile.inc
> @@ -2,6 +2,7 @@
>  
>  SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.S nan.c setjmp.S \
>   sigsetjmp.S
> -SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
> +SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c \
> + usertc.c
>  SRCS+= flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S \
>   fpsetround.S fpsetsticky.S
> diff --git lib/libc/arch/amd64/gen/usertc.c lib/libc/arch/amd64/gen/usertc.c
> new file mode 100644
> index 00000000000..3f3052445cf
> --- /dev/null
> +++ lib/libc/arch/amd64/gen/usertc.c
> @@ -0,0 +1,53 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +static uint64_t
> +rdtsc()
> +{
> + uint32_t hi, lo;
> + asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
> + return ((uint64_t)lo)|(((uint64_t)hi)<<32);
> +}
> +
> +static uint64_t
> +acpihpet()
> +{
> + return rdtsc(); /* JUST TO COMPILE */
> +}
> +
> +static uint64_t (*get_tc[])(void) =
> +{
> + rdtsc,
> + acpihpet,
> +};
> +
> +int
> +tc_get_timecount(struct timekeep *tk, uint64_t *tc)
> +{
> + int tk_user = tk->tk_user;
> +
> + if (tc == NULL || tk_user < 1 || tk_user > tk->tk_nclocks)
> + return -1;
> +
> + *tc = (*get_tc[tk_user - 1])();
> + return 0;
> +}
> +int (*const _tc_get_timecount)(struct timekeep *tk, uint64_t *tc)
> + = tc_get_timecount;
> diff --git lib/libc/arch/arm/gen/Makefile.inc lib/libc/arch/arm/gen/Makefile.inc
> index 1b4ab2f3ae7..27090a0d9dc 100644
> --- lib/libc/arch/arm/gen/Makefile.inc
> +++ lib/libc/arch/arm/gen/Makefile.inc
> @@ -2,5 +2,5 @@
>  # $NetBSD: Makefile.inc,v 1.6 2003/08/01 17:03:47 lukem Exp $
>  
>  SRCS+= byte_swap_2.S byte_swap_4.S divsi3.S fabs.c flt_rounds.c infinity.c
> -SRCS+= ldexp.c modf.c nan.c
> +SRCS+= ldexp.c modf.c nan.c usertc.c
>  SRCS+= setjmp.S _setjmp.S sigsetjmp.S
> diff --git lib/libc/arch/arm/gen/usertc.c lib/libc/arch/arm/gen/usertc.c
> new file mode 100644
> index 00000000000..84a112c2ea3
> --- /dev/null
> +++ lib/libc/arch/arm/gen/usertc.c
> @@ -0,0 +1,21 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
> diff --git lib/libc/arch/hppa/gen/Makefile.inc lib/libc/arch/hppa/gen/Makefile.inc
> index e0c864242fe..1fde24670f1 100644
> --- lib/libc/arch/hppa/gen/Makefile.inc
> +++ lib/libc/arch/hppa/gen/Makefile.inc
> @@ -2,6 +2,6 @@
>  
>  SRCS+= setjmp.S
>  SRCS+= fabs.c
> -SRCS+= infinity.c ldexp.c modf.c nan.c
> +SRCS+= infinity.c ldexp.c modf.c nan.c usertc.c
>  SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
>   fpsetround.c fpsetsticky.c
> diff --git lib/libc/arch/hppa/gen/usertc.c lib/libc/arch/hppa/gen/usertc.c
> new file mode 100644
> index 00000000000..84a112c2ea3
> --- /dev/null
> +++ lib/libc/arch/hppa/gen/usertc.c
> @@ -0,0 +1,21 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
> diff --git lib/libc/arch/i386/gen/Makefile.inc lib/libc/arch/i386/gen/Makefile.inc
> index 4c18e059581..b7dd30adccd 100644
> --- lib/libc/arch/i386/gen/Makefile.inc
> +++ lib/libc/arch/i386/gen/Makefile.inc
> @@ -1,6 +1,6 @@
>  # $OpenBSD: Makefile.inc,v 1.14 2012/04/19 19:14:56 deraadt Exp $
>  
> -SRCS+= _setjmp.S fabs.S infinity.c ldexp.c \
> +SRCS+= _setjmp.S fabs.S infinity.c ldexp.c usertc.c \
>   modf.S nan.c setjmp.S sigsetjmp.S
>  SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
>  SRCS+= flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S \
> diff --git lib/libc/arch/i386/gen/usertc.c lib/libc/arch/i386/gen/usertc.c
> new file mode 100644
> index 00000000000..84a112c2ea3
> --- /dev/null
> +++ lib/libc/arch/i386/gen/usertc.c
> @@ -0,0 +1,21 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
> diff --git lib/libc/arch/m88k/gen/Makefile.inc lib/libc/arch/m88k/gen/Makefile.inc
> index cff75b8d425..d66f66af4af 100644
> --- lib/libc/arch/m88k/gen/Makefile.inc
> +++ lib/libc/arch/m88k/gen/Makefile.inc
> @@ -1,7 +1,7 @@
>  # $OpenBSD: Makefile.inc,v 1.16 2013/06/05 22:06:30 miod Exp $
>  # $NetBSD: Makefile.inc,v 1.3 1995/04/10 21:09:06 jtc Exp $
>  
> -SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c
> +SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.c nan.c usertc.c
>  SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
>   fpsetround.c fpsetsticky.c
>  SRCS+= setjmp.S sigsetjmp.S
> diff --git lib/libc/arch/m88k/gen/usertc.c lib/libc/arch/m88k/gen/usertc.c
> new file mode 100644
> index 00000000000..84a112c2ea3
> --- /dev/null
> +++ lib/libc/arch/m88k/gen/usertc.c
> @@ -0,0 +1,21 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
> diff --git lib/libc/arch/mips64/gen/Makefile.inc lib/libc/arch/mips64/gen/Makefile.inc
> index 8cf1fc2d28a..839241a2069 100644
> --- lib/libc/arch/mips64/gen/Makefile.inc
> +++ lib/libc/arch/mips64/gen/Makefile.inc
> @@ -1,6 +1,6 @@
>  # $OpenBSD: Makefile.inc,v 1.12 2012/04/12 16:14:09 deraadt Exp $
>  
> -SRCS+= _setjmp.S fabs.S infinity.c ldexp.S modf.S nan.c
> +SRCS+= _setjmp.S fabs.S infinity.c ldexp.S modf.S nan.c usertc.c
>  SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
>   fpsetround.c fpsetsticky.c
>  SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c signbitl.c
> diff --git lib/libc/arch/mips64/gen/usertc.c lib/libc/arch/mips64/gen/usertc.c
> new file mode 100644
> index 00000000000..84a112c2ea3
> --- /dev/null
> +++ lib/libc/arch/mips64/gen/usertc.c
> @@ -0,0 +1,21 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
> diff --git lib/libc/arch/powerpc/gen/Makefile.inc lib/libc/arch/powerpc/gen/Makefile.inc
> index 6b2e4613ee8..d4d7b00bff7 100644
> --- lib/libc/arch/powerpc/gen/Makefile.inc
> +++ lib/libc/arch/powerpc/gen/Makefile.inc
> @@ -1,5 +1,5 @@
>  SRCS+= infinity.c setjmp.S sigsetjmp.S flt_rounds.c ldexp.c modf.c nan.c
> -SRCS+= fabs.c
> +SRCS+= fabs.c usertc.c
>  SRCS+= fpgetmask.c fpsetmask.c
>  SRCS+= fpgetround.c fpsetround.c
>  SRCS+= fpgetsticky.c fpsetsticky.c
> diff --git lib/libc/arch/powerpc/gen/usertc.c lib/libc/arch/powerpc/gen/usertc.c
> new file mode 100644
> index 00000000000..84a112c2ea3
> --- /dev/null
> +++ lib/libc/arch/powerpc/gen/usertc.c
> @@ -0,0 +1,21 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
> diff --git lib/libc/arch/sh/gen/Makefile.inc lib/libc/arch/sh/gen/Makefile.inc
> index 55de1973b30..4724fb3a6a8 100644
> --- lib/libc/arch/sh/gen/Makefile.inc
> +++ lib/libc/arch/sh/gen/Makefile.inc
> @@ -3,4 +3,4 @@
>  SRCS+= flt_rounds.c infinity.c ldexp.c modf.c nan.c setjmp.S _setjmp.S
>  SRCS+= sigsetjmp.S
>  SRCS+= fabs.c fpgetmask.c fpgetround.c fpgetsticky.c \
> - fpsetmask.c fpsetround.c fpsetsticky.c
> + fpsetmask.c fpsetround.c fpsetsticky.c usertc.c
> diff --git lib/libc/arch/sh/gen/usertc.c lib/libc/arch/sh/gen/usertc.c
> new file mode 100644
> index 00000000000..84a112c2ea3
> --- /dev/null
> +++ lib/libc/arch/sh/gen/usertc.c
> @@ -0,0 +1,21 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
> diff --git lib/libc/arch/sparc64/gen/Makefile.inc lib/libc/arch/sparc64/gen/Makefile.inc
> index 58259cedef6..a908e022954 100644
> --- lib/libc/arch/sparc64/gen/Makefile.inc
> +++ lib/libc/arch/sparc64/gen/Makefile.inc
> @@ -3,5 +3,5 @@
>  SRCS+= _setjmp.S fabs.S fixunsdfsi.S flt_rounds.c fpclassifyl.c \
>   fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
>   fpsetround.c fpsetsticky.c infinity.c isfinitel.c \
> - isinfl.c isnanl.c isnormall.c ldexp.c modf.S \
> + isinfl.c isnanl.c isnormall.c ldexp.c usertc.c modf.S \
>   mul.S nan.c setjmp.S signbitl.c sigsetjmp.S umul.S
> diff --git lib/libc/arch/sparc64/gen/usertc.c lib/libc/arch/sparc64/gen/usertc.c
> new file mode 100644
> index 00000000000..84a112c2ea3
> --- /dev/null
> +++ lib/libc/arch/sparc64/gen/usertc.c
> @@ -0,0 +1,21 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/timetc.h>
> +
> +int (*const _tc_get_timecount)(struct timekeep *, uint64_t *) = NULL;
> diff --git lib/libc/asr/asr.c lib/libc/asr/asr.c
> index cd056c85719..2b25d49f32a 100644
> --- lib/libc/asr/asr.c
> +++ lib/libc/asr/asr.c
> @@ -196,11 +196,11 @@ poll_intrsafe(struct pollfd *fds, nfds_t nfds, int timeout)
>   struct timespec pollstart, pollend, elapsed;
>   int r;
>  
> - if (clock_gettime(CLOCK_MONOTONIC, &pollstart))
> + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollstart))
>   return -1;
>  
>   while ((r = poll(fds, 1, timeout)) == -1 && errno == EINTR) {
> - if (clock_gettime(CLOCK_MONOTONIC, &pollend))
> + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollend))
>   return -1;
>   timespecsub(&pollend, &pollstart, &elapsed);
>   timeout -= elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000;
> @@ -418,7 +418,7 @@ asr_check_reload(struct asr *asr)
>   asr->a_rtime = 0;
>   }
>  
> - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
> + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1)
>   return;
>  
>   if ((ts.tv_sec - asr->a_rtime) < RELOAD_DELAY && asr->a_rtime != 0)
> diff --git lib/libc/crypt/bcrypt.c lib/libc/crypt/bcrypt.c
> index 82de8fa33b7..02fd3013cc1 100644
> --- lib/libc/crypt/bcrypt.c
> +++ lib/libc/crypt/bcrypt.c
> @@ -248,9 +248,9 @@ _bcrypt_autorounds(void)
>   char buf[_PASSWORD_LEN];
>   int duration;
>  
> - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &before);
> + WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &before);
>   bcrypt_newhash("testpassword", r, buf, sizeof(buf));
> - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &after);
> + WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &after);
>  
>   duration = after.tv_sec - before.tv_sec;
>   duration *= 1000000;
> diff --git lib/libc/dlfcn/init.c lib/libc/dlfcn/init.c
> index 270f54aada5..19d0a2c3ad6 100644
> --- lib/libc/dlfcn/init.c
> +++ lib/libc/dlfcn/init.c
> @@ -20,6 +20,7 @@
>  
>  #include <sys/types.h>
>  #include <sys/syscall.h>
> +#include <sys/timetc.h> /* timekeep */
>  
>  #ifndef PIC
>  #include <sys/mman.h>
> @@ -45,8 +46,9 @@
>  /* XXX should be in an include file shared with csu */
>  char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void));
>  
> -/* provide definition for this */
> +/* provide definitions for these */
>  int _pagesize = 0;
> +void *_timekeep = NULL;
>  
>  /*
>   * In dynamicly linked binaries environ and __progname are overriden by
> @@ -105,6 +107,10 @@ _libc_preinit(int argc, char **argv, char **envp, dl_cb_cb *cb)
>   phnum = aux->au_v;
>   break;
>  #endif /* !PIC */
> + case AUX_openbsd_timekeep:
> + if (_tc_get_timecount)
> + _timekeep = (void *)aux->au_v;
> + break;
>   }
>   }
>  
> diff --git lib/libc/gen/auth_subr.c lib/libc/gen/auth_subr.c
> index 1286a96fe40..32f86eda50f 100644
> --- lib/libc/gen/auth_subr.c
> +++ lib/libc/gen/auth_subr.c
> @@ -752,7 +752,7 @@ auth_check_expire(auth_session_t *as)
>  
>   if (as->pwd && (quad_t)as->pwd->pw_expire != 0) {
>   if (as->now.tv_sec == 0)
> - gettimeofday(&as->now, NULL);
> + WRAP(gettimeofday)(&as->now, NULL);
>   if ((quad_t)as->now.tv_sec >= (quad_t)as->pwd->pw_expire) {
>   as->state &= ~AUTH_ALLOW;
>   as->state |= AUTH_EXPIRED;
> @@ -779,7 +779,7 @@ auth_check_change(auth_session_t *as)
>  
>   if (as->pwd && (quad_t)as->pwd->pw_change) {
>   if (as->now.tv_sec == 0)
> - gettimeofday(&as->now, NULL);
> + WRAP(gettimeofday)(&as->now, NULL);
>   if (as->now.tv_sec >= (quad_t)as->pwd->pw_change) {
>   as->state &= ~AUTH_ALLOW;
>   as->state |= AUTH_PWEXPIRED;
> diff --git lib/libc/gen/time.c lib/libc/gen/time.c
> index 3bbd0d733d1..b3ce9a800f1 100644
> --- lib/libc/gen/time.c
> +++ lib/libc/gen/time.c
> @@ -36,7 +36,7 @@ time(time_t *t)
>  {
>   struct timeval tt;
>  
> - if (gettimeofday(&tt, NULL) == -1)
> + if (WRAP(gettimeofday)(&tt, NULL) == -1)
>   return (-1);
>   if (t)
>   *t = (time_t)tt.tv_sec;
> diff --git lib/libc/gen/times.c lib/libc/gen/times.c
> index 02e4dd44b5c..36841810d1b 100644
> --- lib/libc/gen/times.c
> +++ lib/libc/gen/times.c
> @@ -52,7 +52,7 @@ times(struct tms *tp)
>   return ((clock_t)-1);
>   tp->tms_cutime = CONVTCK(ru.ru_utime);
>   tp->tms_cstime = CONVTCK(ru.ru_stime);
> - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
> + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1)
>   return ((clock_t)-1);
>   return (ts.tv_sec * CLK_TCK + ts.tv_nsec / (1000000000 / CLK_TCK));
>  }
> diff --git lib/libc/gen/timespec_get.c lib/libc/gen/timespec_get.c
> index 520a5954025..845cbe80356 100644
> --- lib/libc/gen/timespec_get.c
> +++ lib/libc/gen/timespec_get.c
> @@ -37,7 +37,7 @@ timespec_get(struct timespec *ts, int base)
>  {
>   switch (base) {
>   case TIME_UTC:
> - if (clock_gettime(CLOCK_REALTIME, ts) == -1)
> + if (WRAP(clock_gettime)(CLOCK_REALTIME, ts) == -1)
>   return 0;
>   break;
>   default:
> diff --git lib/libc/hidden/sys/time.h lib/libc/hidden/sys/time.h
> index ed112320fa2..df717021cab 100644
> --- lib/libc/hidden/sys/time.h
> +++ lib/libc/hidden/sys/time.h
> @@ -24,7 +24,7 @@ PROTO_NORMAL(adjfreq);
>  PROTO_NORMAL(adjtime);
>  PROTO_NORMAL(futimes);
>  PROTO_NORMAL(getitimer);
> -PROTO_NORMAL(gettimeofday);
> +PROTO_WRAP(gettimeofday);
>  PROTO_NORMAL(setitimer);
>  PROTO_NORMAL(settimeofday);
>  PROTO_NORMAL(utimes);
> diff --git lib/libc/hidden/sys/timetc.h lib/libc/hidden/sys/timetc.h
> new file mode 100644
> index 00000000000..d86b31e0d86
> --- /dev/null
> +++ lib/libc/hidden/sys/timetc.h
> @@ -0,0 +1,38 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#ifndef _LIBC_SYS_TIMETC_H_
> +#define _LIBC_SYS_TIMETC_H_
> +
> +#define _LIBC
> +#include <sys/types.h>
> +#include <sys/time.h>
> +
> +#include_next <sys/timetc.h>
> +
> +__BEGIN_HIDDEN_DECLS
> +extern void *_timekeep;
> +
> +extern int (*const _tc_get_timecount)(struct timekeep *, uint64_t *);
> +
> +int _microtime(struct timeval *, struct timekeep *);
> +int _nanotime(struct timespec *, struct timekeep *);
> +int _nanoruntime(struct timespec *, struct timekeep *);
> +int _nanouptime(struct timespec *, struct timekeep *);
> +__END_HIDDEN_DECLS
> +
> +#endif /* !_LIBC_SYS_TIMETC_H_ */
> diff --git lib/libc/hidden/time.h lib/libc/hidden/time.h
> index 18c49f8fcb9..d8e1e0caf64 100644
> --- lib/libc/hidden/time.h
> +++ lib/libc/hidden/time.h
> @@ -29,7 +29,7 @@ PROTO_NORMAL(asctime_r);
>  PROTO_STD_DEPRECATED(clock);
>  PROTO_DEPRECATED(clock_getcpuclockid);
>  PROTO_NORMAL(clock_getres);
> -PROTO_NORMAL(clock_gettime);
> +PROTO_WRAP(clock_gettime);
>  PROTO_NORMAL(clock_settime);
>  PROTO_STD_DEPRECATED(ctime);
>  PROTO_DEPRECATED(ctime_r);
> diff --git lib/libc/net/res_random.c lib/libc/net/res_random.c
> index 763e420bb88..9babb28470a 100644
> --- lib/libc/net/res_random.c
> +++ lib/libc/net/res_random.c
> @@ -219,7 +219,7 @@ res_initid(void)
>   if (ru_prf != NULL)
>   arc4random_buf(ru_prf, sizeof(*ru_prf));
>  
> - clock_gettime(CLOCK_MONOTONIC, &ts);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts);
>   ru_reseed = ts.tv_sec + RU_OUT;
>   ru_msb = ru_msb == 0x8000 ? 0 : 0x8000;
>  }
> @@ -232,7 +232,7 @@ __res_randomid(void)
>   u_int r;
>   static void *randomid_mutex;
>  
> - clock_gettime(CLOCK_MONOTONIC, &ts);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts);
>   pid = getpid();
>  
>   _MUTEX_LOCK(&randomid_mutex);
> diff --git lib/libc/rpc/auth_unix.c lib/libc/rpc/auth_unix.c
> index 402d98cede4..917a6d42b8a 100644
> --- lib/libc/rpc/auth_unix.c
> +++ lib/libc/rpc/auth_unix.c
> @@ -121,7 +121,7 @@ authunix_create(char *machname, int uid, int gid, int len, int *aup_gids)
>   /*
>   * fill in param struct from the given params
>   */
> - (void)gettimeofday(&now,  NULL);
> + (void)WRAP(gettimeofday)(&now,  NULL);
>   aup.aup_time = now.tv_sec;
>   aup.aup_machname = machname;
>   aup.aup_uid = uid;
> @@ -274,7 +274,7 @@ authunix_refresh(AUTH *auth)
>   goto done;
>  
>   /* update the time and serialize in place */
> - (void)gettimeofday(&now, NULL);
> + (void)WRAP(gettimeofday)(&now, NULL);
>   aup.aup_time = now.tv_sec;
>   xdrs.x_op = XDR_ENCODE;
>   XDR_SETPOS(&xdrs, 0);
> diff --git lib/libc/rpc/clnt_tcp.c lib/libc/rpc/clnt_tcp.c
> index 8e6ef515b0e..927b4bf2028 100644
> --- lib/libc/rpc/clnt_tcp.c
> +++ lib/libc/rpc/clnt_tcp.c
> @@ -393,12 +393,12 @@ readtcp(struct ct_data *ct, caddr_t buf, int len)
>   pfd[0].events = POLLIN;
>   TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &wait);
>   delta = wait;
> - clock_gettime(CLOCK_MONOTONIC, &start);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
>   for (;;) {
>   r = ppoll(pfd, 1, &delta, NULL);
>   save_errno = errno;
>  
> - clock_gettime(CLOCK_MONOTONIC, &after);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
>   timespecsub(&start, &after, &duration);
>   timespecsub(&wait, &duration, &delta);
>   if (delta.tv_sec < 0 || !timespecisset(&delta))
> diff --git lib/libc/rpc/clnt_udp.c lib/libc/rpc/clnt_udp.c
> index 68d01674410..92e1d5c350d 100644
> --- lib/libc/rpc/clnt_udp.c
> +++ lib/libc/rpc/clnt_udp.c
> @@ -265,7 +265,7 @@ send_again:
>   reply_msg.acpted_rply.ar_results.where = resultsp;
>   reply_msg.acpted_rply.ar_results.proc = xresults;
>  
> - clock_gettime(CLOCK_MONOTONIC, &start);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
>   for (;;) {
>   switch (ppoll(pfd, 1, &wait, NULL)) {
>   case 0:
> @@ -283,7 +283,7 @@ send_again:
>   /* FALLTHROUGH */
>   case -1:
>   if (errno == EINTR) {
> - clock_gettime(CLOCK_MONOTONIC, &after);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
>   timespecsub(&after, &start, &duration);
>   timespecadd(&time_waited, &duration, &time_waited);
>   if (timespeccmp(&time_waited, &timeout, <))
> diff --git lib/libc/rpc/svc_tcp.c lib/libc/rpc/svc_tcp.c
> index f9d7a70938f..6c99db84359 100644
> --- lib/libc/rpc/svc_tcp.c
> +++ lib/libc/rpc/svc_tcp.c
> @@ -342,7 +342,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len)
>   * A timeout is fatal for the connection.
>   */
>   delta = wait_per_try;
> - clock_gettime(CLOCK_MONOTONIC, &start);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &start);
>   pfd[0].fd = sock;
>   pfd[0].events = POLLIN;
>   do {
> @@ -351,7 +351,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len)
>   case -1:
>   if (errno != EINTR)
>   goto fatal_err;
> - clock_gettime(CLOCK_MONOTONIC, &after);
> + WRAP(clock_gettime)(CLOCK_MONOTONIC, &after);
>   timespecsub(&after, &start, &duration);
>   timespecsub(&wait_per_try, &duration, &delta);
>   if (delta.tv_sec < 0 || !timespecisset(&delta))
> diff --git lib/libc/sys/Makefile.inc lib/libc/sys/Makefile.inc
> index 34769576ced..d57418d81bf 100644
> --- lib/libc/sys/Makefile.inc
> +++ lib/libc/sys/Makefile.inc
> @@ -12,7 +12,8 @@ SRCS+= Ovfork.S brk.S ${CERROR} \
>  
>  # glue to offer userland wrappers for some syscalls
>  SRCS+= posix_madvise.c pthread_sigmask.c \
> - w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c
> + w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c \
> + w_clock_gettime.c w_gettimeofday.c microtime.c
>  
>  # glue for compat with old syscall interfaces.
>  SRCS+= ftruncate.c lseek.c mquery.c mmap.c ptrace.c semctl.c truncate.c \
> @@ -43,7 +44,7 @@ SRCS+= ${CANCEL:%=w_%.c} w_pread.c w_preadv.c w_pwrite.c w_pwritev.c
>  ASM= __semctl.o __syscall.o __thrsigdivert.o \
>   access.o acct.o adjfreq.o adjtime.o \
>   bind.o chdir.o chflags.o chflagsat.o chmod.o chown.o chroot.o \
> - clock_getres.o clock_gettime.o clock_settime.o \
> + clock_getres.o clock_settime.o \
>   dup.o dup2.o dup3.o \
>   execve.o \
>   faccessat.o fchdir.o fchflags.o fchmod.o fchmodat.o fchown.o \
> @@ -54,7 +55,7 @@ ASM= __semctl.o __syscall.o __thrsigdivert.o \
>   getgroups.o getitimer.o getpeername.o getpgid.o \
>   getpriority.o getresgid.o getresuid.o \
>   getrlimit.o getrusage.o getsid.o getsockname.o \
> - getsockopt.o gettimeofday.o ioctl.o \
> + getsockopt.o ioctl.o \
>   kevent.o kill.o kqueue.o ktrace.o lchown.o \
>   link.o linkat.o listen.o lstat.o madvise.o \
>   minherit.o mkdir.o mkdirat.o mkfifo.o mkfifoat.o \
> @@ -109,7 +110,8 @@ PPSEUDO_NOERR=${PSEUDO_NOERR:.o=.po}
>  SPSEUDO_NOERR=${PSEUDO_NOERR:.o=.so}
>  DPSEUDO_NOERR=${PSEUDO_NOERR:.o=.do}
>  
> -HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o}
> +HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o} \
> + clock_gettime.o gettimeofday.o
>  PHIDDEN=${HIDDEN:.o=.po}
>  SHIDDEN=${HIDDEN:.o=.so}
>  DHIDDEN=${HIDDEN:.o=.do}
> diff --git lib/libc/sys/microtime.c lib/libc/sys/microtime.c
> new file mode 100644
> index 00000000000..fc023e8452f
> --- /dev/null
> +++ lib/libc/sys/microtime.c
> @@ -0,0 +1,180 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2000 Poul-Henning Kamp <[hidden email]>
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/atomic.h>
> +#include <sys/timetc.h>
> +
> +#include <time.h>
> +
> +/*
> + * Return the difference between the timehands' counter value now and what
> + * was when we copied it to the timehands' offset_count.
> + */
> +static inline int
> +tc_delta(struct timekeep *tk, u_int *delta)
> +{
> + uint64_t tc;
> + if (delta == NULL || _tc_get_timecount(tk, &tc))
> + return -1;
> + *delta = (tc - tk->tk_offset_count) & tk->tk_counter_mask;
> + return 0;
> +}
> +
> +static inline void
> +bintimeaddfrac(const struct bintime *bt, uint64_t x, struct bintime *ct)
> +{
> + ct->sec = bt->sec;
> + if (bt->frac > bt->frac + x)
> + ct->sec++;
> + ct->frac = bt->frac + x;
> +}
> +
> +static inline void
> +BINTIME_TO_TIMESPEC(const struct bintime *bt, struct timespec *ts)
> +{
> + ts->tv_sec = bt->sec;
> + ts->tv_nsec = (long)(((uint64_t)1000000000 * (uint32_t)(bt->frac >> 32)) >> 32);
> +}
> +
> +static inline void
> +BINTIME_TO_TIMEVAL(const struct bintime *bt, struct timeval *tv)
> +{
> + tv->tv_sec = bt->sec;
> + tv->tv_usec = (long)(((uint64_t)1000000 * (uint32_t)(bt->frac >> 32)) >> 32);
> +}
> +
> +static int
> +binuptime(struct bintime *bt, struct timekeep *tk)
> +{
> + u_int gen, delta;
> +
> + do {
> + gen = tk->tk_generation;
> + membar_consumer();
> + *bt = tk->tk_offset;
> + if (tc_delta(tk, &delta))
> + return -1;
> + bintimeaddfrac(bt, tk->tk_scale * delta, bt);
> + membar_consumer();
> + } while (gen == 0 || gen != tk->tk_generation);
> +
> + return 0;
> +}
> +
> +static inline void
> +bintimeadd(const struct bintime *bt, const struct bintime *ct,
> +    struct bintime *dt)
> +{
> + dt->sec = bt->sec + ct->sec;
> + if (bt->frac > bt->frac + ct->frac)
> + dt->sec++;
> + dt->frac = bt->frac + ct->frac;
> +}
> +
> +static inline void
> +bintimesub(const struct bintime *bt, const struct bintime *ct,
> +    struct bintime *dt)
> +{
> + dt->sec = bt->sec - ct->sec;
> + if (bt->frac < bt->frac - ct->frac)
> + dt->sec--;
> + dt->frac = bt->frac - ct->frac;
> +}
> +
> +static int
> +binruntime(struct bintime *bt, struct timekeep *tk)
> +{
> + u_int gen, delta;
> +
> + do {
> + gen = tk->tk_generation;
> + membar_consumer();
> + if (tc_delta(tk, &delta))
> + return -1;
> + bintimeaddfrac(&tk->tk_offset, tk->tk_scale * delta, bt);
> + bintimesub(bt, &tk->tk_naptime, bt);
> + membar_consumer();
> + } while (gen == 0 || gen != tk->tk_generation);
> +
> + return 0;
> +}
> +
> +static int
> +bintime(struct bintime *bt, struct timekeep *tk)
> +{
> + u_int gen, delta;
> +
> + do {
> + gen = tk->tk_generation;
> + membar_consumer();
> + *bt = tk->tk_offset;
> + if (tc_delta(tk, &delta))
> + return -1;
> + bintimeaddfrac(bt, tk->tk_scale * delta, bt);
> + bintimeadd(bt, &tk->tk_boottime, bt);
> + membar_consumer();
> + } while (gen == 0 || gen != tk->tk_generation);
> +
> + return 0;
> +}
> +
> +int
> +_microtime(struct timeval *tvp, struct timekeep *tk)
> +{
> + struct bintime bt;
> +
> + if (bintime(&bt, tk))
> + return -1;
> + BINTIME_TO_TIMEVAL(&bt, tvp);
> + return 0;
> +}
> +
> +int
> +_nanotime(struct timespec *tsp, struct timekeep *tk)
> +{
> + struct bintime bt;
> +
> + if (bintime(&bt, tk))
> + return -1;
> + BINTIME_TO_TIMESPEC(&bt, tsp);
> + return 0;
> +}
> +
> +int
> +_nanoruntime(struct timespec *ts, struct timekeep *tk)
> +{
> + struct bintime bt;
> +
> + if (binruntime(&bt, tk))
> + return -1;
> + BINTIME_TO_TIMESPEC(&bt, ts);
> + return 0;
> +}
> +
> +
> +int
> +_nanouptime(struct timespec *tsp, struct timekeep *tk)
> +{
> + struct bintime bt;
> +
> + if (binuptime(&bt, tk))
> + return -1;
> + BINTIME_TO_TIMESPEC(&bt, tsp);
> + return 0;
> +}
> diff --git lib/libc/sys/w_clock_gettime.c lib/libc/sys/w_clock_gettime.c
> new file mode 100644
> index 00000000000..decd3342d6d
> --- /dev/null
> +++ lib/libc/sys/w_clock_gettime.c
> @@ -0,0 +1,54 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/timetc.h>
> +
> +#include <time.h>
> +
> +int
> +WRAP(clock_gettime)(clockid_t clock_id, struct timespec *tp)
> +{
> + int rc = 0;
> + struct timekeep *timekeep = _timekeep;
> +
> + if (timekeep == NULL || timekeep->tk_user == 0)
> + return clock_gettime(clock_id, tp);
> +
> + if (timekeep->tk_major != 1 || timekeep->tk_minor != 0)
> + return clock_gettime(clock_id, tp);
> +
> + switch (clock_id) {
> + case CLOCK_REALTIME:
> + rc = _nanotime(tp, timekeep);
> + break;
> + case CLOCK_UPTIME:
> + rc = _nanoruntime(tp, timekeep);
> + break;
> + case CLOCK_MONOTONIC:
> + case CLOCK_BOOTTIME:
> + rc = _nanouptime(tp, timekeep);
> + break;
> + default:
> + return clock_gettime(clock_id, tp);
> + }
> +
> + if (rc)
> + return clock_gettime(clock_id, tp);
> +
> + return 0;
> +}
> +DEF_WRAP(clock_gettime);
> diff --git lib/libc/sys/w_gettimeofday.c lib/libc/sys/w_gettimeofday.c
> new file mode 100644
> index 00000000000..2d9743e62bb
> --- /dev/null
> +++ lib/libc/sys/w_gettimeofday.c
> @@ -0,0 +1,43 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Robert Nagy <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/timetc.h>
> +
> +int
> +WRAP(gettimeofday)(struct timeval *tp, struct timezone *tzp)
> +{
> + int rc = 0;
> + struct timekeep *timekeep = _timekeep;
> + static struct timezone zerotz = { 0, 0 };
> +
> + if (timekeep == NULL || timekeep->tk_user == 0)
> + return gettimeofday(tp, tzp);
> +
> + if (timekeep->tk_major != 1 || timekeep->tk_minor != 0)
> + return gettimeofday(tp, tzp);
> +
> + if (tp)
> + rc = _microtime(tp, timekeep);
> + if (rc)
> + return gettimeofday(tp, tzp);
> +
> + if (tzp)
> + *tzp = zerotz;
> +
> + return 0;
> +}
> +DEF_WRAP(gettimeofday);
> diff --git lib/libc/thread/synch.h lib/libc/thread/synch.h
> index 788890add89..df2239438d2 100644
> --- lib/libc/thread/synch.h
> +++ lib/libc/thread/synch.h
> @@ -33,7 +33,7 @@ _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *
>   if (abs == NULL)
>   return futex(p, FUTEX_WAIT_PRIVATE, val, NULL, NULL);
>  
> - if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel))
> + if (abs->tv_nsec >= 1000000000 || WRAP(clock_gettime)(clockid, &rel))
>   return (EINVAL);
>  
>   rel.tv_sec = abs->tv_sec - rel.tv_sec;
> diff --git regress/lib/libc/timekeep/Makefile regress/lib/libc/timekeep/Makefile
> new file mode 100644
> index 00000000000..a7f3080290d
> --- /dev/null
> +++ regress/lib/libc/timekeep/Makefile
> @@ -0,0 +1,5 @@
> +# $OpenBSD$
> +
> +PROGS= test_clock_gettime test_time_skew test_gettimeofday
> +
> +.include <bsd.regress.mk>
> diff --git regress/lib/libc/timekeep/test_clock_gettime.c regress/lib/libc/timekeep/test_clock_gettime.c
> new file mode 100644
> index 00000000000..859ec368215
> --- /dev/null
> +++ regress/lib/libc/timekeep/test_clock_gettime.c
> @@ -0,0 +1,43 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <assert.h>
> +#include <time.h>
> +
> +#define ASSERT_EQ(a, b) assert((a) == (b))
> +
> +void
> +check()
> +{
> + struct timespec tp = {0};
> +
> + ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp));
> + ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp));
> + ASSERT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &tp));
> + ASSERT_EQ(0, clock_gettime(CLOCK_UPTIME, &tp));
> +
> +
> + ASSERT_EQ(0, clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp));
> + ASSERT_EQ(0, clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp));
> +
> +}
> +
> +int main()
> +{
> + check();
> + return 0;
> +}
> diff --git regress/lib/libc/timekeep/test_gettimeofday.c regress/lib/libc/timekeep/test_gettimeofday.c
> new file mode 100644
> index 00000000000..ea90a1be7e0
> --- /dev/null
> +++ regress/lib/libc/timekeep/test_gettimeofday.c
> @@ -0,0 +1,37 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <assert.h>
> +#include <sys/time.h>
> +
> +#define ASSERT_EQ(a, b) assert((a) == (b))
> +
> +void
> +check()
> +{
> + struct timeval tv = {0};
> + struct timezone tzp;
> +
> + ASSERT_EQ(0, gettimeofday(&tv, NULL));
> + ASSERT_EQ(0, gettimeofday(&tv, &tzp));
> +}
> +
> +int main()
> +{
> + check();
> + return 0;
> +}
> diff --git regress/lib/libc/timekeep/test_time_skew.c regress/lib/libc/timekeep/test_time_skew.c
> new file mode 100644
> index 00000000000..dfa9481c091
> --- /dev/null
> +++ regress/lib/libc/timekeep/test_time_skew.c
> @@ -0,0 +1,55 @@
> +/* $OpenBSD$ */
> +/*
> + * Copyright (c) 2020 Paul Irofti <[hidden email]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/time.h>
> +
> +#include <assert.h>
> +#include <time.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +#define ASSERT_EQ(a, b) assert((a) == (b))
> +#define ASSERT_NE(a, b) assert((a) != (b))
> +
> +void
> +check()
> +{
> +         struct timespec tp1, tp2, tout;
> +
> +         tout.tv_sec = 0;
> +         tout.tv_nsec = 100000;
> +
> +         ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp1));
> +
> +         nanosleep(&tout, NULL);
> +
> +         ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp2));
> +
> +         /* tp1 should never be larger than tp2 */
> +         ASSERT_NE(1, timespeccmp(&tp1, &tp2, >));
> +}
> +
> +int
> +main(void)
> +{
> + int i;
> +
> + for (i = 0; i < 1000; i++)
> + check();
> +
> + return 0;
> +}
> diff --git sys/arch/alpha/alpha/clock.c sys/arch/alpha/alpha/clock.c
> index 3f5f2c5b42b..6eaf8b107c6 100644
> --- sys/arch/alpha/alpha/clock.c
> +++ sys/arch/alpha/alpha/clock.c
> @@ -64,7 +64,7 @@ int clk_irq = 0;
>  
>  u_int rpcc_get_timecount(struct timecounter *);
>  struct timecounter rpcc_timecounter = {
> - rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL
> + rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL, 0
>  };
>  
>  extern todr_chip_handle_t todr_handle;
> diff --git sys/arch/alpha/alpha/machdep.c sys/arch/alpha/alpha/machdep.c
> index 09dc7e9cba5..9e43723959f 100644
> --- sys/arch/alpha/alpha/machdep.c
> +++ sys/arch/alpha/alpha/machdep.c
> @@ -139,6 +139,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
>  struct vm_map *exec_map = NULL;
>  struct vm_map *phys_map = NULL;
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> diff --git sys/arch/amd64/amd64/machdep.c sys/arch/amd64/amd64/machdep.c
> index 9dab8947af0..f58ab1a345c 100644
> --- sys/arch/amd64/amd64/machdep.c
> +++ sys/arch/amd64/amd64/machdep.c
> @@ -193,6 +193,9 @@ int lid_action = 1;
>  int pwr_action = 1;
>  int forceukbd;
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 1;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> diff --git sys/arch/amd64/amd64/tsc.c sys/arch/amd64/amd64/tsc.c
> index 7a1dcb4ad75..3db93d88dec 100644
> --- sys/arch/amd64/amd64/tsc.c
> +++ sys/arch/amd64/amd64/tsc.c
> @@ -50,7 +50,7 @@ extern u_int32_t lapic_per_second;
>  #endif
>  
>  struct timecounter tsc_timecounter = {
> - tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL
> + tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL, 1
>  };
>  
>  uint64_t
> diff --git sys/arch/amd64/isa/clock.c sys/arch/amd64/isa/clock.c
> index 613f7ee0e0f..00da0c6a8d0 100644
> --- sys/arch/amd64/isa/clock.c
> +++ sys/arch/amd64/isa/clock.c
> @@ -116,7 +116,7 @@ u_int i8254_get_timecount(struct timecounter *tc);
>  u_int i8254_simple_get_timecount(struct timecounter *tc);
>  
>  static struct timecounter i8254_timecounter = {
> - i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
> + i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0
>  };
>  
>  int clockintr(void *);
> diff --git sys/arch/arm64/arm64/machdep.c sys/arch/arm64/arm64/machdep.c
> index 4e292479233..2b6165800ca 100644
> --- sys/arch/arm64/arm64/machdep.c
> +++ sys/arch/arm64/arm64/machdep.c
> @@ -90,6 +90,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
>  /* the following is used externally (sysctl_hw) */
>  char    machine[] = MACHINE;            /* from <machine/param.h> */
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  int safepri = 0;
>  
>  struct cpu_info cpu_info_primary;
> diff --git sys/arch/arm64/dev/agtimer.c sys/arch/arm64/dev/agtimer.c
> index 29394141ad5..6b7c6db862f 100644
> --- sys/arch/arm64/dev/agtimer.c
> +++ sys/arch/arm64/dev/agtimer.c
> @@ -43,7 +43,7 @@ int32_t agtimer_frequency = TIMER_FREQUENCY;
>  u_int agtimer_get_timecount(struct timecounter *);
>  
>  static struct timecounter agtimer_timecounter = {
> - agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL
> + agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL, 0
>  };
>  
>  struct agtimer_pcpu_softc {
> diff --git sys/arch/armv7/armv7/armv7_machdep.c sys/arch/armv7/armv7/armv7_machdep.c
> index 1a5418cbf58..8b347ce86fd 100644
> --- sys/arch/armv7/armv7/armv7_machdep.c
> +++ sys/arch/armv7/armv7/armv7_machdep.c
> @@ -186,6 +186,9 @@ pv_addr_t kernel_pt_table[NUM_KERNEL_PTS];
>  
>  extern struct user *proc0paddr;
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> diff --git sys/arch/armv7/omap/gptimer.c sys/arch/armv7/omap/gptimer.c
> index 7605845d5e2..061542d532f 100644
> --- sys/arch/armv7/omap/gptimer.c
> +++ sys/arch/armv7/omap/gptimer.c
> @@ -117,7 +117,7 @@ int gptimer_irq = 0;
>  u_int gptimer_get_timecount(struct timecounter *);
>  
>  static struct timecounter gptimer_timecounter = {
> - gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL
> + gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL, 0
>  };
>  
>  volatile u_int32_t nexttickevent;
> diff --git sys/arch/armv7/omap/omap_machdep.c sys/arch/armv7/omap/omap_machdep.c
> index f62178f04a4..a36229a427c 100644
> --- sys/arch/armv7/omap/omap_machdep.c
> +++ sys/arch/armv7/omap/omap_machdep.c
> @@ -32,6 +32,9 @@
>  #include <armv7/armv7/armv7var.h>
>  #include <armv7/armv7/armv7_machdep.h>
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  extern void omap4_smc_call(uint32_t, uint32_t);
>  extern void omdog_reset(void);
>  extern struct board_dev *omap_board_devs(void);
> diff --git sys/arch/armv7/sunxi/sxitimer.c sys/arch/armv7/sunxi/sxitimer.c
> index 14a243c78d0..41028f9a602 100644
> --- sys/arch/armv7/sunxi/sxitimer.c
> +++ sys/arch/armv7/sunxi/sxitimer.c
> @@ -89,7 +89,7 @@ void sxitimer_delay(u_int);
>  u_int sxitimer_get_timecount(struct timecounter *);
>  
>  static struct timecounter sxitimer_timecounter = {
> - sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL
> + sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL, 0
>  };
>  
>  bus_space_tag_t sxitimer_iot;
> diff --git sys/arch/hppa/dev/clock.c sys/arch/hppa/dev/clock.c
> index 4c594ab5ec7..8cce6c3a893 100644
> --- sys/arch/hppa/dev/clock.c
> +++ sys/arch/hppa/dev/clock.c
> @@ -47,7 +47,7 @@ int cpu_hardclock(void *);
>  u_int itmr_get_timecount(struct timecounter *);
>  
>  struct timecounter itmr_timecounter = {
> - itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL
> + itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL, 0
>  };
>  
>  extern todr_chip_handle_t todr_handle;
> diff --git sys/arch/hppa/hppa/machdep.c sys/arch/hppa/hppa/machdep.c
> index f7bb998d53e..df356e5202f 100644
> --- sys/arch/hppa/hppa/machdep.c
> +++ sys/arch/hppa/hppa/machdep.c
> @@ -152,6 +152,9 @@ void hpmc_dump(void);
>  void cpuid(void);
>  void blink_led_timeout(void *);
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> diff --git sys/arch/i386/i386/machdep.c sys/arch/i386/i386/machdep.c
> index 0d392c75802..c22eb22bafe 100644
> --- sys/arch/i386/i386/machdep.c
> +++ sys/arch/i386/i386/machdep.c
> @@ -235,6 +235,9 @@ int lid_action = 1;
>  int pwr_action = 1;
>  int forceukbd;
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> diff --git sys/arch/i386/isa/clock.c sys/arch/i386/isa/clock.c
> index 09a6db983f2..dd74bd425ad 100644
> --- sys/arch/i386/isa/clock.c
> +++ sys/arch/i386/isa/clock.c
> @@ -129,7 +129,7 @@ u_int i8254_get_timecount(struct timecounter *tc);
>  u_int i8254_simple_get_timecount(struct timecounter *tc);
>  
>  static struct timecounter i8254_timecounter = {
> - i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
> + i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0
>  };
>  struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH);
>  u_long rtclock_tval;
> diff --git sys/arch/i386/pci/geodesc.c sys/arch/i386/pci/geodesc.c
> index 9d9f061eef9..bb8e4c7f9ae 100644
> --- sys/arch/i386/pci/geodesc.c
> +++ sys/arch/i386/pci/geodesc.c
> @@ -65,7 +65,9 @@ struct timecounter geodesc_timecounter = {
>   0xffffffff, /* counter_mask */
>   27000000, /* frequency */
>   "GEOTSC", /* name */
> - 2000 /* quality */
> + 2000, /* quality */
> + NULL, /* private bits */
> + 0 /* expose to user */
>  };
>  
>  int
> diff --git sys/arch/i386/pci/gscpm.c sys/arch/i386/pci/gscpm.c
> index 8b8aa4ac430..a6f324e66f3 100644
> --- sys/arch/i386/pci/gscpm.c
> +++ sys/arch/i386/pci/gscpm.c
> @@ -55,7 +55,9 @@ struct timecounter gscpm_timecounter = {
>   0xffffff, /* counter_mask */
>   3579545, /* frequency */
>   "GSCPM", /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0 /* expose to user */
>  };
>  
>  struct cfattach gscpm_ca = {
> diff --git sys/arch/i386/pci/ichpcib.c sys/arch/i386/pci/ichpcib.c
> index 6abf1627de2..629a86a14ff 100644
> --- sys/arch/i386/pci/ichpcib.c
> +++ sys/arch/i386/pci/ichpcib.c
> @@ -63,7 +63,9 @@ struct timecounter ichpcib_timecounter = {
>   0xffffff, /* counter_mask */
>   3579545, /* frequency */
>   "ICHPM", /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0 /* expose to user */
>  };
>  
>  struct cfattach ichpcib_ca = {
> diff --git sys/arch/landisk/landisk/machdep.c sys/arch/landisk/landisk/machdep.c
> index d5ea8df1740..3b515d191c9 100644
> --- sys/arch/landisk/landisk/machdep.c
> +++ sys/arch/landisk/landisk/machdep.c
> @@ -119,6 +119,9 @@ extern u_int32_t getramsize(void);
>  struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
>  struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> diff --git sys/arch/loongson/loongson/generic3a_machdep.c sys/arch/loongson/loongson/generic3a_machdep.c
> index ac3f1db6ccd..53489b07549 100644
> --- sys/arch/loongson/loongson/generic3a_machdep.c
> +++ sys/arch/loongson/loongson/generic3a_machdep.c
> @@ -98,7 +98,9 @@ struct timecounter rs780e_timecounter = {
>   .tc_counter_mask = 0xffffffffu, /* truncated to 32 bits */
>   .tc_frequency = HPET_FREQ,
>   .tc_name = "hpet",
> - .tc_quality = 100
> + .tc_quality = 100,
> + .tc_priv = NULL,
> + .tc_user = 0,
>  };
>  
>  /* Firmware entry points */
> diff --git sys/arch/loongson/loongson/machdep.c sys/arch/loongson/loongson/machdep.c
> index aaceb54bea8..9c66faa4b50 100644
> --- sys/arch/loongson/loongson/machdep.c
> +++ sys/arch/loongson/loongson/machdep.c
> @@ -103,6 +103,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
>  vm_map_t exec_map;
>  vm_map_t phys_map;
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> diff --git sys/arch/luna88k/luna88k/clock.c sys/arch/luna88k/luna88k/clock.c
> index a04120987e0..6580a4a46bf 100644
> --- sys/arch/luna88k/luna88k/clock.c
> +++ sys/arch/luna88k/luna88k/clock.c
> @@ -112,7 +112,9 @@ struct timecounter clock_tc = {
>   .tc_counter_mask = 0xffffffff,
>   .tc_frequency = 0, /* will be filled in */
>   .tc_name = "clock",
> - .tc_quality = 0
> + .tc_quality = 0,
> + .tc_priv = NULL,
> + .tc_user = 0,
>  };
>  
>  /*
> diff --git sys/arch/luna88k/luna88k/machdep.c sys/arch/luna88k/luna88k/machdep.c
> index 9501ad85210..41bbe6793d4 100644
> --- sys/arch/luna88k/luna88k/machdep.c
> +++ sys/arch/luna88k/luna88k/machdep.c
> @@ -193,6 +193,9 @@ int sysconsole = 1; /* 0 = ttya, 1 = keyboard/mouse, used in dev/sio.c */
>  u_int16_t dipswitch = 0; /* set in locore.S */
>  int hwplanebits; /* set in locore.S */
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  extern struct consdev syscons; /* in dev/siotty.c */
>  
>  extern void syscnattach(int); /* in dev/siotty.c */
> diff --git sys/arch/macppc/macppc/clock.c sys/arch/macppc/macppc/clock.c
> index 4a44a92cfc0..8c3ad620be8 100644
> --- sys/arch/macppc/macppc/clock.c
> +++ sys/arch/macppc/macppc/clock.c
> @@ -57,7 +57,7 @@ u_int32_t ns_per_tick = 320;
>  static int32_t ticks_per_intr;
>  
>  static struct timecounter tb_timecounter = {
> - tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL
> + tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL, 0
>  };
>  
>  /* calibrate the timecounter frequency for the listed models */
> diff --git sys/arch/macppc/macppc/machdep.c sys/arch/macppc/macppc/machdep.c
> index 178fe0995da..af4f68ed1d6 100644
> --- sys/arch/macppc/macppc/machdep.c
> +++ sys/arch/macppc/macppc/machdep.c
> @@ -350,6 +350,9 @@ install_extint(void (*handler)(void))
>   ppc_mtmsr(omsr);
>  }
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> diff --git sys/arch/mips64/mips64/mips64_machdep.c sys/arch/mips64/mips64/mips64_machdep.c
> index d4a42ed5acc..5c4dbadb5bb 100644
> --- sys/arch/mips64/mips64/mips64_machdep.c
> +++ sys/arch/mips64/mips64/mips64_machdep.c
> @@ -327,7 +327,9 @@ struct timecounter cp0_timecounter = {
>   0xffffffff, /* counter_mask */
>   0, /* frequency */
>   "CP0", /* name */
> - 0 /* quality */
> + 0, /* quality */
> + NULL, /* private bits */
> + 0, /* expose to user */
>  };
>  
>  u_int
> diff --git sys/arch/octeon/octeon/machdep.c sys/arch/octeon/octeon/machdep.c
> index 1387af284ca..0cfabfc642a 100644
> --- sys/arch/octeon/octeon/machdep.c
> +++ sys/arch/octeon/octeon/machdep.c
> @@ -107,6 +107,9 @@ struct boot_info *octeon_boot_info;
>  void *octeon_fdt;
>  unsigned int octeon_ver;
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> @@ -151,8 +154,9 @@ struct timecounter ioclock_timecounter = {
>   .tc_name = "ioclock",
>   .tc_quality = 0, /* ioclock can be overridden
>   * by cp0 counter */
> - .tc_priv = 0 /* clock register,
> + .tc_priv = 0, /* clock register,
>   * determined at runtime */
> + .tc_user = 0, /* expose to user */
>  };
>  
>  static int
> diff --git sys/arch/powerpc64/powerpc64/machdep.c sys/arch/powerpc64/powerpc64/machdep.c
> index bae64a1f297..b00bf682b76 100644
> --- sys/arch/powerpc64/powerpc64/machdep.c
> +++ sys/arch/powerpc64/powerpc64/machdep.c
> @@ -43,6 +43,9 @@ int cacheline_size = 128;
>  struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
>  struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  int cold = 1;
>  int safepri = 0;
>  int physmem;
> diff --git sys/arch/sgi/sgi/ip27_machdep.c sys/arch/sgi/sgi/ip27_machdep.c
> index ba7fa558b96..2a2cc144242 100644
> --- sys/arch/sgi/sgi/ip27_machdep.c
> +++ sys/arch/sgi/sgi/ip27_machdep.c
> @@ -111,7 +111,9 @@ struct timecounter ip27_hub_timecounter = {
>   .tc_counter_mask = 0xffffffff, /* truncated to 32 bits. */
>   .tc_frequency = 1250000,
>   .tc_name = "hubrt",
> - .tc_quality = 100
> + .tc_quality = 100,
> + .tc_priv = 0,
> + .tc_user = 0,
>  };
>  
>  volatile uint64_t ip27_spinup_a0;
> diff --git sys/arch/sgi/sgi/machdep.c sys/arch/sgi/sgi/machdep.c
> index d251c15fc01..9b73112addf 100644
> --- sys/arch/sgi/sgi/machdep.c
> +++ sys/arch/sgi/sgi/machdep.c
> @@ -93,6 +93,9 @@ struct uvm_constraint_range *uvm_md_constraints[] = {
>  vm_map_t exec_map;
>  vm_map_t phys_map;
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> diff --git sys/arch/sgi/xbow/xheart.c sys/arch/sgi/xbow/xheart.c
> index 56b29915c70..827775512ac 100644
> --- sys/arch/sgi/xbow/xheart.c
> +++ sys/arch/sgi/xbow/xheart.c
> @@ -83,7 +83,9 @@ struct timecounter xheart_timecounter = {
>   .tc_counter_mask = 0xffffffff, /* truncate 52-bit counter to 32-bit */
>   .tc_frequency = 12500000,
>   .tc_name = "heart",
> - .tc_quality = 100
> + .tc_quality = 100,
> + .tc_priv = NULL,
> + .tc_user = 0,
>  };
>  
>  extern uint32_t ip30_lights_frob(uint32_t, struct trapframe *);
> diff --git sys/arch/sparc64/dev/psycho.c sys/arch/sparc64/dev/psycho.c
> index e24f804dff6..1a7a1afa8c2 100644
> --- sys/arch/sparc64/dev/psycho.c
> +++ sys/arch/sparc64/dev/psycho.c
> @@ -127,7 +127,7 @@ extern struct sparc_pci_chipset _sparc_pci_chipset;
>  u_int stick_get_timecount(struct timecounter *);
>  
>  struct timecounter stick_timecounter = {
> - stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL
> + stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL, 0
>  };
>  
>  /*
> diff --git sys/arch/sparc64/sparc64/clock.c sys/arch/sparc64/sparc64/clock.c
> index fd5e8a9c15b..5c2e47d386b 100644
> --- sys/arch/sparc64/sparc64/clock.c
> +++ sys/arch/sparc64/sparc64/clock.c
> @@ -109,13 +109,13 @@ struct cfdriver clock_cd = {
>  u_int tick_get_timecount(struct timecounter *);
>  
>  struct timecounter tick_timecounter = {
> - tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL
> + tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL, 0
>  };
>  
>  u_int sys_tick_get_timecount(struct timecounter *);
>  
>  struct timecounter sys_tick_timecounter = {
> - sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL
> + sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL, 0
>  };
>  
>  /*
> diff --git sys/arch/sparc64/sparc64/machdep.c sys/arch/sparc64/sparc64/machdep.c
> index 05aa4342943..0ee7ff3b802 100644
> --- sys/arch/sparc64/sparc64/machdep.c
> +++ sys/arch/sparc64/sparc64/machdep.c
> @@ -183,6 +183,9 @@ extern int64_t cecclast;
>  #define MAX_DMA_SEGS 20
>  #endif
>  
> +/* timekeep number of user accesible clocks */
> +int tk_nclocks = 0;
> +
>  /*
>   * safepri is a safe priority for sleep to set for a spin-wait
>   * during autoconfiguration or after a panic.
> diff --git sys/dev/acpi/acpihpet.c sys/dev/acpi/acpihpet.c
> index d0ee72cec9b..13177a909da 100644
> --- sys/dev/acpi/acpihpet.c
> +++ sys/dev/acpi/acpihpet.c
> @@ -45,7 +45,9 @@ static struct timecounter hpet_timecounter = {
>   0xffffffff, /* counter_mask (32 bits) */
>   0, /* frequency */
>   0, /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0, /* expose to user */
>  };
>  
>  #define HPET_TIMERS 3
> diff --git sys/dev/acpi/acpitimer.c sys/dev/acpi/acpitimer.c
> index cdc8c99a17a..89b5a397e47 100644
> --- sys/dev/acpi/acpitimer.c
> +++ sys/dev/acpi/acpitimer.c
> @@ -36,7 +36,9 @@ static struct timecounter acpi_timecounter = {
>   0x00ffffff, /* counter_mask (24 bits) */
>   ACPI_FREQUENCY, /* frequency */
>   0, /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0, /* expose to user */
>  };
>  
>  struct acpitimer_softc {
> diff --git sys/dev/pci/amdpm.c sys/dev/pci/amdpm.c
> index 6df82858016..9610d5bc1f0 100644
> --- sys/dev/pci/amdpm.c
> +++ sys/dev/pci/amdpm.c
> @@ -82,7 +82,9 @@ static struct timecounter amdpm_timecounter = {
>   0xffffff, /* counter_mask */
>   AMDPM_FREQUENCY, /* frequency */
>   "AMDPM", /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0, /* expose to user */
>  };
>  
>  #define AMDPM_CONFREG 0x40
> diff --git sys/dev/pci/viapm.c sys/dev/pci/viapm.c
> index db806eedf80..ce33cd175e6 100644
> --- sys/dev/pci/viapm.c
> +++ sys/dev/pci/viapm.c
> @@ -177,7 +177,9 @@ static struct timecounter viapm_timecounter = {
>   0xffffff, /* counter_mask */
>   VIAPM_FREQUENCY, /* frequency */
>   "VIAPM", /* name */
> - 1000 /* quality */
> + 1000, /* quality */
> + NULL, /* private bits */
> + 0, /* expose to user */
>  };
>  
>  struct timeout viapm_timeout;
> diff --git sys/dev/pv/hyperv.c sys/dev/pv/hyperv.c
> index b32facdacb1..b9ee2feec4c 100644
> --- sys/dev/pv/hyperv.c
> +++ sys/dev/pv/hyperv.c
> @@ -141,7 +141,7 @@ struct {
>  };
>  
>  struct timecounter hv_timecounter = {
> - hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001
> + hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001, NULL, 0
>  };
>  
>  struct cfdriver hyperv_cd = {
> diff --git sys/dev/pv/pvclock.c sys/dev/pv/pvclock.c
> index 6b242f7448d..b80e4d2a484 100644
> --- sys/dev/pv/pvclock.c
> +++ sys/dev/pv/pvclock.c
> @@ -74,7 +74,7 @@ struct cfdriver pvclock_cd = {
>  };
>  
>  struct timecounter pvclock_timecounter = {
> - pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL
> + pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL, 0
>  };
>  
>  int
> diff --git sys/kern/exec_elf.c sys/kern/exec_elf.c
> index 9b5b8eb3acf..59bc923a6fb 100644
> --- sys/kern/exec_elf.c
> +++ sys/kern/exec_elf.c
> @@ -124,7 +124,7 @@ extern char *syscallnames[];
>  /*
>   * How many entries are in the AuxInfo array we pass to the process?
>   */
> -#define ELF_AUX_ENTRIES 8
> +#define ELF_AUX_ENTRIES 9
>  
>  /*
>   * This is the OpenBSD ELF emul
> @@ -860,6 +860,10 @@ exec_elf_fixup(struct proc *p, struct exec_package *epp)
>   a->au_v = ap->arg_entry;
>   a++;
>  
> + a->au_id = AUX_openbsd_timekeep;
> + a->au_v = p->p_p->ps_timekeep;
> + a++;
> +
>   a->au_id = AUX_null;
>   a->au_v = 0;
>   a++;
> diff --git sys/kern/kern_exec.c sys/kern/kern_exec.c
> index 20480c2fc28..215093a01da 100644
> --- sys/kern/kern_exec.c
> +++ sys/kern/kern_exec.c
> @@ -64,6 +64,11 @@
>  #include <uvm/uvm_extern.h>
>  #include <machine/tcb.h>
>  
> +#include <sys/timetc.h>
> +
> +struct uvm_object *timekeep_object;
> +struct timekeep* timekeep;
> +
>  void unveil_destroy(struct process *ps);
>  
>  const struct kmem_va_mode kv_exec = {
> @@ -76,6 +81,11 @@ const struct kmem_va_mode kv_exec = {
>   */
>  int exec_sigcode_map(struct process *, struct emul *);
>  
> +/*
> + * Map the shared timekeep page.
> + */
> +int exec_timekeep_map(struct process *);
> +
>  /*
>   * If non-zero, stackgap_random specifies the upper limit of the random gap size
>   * added to the fixed stack position. Must be n^2.
> @@ -684,6 +694,9 @@ sys_execve(struct proc *p, void *v, register_t *retval)
>   /* map the process's signal trampoline code */
>   if (exec_sigcode_map(pr, pack.ep_emul))
>   goto free_pack_abort;
> + /* map the process's timekeep page */
> + if (exec_timekeep_map(pr))
> + goto free_pack_abort;
>  
>  #ifdef __HAVE_EXEC_MD_MAP
>   /* perform md specific mappings that process might need */
> @@ -863,3 +876,42 @@ exec_sigcode_map(struct process *pr, struct emul *e)
>  
>   return (0);
>  }
> +
> +int
> +exec_timekeep_map(struct process *pr)
> +{
> + size_t timekeep_sz = sizeof(struct timekeep);
> +
> + /*
> + * Similar to the sigcode object, except that there is a single timekeep
> + * object, and not one per emulation.
> + */
> + if (timekeep_object == NULL) {
> + vaddr_t va;
> +
> + timekeep_object = uao_create(timekeep_sz, 0);
> + uao_reference(timekeep_object);
> +
> + if (uvm_map(kernel_map, &va, round_page(timekeep_sz), timekeep_object,
> +    0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
> +    MAP_INHERIT_SHARE, MADV_RANDOM, 0))) {
> + uao_detach(timekeep_object);
> + return (ENOMEM);
> + }
> +
> + timekeep = (struct timekeep *)va;
> + timekeep->tk_major = 1;
> + timekeep->tk_minor = 0;
> + timekeep->tk_nclocks = tk_nclocks;
> + }
> +
> + uao_reference(timekeep_object);
> + if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_timekeep, round_page(timekeep_sz),
> +    timekeep_object, 0, 0, UVM_MAPFLAG(PROT_READ, PROT_READ,
> +    MAP_INHERIT_COPY, MADV_RANDOM, 0))) {
> + uao_detach(timekeep_object);
> + return (ENOMEM);
> + }
> +
> + return (0);
> +}
> diff --git sys/kern/kern_tc.c sys/kern/kern_tc.c
> index 88d4a3379f9..47efbdd0b78 100644
> --- sys/kern/kern_tc.c
> +++ sys/kern/kern_tc.c
> @@ -63,7 +63,7 @@ dummy_get_timecount(struct timecounter *tc)
>  }
>  
>  static struct timecounter dummy_timecounter = {
> - dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000
> + dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000, NULL, 0
>  };
>  
>  /*
> @@ -479,6 +479,34 @@ tc_setclock(const struct timespec *ts)
>  #endif
>  }
>  
> +void
> +tc_update_timekeep(void)
> +{
> + static struct timecounter *last_tc = NULL;
> + struct timehands *th;
> +
> + if (timekeep == NULL)
> + return;
> +
> + th = timehands;
> + timekeep->tk_generation = 0;
> + membar_producer();
> + timekeep->tk_scale = th->th_scale;
> + timekeep->tk_offset_count = th->th_offset_count;
> + timekeep->tk_offset = th->th_offset;
> + timekeep->tk_naptime = th->th_naptime;
> + timekeep->tk_boottime = th->th_boottime;
> + if (last_tc != th->th_counter) {
> + timekeep->tk_counter_mask = th->th_counter->tc_counter_mask;
> + timekeep->tk_user = th->th_counter->tc_user;
> + last_tc = th->th_counter;
> + }
> + membar_producer();
> + timekeep->tk_generation = th->th_generation;
> +
> + return;
> +}
> +
>  /*
>   * Initialize the next struct timehands in the ring and make
>   * it the active timehands.  Along the way we might switch to a different
> @@ -631,6 +659,8 @@ tc_windup(struct bintime *new_boottime, struct bintime *new_offset,
>   time_uptime = th->th_offset.sec;
>   membar_producer();
>   timehands = th;
> +
> + tc_update_timekeep();
>  }
>  
>  /* Report or change the active timecounter hardware. */
> diff --git sys/sys/exec_elf.h sys/sys/exec_elf.h
> index a40e0510273..3084ed595a6 100644
> --- sys/sys/exec_elf.h
> +++ sys/sys/exec_elf.h
> @@ -691,7 +691,8 @@ enum AuxID {
>   AUX_sun_uid = 2000, /* euid */
>   AUX_sun_ruid = 2001, /* ruid */
>   AUX_sun_gid = 2002, /* egid */
> - AUX_sun_rgid = 2003 /* rgid */
> + AUX_sun_rgid = 2003, /* rgid */
> + AUX_openbsd_timekeep = 4000, /* userland clock_gettime */
>  };
>  
>  struct elf_args {
> diff --git sys/sys/proc.h sys/sys/proc.h
> index 357c0c0d52c..c6d54572bdd 100644
> --- sys/sys/proc.h
> +++ sys/sys/proc.h
> @@ -242,6 +242,7 @@ struct process {
>   char ps_comm[MAXCOMLEN+1];
>  
>   vaddr_t ps_strings; /* User pointers to argv/env */
> + vaddr_t ps_timekeep; /* User pointer to timekeep */
>   vaddr_t ps_sigcode; /* User pointer to the signal code */
>   vaddr_t ps_sigcoderet; /* User pointer to sigreturn retPC */
>   u_long ps_sigcookie;
> diff --git sys/sys/time.h sys/sys/time.h
> index e758a64ce07..bcd3acd034d 100644
> --- sys/sys/time.h
> +++ sys/sys/time.h
> @@ -163,7 +163,7 @@ struct clockinfo {
>  };
>  #endif /* __BSD_VISIBLE */
>  
> -#if defined(_KERNEL) || defined(_STANDALONE)
> +#if defined(_KERNEL) || defined(_STANDALONE) || defined (_LIBC)
>  #include <sys/_time.h>
>  
>  /* Time expressed as seconds and fractions of a second + operations on it. */
> @@ -171,6 +171,9 @@ struct bintime {
>   time_t sec;
>   uint64_t frac;
>  };
> +#endif
> +
> +#if defined(_KERNEL) || defined(_STANDALONE)
>  
>  #define bintimecmp(btp, ctp, cmp) \
>   ((btp)->sec == (ctp)->sec ? \
> diff --git sys/sys/timetc.h sys/sys/timetc.h
> index ce81c3475a0..a4a80eecff1 100644
> --- sys/sys/timetc.h
> +++ sys/sys/timetc.h
> @@ -24,7 +24,7 @@
>  #ifndef _SYS_TIMETC_H_
>  #define _SYS_TIMETC_H_
>  
> -#ifndef _KERNEL
> +#if !defined(_KERNEL) && !defined(_LIBC)
>  #error "no user-serviceable parts inside"
>  #endif
>  
> @@ -80,6 +80,8 @@ struct timecounter {
>   */
>   void *tc_priv; /* [I] */
>   /* Pointer to the timecounter's private parts. */
> + int tc_user; /* [I] */
> + /* Expose this timecounter to userland. */
>   SLIST_ENTRY(timecounter) tc_next; /* [I] */
>   /* Pointer to the next timecounter. */
>   int64_t tc_freq_adj; /* [tw] */
> @@ -88,11 +90,34 @@ struct timecounter {
>   /* Precision of the counter.  Computed in tc_init(). */
>  };
>  
> +struct timekeep {
> + /* set at initialization */
> + uint32_t tk_major; /* version major number */
> + uint32_t tk_minor; /* version minor number */
> + int tk_nclocks; /* number of arch user clocks */
> +
> + /* timehands members */
> + uint64_t tk_scale;
> + u_int tk_offset_count;
> + struct bintime tk_offset;
> + struct bintime tk_naptime;
> + struct bintime tk_boottime;
> + volatile u_int tk_generation;
> +
> + /* timecounter members */
> + int tk_user;
> + u_int tk_counter_mask;
> +};
> +extern int tk_nclocks;
> +
>  struct rwlock;
>  extern struct rwlock tc_lock;
>  
>  extern struct timecounter *timecounter;
>  
> +extern struct uvm_object *timekeep_object;
> +extern struct timekeep *timekeep;
> +
>  u_int64_t tc_getfrequency(void);
>  u_int64_t tc_getprecision(void);
>  void tc_init(struct timecounter *tc);
>
>

Reply | Threaded
Open this post in threaded view
|

Re: userland clock_gettime proof of concept

Theo de Raadt-2
In reply to this post by Paul Irofti-4
I think this conversation about major numbers, and now minor numbers,
is incredibly silly.

Do we have a major number on the open(2) system call?  No, and the main
reason is because the code isn't a draft, it was completed.

This needs to support as many architectures as possible, then it goes
in.

This addition of major and minor numbers appears to be a distraction.

12345678 ... 11