Newer
Older
class kvmclock : public clock {
private:
struct pvclock_wall_clock {
u32 version;
u32 sec;
u32 nsec;
} __attribute__((__packed__));
struct pvclock_vcpu_time_info {
u32 version;
u32 pad0;
u64 tsc_timestamp;
u64 system_time;
u32 tsc_to_system_mul;
s8 tsc_shift;
u8 flags;
u8 pad[2];
} __attribute__((__packed__)); /* 32 bytes */
public:
kvmclock();
virtual u64 time();
private:
u64 wall_clock_boot();
u64 system_time();
private:
pvclock_wall_clock* _wall;
pvclock_vcpu_time_info* _sys; // FIXME: make percpu
_wall = new kvmclock::pvclock_wall_clock;
_sys = new kvmclock::pvclock_vcpu_time_info;
memset(_wall, 0, sizeof(_wall));
memset(_sys, 0, sizeof(_sys));
processor::wrmsr(msr::KVM_WALL_CLOCK_NEW, mmu::virt_to_phys(_wall));
processor::wrmsr(msr::KVM_SYSTEM_TIME_NEW, mmu::virt_to_phys(_sys) | 1);
}
u64 kvmclock::time()
{
// FIXME: disable interrupts
return wall_clock_boot() + system_time();
}
u64 kvmclock::wall_clock_boot()
{
u32 v1, v2;
u64 w;
do {
w = u64(_wall->sec) * 1000000000 + _wall->nsec;
} while (v1 != v2);
return w;
}
u64 kvmclock::system_time()
{
u32 v1, v2;
u64 time;
do {
time = processor::rdtsc() - _sys->tsc_timestamp;
if (_sys->tsc_shift >= 0) {
time <<= _sys->tsc_shift;
}
asm("mul %1; shrd $32, %%rdx, %0"
: "+a"(time)
: "rm"(u64(_sys->tsc_to_system_mul))