diff options
author | Vadim Rozenfeld <vrozenfe@redhat.com> | 2014-01-16 04:18:37 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-01-17 04:22:08 -0500 |
commit | e984097b553ed2d6551c805223e4057421370f00 (patch) | |
tree | 8bc58542fbd9680ee70ea83174ea092aa1baf8ad | |
parent | aab6d7ce37cf20753a336dc74473cf8a8aefa7c0 (diff) |
add support for Hyper-V reference time counter
Signed-off: Peter Lieven <pl@kamp.de>
Signed-off: Gleb Natapov
Signed-off: Vadim Rozenfeld <vrozenfe@redhat.com>
After some consideration I decided to submit only Hyper-V reference
counters support this time. I will submit iTSC support as a separate
patch as soon as it is ready.
v1 -> v2
1. mark TSC page dirty as suggested by
Eric Northup <digitaleric@google.com> and Gleb
2. disable local irq when calling get_kernel_ns,
as it was done by Peter Lieven <pl@amp.de>
3. move check for TSC page enable from second patch
to this one.
v3 -> v4
Get rid of ref counter offset.
v4 -> v5
replace __copy_to_user with kvm_write_guest
when updateing iTSC page.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/x86/include/uapi/asm/hyperv.h | 13 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 28 | ||||
-rw-r--r-- | include/uapi/linux/kvm.h | 1 |
4 files changed, 42 insertions, 1 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index ae5d7830855c..33fef0738a29 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -605,6 +605,7 @@ struct kvm_arch { | |||
605 | /* fields used by HYPER-V emulation */ | 605 | /* fields used by HYPER-V emulation */ |
606 | u64 hv_guest_os_id; | 606 | u64 hv_guest_os_id; |
607 | u64 hv_hypercall; | 607 | u64 hv_hypercall; |
608 | u64 hv_tsc_page; | ||
608 | 609 | ||
609 | #ifdef CONFIG_KVM_MMU_AUDIT | 610 | #ifdef CONFIG_KVM_MMU_AUDIT |
610 | int audit_point; | 611 | int audit_point; |
diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index b8f1c0176cbc..462efe746d77 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h | |||
@@ -28,6 +28,9 @@ | |||
28 | /* Partition Reference Counter (HV_X64_MSR_TIME_REF_COUNT) available*/ | 28 | /* Partition Reference Counter (HV_X64_MSR_TIME_REF_COUNT) available*/ |
29 | #define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1) | 29 | #define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1) |
30 | 30 | ||
31 | /* A partition's reference time stamp counter (TSC) page */ | ||
32 | #define HV_X64_MSR_REFERENCE_TSC 0x40000021 | ||
33 | |||
31 | /* | 34 | /* |
32 | * There is a single feature flag that signifies the presence of the MSR | 35 | * There is a single feature flag that signifies the presence of the MSR |
33 | * that can be used to retrieve both the local APIC Timer frequency as | 36 | * that can be used to retrieve both the local APIC Timer frequency as |
@@ -198,6 +201,9 @@ | |||
198 | #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_MASK \ | 201 | #define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_MASK \ |
199 | (~((1ull << HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT) - 1)) | 202 | (~((1ull << HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT) - 1)) |
200 | 203 | ||
204 | #define HV_X64_MSR_TSC_REFERENCE_ENABLE 0x00000001 | ||
205 | #define HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT 12 | ||
206 | |||
201 | #define HV_PROCESSOR_POWER_STATE_C0 0 | 207 | #define HV_PROCESSOR_POWER_STATE_C0 0 |
202 | #define HV_PROCESSOR_POWER_STATE_C1 1 | 208 | #define HV_PROCESSOR_POWER_STATE_C1 1 |
203 | #define HV_PROCESSOR_POWER_STATE_C2 2 | 209 | #define HV_PROCESSOR_POWER_STATE_C2 2 |
@@ -210,4 +216,11 @@ | |||
210 | #define HV_STATUS_INVALID_ALIGNMENT 4 | 216 | #define HV_STATUS_INVALID_ALIGNMENT 4 |
211 | #define HV_STATUS_INSUFFICIENT_BUFFERS 19 | 217 | #define HV_STATUS_INSUFFICIENT_BUFFERS 19 |
212 | 218 | ||
219 | typedef struct _HV_REFERENCE_TSC_PAGE { | ||
220 | __u32 tsc_sequence; | ||
221 | __u32 res1; | ||
222 | __u64 tsc_scale; | ||
223 | __s64 tsc_offset; | ||
224 | } HV_REFERENCE_TSC_PAGE, *PHV_REFERENCE_TSC_PAGE; | ||
225 | |||
213 | #endif | 226 | #endif |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0fbdced78737..0b3fd809a3c7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -839,11 +839,12 @@ EXPORT_SYMBOL_GPL(kvm_rdpmc); | |||
839 | * kvm-specific. Those are put in the beginning of the list. | 839 | * kvm-specific. Those are put in the beginning of the list. |
840 | */ | 840 | */ |
841 | 841 | ||
842 | #define KVM_SAVE_MSRS_BEGIN 10 | 842 | #define KVM_SAVE_MSRS_BEGIN 12 |
843 | static u32 msrs_to_save[] = { | 843 | static u32 msrs_to_save[] = { |
844 | MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, | 844 | MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, |
845 | MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW, | 845 | MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW, |
846 | HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL, | 846 | HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL, |
847 | HV_X64_MSR_TIME_REF_COUNT, HV_X64_MSR_REFERENCE_TSC, | ||
847 | HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME, | 848 | HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME, |
848 | MSR_KVM_PV_EOI_EN, | 849 | MSR_KVM_PV_EOI_EN, |
849 | MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, | 850 | MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, |
@@ -1788,6 +1789,8 @@ static bool kvm_hv_msr_partition_wide(u32 msr) | |||
1788 | switch (msr) { | 1789 | switch (msr) { |
1789 | case HV_X64_MSR_GUEST_OS_ID: | 1790 | case HV_X64_MSR_GUEST_OS_ID: |
1790 | case HV_X64_MSR_HYPERCALL: | 1791 | case HV_X64_MSR_HYPERCALL: |
1792 | case HV_X64_MSR_REFERENCE_TSC: | ||
1793 | case HV_X64_MSR_TIME_REF_COUNT: | ||
1791 | r = true; | 1794 | r = true; |
1792 | break; | 1795 | break; |
1793 | } | 1796 | } |
@@ -1829,6 +1832,20 @@ static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data) | |||
1829 | kvm->arch.hv_hypercall = data; | 1832 | kvm->arch.hv_hypercall = data; |
1830 | break; | 1833 | break; |
1831 | } | 1834 | } |
1835 | case HV_X64_MSR_REFERENCE_TSC: { | ||
1836 | u64 gfn; | ||
1837 | HV_REFERENCE_TSC_PAGE tsc_ref; | ||
1838 | memset(&tsc_ref, 0, sizeof(tsc_ref)); | ||
1839 | kvm->arch.hv_tsc_page = data; | ||
1840 | if (!(data & HV_X64_MSR_TSC_REFERENCE_ENABLE)) | ||
1841 | break; | ||
1842 | gfn = data >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT; | ||
1843 | if (kvm_write_guest(kvm, data, | ||
1844 | &tsc_ref, sizeof(tsc_ref))) | ||
1845 | return 1; | ||
1846 | mark_page_dirty(kvm, gfn); | ||
1847 | break; | ||
1848 | } | ||
1832 | default: | 1849 | default: |
1833 | vcpu_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x " | 1850 | vcpu_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x " |
1834 | "data 0x%llx\n", msr, data); | 1851 | "data 0x%llx\n", msr, data); |
@@ -2253,6 +2270,14 @@ static int get_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) | |||
2253 | case HV_X64_MSR_HYPERCALL: | 2270 | case HV_X64_MSR_HYPERCALL: |
2254 | data = kvm->arch.hv_hypercall; | 2271 | data = kvm->arch.hv_hypercall; |
2255 | break; | 2272 | break; |
2273 | case HV_X64_MSR_TIME_REF_COUNT: { | ||
2274 | data = | ||
2275 | div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100); | ||
2276 | break; | ||
2277 | } | ||
2278 | case HV_X64_MSR_REFERENCE_TSC: | ||
2279 | data = kvm->arch.hv_tsc_page; | ||
2280 | break; | ||
2256 | default: | 2281 | default: |
2257 | vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr); | 2282 | vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr); |
2258 | return 1; | 2283 | return 1; |
@@ -2566,6 +2591,7 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
2566 | #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT | 2591 | #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT |
2567 | case KVM_CAP_ASSIGN_DEV_IRQ: | 2592 | case KVM_CAP_ASSIGN_DEV_IRQ: |
2568 | case KVM_CAP_PCI_2_3: | 2593 | case KVM_CAP_PCI_2_3: |
2594 | case KVM_CAP_HYPERV_TIME: | ||
2569 | #endif | 2595 | #endif |
2570 | r = 1; | 2596 | r = 1; |
2571 | break; | 2597 | break; |
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index b647c2917391..932d7f2637d6 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h | |||
@@ -674,6 +674,7 @@ struct kvm_ppc_smmu_info { | |||
674 | #define KVM_CAP_ARM_EL1_32BIT 93 | 674 | #define KVM_CAP_ARM_EL1_32BIT 93 |
675 | #define KVM_CAP_SPAPR_MULTITCE 94 | 675 | #define KVM_CAP_SPAPR_MULTITCE 94 |
676 | #define KVM_CAP_EXT_EMUL_CPUID 95 | 676 | #define KVM_CAP_EXT_EMUL_CPUID 95 |
677 | #define KVM_CAP_HYPERV_TIME 96 | ||
677 | 678 | ||
678 | #ifdef KVM_CAP_IRQ_ROUTING | 679 | #ifdef KVM_CAP_IRQ_ROUTING |
679 | 680 | ||