Newer
Older
/*
* Copyright (C) 2013 Cloudius Systems, Ltd.
*
* This work is open source software, licensed under the terms of the
* BSD license as described in the LICENSE file in the top-level directory.
*/
#include <osv/pvclock-abi.hh>
class kvmclock : public clock {
public:
kvmclock();
virtual s64 time() __attribute__((no_instrument_function));
virtual s64 uptime() override __attribute__((no_instrument_function));
virtual s64 boot_time() override __attribute__((no_instrument_function));
virtual u64 processor_to_nano(u64 ticks) override __attribute__((no_instrument_function));
static bool probe();
static bool _new_kvmclock_msrs;
static percpu<pvclock_vcpu_time_info> _sys;
bool kvmclock::_new_kvmclock_msrs = true;
PERCPU(pvclock_vcpu_time_info, kvmclock::_sys);
auto wall_time_msr = (_new_kvmclock_msrs) ?
msr::KVM_WALL_CLOCK_NEW : msr::KVM_WALL_CLOCK;
_wall = new pvclock_wall_clock;
processor::wrmsr(wall_time_msr, mmu::virt_to_phys(_wall));
auto system_time_msr = (_new_kvmclock_msrs) ?
msr::KVM_SYSTEM_TIME_NEW : msr::KVM_SYSTEM_TIME;
processor::wrmsr(system_time_msr, mmu::virt_to_phys(&*_sys) | 1);
bool kvmclock::probe()
{
if (processor::features().kvm_clocksource2) {
return true;
if (processor::features().kvm_clocksource) {
_new_kvmclock_msrs = false;
auto r = wall_clock_boot();
// FIXME: during early boot, while _smp_init is still false, we don't
// add system_time() so we return the host's boot time instead of the
// current time. When _smp_init becomes true, the clock jumps forward
// to the correct current time.
// This happens due to problems in init order dependencies (the clock
// depends on the scheduler, for percpu initialization, and vice-versa,
// for idle thread initialization).
if (_smp_init) {
r += system_time();
}
return r;
s64 kvmclock::uptime()
{
if (_smp_init) {
return system_time() - _boot_systemtime;
} else {
return 0;
}
}
s64 kvmclock::boot_time()
{
// The following is time()-uptime():
auto r = wall_clock_boot();
if (_smp_init) {
r += _boot_systemtime;
}
return r;
}
return pvclock::wall_clock_boot(_wall);
auto sys = &*_sys; // avoid recaclulating address each access
auto r = pvclock::system_time(sys);
u64 kvmclock::processor_to_nano(u64 ticks)
{
return pvclock::processor_to_nano(&*_sys, ticks);
}
static __attribute__((constructor(init_prio::clock))) void setup_kvmclock()
if (kvmclock::probe()) {