Commit 938c8745 authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini

KVM: x86: Introduce "struct kvm_caps" to track misc caps/settings

Add kvm_caps to hold a variety of capabilites and defaults that aren't
handled by kvm_cpu_caps because they aren't CPUID bits in order to reduce
the amount of boilerplate code required to add a new feature.  The vast
majority (all?) of the caps interact with vendor code and are written
only during initialization, i.e. should be tagged __read_mostly, declared
extern in x86.h, and exported.

No functional change intended.
Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
Message-Id: <20220524135624.22988-4-chenyi.qiang@intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 30267b43
...@@ -1664,21 +1664,6 @@ extern bool tdp_enabled; ...@@ -1664,21 +1664,6 @@ extern bool tdp_enabled;
u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu); u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu);
/* control of guest tsc rate supported? */
extern bool kvm_has_tsc_control;
/* maximum supported tsc_khz for guests */
extern u32 kvm_max_guest_tsc_khz;
/* number of bits of the fractional part of the TSC scaling ratio */
extern u8 kvm_tsc_scaling_ratio_frac_bits;
/* maximum allowed value of TSC scaling ratio */
extern u64 kvm_max_tsc_scaling_ratio;
/* 1ull << kvm_tsc_scaling_ratio_frac_bits */
extern u64 kvm_default_tsc_scaling_ratio;
/* bus lock detection supported? */
extern bool kvm_has_bus_lock_exit;
extern u64 kvm_mce_cap_supported;
/* /*
* EMULTYPE_NO_DECODE - Set when re-emulating an instruction (after completing * EMULTYPE_NO_DECODE - Set when re-emulating an instruction (after completing
* userspace I/O) to indicate that the emulation context * userspace I/O) to indicate that the emulation context
......
...@@ -200,7 +200,7 @@ void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) ...@@ -200,7 +200,7 @@ void kvm_update_pv_runtime(struct kvm_vcpu *vcpu)
/* /*
* Calculate guest's supported XCR0 taking into account guest CPUID data and * Calculate guest's supported XCR0 taking into account guest CPUID data and
* supported_xcr0 (comprised of host configuration and KVM_SUPPORTED_XCR0). * KVM's supported XCR0 (comprised of host's XCR0 and KVM_SUPPORTED_XCR0).
*/ */
static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent) static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent)
{ {
...@@ -210,7 +210,7 @@ static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent) ...@@ -210,7 +210,7 @@ static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent)
if (!best) if (!best)
return 0; return 0;
return (best->eax | ((u64)best->edx << 32)) & supported_xcr0; return (best->eax | ((u64)best->edx << 32)) & kvm_caps.supported_xcr0;
} }
static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *entries, static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *entries,
...@@ -912,8 +912,8 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) ...@@ -912,8 +912,8 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
} }
break; break;
case 0xd: { case 0xd: {
u64 permitted_xcr0 = supported_xcr0 & xstate_get_guest_group_perm(); u64 permitted_xcr0 = kvm_caps.supported_xcr0 & xstate_get_guest_group_perm();
u64 permitted_xss = supported_xss; u64 permitted_xss = kvm_caps.supported_xss;
entry->eax &= permitted_xcr0; entry->eax &= permitted_xcr0;
entry->ebx = xstate_required_size(permitted_xcr0, false); entry->ebx = xstate_required_size(permitted_xcr0, false);
......
...@@ -48,7 +48,7 @@ DEFINE_SIMPLE_ATTRIBUTE(vcpu_tsc_scaling_fops, vcpu_get_tsc_scaling_ratio, NULL, ...@@ -48,7 +48,7 @@ DEFINE_SIMPLE_ATTRIBUTE(vcpu_tsc_scaling_fops, vcpu_get_tsc_scaling_ratio, NULL,
static int vcpu_get_tsc_scaling_frac_bits(void *data, u64 *val) static int vcpu_get_tsc_scaling_frac_bits(void *data, u64 *val)
{ {
*val = kvm_tsc_scaling_ratio_frac_bits; *val = kvm_caps.tsc_scaling_ratio_frac_bits;
return 0; return 0;
} }
...@@ -66,7 +66,7 @@ void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_ ...@@ -66,7 +66,7 @@ void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_
debugfs_dentry, vcpu, debugfs_dentry, vcpu,
&vcpu_timer_advance_ns_fops); &vcpu_timer_advance_ns_fops);
if (kvm_has_tsc_control) { if (kvm_caps.has_tsc_control) {
debugfs_create_file("tsc-scaling-ratio", 0444, debugfs_create_file("tsc-scaling-ratio", 0444,
debugfs_dentry, vcpu, debugfs_dentry, vcpu,
&vcpu_tsc_scaling_fops); &vcpu_tsc_scaling_fops);
......
...@@ -1603,7 +1603,7 @@ static inline void __wait_lapic_expire(struct kvm_vcpu *vcpu, u64 guest_cycles) ...@@ -1603,7 +1603,7 @@ static inline void __wait_lapic_expire(struct kvm_vcpu *vcpu, u64 guest_cycles)
* that __delay() uses delay_tsc whenever the hardware has TSC, thus * that __delay() uses delay_tsc whenever the hardware has TSC, thus
* always for VMX enabled hardware. * always for VMX enabled hardware.
*/ */
if (vcpu->arch.tsc_scaling_ratio == kvm_default_tsc_scaling_ratio) { if (vcpu->arch.tsc_scaling_ratio == kvm_caps.default_tsc_scaling_ratio) {
__delay(min(guest_cycles, __delay(min(guest_cycles,
nsec_to_cycles(vcpu, timer_advance_ns))); nsec_to_cycles(vcpu, timer_advance_ns)));
} else { } else {
......
...@@ -674,7 +674,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, ...@@ -674,7 +674,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
vmcb02->control.tsc_offset = vcpu->arch.tsc_offset; vmcb02->control.tsc_offset = vcpu->arch.tsc_offset;
if (svm->tsc_ratio_msr != kvm_default_tsc_scaling_ratio) { if (svm->tsc_ratio_msr != kvm_caps.default_tsc_scaling_ratio) {
WARN_ON(!svm->tsc_scaling_enabled); WARN_ON(!svm->tsc_scaling_enabled);
nested_svm_update_tsc_ratio_msr(vcpu); nested_svm_update_tsc_ratio_msr(vcpu);
} }
...@@ -1031,7 +1031,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm) ...@@ -1031,7 +1031,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
vmcb_mark_dirty(vmcb01, VMCB_INTERCEPTS); vmcb_mark_dirty(vmcb01, VMCB_INTERCEPTS);
} }
if (svm->tsc_ratio_msr != kvm_default_tsc_scaling_ratio) { if (svm->tsc_ratio_msr != kvm_caps.default_tsc_scaling_ratio) {
WARN_ON(!svm->tsc_scaling_enabled); WARN_ON(!svm->tsc_scaling_enabled);
vcpu->arch.tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio; vcpu->arch.tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio;
__svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio);
......
...@@ -1285,7 +1285,7 @@ static void __svm_vcpu_reset(struct kvm_vcpu *vcpu) ...@@ -1285,7 +1285,7 @@ static void __svm_vcpu_reset(struct kvm_vcpu *vcpu)
svm_init_osvw(vcpu); svm_init_osvw(vcpu);
vcpu->arch.microcode_version = 0x01000065; vcpu->arch.microcode_version = 0x01000065;
svm->tsc_ratio_msr = kvm_default_tsc_scaling_ratio; svm->tsc_ratio_msr = kvm_caps.default_tsc_scaling_ratio;
if (sev_es_guest(vcpu->kvm)) if (sev_es_guest(vcpu->kvm))
sev_es_vcpu_reset(svm); sev_es_vcpu_reset(svm);
...@@ -4868,7 +4868,7 @@ static __init void svm_set_cpu_caps(void) ...@@ -4868,7 +4868,7 @@ static __init void svm_set_cpu_caps(void)
{ {
kvm_set_cpu_caps(); kvm_set_cpu_caps();
supported_xss = 0; kvm_caps.supported_xss = 0;
/* CPUID 0x80000001 and 0x8000000A (SVM features) */ /* CPUID 0x80000001 and 0x8000000A (SVM features) */
if (nested) { if (nested) {
...@@ -4944,7 +4944,8 @@ static __init int svm_hardware_setup(void) ...@@ -4944,7 +4944,8 @@ static __init int svm_hardware_setup(void)
init_msrpm_offsets(); init_msrpm_offsets();
supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); kvm_caps.supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS |
XFEATURE_MASK_BNDCSR);
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);
...@@ -4954,11 +4955,11 @@ static __init int svm_hardware_setup(void) ...@@ -4954,11 +4955,11 @@ static __init int svm_hardware_setup(void)
tsc_scaling = false; tsc_scaling = false;
} else { } else {
pr_info("TSC scaling supported\n"); pr_info("TSC scaling supported\n");
kvm_has_tsc_control = true; kvm_caps.has_tsc_control = true;
} }
} }
kvm_max_tsc_scaling_ratio = SVM_TSC_RATIO_MAX; kvm_caps.max_tsc_scaling_ratio = SVM_TSC_RATIO_MAX;
kvm_tsc_scaling_ratio_frac_bits = 32; kvm_caps.tsc_scaling_ratio_frac_bits = 32;
tsc_aux_uret_slot = kvm_add_user_return_msr(MSR_TSC_AUX); tsc_aux_uret_slot = kvm_add_user_return_msr(MSR_TSC_AUX);
......
...@@ -2548,7 +2548,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, ...@@ -2548,7 +2548,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
vmx_get_l2_tsc_multiplier(vcpu)); vmx_get_l2_tsc_multiplier(vcpu));
vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset); vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
if (kvm_has_tsc_control) if (kvm_caps.has_tsc_control)
vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio); vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio);
nested_vmx_transition_tlb_flush(vcpu, vmcs12, true); nested_vmx_transition_tlb_flush(vcpu, vmcs12, true);
...@@ -4610,7 +4610,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, ...@@ -4610,7 +4610,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr); vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr); vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset); vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
if (kvm_has_tsc_control) if (kvm_caps.has_tsc_control)
vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio); vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio);
if (vmx->nested.l1_tpr_threshold != -1) if (vmx->nested.l1_tpr_threshold != -1)
......
...@@ -1717,7 +1717,7 @@ u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu) ...@@ -1717,7 +1717,7 @@ u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu)
nested_cpu_has2(vmcs12, SECONDARY_EXEC_TSC_SCALING)) nested_cpu_has2(vmcs12, SECONDARY_EXEC_TSC_SCALING))
return vmcs12->tsc_multiplier; return vmcs12->tsc_multiplier;
return kvm_default_tsc_scaling_ratio; return kvm_caps.default_tsc_scaling_ratio;
} }
static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
...@@ -7544,7 +7544,7 @@ static __init void vmx_set_cpu_caps(void) ...@@ -7544,7 +7544,7 @@ static __init void vmx_set_cpu_caps(void)
kvm_cpu_cap_set(X86_FEATURE_UMIP); kvm_cpu_cap_set(X86_FEATURE_UMIP);
/* CPUID 0xD.1 */ /* CPUID 0xD.1 */
supported_xss = 0; kvm_caps.supported_xss = 0;
if (!cpu_has_vmx_xsaves()) if (!cpu_has_vmx_xsaves())
kvm_cpu_cap_clear(X86_FEATURE_XSAVES); kvm_cpu_cap_clear(X86_FEATURE_XSAVES);
...@@ -7685,9 +7685,9 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc, ...@@ -7685,9 +7685,9 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc,
delta_tsc = 0; delta_tsc = 0;
/* Convert to host delta tsc if tsc scaling is enabled */ /* Convert to host delta tsc if tsc scaling is enabled */
if (vcpu->arch.l1_tsc_scaling_ratio != kvm_default_tsc_scaling_ratio && if (vcpu->arch.l1_tsc_scaling_ratio != kvm_caps.default_tsc_scaling_ratio &&
delta_tsc && u64_shl_div_u64(delta_tsc, delta_tsc && u64_shl_div_u64(delta_tsc,
kvm_tsc_scaling_ratio_frac_bits, kvm_caps.tsc_scaling_ratio_frac_bits,
vcpu->arch.l1_tsc_scaling_ratio, &delta_tsc)) vcpu->arch.l1_tsc_scaling_ratio, &delta_tsc))
return -ERANGE; return -ERANGE;
...@@ -8064,7 +8064,7 @@ static __init int hardware_setup(void) ...@@ -8064,7 +8064,7 @@ static __init int hardware_setup(void)
} }
if (!cpu_has_vmx_mpx()) if (!cpu_has_vmx_mpx())
supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS | kvm_caps.supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS |
XFEATURE_MASK_BNDCSR); XFEATURE_MASK_BNDCSR);
if (!cpu_has_vmx_vpid() || !cpu_has_vmx_invvpid() || if (!cpu_has_vmx_vpid() || !cpu_has_vmx_invvpid() ||
...@@ -8132,11 +8132,11 @@ static __init int hardware_setup(void) ...@@ -8132,11 +8132,11 @@ static __init int hardware_setup(void)
enable_ipiv = false; enable_ipiv = false;
if (cpu_has_vmx_tsc_scaling()) if (cpu_has_vmx_tsc_scaling())
kvm_has_tsc_control = true; kvm_caps.has_tsc_control = true;
kvm_max_tsc_scaling_ratio = KVM_VMX_TSC_MULTIPLIER_MAX; kvm_caps.max_tsc_scaling_ratio = KVM_VMX_TSC_MULTIPLIER_MAX;
kvm_tsc_scaling_ratio_frac_bits = 48; kvm_caps.tsc_scaling_ratio_frac_bits = 48;
kvm_has_bus_lock_exit = cpu_has_vmx_bus_lock_detection(); kvm_caps.has_bus_lock_exit = cpu_has_vmx_bus_lock_detection();
set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
...@@ -8193,7 +8193,7 @@ static __init int hardware_setup(void) ...@@ -8193,7 +8193,7 @@ static __init int hardware_setup(void)
vmx_x86_ops.request_immediate_exit = __kvm_request_immediate_exit; vmx_x86_ops.request_immediate_exit = __kvm_request_immediate_exit;
} }
kvm_mce_cap_supported |= MCG_LMCE_P; kvm_caps.supported_mce_cap |= MCG_LMCE_P;
if (pt_mode != PT_MODE_SYSTEM && pt_mode != PT_MODE_HOST_GUEST) if (pt_mode != PT_MODE_SYSTEM && pt_mode != PT_MODE_HOST_GUEST)
return -EINVAL; return -EINVAL;
......
...@@ -87,8 +87,11 @@ ...@@ -87,8 +87,11 @@
#define MAX_IO_MSRS 256 #define MAX_IO_MSRS 256
#define KVM_MAX_MCE_BANKS 32 #define KVM_MAX_MCE_BANKS 32
u64 __read_mostly kvm_mce_cap_supported = MCG_CTL_P | MCG_SER_P;
EXPORT_SYMBOL_GPL(kvm_mce_cap_supported); struct kvm_caps kvm_caps __read_mostly = {
.supported_mce_cap = MCG_CTL_P | MCG_SER_P,
};
EXPORT_SYMBOL_GPL(kvm_caps);
#define ERR_PTR_USR(e) ((void __user *)ERR_PTR(e)) #define ERR_PTR_USR(e) ((void __user *)ERR_PTR(e))
...@@ -151,19 +154,6 @@ module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR); ...@@ -151,19 +154,6 @@ module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR);
static bool __read_mostly kvmclock_periodic_sync = true; static bool __read_mostly kvmclock_periodic_sync = true;
module_param(kvmclock_periodic_sync, bool, S_IRUGO); module_param(kvmclock_periodic_sync, bool, S_IRUGO);
bool __read_mostly kvm_has_tsc_control;
EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
u32 __read_mostly kvm_max_guest_tsc_khz;
EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz);
u8 __read_mostly kvm_tsc_scaling_ratio_frac_bits;
EXPORT_SYMBOL_GPL(kvm_tsc_scaling_ratio_frac_bits);
u64 __read_mostly kvm_max_tsc_scaling_ratio;
EXPORT_SYMBOL_GPL(kvm_max_tsc_scaling_ratio);
u64 __read_mostly kvm_default_tsc_scaling_ratio;
EXPORT_SYMBOL_GPL(kvm_default_tsc_scaling_ratio);
bool __read_mostly kvm_has_bus_lock_exit;
EXPORT_SYMBOL_GPL(kvm_has_bus_lock_exit);
/* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */ /* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */
static u32 __read_mostly tsc_tolerance_ppm = 250; static u32 __read_mostly tsc_tolerance_ppm = 250;
module_param(tsc_tolerance_ppm, uint, S_IRUGO | S_IWUSR); module_param(tsc_tolerance_ppm, uint, S_IRUGO | S_IWUSR);
...@@ -235,8 +225,6 @@ EXPORT_SYMBOL_GPL(enable_apicv); ...@@ -235,8 +225,6 @@ EXPORT_SYMBOL_GPL(enable_apicv);
u64 __read_mostly host_xss; u64 __read_mostly host_xss;
EXPORT_SYMBOL_GPL(host_xss); EXPORT_SYMBOL_GPL(host_xss);
u64 __read_mostly supported_xss;
EXPORT_SYMBOL_GPL(supported_xss);
const struct _kvm_stats_desc kvm_vm_stats_desc[] = { const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
KVM_GENERIC_VM_STATS(), KVM_GENERIC_VM_STATS(),
...@@ -309,8 +297,6 @@ const struct kvm_stats_header kvm_vcpu_stats_header = { ...@@ -309,8 +297,6 @@ const struct kvm_stats_header kvm_vcpu_stats_header = {
}; };
u64 __read_mostly host_xcr0; u64 __read_mostly host_xcr0;
u64 __read_mostly supported_xcr0;
EXPORT_SYMBOL_GPL(supported_xcr0);
static struct kmem_cache *x86_emulator_cache; static struct kmem_cache *x86_emulator_cache;
...@@ -2345,12 +2331,12 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale) ...@@ -2345,12 +2331,12 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
/* Guest TSC same frequency as host TSC? */ /* Guest TSC same frequency as host TSC? */
if (!scale) { if (!scale) {
kvm_vcpu_write_tsc_multiplier(vcpu, kvm_default_tsc_scaling_ratio); kvm_vcpu_write_tsc_multiplier(vcpu, kvm_caps.default_tsc_scaling_ratio);
return 0; return 0;
} }
/* TSC scaling supported? */ /* TSC scaling supported? */
if (!kvm_has_tsc_control) { if (!kvm_caps.has_tsc_control) {
if (user_tsc_khz > tsc_khz) { if (user_tsc_khz > tsc_khz) {
vcpu->arch.tsc_catchup = 1; vcpu->arch.tsc_catchup = 1;
vcpu->arch.tsc_always_catchup = 1; vcpu->arch.tsc_always_catchup = 1;
...@@ -2362,10 +2348,10 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale) ...@@ -2362,10 +2348,10 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
} }
/* TSC scaling required - calculate ratio */ /* TSC scaling required - calculate ratio */
ratio = mul_u64_u32_div(1ULL << kvm_tsc_scaling_ratio_frac_bits, ratio = mul_u64_u32_div(1ULL << kvm_caps.tsc_scaling_ratio_frac_bits,
user_tsc_khz, tsc_khz); user_tsc_khz, tsc_khz);
if (ratio == 0 || ratio >= kvm_max_tsc_scaling_ratio) { if (ratio == 0 || ratio >= kvm_caps.max_tsc_scaling_ratio) {
pr_warn_ratelimited("Invalid TSC scaling ratio - virtual-tsc-khz=%u\n", pr_warn_ratelimited("Invalid TSC scaling ratio - virtual-tsc-khz=%u\n",
user_tsc_khz); user_tsc_khz);
return -1; return -1;
...@@ -2383,7 +2369,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz) ...@@ -2383,7 +2369,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
/* tsc_khz can be zero if TSC calibration fails */ /* tsc_khz can be zero if TSC calibration fails */
if (user_tsc_khz == 0) { if (user_tsc_khz == 0) {
/* set tsc_scaling_ratio to a safe value */ /* set tsc_scaling_ratio to a safe value */
kvm_vcpu_write_tsc_multiplier(vcpu, kvm_default_tsc_scaling_ratio); kvm_vcpu_write_tsc_multiplier(vcpu, kvm_caps.default_tsc_scaling_ratio);
return -1; return -1;
} }
...@@ -2460,18 +2446,18 @@ static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu) ...@@ -2460,18 +2446,18 @@ static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu)
* (frac) represent the fractional part, ie. ratio represents a fixed * (frac) represent the fractional part, ie. ratio represents a fixed
* point number (mult + frac * 2^(-N)). * point number (mult + frac * 2^(-N)).
* *
* N equals to kvm_tsc_scaling_ratio_frac_bits. * N equals to kvm_caps.tsc_scaling_ratio_frac_bits.
*/ */
static inline u64 __scale_tsc(u64 ratio, u64 tsc) static inline u64 __scale_tsc(u64 ratio, u64 tsc)
{ {
return mul_u64_u64_shr(tsc, ratio, kvm_tsc_scaling_ratio_frac_bits); return mul_u64_u64_shr(tsc, ratio, kvm_caps.tsc_scaling_ratio_frac_bits);
} }
u64 kvm_scale_tsc(u64 tsc, u64 ratio) u64 kvm_scale_tsc(u64 tsc, u64 ratio)
{ {
u64 _tsc = tsc; u64 _tsc = tsc;
if (ratio != kvm_default_tsc_scaling_ratio) if (ratio != kvm_caps.default_tsc_scaling_ratio)
_tsc = __scale_tsc(ratio, tsc); _tsc = __scale_tsc(ratio, tsc);
return _tsc; return _tsc;
...@@ -2498,11 +2484,11 @@ u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier) ...@@ -2498,11 +2484,11 @@ u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier)
{ {
u64 nested_offset; u64 nested_offset;
if (l2_multiplier == kvm_default_tsc_scaling_ratio) if (l2_multiplier == kvm_caps.default_tsc_scaling_ratio)
nested_offset = l1_offset; nested_offset = l1_offset;
else else
nested_offset = mul_s64_u64_shr((s64) l1_offset, l2_multiplier, nested_offset = mul_s64_u64_shr((s64) l1_offset, l2_multiplier,
kvm_tsc_scaling_ratio_frac_bits); kvm_caps.tsc_scaling_ratio_frac_bits);
nested_offset += l2_offset; nested_offset += l2_offset;
return nested_offset; return nested_offset;
...@@ -2511,9 +2497,9 @@ EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_offset); ...@@ -2511,9 +2497,9 @@ EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_offset);
u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier) u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier)
{ {
if (l2_multiplier != kvm_default_tsc_scaling_ratio) if (l2_multiplier != kvm_caps.default_tsc_scaling_ratio)
return mul_u64_u64_shr(l1_multiplier, l2_multiplier, return mul_u64_u64_shr(l1_multiplier, l2_multiplier,
kvm_tsc_scaling_ratio_frac_bits); kvm_caps.tsc_scaling_ratio_frac_bits);
return l1_multiplier; return l1_multiplier;
} }
...@@ -2555,7 +2541,7 @@ static void kvm_vcpu_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 l1_multipli ...@@ -2555,7 +2541,7 @@ static void kvm_vcpu_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 l1_multipli
else else
vcpu->arch.tsc_scaling_ratio = l1_multiplier; vcpu->arch.tsc_scaling_ratio = l1_multiplier;
if (kvm_has_tsc_control) if (kvm_caps.has_tsc_control)
static_call(kvm_x86_write_tsc_multiplier)( static_call(kvm_x86_write_tsc_multiplier)(
vcpu, vcpu->arch.tsc_scaling_ratio); vcpu, vcpu->arch.tsc_scaling_ratio);
} }
...@@ -2691,7 +2677,7 @@ static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, ...@@ -2691,7 +2677,7 @@ static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment) static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
{ {
if (vcpu->arch.l1_tsc_scaling_ratio != kvm_default_tsc_scaling_ratio) if (vcpu->arch.l1_tsc_scaling_ratio != kvm_caps.default_tsc_scaling_ratio)
WARN_ON(adjustment < 0); WARN_ON(adjustment < 0);
adjustment = kvm_scale_tsc((u64) adjustment, adjustment = kvm_scale_tsc((u64) adjustment,
vcpu->arch.l1_tsc_scaling_ratio); vcpu->arch.l1_tsc_scaling_ratio);
...@@ -3104,7 +3090,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) ...@@ -3104,7 +3090,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
/* With all the info we got, fill in the values */ /* With all the info we got, fill in the values */
if (kvm_has_tsc_control) if (kvm_caps.has_tsc_control)
tgt_tsc_khz = kvm_scale_tsc(tgt_tsc_khz, tgt_tsc_khz = kvm_scale_tsc(tgt_tsc_khz,
v->arch.l1_tsc_scaling_ratio); v->arch.l1_tsc_scaling_ratio);
...@@ -3613,7 +3599,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) ...@@ -3613,7 +3599,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
* IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than * IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than
* XSAVES/XRSTORS to save/restore PT MSRs. * XSAVES/XRSTORS to save/restore PT MSRs.
*/ */
if (data & ~supported_xss) if (data & ~kvm_caps.supported_xss)
return 1; return 1;
vcpu->arch.ia32_xss = data; vcpu->arch.ia32_xss = data;
kvm_update_cpuid_runtime(vcpu); kvm_update_cpuid_runtime(vcpu);
...@@ -4374,7 +4360,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) ...@@ -4374,7 +4360,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
break; break;
case KVM_CAP_TSC_CONTROL: case KVM_CAP_TSC_CONTROL:
case KVM_CAP_VM_TSC_CONTROL: case KVM_CAP_VM_TSC_CONTROL:
r = kvm_has_tsc_control; r = kvm_caps.has_tsc_control;
break; break;
case KVM_CAP_X2APIC_API: case KVM_CAP_X2APIC_API:
r = KVM_X2APIC_API_VALID_FLAGS; r = KVM_X2APIC_API_VALID_FLAGS;
...@@ -4396,7 +4382,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) ...@@ -4396,7 +4382,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
r = sched_info_on(); r = sched_info_on();
break; break;
case KVM_CAP_X86_BUS_LOCK_EXIT: case KVM_CAP_X86_BUS_LOCK_EXIT:
if (kvm_has_bus_lock_exit) if (kvm_caps.has_bus_lock_exit)
r = KVM_BUS_LOCK_DETECTION_OFF | r = KVM_BUS_LOCK_DETECTION_OFF |
KVM_BUS_LOCK_DETECTION_EXIT; KVM_BUS_LOCK_DETECTION_EXIT;
else else
...@@ -4405,7 +4391,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) ...@@ -4405,7 +4391,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_XSAVE2: { case KVM_CAP_XSAVE2: {
u64 guest_perm = xstate_get_guest_group_perm(); u64 guest_perm = xstate_get_guest_group_perm();
r = xstate_required_size(supported_xcr0 & guest_perm, false); r = xstate_required_size(kvm_caps.supported_xcr0 & guest_perm, false);
if (r < sizeof(struct kvm_xsave)) if (r < sizeof(struct kvm_xsave))
r = sizeof(struct kvm_xsave); r = sizeof(struct kvm_xsave);
break; break;
...@@ -4443,7 +4429,7 @@ static int kvm_x86_dev_get_attr(struct kvm_device_attr *attr) ...@@ -4443,7 +4429,7 @@ static int kvm_x86_dev_get_attr(struct kvm_device_attr *attr)
switch (attr->attr) { switch (attr->attr) {
case KVM_X86_XCOMP_GUEST_SUPP: case KVM_X86_XCOMP_GUEST_SUPP:
if (put_user(supported_xcr0, uaddr)) if (put_user(kvm_caps.supported_xcr0, uaddr))
return -EFAULT; return -EFAULT;
return 0; return 0;
default: default:
...@@ -4520,8 +4506,8 @@ long kvm_arch_dev_ioctl(struct file *filp, ...@@ -4520,8 +4506,8 @@ long kvm_arch_dev_ioctl(struct file *filp,
} }
case KVM_X86_GET_MCE_CAP_SUPPORTED: case KVM_X86_GET_MCE_CAP_SUPPORTED:
r = -EFAULT; r = -EFAULT;
if (copy_to_user(argp, &kvm_mce_cap_supported, if (copy_to_user(argp, &kvm_caps.supported_mce_cap,
sizeof(kvm_mce_cap_supported))) sizeof(kvm_caps.supported_mce_cap)))
goto out; goto out;
r = 0; r = 0;
break; break;
...@@ -4805,7 +4791,7 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu, ...@@ -4805,7 +4791,7 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu,
r = -EINVAL; r = -EINVAL;
if (!bank_num || bank_num > KVM_MAX_MCE_BANKS) if (!bank_num || bank_num > KVM_MAX_MCE_BANKS)
goto out; goto out;
if (mcg_cap & ~(kvm_mce_cap_supported | 0xff | 0xff0000)) if (mcg_cap & ~(kvm_caps.supported_mce_cap | 0xff | 0xff0000))
goto out; goto out;
r = 0; r = 0;
vcpu->arch.mcg_cap = mcg_cap; vcpu->arch.mcg_cap = mcg_cap;
...@@ -5111,7 +5097,8 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, ...@@ -5111,7 +5097,8 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
return fpu_copy_uabi_to_guest_fpstate(&vcpu->arch.guest_fpu, return fpu_copy_uabi_to_guest_fpstate(&vcpu->arch.guest_fpu,
guest_xsave->region, guest_xsave->region,
supported_xcr0, &vcpu->arch.pkru); kvm_caps.supported_xcr0,
&vcpu->arch.pkru);
} }
static void kvm_vcpu_ioctl_x86_get_xcrs(struct kvm_vcpu *vcpu, static void kvm_vcpu_ioctl_x86_get_xcrs(struct kvm_vcpu *vcpu,
...@@ -5616,8 +5603,8 @@ long kvm_arch_vcpu_ioctl(struct file *filp, ...@@ -5616,8 +5603,8 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = -EINVAL; r = -EINVAL;
user_tsc_khz = (u32)arg; user_tsc_khz = (u32)arg;
if (kvm_has_tsc_control && if (kvm_caps.has_tsc_control &&
user_tsc_khz >= kvm_max_guest_tsc_khz) user_tsc_khz >= kvm_caps.max_guest_tsc_khz)
goto out; goto out;
if (user_tsc_khz == 0) if (user_tsc_khz == 0)
...@@ -6061,7 +6048,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, ...@@ -6061,7 +6048,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
(cap->args[0] & KVM_BUS_LOCK_DETECTION_EXIT)) (cap->args[0] & KVM_BUS_LOCK_DETECTION_EXIT))
break; break;
if (kvm_has_bus_lock_exit && if (kvm_caps.has_bus_lock_exit &&
cap->args[0] & KVM_BUS_LOCK_DETECTION_EXIT) cap->args[0] & KVM_BUS_LOCK_DETECTION_EXIT)
kvm->arch.bus_lock_detection_enabled = true; kvm->arch.bus_lock_detection_enabled = true;
r = 0; r = 0;
...@@ -6610,8 +6597,8 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -6610,8 +6597,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = -EINVAL; r = -EINVAL;
user_tsc_khz = (u32)arg; user_tsc_khz = (u32)arg;
if (kvm_has_tsc_control && if (kvm_caps.has_tsc_control &&
user_tsc_khz >= kvm_max_guest_tsc_khz) user_tsc_khz >= kvm_caps.max_guest_tsc_khz)
goto out; goto out;
if (user_tsc_khz == 0) if (user_tsc_khz == 0)
...@@ -8774,7 +8761,7 @@ static void kvm_hyperv_tsc_notifier(void) ...@@ -8774,7 +8761,7 @@ static void kvm_hyperv_tsc_notifier(void)
/* TSC frequency always matches when on Hyper-V */ /* TSC frequency always matches when on Hyper-V */
for_each_present_cpu(cpu) for_each_present_cpu(cpu)
per_cpu(cpu_tsc_khz, cpu) = tsc_khz; per_cpu(cpu_tsc_khz, cpu) = tsc_khz;
kvm_max_guest_tsc_khz = tsc_khz; kvm_caps.max_guest_tsc_khz = tsc_khz;
list_for_each_entry(kvm, &vm_list, vm_list) { list_for_each_entry(kvm, &vm_list, vm_list) {
__kvm_start_pvclock_update(kvm); __kvm_start_pvclock_update(kvm);
...@@ -9036,7 +9023,7 @@ int kvm_arch_init(void *opaque) ...@@ -9036,7 +9023,7 @@ int kvm_arch_init(void *opaque)
if (boot_cpu_has(X86_FEATURE_XSAVE)) { if (boot_cpu_has(X86_FEATURE_XSAVE)) {
host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
supported_xcr0 = host_xcr0 & KVM_SUPPORTED_XCR0; kvm_caps.supported_xcr0 = host_xcr0 & KVM_SUPPORTED_XCR0;
} }
if (pi_inject_timer == -1) if (pi_inject_timer == -1)
...@@ -11748,13 +11735,13 @@ int kvm_arch_hardware_setup(void *opaque) ...@@ -11748,13 +11735,13 @@ int kvm_arch_hardware_setup(void *opaque)
kvm_register_perf_callbacks(ops->handle_intel_pt_intr); kvm_register_perf_callbacks(ops->handle_intel_pt_intr);
if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES)) if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES))
supported_xss = 0; kvm_caps.supported_xss = 0;
#define __kvm_cpu_cap_has(UNUSED_, f) kvm_cpu_cap_has(f) #define __kvm_cpu_cap_has(UNUSED_, f) kvm_cpu_cap_has(f)
cr4_reserved_bits = __cr4_reserved_bits(__kvm_cpu_cap_has, UNUSED_); cr4_reserved_bits = __cr4_reserved_bits(__kvm_cpu_cap_has, UNUSED_);
#undef __kvm_cpu_cap_has #undef __kvm_cpu_cap_has
if (kvm_has_tsc_control) { if (kvm_caps.has_tsc_control) {
/* /*
* Make sure the user can only configure tsc_khz values that * Make sure the user can only configure tsc_khz values that
* fit into a signed integer. * fit into a signed integer.
...@@ -11762,10 +11749,10 @@ int kvm_arch_hardware_setup(void *opaque) ...@@ -11762,10 +11749,10 @@ int kvm_arch_hardware_setup(void *opaque)
* be 1 on all machines. * be 1 on all machines.
*/ */
u64 max = min(0x7fffffffULL, u64 max = min(0x7fffffffULL,
__scale_tsc(kvm_max_tsc_scaling_ratio, tsc_khz)); __scale_tsc(kvm_caps.max_tsc_scaling_ratio, tsc_khz));
kvm_max_guest_tsc_khz = max; kvm_caps.max_guest_tsc_khz = max;
} }
kvm_default_tsc_scaling_ratio = 1ULL << kvm_tsc_scaling_ratio_frac_bits; kvm_caps.default_tsc_scaling_ratio = 1ULL << kvm_caps.tsc_scaling_ratio_frac_bits;
kvm_init_msr_list(); kvm_init_msr_list();
return 0; return 0;
} }
......
...@@ -8,6 +8,25 @@ ...@@ -8,6 +8,25 @@
#include "kvm_cache_regs.h" #include "kvm_cache_regs.h"
#include "kvm_emulate.h" #include "kvm_emulate.h"
struct kvm_caps {
/* control of guest tsc rate supported? */
bool has_tsc_control;
/* maximum supported tsc_khz for guests */
u32 max_guest_tsc_khz;
/* number of bits of the fractional part of the TSC scaling ratio */
u8 tsc_scaling_ratio_frac_bits;
/* maximum allowed value of TSC scaling ratio */
u64 max_tsc_scaling_ratio;
/* 1ull << kvm_caps.tsc_scaling_ratio_frac_bits */
u64 default_tsc_scaling_ratio;
/* bus lock detection supported? */
bool has_bus_lock_exit;
u64 supported_mce_cap;
u64 supported_xcr0;
u64 supported_xss;
};
void kvm_spurious_fault(void); void kvm_spurious_fault(void);
#define KVM_NESTED_VMENTER_CONSISTENCY_CHECK(consistency_check) \ #define KVM_NESTED_VMENTER_CONSISTENCY_CHECK(consistency_check) \
...@@ -283,14 +302,15 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, ...@@ -283,14 +302,15 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu); fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu);
extern u64 host_xcr0; extern u64 host_xcr0;
extern u64 supported_xcr0;
extern u64 host_xss; extern u64 host_xss;
extern u64 supported_xss;
extern struct kvm_caps kvm_caps;
extern bool enable_pmu; extern bool enable_pmu;
static inline bool kvm_mpx_supported(void) static inline bool kvm_mpx_supported(void)
{ {
return (supported_xcr0 & (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR)) return (kvm_caps.supported_xcr0 & (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR))
== (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); == (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment