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:
parent
857e40999e
commit
92a1f12d25
|
@ -1263,6 +1263,29 @@ struct kvm_assigned_msix_entry {
|
|||
__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
|
||||
|
||||
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;
|
||||
|
||||
/* 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 {
|
||||
EMULATE_DONE, /* no further processing */
|
||||
EMULATE_DO_MMIO, /* kvm_run filled with mmio request */
|
||||
|
|
|
@ -64,6 +64,8 @@ MODULE_LICENSE("GPL");
|
|||
#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
|
||||
|
||||
#define TSC_RATIO_RSVD 0xffffff0000000000ULL
|
||||
#define TSC_RATIO_MIN 0x0000000000000001ULL
|
||||
#define TSC_RATIO_MAX 0x000000ffffffffffULL
|
||||
|
||||
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_check_exception(struct vcpu_svm *svm, unsigned nr,
|
||||
bool has_error_code, u32 error_code);
|
||||
static u64 __scale_tsc(u64 ratio, u64 tsc);
|
||||
|
||||
enum {
|
||||
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))
|
||||
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) {
|
||||
printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
|
||||
kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
|
||||
|
|
|
@ -87,6 +87,11 @@ EXPORT_SYMBOL_GPL(kvm_x86_ops);
|
|||
int ignore_msrs = 0;
|
||||
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
|
||||
|
||||
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_XSAVE:
|
||||
case KVM_CAP_ASYNC_PF:
|
||||
case KVM_CAP_GET_TSC_KHZ:
|
||||
r = 1;
|
||||
break;
|
||||
case KVM_CAP_COALESCED_MMIO:
|
||||
|
@ -2012,6 +2018,9 @@ int kvm_dev_ioctl_check_extension(long ext)
|
|||
case KVM_CAP_XCRS:
|
||||
r = cpu_has_xsave;
|
||||
break;
|
||||
case KVM_CAP_TSC_CONTROL:
|
||||
r = kvm_has_tsc_control;
|
||||
break;
|
||||
default:
|
||||
r = 0;
|
||||
break;
|
||||
|
@ -3045,6 +3054,32 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
|||
r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, u.xcrs);
|
||||
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:
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
|
|
@ -541,6 +541,8 @@ struct kvm_ppc_pvinfo {
|
|||
#define KVM_CAP_PPC_GET_PVINFO 57
|
||||
#define KVM_CAP_PPC_IRQ_LEVEL 58
|
||||
#define KVM_CAP_ASYNC_PF 59
|
||||
#define KVM_CAP_TSC_CONTROL 60
|
||||
#define KVM_CAP_GET_TSC_KHZ 61
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
@ -677,6 +679,9 @@ struct kvm_clock_data {
|
|||
#define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2)
|
||||
/* Available with KVM_CAP_PPC_GET_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
|
||||
|
|
Loading…
Reference in New Issue