[PATCH v2 4/7] HV: ignore the NMI injection request for lapic-pt vCPUs


Kaige Fu
 

NMI will be used as notification signal for lapic-pt vCPUs and
ACRN doesn't support vNMI for lapic-pt vCPUs. Because it is not
possible to distinguish between notification NMIs and external NMIs
for lapic-pt vCPUs in some corner cases, eg: we can use a magic number
as identifier of notification NMIs. If it is set when receiving a NMI,
this NMI is processed as notification NMI. Otherwise, it is a external
NMI for lapic-pt vCPUs. It works well most of the time. But it won't work
for some corner cases, eg:

1. The sender CPU sets the identifier.
2. An external NMI occurs on the target CPU and then the target CPU will
treat this NMI as notification NMI by mistake.
3. The sender CPU sends the NMI to target CPU.

So, this patch ignores the pending NMI request and EXCP with vector 2.

Signed-off-by: Kaige Fu <kaige.fu@...>
---
hypervisor/arch/x86/guest/virq.c | 55 ++++++++++++++++++++------------
1 file changed, 35 insertions(+), 20 deletions(-)

diff --git a/hypervisor/arch/x86/guest/virq.c b/hypervisor/arch/x86/guest/virq.c
index a0be3c3d..174c0fb3 100644
--- a/hypervisor/arch/x86/guest/virq.c
+++ b/hypervisor/arch/x86/guest/virq.c
@@ -212,26 +212,36 @@ int32_t vcpu_queue_exception(struct acrn_vcpu *vcpu, uint32_t vector_arg, uint32
static void vcpu_inject_exception(struct acrn_vcpu *vcpu, uint32_t vector)
{
if (bitmap_test_and_clear_lock(ACRN_REQUEST_EXCP, &vcpu->arch.pending_req)) {
-
- if ((exception_type[vector] & EXCEPTION_ERROR_CODE_VALID) != 0U) {
- exec_vmwrite32(VMX_ENTRY_EXCEPTION_ERROR_CODE,
- vcpu->arch.exception_info.error);
- }
+ if (is_lapic_pt_enabled(vcpu) && (vector == IDT_NMI)) {
+ /*
+ * NMI will be used as notification signal for lapic-pt vCPUs and we
+ * don't support vNMI yet. So, here we just ignore the NMI injection
+ * request.
+ */
+ pr_warn("Don't allow to inject NMI to lapic-pt vCPU%u. Ignore this request.", vcpu->vcpu_id);
+ vcpu->arch.exception_info.exception = VECTOR_INVALID;
+ } else {
+ if ((exception_type[vector] & EXCEPTION_ERROR_CODE_VALID) != 0U) {
+ exec_vmwrite32(VMX_ENTRY_EXCEPTION_ERROR_CODE,
+ vcpu->arch.exception_info.error);
+ }

- exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD, VMX_INT_INFO_VALID |
- (exception_type[vector] << 8U) | (vector & 0xFFU));
+ exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD, VMX_INT_INFO_VALID |
+ (exception_type[vector] << 8U) | (vector & 0xFFU));

- vcpu->arch.exception_info.exception = VECTOR_INVALID;
+ vcpu->arch.exception_info.exception = VECTOR_INVALID;

- /* retain rip for exception injection */
- vcpu_retain_rip(vcpu);
+ /* retain rip for exception injection */
+ vcpu_retain_rip(vcpu);

- /* SDM 17.3.1.1 For any fault-class exception except a debug exception generated in response to an
- * instruction breakpoint, the value pushed for RF is 1.
- * #DB is treated as Trap in get_exception_type, so RF will not be set for instruction breakpoint.
- */
- if (get_exception_type(vector) == EXCEPTION_FAULT) {
- vcpu_set_rflags(vcpu, vcpu_get_rflags(vcpu) | HV_ARCH_VCPU_RFLAGS_RF);
+ /* SDM 17.3.1.1 For any fault-class exception except a debug exception generated
+ * in response to an instruction breakpoint, the value pushed for RF is 1.
+ * #DB is treated as Trap in get_exception_type, so RF will not be set for
+ * instruction breakpoint.
+ */
+ if (get_exception_type(vector) == EXCEPTION_FAULT) {
+ vcpu_set_rflags(vcpu, vcpu_get_rflags(vcpu) | HV_ARCH_VCPU_RFLAGS_RF);
+ }
}
}
}
@@ -389,10 +399,15 @@ 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)) {
- /* Inject NMI vector = 2 */
- exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
- VMX_INT_INFO_VALID | (VMX_INT_TYPE_NMI << 8U) | IDT_NMI);
- injected = true;
+ if (!is_lapic_pt_enabled(vcpu)) {
+ /* Inject NMI vector = 2 */
+ exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
+ VMX_INT_INFO_VALID | (VMX_INT_TYPE_NMI << 8U) | IDT_NMI);
+ injected = true;
+ } else {
+ pr_warn("Don't allow to inject NMI to lapic-pt vCPU%u. Ignore this request.",
+ vcpu->vcpu_id);
+ }
} else {
/* handling pending vector injection:
* there are many reason inject failed, we need re-inject again
--
2.20.0


Yan, Like
 

On Mon, Dec 09, 2019 at 04:47:48PM +0000, Kaige Fu wrote:
NMI will be used as notification signal for lapic-pt vCPUs and
ACRN doesn't support vNMI for lapic-pt vCPUs. Because it is not
possible to distinguish between notification NMIs and external NMIs
for lapic-pt vCPUs in some corner cases, eg: we can use a magic number
as identifier of notification NMIs. If it is set when receiving a NMI,
this NMI is processed as notification NMI. Otherwise, it is a external
NMI for lapic-pt vCPUs. It works well most of the time. But it won't work
for some corner cases, eg:

1. The sender CPU sets the identifier.
2. An external NMI occurs on the target CPU and then the target CPU will
treat this NMI as notification NMI by mistake.
3. The sender CPU sends the NMI to target CPU.

So, this patch ignores the pending NMI request and EXCP with vector 2.

Signed-off-by: Kaige Fu <kaige.fu@...>
---
hypervisor/arch/x86/guest/virq.c | 55 ++++++++++++++++++++------------
1 file changed, 35 insertions(+), 20 deletions(-)

diff --git a/hypervisor/arch/x86/guest/virq.c b/hypervisor/arch/x86/guest/virq.c
index a0be3c3d..174c0fb3 100644
--- a/hypervisor/arch/x86/guest/virq.c
+++ b/hypervisor/arch/x86/guest/virq.c
@@ -212,26 +212,36 @@ int32_t vcpu_queue_exception(struct acrn_vcpu *vcpu, uint32_t vector_arg, uint32
static void vcpu_inject_exception(struct acrn_vcpu *vcpu, uint32_t vector)
{
if (bitmap_test_and_clear_lock(ACRN_REQUEST_EXCP, &vcpu->arch.pending_req)) {
-
- if ((exception_type[vector] & EXCEPTION_ERROR_CODE_VALID) != 0U) {
- exec_vmwrite32(VMX_ENTRY_EXCEPTION_ERROR_CODE,
- vcpu->arch.exception_info.error);
- }
+ if (is_lapic_pt_enabled(vcpu) && (vector == IDT_NMI)) {
The restriction is not support vNMI for RTVM, so I think we should use is_lapic_pt_configured() here.

+ /*
+ * NMI will be used as notification signal for lapic-pt vCPUs and we
+ * don't support vNMI yet. So, here we just ignore the NMI injection
+ * request.
+ */
+ pr_warn("Don't allow to inject NMI to lapic-pt vCPU%u. Ignore this request.", vcpu->vcpu_id);
+ vcpu->arch.exception_info.exception = VECTOR_INVALID;
+ } else {
+ if ((exception_type[vector] & EXCEPTION_ERROR_CODE_VALID) != 0U) {
+ exec_vmwrite32(VMX_ENTRY_EXCEPTION_ERROR_CODE,
+ vcpu->arch.exception_info.error);
+ }

- exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD, VMX_INT_INFO_VALID |
- (exception_type[vector] << 8U) | (vector & 0xFFU));
+ exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD, VMX_INT_INFO_VALID |
+ (exception_type[vector] << 8U) | (vector & 0xFFU));

