diff --git a/hypervisor/arch/x86/guest/ept.c b/hypervisor/arch/x86/guest/ept.c index 8b83b36ba..a7b9d4ce6 100644 --- a/hypervisor/arch/x86/guest/ept.c +++ b/hypervisor/arch/x86/guest/ept.c @@ -241,6 +241,17 @@ void walk_ept_table(struct acrn_vm *vm, pge_handler cb) } } } + /* + * Walk through the whole page tables of one VM is a time-consuming + * operation. Preemption is not support by hypervisor scheduling + * currently, so the walk through page tables operation might occupy + * CPU for long time what starve other threads. + * + * Give chance to release CPU to make other threads happy. + */ + if (need_reschedule(get_pcpu_id())) { + schedule(); + } } } } diff --git a/hypervisor/arch/x86/guest/virq.c b/hypervisor/arch/x86/guest/virq.c index 251bc8147..5390617ff 100644 --- a/hypervisor/arch/x86/guest/virq.c +++ b/hypervisor/arch/x86/guest/virq.c @@ -374,6 +374,9 @@ int32_t acrn_handle_pending_request(struct acrn_vcpu *vcpu) pr_fatal("Triple fault happen -> shutdown!"); ret = -EFAULT; } else { + if (bitmap_test_and_clear_lock(ACRN_REQUEST_WAIT_WBINVD, pending_req_bits)) { + wait_event(&vcpu->events[VCPU_EVENT_SYNC_WBINVD]); + } if (bitmap_test_and_clear_lock(ACRN_REQUEST_EPT_FLUSH, pending_req_bits)) { invept(vcpu->vm->arch_vm.nworld_eptp); diff --git a/hypervisor/arch/x86/guest/vmexit.c b/hypervisor/arch/x86/guest/vmexit.c index 20bc51aa4..dfab7ff41 100644 --- a/hypervisor/arch/x86/guest/vmexit.c +++ b/hypervisor/arch/x86/guest/vmexit.c @@ -379,10 +379,30 @@ static int32_t xsetbv_vmexit_handler(struct acrn_vcpu *vcpu) static int32_t wbinvd_vmexit_handler(struct acrn_vcpu *vcpu) { + uint16_t i; + struct acrn_vcpu *other; + if (has_rt_vm() == false) { cache_flush_invalidate_all(); } else { - walk_ept_table(vcpu->vm, ept_flush_leaf_page); + if (is_rt_vm(vcpu->vm)) { + walk_ept_table(vcpu->vm, ept_flush_leaf_page); + } else { + /* Pause other vcpus and let them wait for the wbinvd completion */ + foreach_vcpu(i, vcpu->vm, other) { + if (other != vcpu) { + vcpu_make_request(other, ACRN_REQUEST_WAIT_WBINVD); + } + } + + walk_ept_table(vcpu->vm, ept_flush_leaf_page); + + foreach_vcpu(i, vcpu->vm, other) { + if (other != vcpu) { + signal_event(&other->events[VCPU_EVENT_SYNC_WBINVD]); + } + } + } } return 0; diff --git a/hypervisor/include/arch/x86/guest/vcpu.h b/hypervisor/include/arch/x86/guest/vcpu.h index ffd301adc..052a69e1e 100644 --- a/hypervisor/include/arch/x86/guest/vcpu.h +++ b/hypervisor/include/arch/x86/guest/vcpu.h @@ -93,6 +93,11 @@ */ #define ACRN_REQUEST_INIT_VMCS 8U +/** + * @brief Request for sync waiting WBINVD + */ +#define ACRN_REQUEST_WAIT_WBINVD 9U + /** * @} */ @@ -148,7 +153,8 @@ enum vm_cpu_mode { #define VCPU_EVENT_IOREQ 0 #define VCPU_EVENT_VIRTUAL_INTERRUPT 1 -#define VCPU_EVENT_NUM 2 +#define VCPU_EVENT_SYNC_WBINVD 2 +#define VCPU_EVENT_NUM 3 enum reset_mode;