aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitaly Kuznetsov <vkuznets@redhat.com>2018-05-16 11:21:29 -0400
committerRadim Krčmář <rkrcmar@redhat.com>2018-05-26 08:14:33 -0400
commite2f11f42824bf2d906468a94888718ae24bf0270 (patch)
tree5959cdfd1bca0b0277fef8037570cc6a4603dffa
parent7053df4edb3ae3ae15c316fe49122c0b3936e9dd (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.h1
-rw-r--r--arch/x86/kvm/hyperv.c58
-rw-r--r--arch/x86/kvm/trace.h24
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
482struct kvm_vcpu_arch { 483struct 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
1245static 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 = &current_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
1245bool kvm_hv_hypercall_enabled(struct kvm *kvm) 1288bool 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
1387set_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 */
1374TRACE_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