- vcpu->arch.exception_info.exception = VECTOR_INVALID;
+ vcpu->arch.exception_info.exception = VECTOR_INVALID;

- /* retain rip for exception injection */
- vcpu_retain_rip(vcpu);
+ /* retain rip for exception injection */
+ vcpu_retain_rip(vcpu);

- /* SDM 17.3.1.1 For any fault-class exception except a debug exception generated in response to an
- * instruction breakpoint, the value pushed for RF is 1.
- * #DB is treated as Trap in get_exception_type, so RF will not be set for instruction breakpoint.
- */
- if (get_exception_type(vector) == EXCEPTION_FAULT) {
- vcpu_set_rflags(vcpu, vcpu_get_rflags(vcpu) | HV_ARCH_VCPU_RFLAGS_RF);
+ /* SDM 17.3.1.1 For any fault-class exception except a debug exception generated
+ * in response to an instruction breakpoint, the value pushed for RF is 1.
+ * #DB is treated as Trap in get_exception_type, so RF will not be set for
+ * instruction breakpoint.
+ */
+ if (get_exception_type(vector) == EXCEPTION_FAULT) {
+ vcpu_set_rflags(vcpu, vcpu_get_rflags(vcpu) | HV_ARCH_VCPU_RFLAGS_RF);
+ }
}
}
}
@@ -389,10 +399,15 @@ 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)) {
- /* Inject NMI vector = 2 */
- exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
- VMX_INT_INFO_VALID | (VMX_INT_TYPE_NMI << 8U) | IDT_NMI);
- injected = true;
+ if (!is_lapic_pt_enabled(vcpu)) {
Ditto

+ /* Inject NMI vector = 2 */
+ exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
+ VMX_INT_INFO_VALID | (VMX_INT_TYPE_NMI << 8U) | IDT_NMI);
+ injected = true;
+ } else {
+ pr_warn("Don't allow to inject NMI to lapic-pt vCPU%u. Ignore this request.",
+ vcpu->vcpu_id);
+ }
} else {
/* handling pending vector injection:
* there are many reason inject failed, we need re-inject again
--
2.20.0




Kaige Fu
 

Hi Like,

-----Original Message-----
From: acrn-dev@... <acrn-dev@...> On
Behalf Of Yan, Like
Sent: Tuesday, December 10, 2019 9:20 AM
To: acrn-dev@...
Subject: Re: [acrn-dev] [PATCH v2 4/7] HV: ignore the NMI injection request
for lapic-pt vCPUs

On Mon, Dec 09, 2019 at 04:47:48PM +0000, Kaige Fu wrote:
NMI will be used as notification signal for lapic-pt vCPUs and ACRN
doesn't support vNMI for lapic-pt vCPUs. Because it is not possible to
distinguish between notification NMIs and external NMIs for lapic-pt
vCPUs in some corner cases, eg: we can use a magic number as
identifier of notification NMIs. If it is set when receiving a NMI,
this NMI is processed as notification NMI. Otherwise, it is a external
NMI for lapic-pt vCPUs. It works well most of the time. But it won't
work for some corner cases, eg:

1. The sender CPU sets the identifier.
2. An external NMI occurs on the target CPU and then the target CPU will
treat this NMI as notification NMI by mistake.
3. The sender CPU sends the NMI to target CPU.

So, this patch ignores the pending NMI request and EXCP with vector 2.

Signed-off-by: Kaige Fu <kaige.fu@...>
---
hypervisor/arch/x86/guest/virq.c | 55
++++++++++++++++++++------------
1 file changed, 35 insertions(+), 20 deletions(-)

diff --git a/hypervisor/arch/x86/guest/virq.c
b/hypervisor/arch/x86/guest/virq.c
index a0be3c3d..174c0fb3 100644
--- a/hypervisor/arch/x86/guest/virq.c
+++ b/hypervisor/arch/x86/guest/virq.c
@@ -212,26 +212,36 @@ int32_t vcpu_queue_exception(struct acrn_vcpu
*vcpu, uint32_t vector_arg, uint32 static void
vcpu_inject_exception(struct acrn_vcpu *vcpu, uint32_t vector) {
if (bitmap_test_and_clear_lock(ACRN_REQUEST_EXCP, &vcpu-
arch.pending_req)) {
-
- if ((exception_type[vector] &
EXCEPTION_ERROR_CODE_VALID) != 0U) {
-
exec_vmwrite32(VMX_ENTRY_EXCEPTION_ERROR_CODE,
- vcpu->arch.exception_info.error);
- }
+ if (is_lapic_pt_enabled(vcpu) && (vector == IDT_NMI)) {
The restriction is not support vNMI for RTVM, so I think we should use
is_lapic_pt_configured() here.
I get one question here. If the is_lapic_pt_configured() is true but is_lapic_pt_enabled() is false,
Do we still take this VM as RTVM?
If yes, we can use is_lapic_pt_configured() here. Otherwise, I think the is_lapic_pt_enabled() is the right function to use here.

+ /*
+ * NMI will be used as notification signal for lapic-pt
vCPUs and we
+ * don't support vNMI yet. So, here we just ignore the
NMI injection
+ * request.
+ */
+ pr_warn("Don't allow to inject NMI to lapic-pt
vCPU%u. Ignore this request.", vcpu->vcpu_id);
+ vcpu->arch.exception_info.exception =
VECTOR_INVALID;
+ } else {
+ if ((exception_type[vector] &
EXCEPTION_ERROR_CODE_VALID) != 0U) {
+
exec_vmwrite32(VMX_ENTRY_EXCEPTION_ERROR_CODE,
+ vcpu-
arch.exception_info.error);
+ }

- exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
VMX_INT_INFO_VALID |
- (exception_type[vector] << 8U) | (vector &
0xFFU));
+ exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
VMX_INT_INFO_VALID |
+ (exception_type[vector] << 8U) |
(vector & 0xFFU));

