diff options
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 3 | ||||
-rw-r--r-- | arch/x86/kvm/mmu.c | 1 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 43 | ||||
-rw-r--r-- | include/trace/events/kvm.h | 17 | ||||
-rw-r--r-- | virt/kvm/async_pf.c | 3 |
5 files changed, 55 insertions, 12 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 0d7039804b4c..167375cc49ff 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -421,6 +421,7 @@ struct kvm_vcpu_arch { | |||
421 | gfn_t gfns[roundup_pow_of_two(ASYNC_PF_PER_VCPU)]; | 421 | gfn_t gfns[roundup_pow_of_two(ASYNC_PF_PER_VCPU)]; |
422 | struct gfn_to_hva_cache data; | 422 | struct gfn_to_hva_cache data; |
423 | u64 msr_val; | 423 | u64 msr_val; |
424 | u32 id; | ||
424 | } apf; | 425 | } apf; |
425 | }; | 426 | }; |
426 | 427 | ||
@@ -596,6 +597,7 @@ struct kvm_x86_ops { | |||
596 | }; | 597 | }; |
597 | 598 | ||
598 | struct kvm_arch_async_pf { | 599 | struct kvm_arch_async_pf { |
600 | u32 token; | ||
599 | gfn_t gfn; | 601 | gfn_t gfn; |
600 | }; | 602 | }; |
601 | 603 | ||
@@ -819,6 +821,7 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, | |||
819 | struct kvm_async_pf *work); | 821 | struct kvm_async_pf *work); |
820 | void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, | 822 | void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, |
821 | struct kvm_async_pf *work); | 823 | struct kvm_async_pf *work); |
824 | bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu); | ||
822 | extern bool kvm_find_async_pf_gfn(struct kvm_vcpu *vcpu, gfn_t gfn); | 825 | extern bool kvm_find_async_pf_gfn(struct kvm_vcpu *vcpu, gfn_t gfn); |
823 | 826 | ||
824 | #endif /* _ASM_X86_KVM_HOST_H */ | 827 | #endif /* _ASM_X86_KVM_HOST_H */ |
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index b2c60986a7ce..64f90db369fb 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -2592,6 +2592,7 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, | |||
2592 | int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn) | 2592 | int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn) |
2593 | { | 2593 | { |
2594 | struct kvm_arch_async_pf arch; | 2594 | struct kvm_arch_async_pf arch; |
2595 | arch.token = (vcpu->arch.apf.id++ << 12) | vcpu->vcpu_id; | ||
2595 | arch.gfn = gfn; | 2596 | arch.gfn = gfn; |
2596 | 2597 | ||
2597 | return kvm_setup_async_pf(vcpu, gva, gfn, &arch); | 2598 | return kvm_setup_async_pf(vcpu, gva, gfn, &arch); |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 063c07296764..ac4c368afd40 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -6248,20 +6248,53 @@ static void kvm_del_async_pf_gfn(struct kvm_vcpu *vcpu, gfn_t gfn) | |||
6248 | } | 6248 | } |
6249 | } | 6249 | } |
6250 | 6250 | ||
6251 | static int apf_put_user(struct kvm_vcpu *vcpu, u32 val) | ||
6252 | { | ||
6253 | |||
6254 | return kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.apf.data, &val, | ||
6255 | sizeof(val)); | ||
6256 | } | ||
6257 | |||
6251 | void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu, | 6258 | void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu, |
6252 | struct kvm_async_pf *work) | 6259 | struct kvm_async_pf *work) |
6253 | { | 6260 | { |
6254 | trace_kvm_async_pf_not_present(work->gva); | 6261 | trace_kvm_async_pf_not_present(work->arch.token, work->gva); |
6255 | |||
6256 | kvm_make_request(KVM_REQ_APF_HALT, vcpu); | ||
6257 | kvm_add_async_pf_gfn(vcpu, work->arch.gfn); | 6262 | kvm_add_async_pf_gfn(vcpu, work->arch.gfn); |
6263 | |||
6264 | if (!(vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED) || | ||
6265 | kvm_x86_ops->get_cpl(vcpu) == 0) | ||
6266 | kvm_make_request(KVM_REQ_APF_HALT, vcpu); | ||
6267 | else if (!apf_put_user(vcpu, KVM_PV_REASON_PAGE_NOT_PRESENT)) { | ||
6268 | vcpu->arch.fault.error_code = 0; | ||
6269 | vcpu->arch.fault.address = work->arch.token; | ||
6270 | kvm_inject_page_fault(vcpu); | ||
6271 | } | ||
6258 | } | 6272 | } |
6259 | 6273 | ||
6260 | void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, | 6274 | void kvm_arch_async_page_present(struct kvm_vcpu *vcpu, |
6261 | struct kvm_async_pf *work) | 6275 | struct kvm_async_pf *work) |
6262 | { | 6276 | { |
6263 | trace_kvm_async_pf_ready(work->gva); | 6277 | trace_kvm_async_pf_ready(work->arch.token, work->gva); |
6264 | kvm_del_async_pf_gfn(vcpu, work->arch.gfn); | 6278 | if (is_error_page(work->page)) |
6279 | work->arch.token = ~0; /* broadcast wakeup */ | ||
6280 | else | ||
6281 | kvm_del_async_pf_gfn(vcpu, work->arch.gfn); | ||
6282 | |||
6283 | if ((vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED) && | ||
6284 | !apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) { | ||
6285 | vcpu->arch.fault.error_code = 0; | ||
6286 | vcpu->arch.fault.address = work->arch.token; | ||
6287 | kvm_inject_page_fault(vcpu); | ||
6288 | } | ||
6289 | } | ||
6290 | |||
6291 | bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu) | ||
6292 | { | ||
6293 | if (!(vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED)) | ||
6294 | return true; | ||
6295 | else | ||
6296 | return !kvm_event_needs_reinjection(vcpu) && | ||
6297 | kvm_x86_ops->interrupt_allowed(vcpu); | ||
6265 | } | 6298 | } |
6266 | 6299 | ||
6267 | EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit); | 6300 | EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit); |
diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h index a78a5e574632..9c2cc6a96e82 100644 --- a/include/trace/events/kvm.h +++ b/include/trace/events/kvm.h | |||
@@ -204,34 +204,39 @@ TRACE_EVENT( | |||
204 | 204 | ||
205 | TRACE_EVENT( | 205 | TRACE_EVENT( |
206 | kvm_async_pf_not_present, | 206 | kvm_async_pf_not_present, |
207 | TP_PROTO(u64 gva), | 207 | TP_PROTO(u64 token, u64 gva), |
208 | TP_ARGS(gva), | 208 | TP_ARGS(token, gva), |
209 | 209 | ||
210 | TP_STRUCT__entry( | 210 | TP_STRUCT__entry( |
211 | __field(__u64, token) | ||
211 | __field(__u64, gva) | 212 | __field(__u64, gva) |
212 | ), | 213 | ), |
213 | 214 | ||
214 | TP_fast_assign( | 215 | TP_fast_assign( |
216 | __entry->token = token; | ||
215 | __entry->gva = gva; | 217 | __entry->gva = gva; |
216 | ), | 218 | ), |
217 | 219 | ||
218 | TP_printk("gva %#llx not present", __entry->gva) | 220 | TP_printk("token %#llx gva %#llx not present", __entry->token, |
221 | __entry->gva) | ||
219 | ); | 222 | ); |
220 | 223 | ||
221 | TRACE_EVENT( | 224 | TRACE_EVENT( |
222 | kvm_async_pf_ready, | 225 | kvm_async_pf_ready, |
223 | TP_PROTO(u64 gva), | 226 | TP_PROTO(u64 token, u64 gva), |
224 | TP_ARGS(gva), | 227 | TP_ARGS(token, gva), |
225 | 228 | ||
226 | TP_STRUCT__entry( | 229 | TP_STRUCT__entry( |
230 | __field(__u64, token) | ||
227 | __field(__u64, gva) | 231 | __field(__u64, gva) |
228 | ), | 232 | ), |
229 | 233 | ||
230 | TP_fast_assign( | 234 | TP_fast_assign( |
235 | __entry->token = token; | ||
231 | __entry->gva = gva; | 236 | __entry->gva = gva; |
232 | ), | 237 | ), |
233 | 238 | ||
234 | TP_printk("gva %#llx ready", __entry->gva) | 239 | TP_printk("token %#llx gva %#llx ready", __entry->token, __entry->gva) |
235 | ); | 240 | ); |
236 | 241 | ||
237 | TRACE_EVENT( | 242 | TRACE_EVENT( |
diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 1f59498561b2..60df9e059e69 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c | |||
@@ -124,7 +124,8 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu) | |||
124 | { | 124 | { |
125 | struct kvm_async_pf *work; | 125 | struct kvm_async_pf *work; |
126 | 126 | ||
127 | if (list_empty_careful(&vcpu->async_pf.done)) | 127 | if (list_empty_careful(&vcpu->async_pf.done) || |
128 | !kvm_arch_can_inject_async_page_present(vcpu)) | ||
128 | return; | 129 | return; |
129 | 130 | ||
130 | spin_lock(&vcpu->async_pf.lock); | 131 | spin_lock(&vcpu->async_pf.lock); |