|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 08/28] x86/hvm: avic: add AVIC_INCOMP_IPI VMEXIT handler
From: Denis Mukhin <dmukhin@xxxxxxxx>
Introduce new VMEXIT reason 0x401 [1] to handle the case when an IPI cannot
be delivered to all targeted guest virtual processors because at least one
guest virtual processor was not allocated to a physical core at the time.
If incomplete IPI occurs, try to emulate an IPI.
[1] AMD64 APM Volume 2, Table 15-22 "Guest vAPIC Register Access Behavior"
Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
xen/arch/x86/hvm/svm/avic.c | 115 +++++++++++++++++++++++
xen/arch/x86/hvm/svm/avic.h | 2 +
xen/arch/x86/hvm/svm/svm.c | 4 +
xen/arch/x86/hvm/svm/vmcb.h | 7 ++
xen/arch/x86/include/asm/hvm/svm-types.h | 10 ++
5 files changed, 138 insertions(+)
diff --git a/xen/arch/x86/hvm/svm/avic.c b/xen/arch/x86/hvm/svm/avic.c
index bc98661a7057..0cfb21cb8e3f 100644
--- a/xen/arch/x86/hvm/svm/avic.c
+++ b/xen/arch/x86/hvm/svm/avic.c
@@ -9,6 +9,7 @@
#include <xen/param.h>
#include "avic.h"
+#include "svm.h"
#include "vmcb.h"
#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK GENMASK_ULL(51, 12U)
@@ -235,6 +236,120 @@ void svm_avic_vmcb_destroy(struct vcpu *v)
vmcb->avic_vapic_bar = 0;
}
+/*
+ * Handle the AVIC_INCOMP_IPI #VMEXIT when AVIC is enabled.
+ *
+ * The hardware generates this fault when an IPI could not be delivered to
+ * all targeted guest virtual processors because at least one guest virtual
+ * processor was not allocated to a physical core at the time.
+ */
+void svm_avic_vmexit_incomp_ipi(struct cpu_user_regs *regs)
+{
+ struct vcpu *v = current;
+ struct domain *d = v->domain;
+ struct svm_vcpu *sv = &v->arch.hvm.svm;
+ const struct vmcb_struct *vmcb = sv->vmcb;
+ uint32_t icrh = vmcb->exitinfo1 >> 32;
+ uint32_t icrl = vmcb->exitinfo1;
+ uint32_t id = vmcb->exitinfo2 >> 32;
+ uint32_t index = vmcb->exitinfo2 & 0x1FFU;
+
+ if ( id >= AVIC_IPI_FAILURE_MAX )
+ {
+ domain_crash(
+ d, "%pv: AVIC: Unknown IPI interception (exitinfo1=%#"PRIx64"
exitinfo2=%#"PRIx64")\n",
+ v, vmcb->exitinfo1, vmcb->exitinfo2);
+ return;
+ }
+
+ BUG_ON(sv->avic_physical_id == NULL);
+
+ switch ( id )
+ {
+ case AVIC_IPI_FAILURE_INVALID_INT_TYPE:
+ /*
+ * AVIC hardware handles the delivery of IPIs when the specified
+ * Message Type is Fixed (also known as fixed delivery mode) and the
+ * Trigger Mode is edge-triggered. The hardware also supports self and
+ * broadcast delivery modes specified via the Destination
+ * Shorthand(DSH) field of the ICRL. Logical and physical APIC ID
+ * formats are supported. All other IPI types cause a #VMEXIT, which
+ * needs to emulated.
+ */
+ gprintk(XENLOG_ERR,
+ "%pv: AVIC: Invalid IPI type (icr=%#08x:%08x, idx=%u)"
+ " avic_physical_id=%#"PRIx64"\n",
+ v, icrh, icrl, index, ACCESS_ONCE(*sv->avic_physical_id));
+
+ vlapic_reg_write(v, APIC_ICR2, icrh);
+ vlapic_reg_write(v, APIC_ICR, icrl);
+
+ break;
+
+ case AVIC_IPI_FAILURE_INVALID_TARGET:
+ /*
+ * AVIC can report an invalid target for guest IPIs, for example when
+ * a logical destination mask contains IDs that are not backed by
+ * vCPUs. This is guest-controlled input and is not a reason to crash
+ * the domain. Handle invalid-target exits like unsupported interrupt
+ * types.
+ */
+ gprintk(XENLOG_ERR,
+ "%pv: AVIC: Invalid IPI target (icr=%#08x:%08x, idx=%u)"
+ " avic_physical_id=%#"PRIx64"\n",
+ v, icrh, icrl, index, ACCESS_ONCE(*sv->avic_physical_id));
+
+ vlapic_reg_write(v, APIC_ICR2, icrh);
+ vlapic_reg_write(v, APIC_ICR, icrl);
+
+ break;
+
+ case AVIC_IPI_FAILURE_TARGET_NOT_RUNNING:
+ {
+ /*
+ * At this point, we expect that the AVIC HW has already set the
+ * appropriate IRR bits on the valid target vCPUs. Kick all the
+ * appropriate vCPUs (e.g. logically addressed or broadcast IPI).
+ */
+ struct vcpu *target;
+ uint32_t dest = GET_xAPIC_DEST_FIELD(icrh);
+ uint32_t short_hand = icrl & APIC_SHORT_MASK;
+ bool dest_mode = icrl & APIC_DEST_MASK;
+
+ for_each_vcpu ( d, target )
+ {
+ if ( target == v )
+ continue;
+
+ if ( vlapic_match_dest(vcpu_vlapic(target),
+ vcpu_vlapic(v),
+ short_hand, dest, dest_mode) )
+ {
+ vcpu_kick(target);
+ }
+ }
+
+ break;
+ }
+
+ case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE:
+ domain_crash(
+ d, "%pv: AVIC: Invalid backing page (icr=%#08x:%08x, idx=%u)\n",
+ v, icrh, icrl, index);
+ break;
+
+ case AVIC_IPI_FAILURE_INVALID_IPI_VECTOR:
+ domain_crash(
+ d, "%pv: AVIC: Invalid IPI with vector < 16 (%#x)\n",
+ v, index);
+ break;
+
+ default:
+ ASSERT_UNREACHABLE();
+ break;
+ }
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/arch/x86/hvm/svm/avic.h b/xen/arch/x86/hvm/svm/avic.h
index 1084ae683944..2668d4481425 100644
--- a/xen/arch/x86/hvm/svm/avic.h
+++ b/xen/arch/x86/hvm/svm/avic.h
@@ -14,4 +14,6 @@ void svm_avic_domain_relinquish_resources(struct domain *d);
int svm_avic_vmcb_create(struct vcpu *v);
void svm_avic_vmcb_destroy(struct vcpu *v);
+void svm_avic_vmexit_incomp_ipi(struct cpu_user_regs *regs);
+
#endif /* __SVM_AVIC_H__ */
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 8b7bfed0049f..693b5c29287a 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -3078,6 +3078,10 @@ void asmlinkage svm_vmexit_handler(void)
vmcb->bus_lock_count = 1;
break;
+ case VMEXIT_AVIC_INCOMP_IPI:
+ svm_avic_vmexit_incomp_ipi(regs);
+ break;
+
default:
unexpected_exit_type:
gprintk(XENLOG_ERR, "Unexpected vmexit: reason %#"PRIx64", "
diff --git a/xen/arch/x86/hvm/svm/vmcb.h b/xen/arch/x86/hvm/svm/vmcb.h
index 1ee5da053a9a..532382bd02f3 100644
--- a/xen/arch/x86/hvm/svm/vmcb.h
+++ b/xen/arch/x86/hvm/svm/vmcb.h
@@ -291,6 +291,13 @@ enum VMEXIT_EXITCODE
VMEXIT_BUS_LOCK = 165, /* 0xa5 */
/* Remember to also update VMEXIT_NPF_PERFC! */
VMEXIT_NPF = 1024, /* 0x400, nested paging fault */
+
+ /*
+ * AMD64 Architecture Programmer's Manual Volume 2: System Programming
+ * Table 15-22. Guest vAPIC Register Access Behavior
+ */
+ VMEXIT_AVIC_INCOMP_IPI = 1025, /* 0x401 */
+
/* Remember to also update SVM_PERF_EXIT_REASON_SIZE! */
VMEXIT_INVALID = -1
};
diff --git a/xen/arch/x86/include/asm/hvm/svm-types.h
b/xen/arch/x86/include/asm/hvm/svm-types.h
index 30bdaf27a856..93629418c225 100644
--- a/xen/arch/x86/include/asm/hvm/svm-types.h
+++ b/xen/arch/x86/include/asm/hvm/svm-types.h
@@ -25,6 +25,16 @@ struct svm_domain {
uint64_t *avic_physical_id_table;
};
+/* AVIC_INCOMP_IPI #VMEXIT reason. */
+enum avic_ipi_failure_cause {
+ AVIC_IPI_FAILURE_INVALID_INT_TYPE = 0,
+ AVIC_IPI_FAILURE_TARGET_NOT_RUNNING = 1,
+ AVIC_IPI_FAILURE_INVALID_TARGET = 2,
+ AVIC_IPI_FAILURE_INVALID_BACKING_PAGE = 3,
+ AVIC_IPI_FAILURE_INVALID_IPI_VECTOR = 4,
+ AVIC_IPI_FAILURE_MAX,
+};
+
struct svm_vcpu {
struct vmcb_struct *vmcb;
unsigned long *msrpm;
--
2.55.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |