diff options
author | Vitaly Kuznetsov <vkuznets@redhat.com> | 2018-05-16 11:21:29 -0400 |
---|---|---|
committer | Radim Krčmář <rkrcmar@redhat.com> | 2018-05-26 08:14:33 -0400 |
commit | e2f11f42824bf2d906468a94888718ae24bf0270 (patch) | |
tree | 5959cdfd1bca0b0277fef8037570cc6a4603dffa | |
parent | 7053df4edb3ae3ae15c316fe49122c0b3936e9dd (diff) |
KVM: x86: hyperv: simplistic HVCALL_FLUSH_VIRTUAL_ADDRESS_{LIST,SPACE} implementation
Implement HvFlushVirtualAddress{List,Space} hypercalls in a simplistic way:
do full TLB flush with KVM_REQ_TLB_FLUSH and kick vCPUs which are currently
IN_GUEST_MODE.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/hyperv.c | 58 | ||||
-rw-r--r-- | arch/x86/kvm/trace.h | 24 |
3 files changed, 82 insertions, 1 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index b27de80f5870..0ebe659f2802 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -477,6 +477,7 @@ struct kvm_vcpu_hv { | |||
477 | struct kvm_hyperv_exit exit; | 477 | struct kvm_hyperv_exit exit; |
478 | struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT]; | 478 | struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT]; |
479 | DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT); | 479 | DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT); |
480 | cpumask_t tlb_lush; | ||
480 | }; | 481 | }; |
481 | 482 | ||
482 | struct kvm_vcpu_arch { | 483 | struct kvm_vcpu_arch { |
diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index edb1ac44d628..0d916606519d 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c | |||
@@ -1242,6 +1242,49 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) | |||
1242 | return kvm_hv_get_msr(vcpu, msr, pdata); | 1242 | return kvm_hv_get_msr(vcpu, msr, pdata); |
1243 | } | 1243 | } |
1244 | 1244 | ||
1245 | static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa, | ||
1246 | u16 rep_cnt) | ||
1247 | { | ||
1248 | struct kvm *kvm = current_vcpu->kvm; | ||
1249 | struct kvm_vcpu_hv *hv_current = ¤t_vcpu->arch.hyperv; | ||
1250 | struct hv_tlb_flush flush; | ||
1251 | struct kvm_vcpu *vcpu; | ||
1252 | unsigned long vcpu_bitmap[BITS_TO_LONGS(KVM_MAX_VCPUS)] = {0}; | ||
1253 | int i; | ||
1254 | |||
1255 | if (unlikely(kvm_read_guest(kvm, ingpa, &flush, sizeof(flush)))) | ||
1256 | return HV_STATUS_INVALID_HYPERCALL_INPUT; | ||
1257 | |||
1258 | trace_kvm_hv_flush_tlb(flush.processor_mask, flush.address_space, | ||
1259 | flush.flags); | ||
1260 | |||
1261 | cpumask_clear(&hv_current->tlb_lush); | ||
1262 | |||
1263 | kvm_for_each_vcpu(i, vcpu, kvm) { | ||
1264 | struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; | ||
1265 | |||
1266 | if (!(flush.flags & HV_FLUSH_ALL_PROCESSORS) && | ||
1267 | (hv->vp_index >= 64 || | ||
1268 | !(flush.processor_mask & BIT_ULL(hv->vp_index)))) | ||
1269 | continue; | ||
1270 | |||
1271 | /* | ||
1272 | * vcpu->arch.cr3 may not be up-to-date for running vCPUs so we | ||
1273 | * can't analyze it here, flush TLB regardless of the specified | ||
1274 | * address space. | ||
1275 | */ | ||
1276 | __set_bit(i, vcpu_bitmap); | ||
1277 | } | ||
1278 | |||
1279 | kvm_make_vcpus_request_mask(kvm, | ||
1280 | KVM_REQ_TLB_FLUSH | KVM_REQUEST_NO_WAKEUP, | ||
1281 | vcpu_bitmap, &hv_current->tlb_lush); | ||
1282 | |||
1283 | /* We always do full TLB flush, set rep_done = rep_cnt. */ | ||
1284 | return (u64)HV_STATUS_SUCCESS | | ||
1285 | ((u64)rep_cnt << HV_HYPERCALL_REP_COMP_OFFSET); | ||
1286 | } | ||
1287 | |||
1245 | bool kvm_hv_hypercall_enabled(struct kvm *kvm) | 1288 | bool kvm_hv_hypercall_enabled(struct kvm *kvm) |
1246 | { | 1289 | { |
1247 | return READ_ONCE(kvm->arch.hyperv.hv_hypercall) & HV_X64_MSR_HYPERCALL_ENABLE; | 1290 | return READ_ONCE(kvm->arch.hyperv.hv_hypercall) & HV_X64_MSR_HYPERCALL_ENABLE; |
@@ -1379,12 +1422,25 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) | |||
1379 | vcpu->arch.complete_userspace_io = | 1422 | vcpu->arch.complete_userspace_io = |
1380 | kvm_hv_hypercall_complete_userspace; | 1423 | kvm_hv_hypercall_complete_userspace; |
1381 | return 0; | 1424 | return 0; |
1425 | case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST: | ||
1426 | if (unlikely(fast || !rep_cnt || rep_idx)) { | ||
1427 | ret = HV_STATUS_INVALID_HYPERCALL_INPUT; | ||
1428 | break; | ||
1429 | } | ||
1430 | ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt); | ||
1431 | break; | ||
1432 | case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE: | ||
1433 | if (unlikely(fast || rep)) { | ||
1434 | ret = HV_STATUS_INVALID_HYPERCALL_INPUT; | ||
1435 | break; | ||
1436 | } | ||
1437 | ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt); | ||
1438 | break; | ||
1382 | default: | 1439 | default: |
1383 | ret = HV_STATUS_INVALID_HYPERCALL_CODE; | 1440 | ret = HV_STATUS_INVALID_HYPERCALL_CODE; |
1384 | break; | 1441 | break; |
1385 | } | 1442 | } |
1386 | 1443 | ||
1387 | set_result: | ||
1388 | kvm_hv_hypercall_set_result(vcpu, ret); | 1444 | kvm_hv_hypercall_set_result(vcpu, ret); |
1389 | return 1; | 1445 | return 1; |
1390 | } | 1446 | } |
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index 9807c314c478..47a4fd758743 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h | |||
@@ -1367,6 +1367,30 @@ TRACE_EVENT(kvm_hv_timer_state, | |||
1367 | __entry->vcpu_id, | 1367 | __entry->vcpu_id, |
1368 | __entry->hv_timer_in_use) | 1368 | __entry->hv_timer_in_use) |
1369 | ); | 1369 | ); |
1370 | |||
1371 | /* | ||
1372 | * Tracepoint for kvm_hv_flush_tlb. | ||
1373 | */ | ||
1374 | TRACE_EVENT(kvm_hv_flush_tlb, | ||
1375 | TP_PROTO(u64 processor_mask, u64 address_space, u64 flags), | ||
1376 | TP_ARGS(processor_mask, address_space, flags), | ||
1377 | |||
1378 | TP_STRUCT__entry( | ||
1379 | __field(u64, processor_mask) | ||
1380 | __field(u64, address_space) | ||
1381 | __field(u64, flags) | ||
1382 | ), | ||
1383 | |||
1384 | TP_fast_assign( | ||
1385 | __entry->processor_mask = processor_mask; | ||
1386 | __entry->address_space = address_space; | ||
1387 | __entry->flags = flags; | ||
1388 | ), | ||
1389 | |||
1390 | TP_printk("processor_mask 0x%llx address_space 0x%llx flags 0x%llx", | ||
1391 | __entry->processor_mask, __entry->address_space, | ||
1392 | __entry->flags) | ||
1393 | ); | ||
1370 | #endif /* _TRACE_KVM_H */ | 1394 | #endif /* _TRACE_KVM_H */ |
1371 | 1395 | ||
1372 | #undef TRACE_INCLUDE_PATH | 1396 | #undef TRACE_INCLUDE_PATH |