|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2 2/2] x86/svm: Use the virtual NMI when available
With vNMI, the pending NMI is simply stuffed into the VMCB and handed off
to the hardware. This means that Xen needs to be able to set a vNMI pending
on-demand, and also query if a vNMI is pending, e.g. to honor the "at most
one NMI pending" rule and to preserve all NMIs across save and restore.
Introduce two new hvm_function_table callbacks to support the SVM's vNMI to
allow the Xen hypervisor to query if a vNMI is pending and to set VMCB's
_vintr pending flag so the NMIs are serviced by hardware if/when the virtual
NMIs become unblocked.
Signed-off-by: Abdelkareem Abdelsaamad <abdelkareem.abdelsaamad@xxxxxxxxxx>
---
xen/arch/x86/hvm/svm/intr.c | 13 ++++++++++--
xen/arch/x86/hvm/svm/svm.c | 33 ++++++++++++++++++++++++++++--
xen/arch/x86/hvm/svm/vmcb.c | 2 ++
xen/arch/x86/include/asm/hvm/hvm.h | 9 ++++++++
4 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/xen/arch/x86/hvm/svm/intr.c b/xen/arch/x86/hvm/svm/intr.c
index 6453a46b85..bc52f8e189 100644
--- a/xen/arch/x86/hvm/svm/intr.c
+++ b/xen/arch/x86/hvm/svm/intr.c
@@ -29,10 +29,19 @@
static void svm_inject_nmi(struct vcpu *v)
{
- struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
- u32 general1_intercepts = vmcb_get_general1_intercepts(vmcb);
+ struct vmcb_struct *vmcb;
+ u32 general1_intercepts;
intinfo_t event;
+ if ( hvm_funcs.is_vnmi_enabled(v) )
+ {
+ hvm_funcs.set_vnmi_pending(v);
+ return;
+ }
+
+ vmcb = v->arch.hvm.svm.vmcb;
+ general1_intercepts = vmcb_get_general1_intercepts(vmcb);
+
event.raw = 0;
event.v = true;
event.type = X86_ET_NMI;
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 6e380890bd..00e5630025 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -297,6 +297,32 @@ void svm_intercept_msr(struct vcpu *v, uint32_t msr, int
flags)
__clear_bit(msr * 2 + 1, msr_bit);
}
+static bool cf_check svm_is_vnmi_enabled(struct vcpu *vcpu)
+{
+ return ( hvm_funcs.caps.vNMI &&
+ vcpu->arch.hvm.svm.vmcb->_vintr.fields.vnmi_enable );
+}
+
+static bool cf_check svm_is_vnmi_masked(struct vcpu *vcpu)
+{
+ if ( !svm_is_vnmi_enabled(vcpu) )
+ return false;
+
+ return ( vcpu->arch.hvm.svm.vmcb->_vintr.fields.vnmi_blocking );
+}
+
+static bool cf_check svm_set_vnmi_pending(struct vcpu *vcpu)
+{
+ if ( !svm_is_vnmi_enabled(vcpu) )
+ return false;
+
+ if ( vcpu->arch.hvm.svm.vmcb->_vintr.fields.vnmi_pending )
+ return false;
+
+ vcpu->arch.hvm.svm.vmcb->_vintr.fields.vnmi_pending = 1;
+ return true;
+}
+
#ifdef CONFIG_VM_EVENT
static void cf_check svm_enable_msr_interception(struct domain *d, uint32_t
msr)
{
@@ -545,7 +571,7 @@ static unsigned cf_check int
svm_get_interrupt_shadow(struct vcpu *v)
struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
unsigned int intr_shadow = 0;
- if ( vmcb->int_stat.intr_shadow )
+ if ( vmcb->int_stat.intr_shadow || svm_is_vnmi_masked(v) )
intr_shadow |= HVM_INTR_SHADOW_MOV_SS | HVM_INTR_SHADOW_STI;
if ( vmcb_get_general1_intercepts(vmcb) & GENERAL1_INTERCEPT_IRET )
@@ -2464,7 +2490,9 @@ static struct hvm_function_table __initdata_cf_clobber
svm_function_table = {
#endif
.set_rdtsc_exiting = svm_set_rdtsc_exiting,
.get_insn_bytes = svm_get_insn_bytes,
-
+ .is_vnmi_enabled = svm_is_vnmi_enabled,
+ .is_vnmi_masked = svm_is_vnmi_masked,
+ .set_vnmi_pending = svm_set_vnmi_pending,
.nhvm_vcpu_initialise = nsvm_vcpu_initialise,
.nhvm_vcpu_destroy = nsvm_vcpu_destroy,
.nhvm_vcpu_reset = nsvm_vcpu_reset,
@@ -2524,6 +2552,7 @@ const struct hvm_function_table * __init start_svm(void)
P(cpu_has_tsc_ratio, "TSC Rate MSR");
P(cpu_has_svm_sss, "NPT Supervisor Shadow Stack");
P(cpu_has_svm_spec_ctrl, "MSR_SPEC_CTRL virtualisation");
+ P(cpu_has_svm_vnmi, "Virtual NMI");
P(cpu_has_svm_bus_lock, "Bus Lock Filter");
#undef P
diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c
index e583ef8548..e90bbac332 100644
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -184,6 +184,8 @@ static int construct_vmcb(struct vcpu *v)
if ( default_xen_spec_ctrl == SPEC_CTRL_STIBP )
v->arch.msrs->spec_ctrl.raw = SPEC_CTRL_STIBP;
+ vmcb->_vintr.fields.vnmi_enable = cpu_has_svm_vnmi;
+
return 0;
}
diff --git a/xen/arch/x86/include/asm/hvm/hvm.h
b/xen/arch/x86/include/asm/hvm/hvm.h
index ad17ea73e9..9dc8b35f91 100644
--- a/xen/arch/x86/include/asm/hvm/hvm.h
+++ b/xen/arch/x86/include/asm/hvm/hvm.h
@@ -224,6 +224,15 @@ struct hvm_function_table {
int (*pi_update_irte)(const struct vcpu *v, const struct pirq *pirq,
uint8_t gvec);
void (*update_vlapic_mode)(struct vcpu *v);
+ /* Whether or not virtual NMI is enabled. */
+ bool (*is_vnmi_enabled)(struct vcpu *vcpu);
+ /* Whether or not a virtual NMI is masked in hardware. */
+ bool (*is_vnmi_masked)(struct vcpu *vcpu);
+ /*
+ * Attempt to pend a virtual NMI in harware.
+ * Returns %true on success
+ */
+ bool (*set_vnmi_pending)(struct vcpu *vcpu);
/*Walk nested p2m */
int (*nhvm_hap_walk_L1_p2m)(struct vcpu *v, paddr_t L2_gpa,
--
2.52.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |