Index: lib/libc/x86/sys/__vdso_gettc.c =================================================================== --- lib/libc/x86/sys/__vdso_gettc.c +++ lib/libc/x86/sys/__vdso_gettc.c @@ -45,6 +45,10 @@ #include #include #include +#ifdef __amd64__ +#include +#include +#endif #include "libc_private.h" static void @@ -144,6 +148,58 @@ _close(fd); } +#ifdef __amd64__ + +#define HYPERV_REFTSC_DEVPATH "/dev/" HYPERV_REFTSC_DEVNAME + +static struct hyperv_reftsc *hyperv_ref_tsc = MAP_FAILED; + +static void +__vdso_init_hyperv_tsc(void) +{ + int fd; + + fd = _open(HYPERV_REFTSC_DEVPATH, O_RDONLY); + if (fd < 0) + 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) +{ + uint32_t seq; + + while ((seq = atomic_load_acq_int(&tsc_ref->tsc_seq)) != 0) { + uint64_t disc, ret, tsc; + uint64_t scale = tsc_ref->tsc_scale; + int64_t ofs = tsc_ref->tsc_ofs; + + /* XXX mfence for AMD cpus. */ + 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 +221,15 @@ 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 == MAP_FAILED) { + __vdso_init_hyperv_tsc(); + if (hyperv_ref_tsc == MAP_FAILED) + return (ENOSYS); + } + return (__vdso_hyperv_tsc(hyperv_ref_tsc, tc)); +#endif default: return (ENOSYS); } Index: sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c =================================================================== --- sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c +++ sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -52,18 +53,28 @@ struct hyperv_dma tsc_ref_dma; }; +static uint32_t hyperv_tsc_vdso_timehands( + struct vdso_timehands *, + struct timecounter *); +#ifdef COMPAT_FREEBSD32 +static uint32_t hyperv_tsc_vdso_timehands32( + struct vdso_timehands32 *, + struct timecounter *); +#endif + static d_open_t hyperv_tsc_open; static d_mmap_t hyperv_tsc_mmap; static struct timecounter hyperv_tsc_timecounter = { .tc_get_timecount = NULL, /* based on CPU vendor. */ - .tc_poll_pps = NULL, .tc_counter_mask = 0xffffffff, .tc_frequency = HYPERV_TIMER_FREQ, .tc_name = "Hyper-V-TSC", .tc_quality = 3000, - .tc_flags = 0, - .tc_priv = NULL + .tc_fill_vdso_timehands = hyperv_tsc_vdso_timehands, +#ifdef COMPAT_FREEBSD32 + .tc_fill_vdso_timehands32 = hyperv_tsc_vdso_timehands32 +#endif }; static struct cdevsw hyperv_tsc_cdevsw = { @@ -117,6 +128,32 @@ return (0); } +static uint32_t +hyperv_tsc_vdso_timehands(struct vdso_timehands *vdso_th, + struct timecounter *tc __unused) +{ + + vdso_th->th_algo = VDSO_TH_ALGO_X86_HVTSC; + vdso_th->th_x86_shift = 0; + vdso_th->th_x86_hpet_idx = 0xffffffff; + bzero(vdso_th->th_res, sizeof(vdso_th->th_res)); + return (1); +} + +#ifdef COMPAT_FREEBSD32 +static uint32_t +hyperv_tsc_vdso_timehands32(struct vdso_timehands32 *vdso_th32, + struct timecounter *tc __unused) +{ + + vdso_th32->th_algo = VDSO_TH_ALGO_X86_HVTSC; + vdso_th32->th_x86_shift = 0; + vdso_th32->th_x86_hpet_idx = 0xffffffff; + bzero(vdso_th32->th_res, sizeof(vdso_th32->th_res)); + return (1); +} +#endif /* COMPAT_FREEBSD32 */ + #define HYPERV_TSC_TIMECOUNT(fence) \ static u_int \ hyperv_tsc_timecount_##fence(struct timecounter *tc) \ Index: sys/sys/vdso.h =================================================================== --- sys/sys/vdso.h +++ sys/sys/vdso.h @@ -54,6 +54,8 @@ #define VDSO_TK_VER_CURR VDSO_TK_VER_1 #define VDSO_TH_ALGO_1 0x1 #define VDSO_TH_ALGO_2 0x2 +#define VDSO_TH_ALGO_3 0x3 +#define VDSO_TH_ALGO_4 0x4 #ifndef _KERNEL Index: sys/x86/include/vdso.h =================================================================== --- sys/x86/include/vdso.h +++ sys/x86/include/vdso.h @@ -39,6 +39,7 @@ #define VDSO_TH_ALGO_X86_TSC VDSO_TH_ALGO_1 #define VDSO_TH_ALGO_X86_HPET VDSO_TH_ALGO_2 +#define VDSO_TH_ALGO_X86_HVTSC VDSO_TH_ALGO_3 /* Hyper-V ref. TSC */ #ifdef _KERNEL #ifdef COMPAT_FREEBSD32