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 <p...@irofti.net>
> > > 
> > > 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@freebsd.org>
+ * Copyright (c) 2020 Paul Irofti <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <rob...@openbsd.org>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 <p...@irofti.net>
+ *
+ * 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 via email to