- vcpu->arch.exception_info.exception = VECTOR_INVALID;
+ vcpu->arch.exception_info.exception =
VECTOR_INVALID;

- /* retain rip for exception injection */
- vcpu_retain_rip(vcpu);
+ /* retain rip for exception injection */
+ vcpu_retain_rip(vcpu);

- /* SDM 17.3.1.1 For any fault-class exception except a debug
exception generated in response to an
- * instruction breakpoint, the value pushed for RF is 1.
- * #DB is treated as Trap in get_exception_type, so RF will not
be set for instruction breakpoint.
- */
- if (get_exception_type(vector) == EXCEPTION_FAULT) {
- vcpu_set_rflags(vcpu, vcpu_get_rflags(vcpu) |
HV_ARCH_VCPU_RFLAGS_RF);
+ /* SDM 17.3.1.1 For any fault-class exception except
a debug exception generated
+ * in response to an instruction breakpoint, the value
pushed for RF is 1.
+ * #DB is treated as Trap in get_exception_type, so RF
will not be set for
+ * instruction breakpoint.
+ */
+ if (get_exception_type(vector) == EXCEPTION_FAULT)
{
+ vcpu_set_rflags(vcpu, vcpu_get_rflags(vcpu)
| HV_ARCH_VCPU_RFLAGS_RF);
+ }
}
}
}
@@ -389,10 +399,15 @@ 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)) {
- /* Inject NMI vector = 2 */
-
exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
- VMX_INT_INFO_VALID |
(VMX_INT_TYPE_NMI << 8U) | IDT_NMI);
- injected = true;
+ if (!is_lapic_pt_enabled(vcpu)) {
Ditto

+ /* Inject NMI vector = 2 */
+
exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
+
VMX_INT_INFO_VALID | (VMX_INT_TYPE_NMI << 8U) | IDT_NMI);
+ injected = true;
+ } else {
+ pr_warn("Don't allow to inject NMI to
lapic-pt vCPU%u. Ignore this request.",
+ vcpu->vcpu_id);
+ }
} else {
/* handling pending vector injection:
* there are many reason inject failed, we
need re-inject again
--
2.20.0




Yan, Like
 

On Tue, Dec 10, 2019 at 02:05:38AM +0000, Kaige Fu wrote:
Hi Like,

-----Original Message-----
From: acrn-dev@... <acrn-dev@...> On
Behalf Of Yan, Like
Sent: Tuesday, December 10, 2019 9:20 AM
To: acrn-dev@...
Subject: Re: [acrn-dev] [PATCH v2 4/7] HV: ignore the NMI injection request
for lapic-pt vCPUs

On Mon, Dec 09, 2019 at 04:47:48PM +0000, Kaige Fu wrote:
NMI will be used as notification signal for lapic-pt vCPUs and ACRN
doesn't support vNMI for lapic-pt vCPUs. Because it is not possible to
distinguish between notification NMIs and external NMIs for lapic-pt
vCPUs in some corner cases, eg: we can use a magic number as
identifier of notification NMIs. If it is set when receiving a NMI,
this NMI is processed as notification NMI. Otherwise, it is a external
NMI for lapic-pt vCPUs. It works well most of the time. But it won't
work for some corner cases, eg:

1. The sender CPU sets the identifier.
2. An external NMI occurs on the target CPU and then the target CPU will
treat this NMI as notification NMI by mistake.
3. The sender CPU sends the NMI to target CPU.

So, this patch ignores the pending NMI request and EXCP with vector 2.

Signed-off-by: Kaige Fu <kaige.fu@...>
---
hypervisor/arch/x86/guest/virq.c | 55
++++++++++++++++++++------------
1 file changed, 35 insertions(+), 20 deletions(-)

diff --git a/hypervisor/arch/x86/guest/virq.c
b/hypervisor/arch/x86/guest/virq.c
index a0be3c3d..174c0fb3 100644
--- a/hypervisor/arch/x86/guest/virq.c
+++ b/hypervisor/arch/x86/guest/virq.c
@@ -212,26 +212,36 @@ int32_t vcpu_queue_exception(struct acrn_vcpu
*vcpu, uint32_t vector_arg, uint32 static void
vcpu_inject_exception(struct acrn_vcpu *vcpu, uint32_t vector) {
if (bitmap_test_and_clear_lock(ACRN_REQUEST_EXCP, &vcpu-
arch.pending_req)) {
-
- if ((exception_type[vector] &
EXCEPTION_ERROR_CODE_VALID) != 0U) {
-
exec_vmwrite32(VMX_ENTRY_EXCEPTION_ERROR_CODE,
- vcpu->arch.exception_info.error);
- }
+ if (is_lapic_pt_enabled(vcpu) && (vector == IDT_NMI)) {
The restriction is not support vNMI for RTVM, so I think we should use
is_lapic_pt_configured() here.
I get one question here. If the is_lapic_pt_configured() is true but is_lapic_pt_enabled() is false,
Do we still take this VM as RTVM?
If yes, we can use is_lapic_pt_configured() here. Otherwise, I think the is_lapic_pt_enabled() is the right function to use here.
Logically, it's hard RTVM once lapic_pt configured.
If it's configured but never enabled, that's a wrong configuration of RT OS.


+ /*
+ * NMI will be used as notification signal for lapic-pt
vCPUs and we
+ * don't support vNMI yet. So, here we just ignore the
NMI injection
+ * request.
+ */
+ pr_warn("Don't allow to inject NMI to lapic-pt
vCPU%u. Ignore this request.", vcpu->vcpu_id);
+ vcpu->arch.exception_info.exception =
VECTOR_INVALID;
+ } else {
+ if ((exception_type[vector] &
EXCEPTION_ERROR_CODE_VALID) != 0U) {
+
exec_vmwrite32(VMX_ENTRY_EXCEPTION_ERROR_CODE,
+ vcpu-
arch.exception_info.error);
+ }

- exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
VMX_INT_INFO_VALID |
- (exception_type[vector] << 8U) | (vector &
0xFFU));
+ exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
VMX_INT_INFO_VALID |
+ (exception_type[vector] << 8U) |
(vector & 0xFFU));

