diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2011-03-25 04:44:51 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-05-11 07:57:06 -0400 |
commit | 92a1f12d2598f429bd8639e21d89305e787115c5 (patch) | |
tree | 48a6b7d6c50b5583b5163185dd097db100a471c6 | |
parent | 857e40999e35906baa367a79137019912cfb5434 (diff) |
KVM: X86: Implement userspace interface to set virtual_tsc_khz
This patch implements two new vm-ioctls to get and set the
virtual_tsc_khz if the machine supports tsc-scaling. Setting
the tsc-frequency is only possible before userspace creates
any vcpu.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | Documentation/kvm/api.txt | 23 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 7 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 20 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 35 | ||||
-rw-r--r-- | include/linux/kvm.h | 5 |
5 files changed, 90 insertions, 0 deletions
diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt index 9bef4e4cec50..1b9eaa7e8856 100644 --- a/Documentation/kvm/api.txt +++ b/Documentation/kvm/api.txt | |||
@@ -1263,6 +1263,29 @@ struct kvm_assigned_msix_entry { | |||
1263 | __u16 padding[3]; | 1263 | __u16 padding[3]; |
1264 | }; | 1264 | }; |
1265 | 1265 | ||
1266 | 4.54 KVM_SET_TSC_KHZ | ||
1267 | |||
1268 | Capability: KVM_CAP_TSC_CONTROL | ||
1269 | Architectures: x86 | ||
1270 | Type: vcpu ioctl | ||
1271 | Parameters: virtual tsc_khz | ||
1272 | Returns: 0 on success, -1 on error | ||
1273 | |||
1274 | Specifies the tsc frequency for the virtual machine. The unit of the | ||
1275 | frequency is KHz. | ||
1276 | |||
1277 | 4.55 KVM_GET_TSC_KHZ | ||
1278 | |||
1279 | Capability: KVM_CAP_GET_TSC_KHZ | ||
1280 | Architectures: x86 | ||
1281 | Type: vcpu ioctl | ||
1282 | Parameters: none | ||
1283 | Returns: virtual tsc-khz on success, negative value on error | ||
1284 | |||
1285 | Returns the tsc frequency of the guest. The unit of the return value is | ||
1286 | KHz. If the host has unstable tsc this ioctl returns -EIO instead as an | ||
1287 | error. | ||
1288 | |||
1266 | 5. The kvm_run structure | 1289 | 5. The kvm_run structure |
1267 | 1290 | ||
1268 | Application code obtains a pointer to the kvm_run structure by | 1291 | Application code obtains a pointer to the kvm_run structure by |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index da0a8ce3a139..bd57639fd5db 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -655,6 +655,13 @@ u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn); | |||
655 | 655 | ||
656 | extern bool tdp_enabled; | 656 | extern bool tdp_enabled; |
657 | 657 | ||
658 | /* control of guest tsc rate supported? */ | ||
659 | extern bool kvm_has_tsc_control; | ||
660 | /* minimum supported tsc_khz for guests */ | ||
661 | extern u32 kvm_min_guest_tsc_khz; | ||
662 | /* maximum supported tsc_khz for guests */ | ||
663 | extern u32 kvm_max_guest_tsc_khz; | ||
664 | |||
658 | enum emulation_result { | 665 | enum emulation_result { |
659 | EMULATE_DONE, /* no further processing */ | 666 | EMULATE_DONE, /* no further processing */ |
660 | EMULATE_DO_MMIO, /* kvm_run filled with mmio request */ | 667 | EMULATE_DO_MMIO, /* kvm_run filled with mmio request */ |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 8c4549bef4ed..a98873762433 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -64,6 +64,8 @@ MODULE_LICENSE("GPL"); | |||
64 | #define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) | 64 | #define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) |
65 | 65 | ||
66 | #define TSC_RATIO_RSVD 0xffffff0000000000ULL | 66 | #define TSC_RATIO_RSVD 0xffffff0000000000ULL |
67 | #define TSC_RATIO_MIN 0x0000000000000001ULL | ||
68 | #define TSC_RATIO_MAX 0x000000ffffffffffULL | ||
67 | 69 | ||
68 | static bool erratum_383_found __read_mostly; | 70 | static bool erratum_383_found __read_mostly; |
69 | 71 | ||
@@ -189,6 +191,7 @@ static int nested_svm_intercept(struct vcpu_svm *svm); | |||
189 | static int nested_svm_vmexit(struct vcpu_svm *svm); | 191 | static int nested_svm_vmexit(struct vcpu_svm *svm); |
190 | static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr, | 192 | static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr, |
191 | bool has_error_code, u32 error_code); | 193 | bool has_error_code, u32 error_code); |
194 | static u64 __scale_tsc(u64 ratio, u64 tsc); | ||
192 | 195 | ||
193 | enum { | 196 | enum { |
194 | VMCB_INTERCEPTS, /* Intercept vectors, TSC offset, | 197 | VMCB_INTERCEPTS, /* Intercept vectors, TSC offset, |
@@ -798,6 +801,23 @@ static __init int svm_hardware_setup(void) | |||
798 | if (boot_cpu_has(X86_FEATURE_FXSR_OPT)) | 801 | if (boot_cpu_has(X86_FEATURE_FXSR_OPT)) |
799 | kvm_enable_efer_bits(EFER_FFXSR); | 802 | kvm_enable_efer_bits(EFER_FFXSR); |
800 | 803 | ||
804 | if (boot_cpu_has(X86_FEATURE_TSCRATEMSR)) { | ||
805 | u64 max; | ||
806 | |||
807 | kvm_has_tsc_control = true; | ||
808 | |||
809 | /* | ||
810 | * Make sure the user can only configure tsc_khz values that | ||
811 | * fit into a signed integer. | ||
812 | * A min value is not calculated needed because it will always | ||
813 | * be 1 on all machines and a value of 0 is used to disable | ||
814 | * tsc-scaling for the vcpu. | ||
815 | */ | ||
816 | max = min(0x7fffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX)); | ||
817 | |||
818 | kvm_max_guest_tsc_khz = max; | ||
819 | } | ||
820 | |||
801 | if (nested) { | 821 | if (nested) { |
802 | printk(KERN_INFO "kvm: Nested Virtualization enabled\n"); | 822 | printk(KERN_INFO "kvm: Nested Virtualization enabled\n"); |
803 | kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE); | 823 | kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE); |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 579ce34e7904..1d5a7f418795 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -87,6 +87,11 @@ EXPORT_SYMBOL_GPL(kvm_x86_ops); | |||
87 | int ignore_msrs = 0; | 87 | int ignore_msrs = 0; |
88 | module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR); | 88 | module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR); |
89 | 89 | ||
90 | bool kvm_has_tsc_control; | ||
91 | EXPORT_SYMBOL_GPL(kvm_has_tsc_control); | ||
92 | u32 kvm_max_guest_tsc_khz; | ||
93 | EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz); | ||
94 | |||
90 | #define KVM_NR_SHARED_MSRS 16 | 95 | #define KVM_NR_SHARED_MSRS 16 |
91 | 96 | ||
92 | struct kvm_shared_msrs_global { | 97 | struct kvm_shared_msrs_global { |
@@ -1986,6 +1991,7 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
1986 | case KVM_CAP_X86_ROBUST_SINGLESTEP: | 1991 | case KVM_CAP_X86_ROBUST_SINGLESTEP: |
1987 | case KVM_CAP_XSAVE: | 1992 | case KVM_CAP_XSAVE: |
1988 | case KVM_CAP_ASYNC_PF: | 1993 | case KVM_CAP_ASYNC_PF: |
1994 | case KVM_CAP_GET_TSC_KHZ: | ||
1989 | r = 1; | 1995 | r = 1; |
1990 | break; | 1996 | break; |
1991 | case KVM_CAP_COALESCED_MMIO: | 1997 | case KVM_CAP_COALESCED_MMIO: |
@@ -2012,6 +2018,9 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
2012 | case KVM_CAP_XCRS: | 2018 | case KVM_CAP_XCRS: |
2013 | r = cpu_has_xsave; | 2019 | r = cpu_has_xsave; |
2014 | break; | 2020 | break; |
2021 | case KVM_CAP_TSC_CONTROL: | ||
2022 | r = kvm_has_tsc_control; | ||
2023 | break; | ||
2015 | default: | 2024 | default: |
2016 | r = 0; | 2025 | r = 0; |
2017 | break; | 2026 | break; |
@@ -3045,6 +3054,32 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | |||
3045 | r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, u.xcrs); | 3054 | r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, u.xcrs); |
3046 | break; | 3055 | break; |
3047 | } | 3056 | } |
3057 | case KVM_SET_TSC_KHZ: { | ||
3058 | u32 user_tsc_khz; | ||
3059 | |||
3060 | r = -EINVAL; | ||
3061 | if (!kvm_has_tsc_control) | ||
3062 | break; | ||
3063 | |||
3064 | user_tsc_khz = (u32)arg; | ||
3065 | |||
3066 | if (user_tsc_khz >= kvm_max_guest_tsc_khz) | ||
3067 | goto out; | ||
3068 | |||
3069 | kvm_x86_ops->set_tsc_khz(vcpu, user_tsc_khz); | ||
3070 | |||
3071 | r = 0; | ||
3072 | goto out; | ||
3073 | } | ||
3074 | case KVM_GET_TSC_KHZ: { | ||
3075 | r = -EIO; | ||
3076 | if (check_tsc_unstable()) | ||
3077 | goto out; | ||
3078 | |||
3079 | r = vcpu_tsc_khz(vcpu); | ||
3080 | |||
3081 | goto out; | ||
3082 | } | ||
3048 | default: | 3083 | default: |
3049 | r = -EINVAL; | 3084 | r = -EINVAL; |
3050 | } | 3085 | } |
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index ea2dc1a2e13d..2f63ebeac639 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -541,6 +541,8 @@ struct kvm_ppc_pvinfo { | |||
541 | #define KVM_CAP_PPC_GET_PVINFO 57 | 541 | #define KVM_CAP_PPC_GET_PVINFO 57 |
542 | #define KVM_CAP_PPC_IRQ_LEVEL 58 | 542 | #define KVM_CAP_PPC_IRQ_LEVEL 58 |
543 | #define KVM_CAP_ASYNC_PF 59 | 543 | #define KVM_CAP_ASYNC_PF 59 |
544 | #define KVM_CAP_TSC_CONTROL 60 | ||
545 | #define KVM_CAP_GET_TSC_KHZ 61 | ||
544 | 546 | ||
545 | #ifdef KVM_CAP_IRQ_ROUTING | 547 | #ifdef KVM_CAP_IRQ_ROUTING |
546 | 548 | ||
@@ -677,6 +679,9 @@ struct kvm_clock_data { | |||
677 | #define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2) | 679 | #define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2) |
678 | /* Available with KVM_CAP_PPC_GET_PVINFO */ | 680 | /* Available with KVM_CAP_PPC_GET_PVINFO */ |
679 | #define KVM_PPC_GET_PVINFO _IOW(KVMIO, 0xa1, struct kvm_ppc_pvinfo) | 681 | #define KVM_PPC_GET_PVINFO _IOW(KVMIO, 0xa1, struct kvm_ppc_pvinfo) |
682 | /* Available with KVM_CAP_TSC_CONTROL */ | ||
683 | #define KVM_SET_TSC_KHZ _IO(KVMIO, 0xa2) | ||
684 | #define KVM_GET_TSC_KHZ _IO(KVMIO, 0xa3) | ||
680 | 685 | ||
681 | /* | 686 | /* |
682 | * ioctls for vcpu fds | 687 | * ioctls for vcpu fds |