Index: lib/libc/x86/sys/__vdso_gettc.c =================================================================== --- lib/libc/x86/sys/__vdso_gettc.c +++ lib/libc/x86/sys/__vdso_gettc.c @@ -45,10 +45,8 @@ #include #include #include -#ifdef __amd64__ #include #include -#endif #include "libc_private.h" static void @@ -148,8 +146,6 @@ _close(fd); } -#ifdef __amd64__ - #define HYPERV_REFTSC_DEVPATH "/dev/" HYPERV_REFTSC_DEVNAME /* @@ -176,10 +172,61 @@ _close(fd); } +#if defined(__amd64__) +static __inline uint64_t +__vdso_hyperv_mulqhi(uint64_t tsc, uint64_t scale) +{ + uint64_t disc, ret; + + __asm__ __volatile__ ("mulq %3" : "=d" (ret), "=a" (disc) : + "a" (tsc), "r" (scale)); + return (ret); +} +#elif defined(__i386__) +/* + * Copied from compiler-rt multi3.c + */ +typedef long long di_int; +typedef unsigned long long du_int; +typedef int ti_int __attribute__((mode (TI))); + +typedef union { + ti_int all; + struct { + du_int low; + di_int high; + } s; +} twords; + +static __inline uint64_t +__vdso_hyperv_mulqhi(du_int a, du_int b) +{ + twords r; + const int bits_in_dword_2 = (int)(sizeof(di_int) * CHAR_BIT) / 2; + const du_int lower_mask = (du_int)~0 >> bits_in_dword_2; + + r.s.low = (a & lower_mask) * (b & lower_mask); + du_int t = r.s.low >> bits_in_dword_2; + r.s.low &= lower_mask; + t += (a >> bits_in_dword_2) * (b & lower_mask); + r.s.low += (t & lower_mask) << bits_in_dword_2; + r.s.high = t >> bits_in_dword_2; + t = r.s.low >> bits_in_dword_2; + r.s.low &= lower_mask; + t += (b >> bits_in_dword_2) * (a & lower_mask); + r.s.low += (t & lower_mask) << bits_in_dword_2; + r.s.high += t >> bits_in_dword_2; + r.s.high += (a >> bits_in_dword_2) * (b >> bits_in_dword_2); + return (r.s.high); +} +#else +#error "unknown arch" +#endif + static int __vdso_hyperv_tsc(struct hyperv_reftsc *tsc_ref, u_int *tc) { - uint64_t disc, ret, tsc, scale; + uint64_t ret, tsc, scale; uint32_t seq; int64_t ofs; @@ -191,9 +238,7 @@ tsc = rdtsc(); /* ret = ((tsc * scale) >> 64) + ofs */ - __asm__ __volatile__ ("mulq %3" : - "=d" (ret), "=a" (disc) : - "a" (tsc), "r" (scale)); + ret = __vdso_hyperv_mulqhi(tsc, scale); ret += ofs; atomic_thread_fence_acq(); @@ -207,8 +252,6 @@ return (ENOSYS); } -#endif /* __amd64__ */ - #pragma weak __vdso_gettc int __vdso_gettc(const struct vdso_timehands *th, u_int *tc) @@ -230,14 +273,12 @@ 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); } 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 @@ -56,6 +56,11 @@ 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; @@ -67,6 +72,9 @@ .tc_name = "Hyper-V-TSC", .tc_quality = 3000, .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 = { @@ -132,6 +140,20 @@ 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 = 0; + 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) \