Skip to content

Commit 52a5c15

Browse files
Wanpeng Lirkrcmar
authored andcommitted
KVM: async_pf: Let guest support delivery of async_pf from guest mode
Adds another flag bit (bit 2) to MSR_KVM_ASYNC_PF_EN. If bit 2 is 1, async page faults are delivered to L1 as #PF vmexits; if bit 2 is 0, kvm_can_do_async_pf returns 0 if in guest mode. This is similar to what svm.c wanted to do all along, but it is only enabled for Linux as L1 hypervisor. Foreign hypervisors must never receive async page faults as vmexits, because they'd probably be very confused about that. Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Radim Krčmář <rkrcmar@redhat.com> Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com> Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
1 parent adfe20f commit 52a5c15

File tree

7 files changed

+16
-7
lines changed

7 files changed

+16
-7
lines changed

Documentation/virtual/kvm/msr.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,11 @@ MSR_KVM_SYSTEM_TIME: 0x12
166166
MSR_KVM_ASYNC_PF_EN: 0x4b564d02
167167
data: Bits 63-6 hold 64-byte aligned physical address of a
168168
64 byte memory area which must be in guest RAM and must be
169-
zeroed. Bits 5-2 are reserved and should be zero. Bit 0 is 1
169+
zeroed. Bits 5-3 are reserved and should be zero. Bit 0 is 1
170170
when asynchronous page faults are enabled on the vcpu 0 when
171171
disabled. Bit 1 is 1 if asynchronous page faults can be injected
172-
when vcpu is in cpl == 0.
172+
when vcpu is in cpl == 0. Bit 2 is 1 if asynchronous page faults
173+
are delivered to L1 as #PF vmexits.
173174

174175
First 4 byte of 64 byte memory location will be written to by
175176
the hypervisor at the time of asynchronous page fault (APF)

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ struct kvm_vcpu_arch {
653653
bool send_user_only;
654654
u32 host_apf_reason;
655655
unsigned long nested_apf_token;
656+
bool delivery_as_pf_vmexit;
656657
} apf;
657658

658659
/* OSVW MSRs (AMD only) */

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ struct kvm_clock_pairing {
6767

6868
#define KVM_ASYNC_PF_ENABLED (1 << 0)
6969
#define KVM_ASYNC_PF_SEND_ALWAYS (1 << 1)
70+
#define KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT (1 << 2)
7071

7172
/* Operations for KVM_HC_MMU_OP */
7273
#define KVM_MMU_OP_WRITE_PTE 1

arch/x86/kernel/kvm.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,12 @@ static void kvm_guest_cpu_init(void)
330330
#ifdef CONFIG_PREEMPT
331331
pa |= KVM_ASYNC_PF_SEND_ALWAYS;
332332
#endif
333-
wrmsrl(MSR_KVM_ASYNC_PF_EN, pa | KVM_ASYNC_PF_ENABLED);
333+
pa |= KVM_ASYNC_PF_ENABLED;
334+
335+
/* Async page fault support for L1 hypervisor is optional */
336+
if (wrmsr_safe(MSR_KVM_ASYNC_PF_EN,
337+
(pa | KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT) & 0xffffffff, pa >> 32) < 0)
338+
wrmsrl(MSR_KVM_ASYNC_PF_EN, pa);
334339
__this_cpu_write(apf_reason.enabled, 1);
335340
printk(KERN_INFO"KVM setup async PF for cpu %d\n",
336341
smp_processor_id());

arch/x86/kvm/mmu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3749,7 +3749,7 @@ bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)
37493749
kvm_event_needs_reinjection(vcpu)))
37503750
return false;
37513751

3752-
if (is_guest_mode(vcpu))
3752+
if (!vcpu->arch.apf.delivery_as_pf_vmexit && is_guest_mode(vcpu))
37533753
return false;
37543754

37553755
return kvm_x86_ops->interrupt_allowed(vcpu);

arch/x86/kvm/vmx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8037,7 +8037,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
80378037
if (is_nmi(intr_info))
80388038
return false;
80398039
else if (is_page_fault(intr_info))
8040-
return enable_ept;
8040+
return !vmx->vcpu.arch.apf.host_apf_reason && enable_ept;
80418041
else if (is_no_device(intr_info) &&
80428042
!(vmcs12->guest_cr0 & X86_CR0_TS))
80438043
return false;

arch/x86/kvm/x86.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2063,8 +2063,8 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
20632063
{
20642064
gpa_t gpa = data & ~0x3f;
20652065

2066-
/* Bits 2:5 are reserved, Should be zero */
2067-
if (data & 0x3c)
2066+
/* Bits 3:5 are reserved, Should be zero */
2067+
if (data & 0x38)
20682068
return 1;
20692069

20702070
vcpu->arch.apf.msr_val = data;
@@ -2080,6 +2080,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
20802080
return 1;
20812081

20822082
vcpu->arch.apf.send_user_only = !(data & KVM_ASYNC_PF_SEND_ALWAYS);
2083+
vcpu->arch.apf.delivery_as_pf_vmexit = data & KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT;
20832084
kvm_async_pf_wakeup_all(vcpu);
20842085
return 0;
20852086
}

0 commit comments

Comments
 (0)