From 11c2f3eabbfcbc91a2f0a66260ee2441bf3c65f5 Mon Sep 17 00:00:00 2001 From: Zide Chen Date: Wed, 18 Aug 2021 11:54:33 -0700 Subject: [PATCH] hv: check bitmap before calling bitmap_test_and_clear_lock() The locked btr instruction is expensive. This patch changes the logic to ensure that the bitmap is non-zero before executing bitmap_test_and_clear_lock(). The VMX transition time gets significant improvement. SOS running on TGL, the CPUID roundtrip reduces from ~2400 cycles to ~2000 cycles. Tracked-On: #6289 Signed-off-by: Zide Chen Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/vcpu.c | 25 ++++++++++---- hypervisor/arch/x86/guest/virq.c | 59 +++++++++++++++++--------------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index 6a7785ca9..0a5628e18 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -603,16 +603,12 @@ int32_t create_vcpu(uint16_t pcpu_id, struct acrn_vm *vm, struct acrn_vcpu **rtn } /* - * @pre vcpu != NULL + * @pre vcpu != NULL */ -int32_t run_vcpu(struct acrn_vcpu *vcpu) +static void write_cached_registers(struct acrn_vcpu *vcpu) { - uint32_t instlen, cs_attr; - uint64_t rip, ia32_efer, cr0; struct run_context *ctx = &vcpu->arch.contexts[vcpu->arch.cur_context].run_ctx; - int32_t status = 0; - int32_t ibrs_type = get_ibrs_type(); if (bitmap_test_and_clear_lock(CPU_REG_RIP, &vcpu->reg_updated)) { exec_vmwrite(VMX_GUEST_RIP, ctx->rip); @@ -639,6 +635,23 @@ int32_t run_vcpu(struct acrn_vcpu *vcpu) if (bitmap_test_and_clear_lock(CPU_REG_CR4, &vcpu->reg_updated)) { vcpu_set_cr4(vcpu, ctx->cr4); } +} + +/* + * @pre vcpu != NULL + */ +int32_t run_vcpu(struct acrn_vcpu *vcpu) +{ + uint32_t instlen, cs_attr; + uint64_t rip, ia32_efer, cr0; + struct run_context *ctx = + &vcpu->arch.contexts[vcpu->arch.cur_context].run_ctx; + int32_t status = 0; + int32_t ibrs_type = get_ibrs_type(); + + if (vcpu->reg_updated != 0UL) { + write_cached_registers(vcpu); + } /* If this VCPU is not already launched, launch it */ if (!vcpu->launched) { diff --git a/hypervisor/arch/x86/guest/virq.c b/hypervisor/arch/x86/guest/virq.c index de13a7153..8a2b4c677 100644 --- a/hypervisor/arch/x86/guest/virq.c +++ b/hypervisor/arch/x86/guest/virq.c @@ -376,38 +376,42 @@ int32_t acrn_handle_pending_request(struct acrn_vcpu *vcpu) struct acrn_vcpu_arch *arch = &vcpu->arch; uint64_t *pending_req_bits = &arch->pending_req; - /* make sure ACRN_REQUEST_INIT_VMCS handler as the first one */ - if (bitmap_test_and_clear_lock(ACRN_REQUEST_INIT_VMCS, pending_req_bits)) { - init_vmcs(vcpu); - } - - if (bitmap_test_and_clear_lock(ACRN_REQUEST_TRP_FAULT, pending_req_bits)) { - 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 (*pending_req_bits != 0UL) { + /* make sure ACRN_REQUEST_INIT_VMCS handler as the first one */ + if (bitmap_test_and_clear_lock(ACRN_REQUEST_INIT_VMCS, pending_req_bits)) { + init_vmcs(vcpu); } - if (bitmap_test_and_clear_lock(ACRN_REQUEST_SPLIT_LOCK, pending_req_bits)) { - wait_event(&vcpu->events[VCPU_EVENT_SPLIT_LOCK]); - } + if (bitmap_test_and_clear_lock(ACRN_REQUEST_TRP_FAULT, pending_req_bits)) { + 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); - if (vcpu->vm->sworld_control.flag.active != 0UL) { - invept(vcpu->vm->arch_vm.sworld_eptp); + if (bitmap_test_and_clear_lock(ACRN_REQUEST_SPLIT_LOCK, pending_req_bits)) { + wait_event(&vcpu->events[VCPU_EVENT_SPLIT_LOCK]); + } + + if (bitmap_test_and_clear_lock(ACRN_REQUEST_EPT_FLUSH, pending_req_bits)) { + invept(vcpu->vm->arch_vm.nworld_eptp); + if (vcpu->vm->sworld_control.flag.active != 0UL) { + invept(vcpu->vm->arch_vm.sworld_eptp); + } + } + + if (bitmap_test_and_clear_lock(ACRN_REQUEST_VPID_FLUSH, pending_req_bits)) { + flush_vpid_single(arch->vpid); + } + + if (bitmap_test_and_clear_lock(ACRN_REQUEST_EOI_EXIT_BITMAP_UPDATE, pending_req_bits)) { + vcpu_set_vmcs_eoi_exit(vcpu); } } + } - if (bitmap_test_and_clear_lock(ACRN_REQUEST_VPID_FLUSH, pending_req_bits)) { - flush_vpid_single(arch->vpid); - } - - if (bitmap_test_and_clear_lock(ACRN_REQUEST_EOI_EXIT_BITMAP_UPDATE, pending_req_bits)) { - vcpu_set_vmcs_eoi_exit(vcpu); - } - + if (ret == 0) { /* * Inject pending exception prior pending interrupt to complete the previous instruction. */ @@ -415,7 +419,8 @@ int32_t acrn_handle_pending_request(struct acrn_vcpu *vcpu) if (!injected) { /* inject NMI before maskable hardware interrupt */ - if (bitmap_test_and_clear_lock(ACRN_REQUEST_NMI, pending_req_bits)) { + if ((*pending_req_bits != 0UL) && + bitmap_test_and_clear_lock(ACRN_REQUEST_NMI, pending_req_bits)) { if (is_nmi_injectable()) { /* Inject NMI vector = 2 */ exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,