Skip to content

Commit eeeb4f6

Browse files
Sean Christophersonbonzini
authored andcommitted
KVM: x86: Introduce KVM_REQ_TLB_FLUSH_CURRENT to flush current ASID
Add KVM_REQ_TLB_FLUSH_CURRENT to allow optimized TLB flushing of VMX's EPTP/VPID contexts[*] from the KVM MMU and/or in a deferred manner, e.g. to flush L2's context during nested VM-Enter. Convert KVM_REQ_TLB_FLUSH to KVM_REQ_TLB_FLUSH_CURRENT in flows where the flush is directly associated with vCPU-scoped instruction emulation, i.e. MOV CR3 and INVPCID. Add a comment in vmx_vcpu_load_vmcs() above its KVM_REQ_TLB_FLUSH to make it clear that it deliberately requests a flush of all contexts. Service any pending flush request on nested VM-Exit as it's possible a nested VM-Exit could occur after requesting a flush for L2. Add the same logic for nested VM-Enter even though it's _extremely_ unlikely for flush to be pending on nested VM-Enter, but theoretically possible (in the future) due to RSM (SMM) emulation. [*] Intel also has an Address Space Identifier (ASID) concept, e.g. EPTP+VPID+PCID == ASID, it's just not documented in the SDM because the rules of invalidation are different based on which piece of the ASID is being changed, i.e. whether the EPTP, VPID, or PCID context must be invalidated. Signed-off-by: Sean Christopherson <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 50b265a commit eeeb4f6

File tree

6 files changed

+32
-4
lines changed

6 files changed

+32
-4
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@
8383
#define KVM_REQ_GET_VMCS12_PAGES KVM_ARCH_REQ(24)
8484
#define KVM_REQ_APICV_UPDATE \
8585
KVM_ARCH_REQ_FLAGS(25, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
86+
#define KVM_REQ_TLB_FLUSH_CURRENT KVM_ARCH_REQ(26)
8687
#define KVM_REQ_HV_TLB_FLUSH \
87-
KVM_ARCH_REQ_FLAGS(26, KVM_REQUEST_NO_WAKEUP)
88+
KVM_ARCH_REQ_FLAGS(27, KVM_REQUEST_NO_WAKEUP)
8889

8990
#define CR0_RESERVED_BITS \
9091
(~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
@@ -1104,6 +1105,7 @@ struct kvm_x86_ops {
11041105
void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
11051106

11061107
void (*tlb_flush_all)(struct kvm_vcpu *vcpu);
1108+
void (*tlb_flush_current)(struct kvm_vcpu *vcpu);
11071109
int (*tlb_remote_flush)(struct kvm *kvm);
11081110
int (*tlb_remote_flush_with_range)(struct kvm *kvm,
11091111
struct kvm_tlb_range *range);

arch/x86/kvm/svm/svm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3945,6 +3945,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
39453945
.set_rflags = svm_set_rflags,
39463946

39473947
.tlb_flush_all = svm_flush_tlb,
3948+
.tlb_flush_current = svm_flush_tlb,
39483949
.tlb_flush_gva = svm_flush_tlb_gva,
39493950
.tlb_flush_guest = svm_flush_tlb,
39503951

arch/x86/kvm/vmx/nested.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3208,6 +3208,9 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
32083208
u32 exit_reason = EXIT_REASON_INVALID_STATE;
32093209
u32 exit_qual;
32103210

3211+
if (kvm_check_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu))
3212+
kvm_vcpu_flush_tlb_current(vcpu);
3213+
32113214
evaluate_pending_interrupts = exec_controls_get(vmx) &
32123215
(CPU_BASED_INTR_WINDOW_EXITING | CPU_BASED_NMI_WINDOW_EXITING);
32133216
if (likely(!evaluate_pending_interrupts) && kvm_vcpu_apicv_active(vcpu))
@@ -4274,6 +4277,10 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
42744277
/* trying to cancel vmlaunch/vmresume is a bug */
42754278
WARN_ON_ONCE(vmx->nested.nested_run_pending);
42764279

4280+
/* Service the TLB flush request for L2 before switching to L1. */
4281+
if (kvm_check_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu))
4282+
kvm_vcpu_flush_tlb_current(vcpu);
4283+
42774284
leave_guest_mode(vcpu);
42784285

42794286
if (nested_cpu_has_preemption_timer(vmcs12))

arch/x86/kvm/vmx/vmx.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1338,6 +1338,10 @@ void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu)
13381338
void *gdt = get_current_gdt_ro();
13391339
unsigned long sysenter_esp;
13401340

1341+
/*
1342+
* Flush all EPTP/VPID contexts, the new pCPU may have stale
1343+
* TLB entries from its previous association with the vCPU.
1344+
*/
13411345
kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
13421346

13431347
/*
@@ -5468,7 +5472,7 @@ static int handle_invpcid(struct kvm_vcpu *vcpu)
54685472

54695473
if (kvm_get_active_pcid(vcpu) == operand.pcid) {
54705474
kvm_mmu_sync_roots(vcpu);
5471-
kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
5475+
kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
54725476
}
54735477

54745478
for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++)
@@ -7764,6 +7768,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
77647768
.set_rflags = vmx_set_rflags,
77657769

77667770
.tlb_flush_all = vmx_flush_tlb_all,
7771+
.tlb_flush_current = vmx_flush_tlb_current,
77677772
.tlb_flush_gva = vmx_flush_tlb_gva,
77687773
.tlb_flush_guest = vmx_flush_tlb_guest,
77697774

arch/x86/kvm/x86.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
10191019
if (cr3 == kvm_read_cr3(vcpu) && !pdptrs_changed(vcpu)) {
10201020
if (!skip_tlb_flush) {
10211021
kvm_mmu_sync_roots(vcpu);
1022-
kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
1022+
kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
10231023
}
10241024
return 0;
10251025
}
@@ -8222,10 +8222,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
82228222
kvm_mmu_sync_roots(vcpu);
82238223
if (kvm_check_request(KVM_REQ_LOAD_MMU_PGD, vcpu))
82248224
kvm_mmu_load_pgd(vcpu);
8225-
if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
8225+
if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu)) {
82268226
kvm_vcpu_flush_tlb_all(vcpu);
8227+
8228+
/* Flushing all ASIDs flushes the current ASID... */
8229+
kvm_clear_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
8230+
}
8231+
if (kvm_check_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu))
8232+
kvm_vcpu_flush_tlb_current(vcpu);
82278233
if (kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu))
82288234
kvm_vcpu_flush_tlb_guest(vcpu);
8235+
82298236
if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
82308237
vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
82318238
r = 0;

arch/x86/kvm/x86.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ static inline bool mmu_is_nested(struct kvm_vcpu *vcpu)
125125
return vcpu->arch.walk_mmu == &vcpu->arch.nested_mmu;
126126
}
127127

128+
static inline void kvm_vcpu_flush_tlb_current(struct kvm_vcpu *vcpu)
129+
{
130+
++vcpu->stat.tlb_flush;
131+
kvm_x86_ops.tlb_flush_current(vcpu);
132+
}
133+
128134
static inline int is_pae(struct kvm_vcpu *vcpu)
129135
{
130136
return kvm_read_cr4_bits(vcpu, X86_CR4_PAE);

0 commit comments

Comments
 (0)