Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/include/pvclock.h
Show All 23 Lines | |||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
* | * | ||||
* $FreeBSD$ | * $FreeBSD$ | ||||
*/ | */ | ||||
#ifndef X86_PVCLOCK | #ifndef X86_PVCLOCK | ||||
#define X86_PVCLOCK | #define X86_PVCLOCK | ||||
#ifdef _KERNEL | |||||
#include <sys/timetc.h> | |||||
#endif /* _KERNEL */ | |||||
#define PVCLOCK_CDEVNAME "pvclock" | |||||
struct pvclock_vcpu_time_info { | struct pvclock_vcpu_time_info { | ||||
uint32_t version; | uint32_t version; | ||||
uint32_t pad0; | uint32_t pad0; | ||||
uint64_t tsc_timestamp; | uint64_t tsc_timestamp; | ||||
uint64_t system_time; | uint64_t system_time; | ||||
uint32_t tsc_to_system_mul; | uint32_t tsc_to_system_mul; | ||||
int8_t tsc_shift; | int8_t tsc_shift; | ||||
uint8_t flags; | uint8_t flags; | ||||
uint8_t pad[2]; | uint8_t pad[2]; | ||||
}; | }; | ||||
#define PVCLOCK_FLAG_TSC_STABLE 0x01 | #define PVCLOCK_FLAG_TSC_STABLE 0x01 | ||||
#define PVCLOCK_FLAG_GUEST_PASUED 0x02 | #define PVCLOCK_FLAG_GUEST_PASUED 0x02 | ||||
/* | |||||
* Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, | |||||
* yielding a 64-bit result. | |||||
*/ | |||||
static inline uint64_t | |||||
pvclock_scale_delta(uint64_t delta, uint32_t mul_frac, int shift) | |||||
{ | |||||
uint64_t product; | |||||
if (shift < 0) | |||||
delta >>= -shift; | |||||
else | |||||
delta <<= shift; | |||||
#if defined(__i386__) | |||||
{ | |||||
uint32_t tmp1, tmp2; | |||||
/** | |||||
* For i386, the formula looks like: | |||||
* | |||||
* lower = (mul_frac * (delta & UINT_MAX)) >> 32 | |||||
* upper = mul_frac * (delta >> 32) | |||||
* product = lower + upper | |||||
*/ | |||||
__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" ((uint32_t)delta), "1" ((uint32_t)(delta >> 32)), | |||||
"2" (mul_frac) ); | |||||
} | |||||
#elif defined(__amd64__) | |||||
{ | |||||
unsigned long tmp; | |||||
__asm__ ( | |||||
"mulq %[mul_frac] ; shrd $32, %[hi], %[lo]" | |||||
: [lo]"=a" (product), [hi]"=d" (tmp) | |||||
: "0" (delta), [mul_frac]"rm"((uint64_t)mul_frac)); | |||||
} | |||||
#else | |||||
#error "pvclock: unsupported x86 architecture?" | |||||
#endif | |||||
return (product); | |||||
} | |||||
static inline uint64_t | |||||
pvclock_get_nsec_offset(struct pvclock_vcpu_time_info *ti) | |||||
{ | |||||
uint64_t delta; | |||||
delta = rdtsc() - ti->tsc_timestamp; | |||||
return (pvclock_scale_delta(delta, ti->tsc_to_system_mul, | |||||
ti->tsc_shift)); | |||||
} | |||||
static inline void | |||||
pvclock_read_time_info(struct pvclock_vcpu_time_info *ti, | |||||
uint64_t *ns, uint8_t *flags) | |||||
{ | |||||
uint32_t version; | |||||
do { | |||||
version = ti->version; | |||||
rmb(); | |||||
*ns = ti->system_time + pvclock_get_nsec_offset(ti); | |||||
*flags = ti->flags; | |||||
rmb(); | |||||
} while ((ti->version & 1) != 0 || ti->version != version); | |||||
} | |||||
#ifdef _KERNEL | |||||
typedef struct pvclock_vcpu_time_info *pvclock_get_curcpu_timeinfo_t(void *arg); | |||||
typedef struct pvclock_wall_clock *pvclock_get_wallclock_t(void *arg); | |||||
struct pvclock_wall_clock { | struct pvclock_wall_clock { | ||||
uint32_t version; | uint32_t version; | ||||
uint32_t sec; | uint32_t sec; | ||||
uint32_t nsec; | uint32_t nsec; | ||||
}; | }; | ||||
struct pvclock { | |||||
/* Public; initialized by the caller of 'pvclock_init()': */ | |||||
pvclock_get_curcpu_timeinfo_t *get_curcpu_ti; | |||||
void *get_curcpu_ti_arg; | |||||
pvclock_get_wallclock_t *get_wallclock; | |||||
void *get_wallclock_arg; | |||||
struct pvclock_vcpu_time_info *ti_vcpu0_page; | |||||
bool stable_flag_supported; | |||||
/* Private; initialized by the 'pvclock' API: */ | |||||
struct timecounter tc; | |||||
struct cdev *cdev; | |||||
}; | |||||
void pvclock_resume(void); | void pvclock_resume(void); | ||||
uint64_t pvclock_get_last_cycles(void); | uint64_t pvclock_get_last_cycles(void); | ||||
uint64_t pvclock_tsc_freq(struct pvclock_vcpu_time_info *ti); | uint64_t pvclock_tsc_freq(struct pvclock_vcpu_time_info *ti); | ||||
uint64_t pvclock_get_timecount(struct pvclock_vcpu_time_info *ti); | uint64_t pvclock_get_timecount(struct pvclock_vcpu_time_info *ti); | ||||
void pvclock_get_wallclock(struct pvclock_wall_clock *wc, | void pvclock_get_wallclock(struct pvclock_wall_clock *wc, | ||||
struct timespec *ts); | struct timespec *ts); | ||||
void pvclock_init(struct pvclock *pvc, device_t dev, | |||||
const char *tc_name, int tc_quality, u_int tc_flags); | |||||
void pvclock_gettime(struct pvclock *pvc, struct timespec *ts); | |||||
int pvclock_destroy(struct pvclock *pvc); | |||||
#endif /* _KERNEL */ | |||||
#endif | #endif |