- vcpu->arch.exception_info.exception = VECTOR_INVALID;
+ vcpu->arch.exception_info.exception =
VECTOR_INVALID;

- /* retain rip for exception injection */
- vcpu_retain_rip(vcpu);
+ /* retain rip for exception injection */
+ vcpu_retain_rip(vcpu);

- /* SDM 17.3.1.1 For any fault-class exception except a debug
exception generated in response to an
- * instruction breakpoint, the value pushed for RF is 1.
- * #DB is treated as Trap in get_exception_type, so RF will not
be set for instruction breakpoint.
- */
- if (get_exception_type(vector) == EXCEPTION_FAULT) {
- vcpu_set_rflags(vcpu, vcpu_get_rflags(vcpu) |
HV_ARCH_VCPU_RFLAGS_RF);
+ /* SDM 17.3.1.1 For any fault-class exception except
a debug exception generated
+ * in response to an instruction breakpoint, the value
pushed for RF is 1.
+ * #DB is treated as Trap in get_exception_type, so RF
will not be set for
+ * instruction breakpoint.
+ */
+ if (get_exception_type(vector) == EXCEPTION_FAULT)
{
+ vcpu_set_rflags(vcpu, vcpu_get_rflags(vcpu)
| HV_ARCH_VCPU_RFLAGS_RF);
+ }
}
}
}
@@ -389,10 +399,15 @@ 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)) {
- /* Inject NMI vector = 2 */
-
exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
- VMX_INT_INFO_VALID |
(VMX_INT_TYPE_NMI << 8U) | IDT_NMI);
- injected = true;
+ if (!is_lapic_pt_enabled(vcpu)) {
Ditto

+ /* Inject NMI vector = 2 */
+
exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
+
VMX_INT_INFO_VALID | (VMX_INT_TYPE_NMI << 8U) | IDT_NMI);
+ injected = true;
+ } else {
+ pr_warn("Don't allow to inject NMI to
lapic-pt vCPU%u. Ignore this request.",
+ vcpu->vcpu_id);
+ }
} else {
/* handling pending vector injection:
* there are many reason inject failed, we
need re-inject again
--
2.20.0






Kaige Fu
 

-----Original Message-----
From: acrn-dev@... <acrn-dev@...> On
Behalf Of Yan, Like
Sent: Tuesday, December 10, 2019 10:27 AM
To: acrn-dev@...
Subject: Re: [acrn-dev] [PATCH v2 4/7] HV: ignore the NMI injection request
for lapic-pt vCPUs

On Tue, Dec 10, 2019 at 02:05:38AM +0000, Kaige Fu wrote:
Hi Like,

-----Original Message-----
From: acrn-dev@...
<acrn-dev@...> On Behalf Of Yan, Like
Sent: Tuesday, December 10, 2019 9:20 AM
To: acrn-dev@...
Subject: Re: [acrn-dev] [PATCH v2 4/7] HV: ignore the NMI injection
request for lapic-pt vCPUs

On Mon, Dec 09, 2019 at 04:47:48PM +0000, Kaige Fu wrote:
NMI will be used as notification signal for lapic-pt vCPUs and
ACRN doesn't support vNMI for lapic-pt vCPUs. Because it is not
possible to distinguish between notification NMIs and external
NMIs for lapic-pt vCPUs in some corner cases, eg: we can use a
magic number as identifier of notification NMIs. If it is set when
receiving a NMI, this NMI is processed as notification NMI.
Otherwise, it is a external NMI for lapic-pt vCPUs. It works well
most of the time. But it won't work for some corner cases, eg:

1. The sender CPU sets the identifier.
2. An external NMI occurs on the target CPU and then the target CPU
will
treat this NMI as notification NMI by mistake.
3. The sender CPU sends the NMI to target CPU.

So, this patch ignores the pending NMI request and EXCP with vector 2.

Signed-off-by: Kaige Fu <kaige.fu@...>
---
hypervisor/arch/x86/guest/virq.c | 55
++++++++++++++++++++------------
1 file changed, 35 insertions(+), 20 deletions(-)

diff --git a/hypervisor/arch/x86/guest/virq.c
b/hypervisor/arch/x86/guest/virq.c
index a0be3c3d..174c0fb3 100644
--- a/hypervisor/arch/x86/guest/virq.c
+++ b/hypervisor/arch/x86/guest/virq.c
@@ -212,26 +212,36 @@ int32_t vcpu_queue_exception(struct
acrn_vcpu *vcpu, uint32_t vector_arg, uint32 static void
vcpu_inject_exception(struct acrn_vcpu *vcpu, uint32_t vector) {
if (bitmap_test_and_clear_lock(ACRN_REQUEST_EXCP, &vcpu-
arch.pending_req)) {
-
- if ((exception_type[vector] &
EXCEPTION_ERROR_CODE_VALID) != 0U) {
-
exec_vmwrite32(VMX_ENTRY_EXCEPTION_ERROR_CODE,
- vcpu->arch.exception_info.error);
- }
+ if (is_lapic_pt_enabled(vcpu) && (vector == IDT_NMI)) {
The restriction is not support vNMI for RTVM, so I think we should
use
is_lapic_pt_configured() here.
I get one question here. If the is_lapic_pt_configured() is true but
is_lapic_pt_enabled() is false, Do we still take this VM as RTVM?
If yes, we can use is_lapic_pt_configured() here. Otherwise, I think the
is_lapic_pt_enabled() is the right function to use here.

Logically, it's hard RTVM once lapic_pt configured.
If it's configured but never enabled, that's a wrong configuration of RT OS.
Got it. Will use is_lapic_pt_configured() next version.


+ /*
+ * NMI will be used as notification signal for lapic-pt
vCPUs and we
+ * don't support vNMI yet. So, here we just ignore the
NMI injection
+ * request.
+ */
+ pr_warn("Don't allow to inject NMI to lapic-pt
vCPU%u. Ignore this request.", vcpu->vcpu_id);
+ vcpu->arch.exception_info.exception =
VECTOR_INVALID;
+ } else {
+ if ((exception_type[vector] &
EXCEPTION_ERROR_CODE_VALID) != 0U) {
+
exec_vmwrite32(VMX_ENTRY_EXCEPTION_ERROR_CODE,
+ vcpu-
arch.exception_info.error);
+ }

- exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
VMX_INT_INFO_VALID |
- (exception_type[vector] << 8U) | (vector &
0xFFU));
+ exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
VMX_INT_INFO_VALID |
+ (exception_type[vector] << 8U) |
(vector & 0xFFU));

