Skip to content

Commit fe6b6bc

Browse files
Qiangcybonzini
authored andcommitted
KVM: VMX: Enable bus lock VM exit
Virtual Machine can exploit bus locks to degrade the performance of system. Bus lock can be caused by split locked access to writeback(WB) memory or by using locks on uncacheable(UC) memory. The bus lock is typically >1000 cycles slower than an atomic operation within a cache line. It also disrupts performance on other cores (which must wait for the bus lock to be released before their memory operations can complete). To address the threat, bus lock VM exit is introduced to notify the VMM when a bus lock was acquired, allowing it to enforce throttling or other policy based mitigations. A VMM can enable VM exit due to bus locks by setting a new "Bus Lock Detection" VM-execution control(bit 30 of Secondary Processor-based VM execution controls). If delivery of this VM exit was preempted by a higher priority VM exit (e.g. EPT misconfiguration, EPT violation, APIC access VM exit, APIC write VM exit, exception bitmap exiting), bit 26 of exit reason in vmcs field is set to 1. In current implementation, the KVM exposes this capability through KVM_CAP_X86_BUS_LOCK_EXIT. The user can get the supported mode bitmap (i.e. off and exit) and enable it explicitly (disabled by default). If bus locks in guest are detected by KVM, exit to user space even when current exit reason is handled by KVM internally. Set a new field KVM_RUN_BUS_LOCK in vcpu->run->flags to inform the user space that there is a bus lock detected in guest. Document for Bus Lock VM exit is now available at the latest "Intel Architecture Instruction Set Extensions Programming Reference". Document Link: https://software.intel.com/content/www/us/en/develop/download/intel-architecture-instruction-set-extensions-programming-reference.html Co-developed-by: Xiaoyao Li <[email protected]> Signed-off-by: Xiaoyao Li <[email protected]> Signed-off-by: Chenyi Qiang <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 15aad3b commit fe6b6bc

File tree

10 files changed

+83
-4
lines changed

10 files changed

+83
-4
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
#define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
5353
KVM_DIRTY_LOG_INITIALLY_SET)
5454

55+
#define KVM_BUS_LOCK_DETECTION_VALID_MODE (KVM_BUS_LOCK_DETECTION_OFF | \
56+
KVM_BUS_LOCK_DETECTION_EXIT)
57+
5558
/* x86-specific vcpu->requests bit members */
5659
#define KVM_REQ_MIGRATE_TIMER KVM_ARCH_REQ(0)
5760
#define KVM_REQ_REPORT_TPR_ACCESS KVM_ARCH_REQ(1)
@@ -996,6 +999,8 @@ struct kvm_arch {
996999
struct msr_bitmap_range ranges[16];
9971000
} msr_filter;
9981001

1002+
bool bus_lock_detection_enabled;
1003+
9991004
struct kvm_pmu_event_filter *pmu_event_filter;
10001005
struct task_struct *nx_lpage_recovery_thread;
10011006

@@ -1418,6 +1423,8 @@ extern u8 kvm_tsc_scaling_ratio_frac_bits;
14181423
extern u64 kvm_max_tsc_scaling_ratio;
14191424
/* 1ull << kvm_tsc_scaling_ratio_frac_bits */
14201425
extern u64 kvm_default_tsc_scaling_ratio;
1426+
/* bus lock detection supported? */
1427+
extern bool kvm_has_bus_lock_exit;
14211428

14221429
extern u64 kvm_mce_cap_supported;
14231430

arch/x86/include/asm/vmx.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#define SECONDARY_EXEC_PT_USE_GPA VMCS_CONTROL_BIT(PT_USE_GPA)
7474
#define SECONDARY_EXEC_TSC_SCALING VMCS_CONTROL_BIT(TSC_SCALING)
7575
#define SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE VMCS_CONTROL_BIT(USR_WAIT_PAUSE)
76+
#define SECONDARY_EXEC_BUS_LOCK_DETECTION VMCS_CONTROL_BIT(BUS_LOCK_DETECTION)
7677

7778
#define PIN_BASED_EXT_INTR_MASK VMCS_CONTROL_BIT(INTR_EXITING)
7879
#define PIN_BASED_NMI_EXITING VMCS_CONTROL_BIT(NMI_EXITING)

arch/x86/include/asm/vmxfeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,6 @@
8383
#define VMX_FEATURE_TSC_SCALING ( 2*32+ 25) /* Scale hardware TSC when read in guest */
8484
#define VMX_FEATURE_USR_WAIT_PAUSE ( 2*32+ 26) /* Enable TPAUSE, UMONITOR, UMWAIT in guest */
8585
#define VMX_FEATURE_ENCLV_EXITING ( 2*32+ 28) /* "" VM-Exit on ENCLV (leaf dependent) */
86+
#define VMX_FEATURE_BUS_LOCK_DETECTION ( 2*32+ 30) /* "" VM-Exit when bus lock caused */
8687

8788
#endif /* _ASM_X86_VMXFEATURES_H */

