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