Regards, Anthony Liguori
Subject: [PATCH] KVM: paravirt time source Author: Anthony Liguori <aliguori@xxxxxxxxxx> This is a paravirt time source for KVM based on Ingo Molnars similar patch. A very different patch will probably be needed that takes advantage of hrtimers but I have to learn a bit more about that first. Signed-off-by: Anthony Liguori <aliguori@xxxxxxxxxx> diff --git a/arch/i386/kernel/kvm.c b/arch/i386/kernel/kvm.c index 77c36f4..25fb2c1 100644 --- a/arch/i386/kernel/kvm.c +++ b/arch/i386/kernel/kvm.c @@ -26,6 +26,16 @@ #include <linux/cpu.h> #include <linux/mm.h> +#include <linux/clocksource.h> +#include <linux/workqueue.h> +#include <linux/cpufreq.h> +#include <linux/jiffies.h> +#include <linux/init.h> +#include <linux/dmi.h> +#include <linux/acpi_pmtmr.h> + +#include "mach_timer.h" + #define CR0_TS_MASK (1ULL << 3) struct kvm_paravirt_state @@ -48,6 +58,7 @@ static int do_hypercall_batching; static int do_mmu_write; static int do_cr_read_caching; static int do_nop_io_delay; +static int do_paravirt_clock; static u64 msr_set_vmca; static long _kvm_hypercall(struct kvm_paravirt_state *state, @@ -120,6 +131,27 @@ static long kvm_hypercall(unsigned int nr, unsigned long p1, return ret; } +static cycle_t read_hyper(void) +{ + struct timespec now; + int ret; + + ret = kvm_hypercall(KVM_HYPERCALL_GET_KTIME, (u32)&now, 0, 0, 0); + WARN_ON(ret); + + return now.tv_nsec + now.tv_sec * (cycles_t)1e9; +} + +static struct clocksource clocksource_hyper = { + .name = "hyper", + .rating = 200, + .read = read_hyper, + .mask = CLOCKSOURCE_MASK(64), + .mult = 1, + .shift = 0, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + /* * No need for any "IO delay" on KVM */ @@ -317,6 +349,14 @@ static void kvm_paravirt_ops_setup(void) if (do_hypercall_batching) paravirt_ops.set_lazy_mode = kvm_set_lazy_mode; + if (do_paravirt_clock) { + int err; + + err = clocksource_register(&clocksource_hyper); + WARN_ON(err); + printk(KERN_INFO "KVM: using paravirt clock source\n"); + } + paravirt_ops.paravirt_enabled = 1; apply_paravirt(__parainstructions, __parainstructions_end); @@ -364,6 +404,9 @@ static int kvm_paravirt_initialize(void) if ((edx & KVM_FEATURE_HYPERCALL_BATCHING)) do_hypercall_batching = 1; + if ((edx & KVM_FEATURE_PARAVIRT_CLOCK)) + do_paravirt_clock = 1; + on_each_cpu(kvm_paravirt_activate, NULL, 0, 1); return 0; diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 55711a0..b8a0811 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -44,6 +44,7 @@ #include <linux/cpumask.h> #include <linux/smp.h> #include <linux/kvm_para.h> +#include <linux/delay.h> #include "x86_emulate.h" #include "segment_descriptor.h" @@ -95,7 +96,7 @@ struct vfsmount *kvmfs_mnt; #define KVM_PARAVIRT_FEATURES \ (KVM_FEATURE_VMCA | KVM_FEATURE_NOP_IO_DELAY | \ KVM_FEATURE_CR_READ_CACHE | KVM_FEATURE_MMU_WRITE | \ - KVM_FEATURE_HYPERCALL_BATCHING) + KVM_FEATURE_HYPERCALL_BATCHING | KVM_FEATURE_PARAVIRT_CLOCK) #define KVM_MSR_SET_VMCA 0x87655678 @@ -1388,6 +1389,20 @@ static int kvm_hypercall_set_cr(struct kvm_vcpu *vcpu, return 0; } +static int kvm_hypercall_get_ktime(struct kvm_vcpu *vcpu, gva_t va) +{ + struct timespec now; + int ret; + + ktime_get_ts(&now); + + ret = kvm_write_guest(vcpu, va, sizeof(now), &now); + if (unlikely(ret)) + return -EFAULT; + + return 0; +} + static int dispatch_hypercall(struct kvm_vcpu *vcpu, unsigned long nr, unsigned long p1, unsigned long p2, unsigned long p3, unsigned long p4) @@ -1397,6 +1412,8 @@ static int dispatch_hypercall(struct kvm_vcpu *vcpu, unsigned long nr, return kvm_hypercall_mmu_write(vcpu, p1, p2, p3, p4); case KVM_HYPERCALL_SET_CR: return kvm_hypercall_set_cr(vcpu, p1, p2); + case KVM_HYPERCALL_GET_KTIME: + return kvm_hypercall_get_ktime(vcpu, p1); } return -ENOSYS; } diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h index 7dd0cef..9aed003 100644 --- a/include/linux/kvm_para.h +++ b/include/linux/kvm_para.h @@ -16,6 +16,7 @@ #define KVM_FEATURE_CR_READ_CACHE (1UL << 2) #define KVM_FEATURE_MMU_WRITE (1UL << 3) #define KVM_FEATURE_HYPERCALL_BATCHING (1UL << 4) +#define KVM_FEATURE_PARAVIRT_CLOCK (1UL << 5) struct kvm_vmca { @@ -48,5 +49,6 @@ struct kvm_hypercall_entry #define KVM_HYPERCALL_MMU_WRITE 0 #define KVM_HYPERCALL_SET_CR 1 #define KVM_HYPERCALL_FLUSH 2 +#define KVM_HYPERCALL_GET_KTIME 3 #endif
_______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/virtualization