arch/x86/include/uapi/asm/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ struct kvm_ioapic_state {
112112
#define KVM_NR_IRQCHIPS 3
113113

114114
#define KVM_RUN_X86_SMM (1 << 0)
115+
#define KVM_RUN_X86_BUS_LOCK (1 << 1)
115116

116117
/* for KVM_GET_REGS and KVM_SET_REGS */
117118
struct kvm_regs {

arch/x86/include/uapi/asm/vmx.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
#define EXIT_REASON_XRSTORS 64
9090
#define EXIT_REASON_UMWAIT 67
9191
#define EXIT_REASON_TPAUSE 68
92+
#define EXIT_REASON_BUS_LOCK 74
9293

9394
#define VMX_EXIT_REASONS \
9495
{ EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \
@@ -150,7 +151,8 @@
150151
{ EXIT_REASON_XSAVES, "XSAVES" }, \
151152
{ EXIT_REASON_XRSTORS, "XRSTORS" }, \
152153
{ EXIT_REASON_UMWAIT, "UMWAIT" }, \
153-
{ EXIT_REASON_TPAUSE, "TPAUSE" }
154+
{ EXIT_REASON_TPAUSE, "TPAUSE" }, \
155+
{ EXIT_REASON_BUS_LOCK, "BUS_LOCK" }
154156

155157
#define VMX_EXIT_REASON_FLAGS \
156158
{ VMX_EXIT_REASONS_FAILED_VMENTRY, "FAILED_VMENTRY" }

arch/x86/kvm/vmx/capabilities.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,12 @@ static inline bool cpu_has_vmx_tsc_scaling(void)
262262
SECONDARY_EXEC_TSC_SCALING;
263263
}
264264

265+
static inline bool cpu_has_vmx_bus_lock_detection(void)
266+
{
267+
return vmcs_config.cpu_based_2nd_exec_ctrl &
268+
SECONDARY_EXEC_BUS_LOCK_DETECTION;
269+
}
270+
265271
static inline bool cpu_has_vmx_apicv(void)
266272
{
267273
return cpu_has_vmx_apic_register_virt() &&

arch/x86/kvm/vmx/vmx.c

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2428,7 +2428,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,
24282428
SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE |
24292429
SECONDARY_EXEC_PT_USE_GPA |
24302430
SECONDARY_EXEC_PT_CONCEAL_VMX |
2431-
SECONDARY_EXEC_ENABLE_VMFUNC;
2431+
SECONDARY_EXEC_ENABLE_VMFUNC |
2432+
SECONDARY_EXEC_BUS_LOCK_DETECTION;
24322433
if (cpu_has_sgx())
24332434
opt2 |= SECONDARY_EXEC_ENCLS_EXITING;
24342435
if (adjust_vmx_controls(min2, opt2,
@@ -4269,6 +4270,9 @@ static void vmx_compute_secondary_exec_control(struct vcpu_vmx *vmx)
42694270
vmx_adjust_sec_exec_control(vmx, &exec_control, waitpkg, WAITPKG,
42704271
ENABLE_USR_WAIT_PAUSE, false);
42714272

4273+
if (!vcpu->kvm->arch.bus_lock_detection_enabled)
4274+
exec_control &= ~SECONDARY_EXEC_BUS_LOCK_DETECTION;
4275+
42724276
vmx->secondary_exec_control = exec_control;
42734277
}
42744278

@@ -5600,6 +5604,13 @@ static int handle_encls(struct kvm_vcpu *vcpu)
56005604
return 1;
56015605
}
56025606

5607+
static int handle_bus_lock_vmexit(struct kvm_vcpu *vcpu)
5608+
{
5609+
vcpu->run->exit_reason = KVM_EXIT_X86_BUS_LOCK;
5610+
vcpu->run->flags |= KVM_RUN_X86_BUS_LOCK;
5611+
return 0;
5612+
}
5613+
56035614
/*
56045615
* The exit handlers return 1 if the exit was handled fully and guest execution
56055616
* may resume. Otherwise they set the kvm_run parameter to indicate what needs
@@ -5656,6 +5667,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
56565667
[EXIT_REASON_VMFUNC] = handle_vmx_instruction,
56575668
[EXIT_REASON_PREEMPTION_TIMER] = handle_preemption_timer,
56585669
[EXIT_REASON_ENCLS] = handle_encls,
5670+
[EXIT_REASON_BUS_LOCK] = handle_bus_lock_vmexit,
56595671
};
56605672

56615673
static const int kvm_vmx_max_exit_handlers =
@@ -5908,7 +5920,7 @@ void dump_vmcs(void)
59085920
* The guest has exited. See if we can fix it or if we need userspace
59095921
* assistance.
59105922
*/
5911-
static int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
5923+
static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
59125924
{
59135925
struct vcpu_vmx *vmx = to_vmx(vcpu);
59145926
union vmx_exit_reason exit_reason = vmx->exit_reason;
@@ -6061,6 +6073,25 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
60616073
return 0;
60626074
}
60636075

6076+
static int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
6077+
{
6078+
int ret = __vmx_handle_exit(vcpu, exit_fastpath);
6079+
6080+
/*
6081+
* Even when current exit reason is handled by KVM internally, we
6082+
* still need to exit to user space when bus lock detected to inform
6083+
* that there is a bus lock in guest.
6084+
*/
6085+
if (to_vmx(vcpu)->exit_reason.bus_lock_detected) {
6086+
if (ret > 0)
6087+
vcpu->run->exit_reason = KVM_EXIT_X86_BUS_LOCK;
6088+
6089+
vcpu->run->flags |= KVM_RUN_X86_BUS_LOCK;
6090+
return 0;
6091+
}
6092+
return ret;
6093+
}
6094+
60646095
/*
60656096
* Software based L1D cache flush which is used when microcode providing
60666097
* the cache control MSR is not loaded.
@@ -7812,6 +7843,8 @@ static __init int hardware_setup(void)
78127843
kvm_tsc_scaling_ratio_frac_bits = 48;
78137844
}
78147845

7846+
kvm_has_bus_lock_exit = cpu_has_vmx_bus_lock_detection();
7847+
78157848
set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
78167849

78177850
if (enable_ept)

arch/x86/kvm/vmx/vmx.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ union vmx_exit_reason {
8383
u32 reserved23 : 1;
8484
u32 reserved24 : 1;
8585
u32 reserved25 : 1;
86-
u32 reserved26 : 1;
86+
u32 bus_lock_detected : 1;
8787
u32 enclave_mode : 1;
8888
u32 smi_pending_mtf : 1;
8989
u32 smi_from_vmx_root : 1;

arch/x86/kvm/x86.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ u64 __read_mostly kvm_max_tsc_scaling_ratio;
136136
EXPORT_SYMBOL_GPL(kvm_max_tsc_scaling_ratio);
137137
u64 __read_mostly kvm_default_tsc_scaling_ratio;
138138
EXPORT_SYMBOL_GPL(kvm_default_tsc_scaling_ratio);
139+
bool __read_mostly kvm_has_bus_lock_exit;
140+
EXPORT_SYMBOL_GPL(kvm_has_bus_lock_exit);
139141

140142
/* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */
141143
static u32 __read_mostly tsc_tolerance_ppm = 250;
@@ -3843,6 +3845,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
38433845
case KVM_CAP_STEAL_TIME:
38443846
r = sched_info_on();
38453847
break;
3848+
case KVM_CAP_X86_BUS_LOCK_EXIT:
3849+
if (kvm_has_bus_lock_exit)
3850+
r = KVM_BUS_LOCK_DETECTION_OFF |
3851+
KVM_BUS_LOCK_DETECTION_EXIT;
3852+
else
3853+
r = 0;
3854+
break;
38463855
default:
38473856
break;
38483857
}
@@ -5298,6 +5307,20 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
52985307
kvm->arch.user_space_msr_mask = cap->args[0];
52995308
r = 0;
53005309
break;
5310+
case KVM_CAP_X86_BUS_LOCK_EXIT:
5311+
r = -EINVAL;
5312+
if (cap->args[0] & ~KVM_BUS_LOCK_DETECTION_VALID_MODE)
5313+
break;
5314+
5315+
if ((cap->args[0] & KVM_BUS_LOCK_DETECTION_OFF) &&
5316+
(cap->args[0] & KVM_BUS_LOCK_DETECTION_EXIT))
5317+
break;
5318+
5319+
if (kvm_has_bus_lock_exit &&
5320+
cap->args[0] & KVM_BUS_LOCK_DETECTION_EXIT)
5321+
kvm->arch.bus_lock_detection_enabled = true;
5322+
r = 0;
5323+
break;
53015324
default:
53025325
r = -EINVAL;
53035326
break;

include/uapi/linux/kvm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ struct kvm_hyperv_exit {
252252
#define KVM_EXIT_X86_WRMSR 30
253253
#define KVM_EXIT_DIRTY_RING_FULL 31
254254
#define KVM_EXIT_AP_RESET_HOLD 32
255+
#define KVM_EXIT_X86_BUS_LOCK 33
255256

256257
/* For KVM_EXIT_INTERNAL_ERROR */
257258
/* Emulate instruction failed. */
@@ -1058,6 +1059,7 @@ struct kvm_ppc_resize_hpt {
10581059
#define KVM_CAP_ENFORCE_PV_FEATURE_CPUID 190
10591060
#define KVM_CAP_SYS_HYPERV_CPUID 191
10601061
#define KVM_CAP_DIRTY_LOG_RING 192
1062+
#define KVM_CAP_X86_BUS_LOCK_EXIT 193
10611063

10621064
#ifdef KVM_CAP_IRQ_ROUTING
10631065

@@ -1774,4 +1776,7 @@ struct kvm_dirty_gfn {
17741776
__u64 offset;
17751777
};
17761778

1779+
#define KVM_BUS_LOCK_DETECTION_OFF (1 << 0)
1780+
#define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1)
1781+
17771782
#endif /* __LINUX_KVM_H */

0 commit comments

Comments
 (0)