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>
This commit is contained in:
@@ -1263,6 +1263,29 @@ struct kvm_assigned_msix_entry {
|
|||||||
__u16 padding[3];
|
__u16 padding[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
4.54 KVM_SET_TSC_KHZ
|
||||||
|
|
||||||
|
Capability: KVM_CAP_TSC_CONTROL
|
||||||
|
Architectures: x86
|
||||||
|
Type: vcpu ioctl
|
||||||
|
Parameters: virtual tsc_khz
|
||||||
|
Returns: 0 on success, -1 on error
|
||||||
|
|
||||||
|
Specifies the tsc frequency for the virtual machine. The unit of the
|
||||||
|
frequency is KHz.
|
||||||
|
|
||||||
|
4.55 KVM_GET_TSC_KHZ
|
||||||
|
|
||||||
|
Capability: KVM_CAP_GET_TSC_KHZ
|
||||||
|
Architectures: x86
|
||||||
|
Type: vcpu ioctl
|
||||||
|
Parameters: none
|
||||||
|
Returns: virtual tsc-khz on success, negative value on error
|
||||||
|
|
||||||
|
Returns the tsc frequency of the guest. The unit of the return value is
|
||||||
|
KHz. If the host has unstable tsc this ioctl returns -EIO instead as an
|
||||||
|
error.
|
||||||
|
|
||||||
5. The kvm_run structure
|
5. The kvm_run structure
|
||||||
|
|
||||||
Application code obtains a pointer to the kvm_run structure by
|
Application code obtains a pointer to the kvm_run structure by
|
||||||
|
@@ -655,6 +655,13 @@ u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn);
|
|||||||
|
|
||||||
extern bool tdp_enabled;
|
extern bool tdp_enabled;
|
||||||
|
|
||||||
|
/* control of guest tsc rate supported? */
|
||||||
|
extern bool kvm_has_tsc_control;
|
||||||
|
/* minimum supported tsc_khz for guests */
|
||||||
|
extern u32 kvm_min_guest_tsc_khz;
|
||||||
|
/* maximum supported tsc_khz for guests */
|
||||||
|
extern u32 kvm_max_guest_tsc_khz;
|
||||||
|
|
||||||
enum emulation_result {
|
enum emulation_result {
|
||||||
EMULATE_DONE, /* no further processing */
|
EMULATE_DONE, /* no further processing */
|
||||||
EMULATE_DO_MMIO, /* kvm_run filled with mmio request */
|
EMULATE_DO_MMIO, /* kvm_run filled with mmio request */
|
||||||
|
@@ -64,6 +64,8 @@ MODULE_LICENSE("GPL");
|
|||||||
#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
|
#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
|
||||||
|
|
||||||
#define TSC_RATIO_RSVD 0xffffff0000000000ULL
|
#define TSC_RATIO_RSVD 0xffffff0000000000ULL
|
||||||
|
#define TSC_RATIO_MIN 0x0000000000000001ULL
|
||||||
|
#define TSC_RATIO_MAX 0x000000ffffffffffULL
|
||||||
|
|
||||||
static bool erratum_383_found __read_mostly;
|
static bool erratum_383_found __read_mostly;
|
||||||
|
|
||||||
@@ -189,6 +191,7 @@ static int nested_svm_intercept(struct vcpu_svm *svm);
|
|||||||
static int nested_svm_vmexit(struct vcpu_svm *svm);
|
static int nested_svm_vmexit(struct vcpu_svm *svm);
|
||||||
static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
|
static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
|
||||||
bool has_error_code, u32 error_code);
|
bool has_error_code, u32 error_code);
|
||||||
|
static u64 __scale_tsc(u64 ratio, u64 tsc);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
|
VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
|
||||||
@@ -798,6 +801,23 @@ static __init int svm_hardware_setup(void)
|
|||||||
if (boot_cpu_has(X86_FEATURE_FXSR_OPT))
|
if (boot_cpu_has(X86_FEATURE_FXSR_OPT))
|
||||||
kvm_enable_efer_bits(EFER_FFXSR);
|
kvm_enable_efer_bits(EFER_FFXSR);
|
||||||
|
|
||||||
|
if (boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
|
||||||
|
u64 max;
|
||||||
|
|
||||||
|
kvm_has_tsc_control = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure the user can only configure tsc_khz values that
|
||||||
|
* fit into a signed integer.
|
||||||
|
* A min value is not calculated needed because it will always
|
||||||
|
* be 1 on all machines and a value of 0 is used to disable
|
||||||
|
* tsc-scaling for the vcpu.
|
||||||
|
*/
|
||||||
|
max = min(0x7fffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX));
|
||||||
|
|
||||||
|
kvm_max_guest_tsc_khz = max;
|
||||||
|
}
|
||||||
|
|
||||||
if (nested) {
|
if (nested) {
|
||||||
printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
|
printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
|
||||||
kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
|
kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
|
||||||
|
@@ -87,6 +87,11 @@ EXPORT_SYMBOL_GPL(kvm_x86_ops);
|
|||||||
int ignore_msrs = 0;
|
int ignore_msrs = 0;
|
||||||
module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR);
|
module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR);
|
||||||
|
|
||||||
|
bool kvm_has_tsc_control;
|
||||||
|
EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
|
||||||
|
u32 kvm_max_guest_tsc_khz;
|
||||||
|
EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz);
|
||||||
|
|
||||||
#define KVM_NR_SHARED_MSRS 16
|
#define KVM_NR_SHARED_MSRS 16
|
||||||
|
|
||||||
struct kvm_shared_msrs_global {
|
struct kvm_shared_msrs_global {
|
||||||
@@ -1986,6 +1991,7 @@ int kvm_dev_ioctl_check_extension(long ext)
|
|||||||
case KVM_CAP_X86_ROBUST_SINGLESTEP:
|
case KVM_CAP_X86_ROBUST_SINGLESTEP:
|
||||||
case KVM_CAP_XSAVE:
|
case KVM_CAP_XSAVE:
|
||||||
case KVM_CAP_ASYNC_PF:
|
case KVM_CAP_ASYNC_PF:
|
||||||
|
case KVM_CAP_GET_TSC_KHZ:
|
||||||
r = 1;
|
r = 1;
|
||||||
break;
|
break;
|
||||||
case KVM_CAP_COALESCED_MMIO:
|
case KVM_CAP_COALESCED_MMIO:
|
||||||
@@ -2012,6 +2018,9 @@ int kvm_dev_ioctl_check_extension(long ext)
|
|||||||
case KVM_CAP_XCRS:
|
case KVM_CAP_XCRS:
|
||||||
r = cpu_has_xsave;
|
r = cpu_has_xsave;
|
||||||
break;
|
break;
|
||||||
|
case KVM_CAP_TSC_CONTROL:
|
||||||
|
r = kvm_has_tsc_control;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
r = 0;
|
r = 0;
|
||||||
break;
|
break;
|
||||||
@@ -3045,6 +3054,32 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
|||||||
r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, u.xcrs);
|
r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, u.xcrs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case KVM_SET_TSC_KHZ: {
|
||||||
|
u32 user_tsc_khz;
|
||||||
|
|
||||||
|
r = -EINVAL;
|
||||||
|
if (!kvm_has_tsc_control)
|
||||||
|
break;
|
||||||
|
|
||||||
|
user_tsc_khz = (u32)arg;
|
||||||
|
|
||||||
|
if (user_tsc_khz >= kvm_max_guest_tsc_khz)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
kvm_x86_ops->set_tsc_khz(vcpu, user_tsc_khz);
|
||||||
|
|
||||||
|
r = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
case KVM_GET_TSC_KHZ: {
|
||||||
|
r = -EIO;
|
||||||
|
if (check_tsc_unstable())
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
r = vcpu_tsc_khz(vcpu);
|
||||||
|
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
r = -EINVAL;
|
r = -EINVAL;
|
||||||
}
|
}
|
||||||
|
@@ -541,6 +541,8 @@ struct kvm_ppc_pvinfo {
|
|||||||
#define KVM_CAP_PPC_GET_PVINFO 57
|
#define KVM_CAP_PPC_GET_PVINFO 57
|
||||||
#define KVM_CAP_PPC_IRQ_LEVEL 58
|
#define KVM_CAP_PPC_IRQ_LEVEL 58
|
||||||
#define KVM_CAP_ASYNC_PF 59
|
#define KVM_CAP_ASYNC_PF 59
|
||||||
|
#define KVM_CAP_TSC_CONTROL 60
|
||||||
|
#define KVM_CAP_GET_TSC_KHZ 61
|
||||||
|
|
||||||
#ifdef KVM_CAP_IRQ_ROUTING
|
#ifdef KVM_CAP_IRQ_ROUTING
|
||||||
|
|
||||||
@@ -677,6 +679,9 @@ struct kvm_clock_data {
|
|||||||
#define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2)
|
#define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2)
|
||||||
/* Available with KVM_CAP_PPC_GET_PVINFO */
|
/* Available with KVM_CAP_PPC_GET_PVINFO */
|
||||||
#define KVM_PPC_GET_PVINFO _IOW(KVMIO, 0xa1, struct kvm_ppc_pvinfo)
|
#define KVM_PPC_GET_PVINFO _IOW(KVMIO, 0xa1, struct kvm_ppc_pvinfo)
|
||||||
|
/* Available with KVM_CAP_TSC_CONTROL */
|
||||||
|
#define KVM_SET_TSC_KHZ _IO(KVMIO, 0xa2)
|
||||||
|
#define KVM_GET_TSC_KHZ _IO(KVMIO, 0xa3)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ioctls for vcpu fds
|
* ioctls for vcpu fds
|
||||||
|
Reference in New Issue
Block a user