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));
static bool probe();
private:
u64 wall_clock_boot();
u64 system_time();
static bool _new_kvmclock_msrs;
u64 _wall_ns;
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));
_wall_ns = wall_clock_boot();
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_ns;
// Due to problems in init order dependencies (the clock depends
// on the scheduler, for percpu initialization, and vice-versa, for
// idle thread initialization, don't loop up system time until at least
// one cpu is initialized.
if (_smp_init) {
r += system_time();
}
return r;
return pvclock::wall_clock_boot(_wall);
auto sys = &*_sys; // avoid recaclulating address each access
auto r = pvclock::system_time(sys);
static __attribute__((constructor(init_prio::clock))) void setup_kvmclock()
if (kvmclock::probe()) {