mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-27 06:34:11 +08:00
e27c49291a
The x86 platform operations are fairly isolated, so it's easy to change them from using timespec to timespec64. It has been checked that all the users and callers are safe, and there is only one critical function that is broken beyond 2106: pvclock_read_wallclock() uses a 32-bit number of seconds since the epoch to communicate the boot time between host and guest in a virtual environment. This will work until 2106, but fixing this is outside the scope of this change, Add a comment at least. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Acked-by: Radim Krčmář <rkrcmar@redhat.com> Acked-by: Jan Kiszka <jan.kiszka@siemens.com> Cc: Juergen Gross <jgross@suse.com> Cc: jailhouse-dev@googlegroups.com Cc: Borislav Petkov <bp@suse.de> Cc: kvm@vger.kernel.org Cc: y2038@lists.linaro.org Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com> Cc: xen-devel@lists.xenproject.org Cc: John Stultz <john.stultz@linaro.org> Cc: Andy Lutomirski <luto@kernel.org> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Joao Martins <joao.m.martins@oracle.com> Link: https://lkml.kernel.org/r/20180427201435.3194219-1-arnd@arndb.de
107 lines
2.6 KiB
C
107 lines
2.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _ASM_X86_PVCLOCK_H
|
|
#define _ASM_X86_PVCLOCK_H
|
|
|
|
#include <linux/clocksource.h>
|
|
#include <asm/pvclock-abi.h>
|
|
|
|
/* some helper functions for xen and kvm pv clock sources */
|
|
u64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src);
|
|
u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src);
|
|
void pvclock_set_flags(u8 flags);
|
|
unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src);
|
|
void pvclock_read_wallclock(struct pvclock_wall_clock *wall,
|
|
struct pvclock_vcpu_time_info *vcpu,
|
|
struct timespec64 *ts);
|
|
void pvclock_resume(void);
|
|
|
|
void pvclock_touch_watchdogs(void);
|
|
|
|
static __always_inline
|
|
unsigned pvclock_read_begin(const struct pvclock_vcpu_time_info *src)
|
|
{
|
|
unsigned version = src->version & ~1;
|
|
/* Make sure that the version is read before the data. */
|
|
virt_rmb();
|
|
return version;
|
|
}
|
|
|
|
static __always_inline
|
|
bool pvclock_read_retry(const struct pvclock_vcpu_time_info *src,
|
|
unsigned version)
|
|
{
|
|
/* Make sure that the version is re-read after the data. */
|
|
virt_rmb();
|
|
return unlikely(version != src->version);
|
|
}
|
|
|
|
/*
|
|
* Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
|
|
* yielding a 64-bit result.
|
|
*/
|
|
static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift)
|
|
{
|
|
u64 product;
|
|
#ifdef __i386__
|
|
u32 tmp1, tmp2;
|
|
#else
|
|
ulong tmp;
|
|
#endif
|
|
|
|
if (shift < 0)
|
|
delta >>= -shift;
|
|
else
|
|
delta <<= shift;
|
|
|
|
#ifdef __i386__
|
|
__asm__ (
|
|
"mul %5 ; "
|
|
"mov %4,%%eax ; "
|
|
"mov %%edx,%4 ; "
|
|
"mul %5 ; "
|
|
"xor %5,%5 ; "
|
|
"add %4,%%eax ; "
|
|
"adc %5,%%edx ; "
|
|
: "=A" (product), "=r" (tmp1), "=r" (tmp2)
|
|
: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
|
|
#elif defined(__x86_64__)
|
|
__asm__ (
|
|
"mulq %[mul_frac] ; shrd $32, %[hi], %[lo]"
|
|
: [lo]"=a"(product),
|
|
[hi]"=d"(tmp)
|
|
: "0"(delta),
|
|
[mul_frac]"rm"((u64)mul_frac));
|
|
#else
|
|
#error implement me!
|
|
#endif
|
|
|
|
return product;
|
|
}
|
|
|
|
static __always_inline
|
|
u64 __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src, u64 tsc)
|
|
{
|
|
u64 delta = tsc - src->tsc_timestamp;
|
|
u64 offset = pvclock_scale_delta(delta, src->tsc_to_system_mul,
|
|
src->tsc_shift);
|
|
return src->system_time + offset;
|
|
}
|
|
|
|
struct pvclock_vsyscall_time_info {
|
|
struct pvclock_vcpu_time_info pvti;
|
|
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
|
|
|
|
#define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info)
|
|
|
|
#ifdef CONFIG_PARAVIRT_CLOCK
|
|
void pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti);
|
|
struct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void);
|
|
#else
|
|
static inline struct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void)
|
|
{
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
#endif /* _ASM_X86_PVCLOCK_H */
|