HV: Use NMI-window exiting to address req missing issue
There is a window where we may miss the current request in the notification period when the work flow is as the following: CPUx + + CPUr | | | +--+ | | | Handle pending req | <--+ +--+ | | | Set req flag | <--+ | +------------------>---+ | Send NMI | | Handle NMI | <--+ | | | | | +--> vCPU enter | | + + So, this patch enables the NMI-window exiting to trigger the next vmexit once there is no "virtual-NMI blocking" after vCPU enter into VMX non-root mode. Then we can process the pending request on time. Tracked-On: #3886 Acked-by: Eddie Dong <eddie.dong@intel.com> Signed-off-by: Kaige Fu <kaige.fu@intel.com>
This commit is contained in:
parent
40ba7e8686
commit
a13909cedc
|
@ -531,3 +531,20 @@ int32_t exception_vmexit_handler(struct acrn_vcpu *vcpu)
|
|||
|
||||
return status;
|
||||
}
|
||||
|
||||
int32_t nmi_window_vmexit_handler(struct acrn_vcpu *vcpu)
|
||||
{
|
||||
uint32_t value32;
|
||||
|
||||
/*
|
||||
* Disable NMI-window exiting here. We will process
|
||||
* the pending request in acrn_handle_pending_request later
|
||||
*/
|
||||
value32 = exec_vmread32(VMX_PROC_VM_EXEC_CONTROLS);
|
||||
value32 &= ~VMX_PROCBASED_CTLS_NMI_WINEXIT;
|
||||
exec_vmwrite32(VMX_PROC_VM_EXEC_CONTROLS, value32);
|
||||
|
||||
vcpu_retain_rip(vcpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -582,7 +582,7 @@ void switch_apicv_mode_x2apic(struct acrn_vcpu *vcpu)
|
|||
* directly without vmexit. So, here we enable NMI-exiting and use NMI
|
||||
* as notification signal after passthroughing the lapic to vCPU.
|
||||
*/
|
||||
value32 |= VMX_PINBASED_CTLS_NMI_EXIT;
|
||||
value32 |= VMX_PINBASED_CTLS_NMI_EXIT | VMX_PINBASED_CTLS_VIRT_NMI;
|
||||
exec_vmwrite32(VMX_PIN_VM_EXEC_CONTROLS, value32);
|
||||
|
||||
value32 = exec_vmread32(VMX_EXIT_CONTROLS);
|
||||
|
|
|
@ -51,7 +51,7 @@ static const struct vm_exit_dispatch dispatch_table[NR_VMX_EXIT_REASONS] = {
|
|||
[VMX_EXIT_REASON_INTERRUPT_WINDOW] = {
|
||||
.handler = interrupt_window_vmexit_handler},
|
||||
[VMX_EXIT_REASON_NMI_WINDOW] = {
|
||||
.handler = unhandled_vmexit_handler},
|
||||
.handler = nmi_window_vmexit_handler},
|
||||
[VMX_EXIT_REASON_TASK_SWITCH] = {
|
||||
.handler = unhandled_vmexit_handler},
|
||||
[VMX_EXIT_REASON_CPUID] = {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <vboot.h>
|
||||
#include <dump.h>
|
||||
#include <logmsg.h>
|
||||
#include <vmx.h>
|
||||
|
||||
static spinlock_t exception_spinlock = { .head = 0U, .tail = 0U, };
|
||||
static spinlock_t irq_alloc_spinlock = { .head = 0U, .tail = 0U, };
|
||||
|
@ -384,10 +385,36 @@ void dispatch_exception(struct intr_excp_ctx *ctx)
|
|||
|
||||
void handle_nmi(__unused struct intr_excp_ctx *ctx)
|
||||
{
|
||||
uint32_t value32;
|
||||
|
||||
/*
|
||||
* Just ignore the NMI here for now.
|
||||
* TODO: implement specific NMI handling function.
|
||||
* There is a window where we may miss the current request in this
|
||||
* notification period when the work flow is as the following:
|
||||
*
|
||||
* CPUx + + CPUr
|
||||
* | |
|
||||
* | +--+
|
||||
* | | | Handle pending req
|
||||
* | <--+
|
||||
* +--+ |
|
||||
* | | Set req flag |
|
||||
* <--+ |
|
||||
* +------------------>---+
|
||||
* | Send NMI | | Handle NMI
|
||||
* | <--+
|
||||
* | |
|
||||
* | |
|
||||
* | +--> vCPU enter
|
||||
* | |
|
||||
* + +
|
||||
*
|
||||
* So, here we enable the NMI-window exiting to trigger the next vmexit
|
||||
* once there is no "virtual-NMI blocking" after vCPU enter into VMX non-root
|
||||
* mode. Then we can process the pending request on time.
|
||||
*/
|
||||
value32 = exec_vmread32(VMX_PROC_VM_EXEC_CONTROLS);
|
||||
value32 |= VMX_PROCBASED_CTLS_NMI_WINEXIT;
|
||||
exec_vmwrite32(VMX_PROC_VM_EXEC_CONTROLS, value32);
|
||||
}
|
||||
|
||||
static void init_irq_descs(void)
|
||||
|
|
|
@ -209,6 +209,7 @@ void vcpu_make_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);
|
||||
|
|
Loading…
Reference in New Issue