1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _ASM_X86_PVCLOCK_H 3 #define _ASM_X86_PVCLOCK_H 4 5 #include <linux/clocksource.h> 6 #include <asm/pvclock-abi.h> 7 8 #ifdef CONFIG_KVM_GUEST 9 extern struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void); 10 #else 11 static inline struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void) 12 { 13 return NULL; 14 } 15 #endif 16 17 /* some helper functions for xen and kvm pv clock sources */ 18 u64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src); 19 u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src); 20 void pvclock_set_flags(u8 flags); 21 unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src); 22 void pvclock_read_wallclock(struct pvclock_wall_clock *wall, 23 struct pvclock_vcpu_time_info *vcpu, 24 struct timespec *ts); 25 void pvclock_resume(void); 26 27 void pvclock_touch_watchdogs(void); 28 29 static __always_inline 30 unsigned pvclock_read_begin(const struct pvclock_vcpu_time_info *src) 31 { 32 unsigned version = src->version & ~1; 33 /* Make sure that the version is read before the data. */ 34 virt_rmb(); 35 return version; 36 } 37 38 static __always_inline 39 bool pvclock_read_retry(const struct pvclock_vcpu_time_info *src, 40 unsigned version) 41 { 42 /* Make sure that the version is re-read after the data. */ 43 virt_rmb(); 44 return unlikely(version != src->version); 45 } 46 47 /* 48 * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, 49 * yielding a 64-bit result. 50 */ 51 static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift) 52 { 53 u64 product; 54 #ifdef __i386__ 55 u32 tmp1, tmp2; 56 #else 57 ulong tmp; 58 #endif 59 60 if (shift < 0) 61 delta >>= -shift; 62 else 63 delta <<= shift; 64 65 #ifdef __i386__ 66 __asm__ ( 67 "mul %5 ; " 68 "mov %4,%%eax ; " 69 "mov %%edx,%4 ; " 70 "mul %5 ; " 71 "xor %5,%5 ; " 72 "add %4,%%eax ; " 73 "adc %5,%%edx ; " 74 : "=A" (product), "=r" (tmp1), "=r" (tmp2) 75 : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) ); 76 #elif defined(__x86_64__) 77 __asm__ ( 78 "mulq %[mul_frac] ; shrd $32, %[hi], %[lo]" 79 : [lo]"=a"(product), 80 [hi]"=d"(tmp) 81 : "0"(delta), 82 [mul_frac]"rm"((u64)mul_frac)); 83 #else 84 #error implement me! 85 #endif 86 87 return product; 88 } 89 90 static __always_inline 91 u64 __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src, u64 tsc) 92 { 93 u64 delta = tsc - src->tsc_timestamp; 94 u64 offset = pvclock_scale_delta(delta, src->tsc_to_system_mul, 95 src->tsc_shift); 96 return src->system_time + offset; 97 } 98 99 struct pvclock_vsyscall_time_info { 100 struct pvclock_vcpu_time_info pvti; 101 } __attribute__((__aligned__(SMP_CACHE_BYTES))); 102 103 #define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info) 104 105 #endif /* _ASM_X86_PVCLOCK_H */ 106