acrn-hypervisor/hypervisor/include/arch/x86/asm/guest/virq.h
Yifan Liu 10963b04d1 hv: Fix vcpu signaling racing problem in lock instruction emulation
In lock instruction emulation, we use vcpu_make_request and
signal_event pairs to shoot down/release other vcpus.
However, vcpu_make_request is async and does not guarantee an execution
of wait_event on target vcpu, and we want wait_event to be consistent
with signal_event.

Consider following scenarios:

1, When target vcpu's state has not yet turned to VCPU_RUNNING,
vcpu_make_request on ACRN_REQUEST_SPLIT_LOCK does not make sense, and will
not result in wait_event.

2, When target vcpu is already requested on ACRN_REQUEST_SPLIT_LOCK (i.e., the
corresponding bit in pending_req is set) but not yet handled,
the vcpu_make_request call does not result in wait_event as 1 bit is not
enough to cache multiple requests.

This patch tries to add checks in vcpu_kick_lock_instr_emulation and
vcpu_complete_lock_instr_emulation to resolve these issues.

Tracked-On: #6502
Signed-off-by: Yifan Liu <yifan1.liu@intel.com>
Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com>
2021-11-02 15:01:20 +08:00

124 lines
2.6 KiB
C

/*
* Copyright (C) 2021 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef ARCH_X86_GUEST_VIRQ_H
#define ARCH_X86_GUEST_VIRQ_H
struct acrn_vcpu;
struct acrn_vm;
/**
* @brief virtual IRQ
*
* @addtogroup acrn_virq ACRN vIRQ
* @{
*/
/**
* @brief Queue exception to guest.
*
* This exception may be injected immediately or later,
* depends on the exeception class.
*
* @param[in] vcpu Pointer to vCPU.
* @param[in] vector_arg Vector of the exeception.
* @param[in] err_code_arg Error Code to be injected.
*
* @retval 0 on success
* @retval -EINVAL on error that vector is invalid.
*
* @pre vcpu != NULL
*/
int32_t vcpu_queue_exception(struct acrn_vcpu *vcpu, uint32_t vector_arg, uint32_t err_code_arg);
/**
* @brief Inject external interrupt to guest.
*
* @param[in] vcpu Pointer to vCPU.
*
* @return None
*
* @pre vcpu != NULL
*/
void vcpu_inject_extint(struct acrn_vcpu *vcpu);
/**
* @brief Inject NMI to guest.
*
* @param[in] vcpu Pointer to vCPU.
*
* @return None
*
* @pre vcpu != NULL
*/
void vcpu_inject_nmi(struct acrn_vcpu *vcpu);
/**
* @brief Inject general protection exeception(GP) to guest.
*
* @param[in] vcpu Pointer to vCPU.
* @param[in] err_code Error Code to be injected.
*
* @return None
*
* @pre vcpu != NULL
*/
void vcpu_inject_gp(struct acrn_vcpu *vcpu, uint32_t err_code);
/**
* @brief Inject page fault exeception(PF) to guest.
*
* @param[in] vcpu Pointer to vCPU.
* @param[in] addr Address that result in PF.
* @param[in] err_code Error Code to be injected.
*
* @return None
*
* @pre vcpu != NULL
*/
void vcpu_inject_pf(struct acrn_vcpu *vcpu, uint64_t addr, uint32_t err_code);
/**
* @brief Inject invalid opcode exeception(UD) to guest.
*
* @param[in] vcpu Pointer to vCPU.
*
* @return None
*
* @pre vcpu != NULL
*/
void vcpu_inject_ud(struct acrn_vcpu *vcpu);
/**
* @brief Inject stack fault exeception(SS) to guest.
*
* @param[in] vcpu Pointer to vCPU.
*
* @return None
*
* @pre vcpu != NULL
*/
void vcpu_inject_ss(struct acrn_vcpu *vcpu);
void vcpu_make_request(struct acrn_vcpu *vcpu, uint16_t eventid);
bool vcpu_try_cancel_request(struct acrn_vcpu *vcpu, uint16_t eventid);
/*
* @pre vcpu != NULL
*/
int32_t exception_vmexit_handler(struct acrn_vcpu *vcpu);
int32_t nmi_window_vmexit_handler(struct acrn_vcpu *vcpu);
int32_t interrupt_window_vmexit_handler(struct acrn_vcpu *vcpu);
int32_t external_interrupt_vmexit_handler(struct acrn_vcpu *vcpu);
int32_t acrn_handle_pending_request(struct acrn_vcpu *vcpu);
/**
* @}
*/
/* End of acrn_virq */
#endif /* ARCH_X86_GUEST_VIRQ_H */