- vcpu->arch.exception_info.exception = VECTOR_INVALID;
+ vcpu->arch.exception_info.exception =
VECTOR_INVALID;

- /* retain rip for exception injection */
- vcpu_retain_rip(vcpu);
+ /* retain rip for exception injection */
+ vcpu_retain_rip(vcpu);

- /* SDM 17.3.1.1 For any fault-class exception except a debug
exception generated in response to an
- * instruction breakpoint, the value pushed for RF is 1.
- * #DB is treated as Trap in get_exception_type, so RF will not
be set for instruction breakpoint.
- */
- if (get_exception_type(vector) == EXCEPTION_FAULT) {
- vcpu_set_rflags(vcpu, vcpu_get_rflags(vcpu) |
HV_ARCH_VCPU_RFLAGS_RF);
+ /* SDM 17.3.1.1 For any fault-class exception except
a debug exception generated
+ * in response to an instruction breakpoint, the value
pushed for RF is 1.
+ * #DB is treated as Trap in get_exception_type, so RF
will not be set for
+ * instruction breakpoint.
+ */
+ if (get_exception_type(vector) == EXCEPTION_FAULT)
{
+ vcpu_set_rflags(vcpu, vcpu_get_rflags(vcpu)
| HV_ARCH_VCPU_RFLAGS_RF);
+ }
}
}
}
@@ -389,10 +399,15 @@ 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)) {
- /* Inject NMI vector = 2 */
-
exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
- VMX_INT_INFO_VALID |
(VMX_INT_TYPE_NMI << 8U) | IDT_NMI);
- injected = true;
+ if (!is_lapic_pt_enabled(vcpu)) {
Ditto

+ /* Inject NMI vector = 2 */
+
exec_vmwrite32(VMX_ENTRY_INT_INFO_FIELD,
+
VMX_INT_INFO_VALID | (VMX_INT_TYPE_NMI << 8U) | IDT_NMI);
+ injected = true;
+ } else {
+ pr_warn("Don't allow to inject NMI to
lapic-pt vCPU%u. Ignore this request.",
+ vcpu->vcpu_id);
+ }
} else {
/* handling pending vector injection:
* there are many reason inject failed, we
need re-inject again
--
2.20.0