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