diff options
author | sephe <sephe@FreeBSD.org> | 2017-01-05 07:42:08 +0000 |
---|---|---|
committer | sephe <sephe@FreeBSD.org> | 2017-01-05 07:42:08 +0000 |
commit | 8642827c9ec3822a0bfd998c63fdd355df1a0c2f (patch) | |
tree | 048d603f5a92a9d0f36d7934b10d794d55ecd06d /lib | |
parent | f3f5d2cf4cd3a521294d7371ddaa067322ec55d2 (diff) | |
download | FreeBSD-src-8642827c9ec3822a0bfd998c63fdd355df1a0c2f.zip FreeBSD-src-8642827c9ec3822a0bfd998c63fdd355df1a0c2f.tar.gz |
MFC 310048,310101,310239
310048
hyperv: Implement "enlightened" time counter, which is rdtsc based.
Reviewed by: kib
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8763
310101
hyperv: Allow userland to ro-mmap reference TSC page
This paves way to implement VDSO for the enlightened time counter.
Reviewed by: kib
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8768
310239
hyperv: Implement userspace gettimeofday(2) with Hyper-V reference TSC
This 6 times gettimeofday performance, as measured by
tools/tools/syscall_timing
Reviewed by: kib
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8789
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/x86/sys/__vdso_gettc.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/lib/libc/x86/sys/__vdso_gettc.c b/lib/libc/x86/sys/__vdso_gettc.c index 743b3ad..5097ad5 100644 --- a/lib/libc/x86/sys/__vdso_gettc.c +++ b/lib/libc/x86/sys/__vdso_gettc.c @@ -45,6 +45,10 @@ __FBSDID("$FreeBSD$"); #include <machine/cpufunc.h> #include <machine/specialreg.h> #include <dev/acpica/acpi_hpet.h> +#ifdef __amd64__ +#include <machine/atomic.h> +#include <dev/hyperv/hyperv.h> +#endif #include "libc_private.h" static void @@ -144,6 +148,67 @@ __vdso_init_hpet(uint32_t u) _close(fd); } +#ifdef __amd64__ + +#define HYPERV_REFTSC_DEVPATH "/dev/" HYPERV_REFTSC_DEVNAME + +/* + * NOTE: + * We use 'NULL' for this variable to indicate that initialization + * is required. And if this variable is 'MAP_FAILED', then Hyper-V + * reference TSC can not be used, e.g. in misconfigured jail. + */ +static struct hyperv_reftsc *hyperv_ref_tsc; + +static void +__vdso_init_hyperv_tsc(void) +{ + int fd; + + fd = _open(HYPERV_REFTSC_DEVPATH, O_RDONLY); + if (fd < 0) { + /* Prevent the caller from re-entering. */ + hyperv_ref_tsc = MAP_FAILED; + return; + } + hyperv_ref_tsc = mmap(NULL, sizeof(*hyperv_ref_tsc), PROT_READ, + MAP_SHARED, fd, 0); + _close(fd); +} + +static int +__vdso_hyperv_tsc(struct hyperv_reftsc *tsc_ref, u_int *tc) +{ + uint64_t disc, ret, tsc, scale; + uint32_t seq; + int64_t ofs; + + while ((seq = atomic_load_acq_int(&tsc_ref->tsc_seq)) != 0) { + scale = tsc_ref->tsc_scale; + ofs = tsc_ref->tsc_ofs; + + lfence_mb(); + tsc = rdtsc(); + + /* ret = ((tsc * scale) >> 64) + ofs */ + __asm__ __volatile__ ("mulq %3" : + "=d" (ret), "=a" (disc) : + "a" (tsc), "r" (scale)); + ret += ofs; + + atomic_thread_fence_acq(); + if (tsc_ref->tsc_seq == seq) { + *tc = ret; + return (0); + } + + /* Sequence changed; re-sync. */ + } + return (ENOSYS); +} + +#endif /* __amd64__ */ + #pragma weak __vdso_gettc int __vdso_gettc(const struct vdso_timehands *th, u_int *tc) @@ -165,6 +230,14 @@ __vdso_gettc(const struct vdso_timehands *th, u_int *tc) return (ENOSYS); *tc = *(volatile uint32_t *)(hpet_dev_map + HPET_MAIN_COUNTER); return (0); +#ifdef __amd64__ + case VDSO_TH_ALGO_X86_HVTSC: + if (hyperv_ref_tsc == NULL) + __vdso_init_hyperv_tsc(); + if (hyperv_ref_tsc == MAP_FAILED) + return (ENOSYS); + return (__vdso_hyperv_tsc(hyperv_ref_tsc, tc)); +#endif default: return (ENOSYS); } |