|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 21/28] x86/hvm: enable debug hypercall for posted interrupts
From: Denis Mukhin <dmukhin@xxxxxxxx>
There is a need to change AVIC behavior at run-time to enable feature
testing.
Add new subcommand XEN_DOMCTL_DEBUG_OP_POSTED_INTR for XEN_DOMCTL_debug_op
hypercall.
Perform necessary plumbing through hvm_function_table and export
convenience functions for AVIC.
Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
xen/arch/x86/hvm/hvm.c | 15 ++++
xen/arch/x86/hvm/svm/avic.c | 132 +++++++++++++++++++++++++++++
xen/arch/x86/hvm/svm/avic.h | 2 +
xen/arch/x86/hvm/svm/svm.c | 1 +
xen/arch/x86/include/asm/hvm/hvm.h | 17 ++++
xen/include/public/domctl.h | 1 +
6 files changed, 168 insertions(+)
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 42139837904a..a6ca56b08942 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -5257,6 +5257,21 @@ int hvm_debug_op(struct domain *d, unsigned int op,
unsigned int vcpu,
break;
+ case XEN_DOMCTL_DEBUG_OP_POSTED_INTR:
+ gdprintk(XENLOG_G_INFO,
+ "%pd: XEN_DOMCTL_DEBUG_OP_POSTED_INTR %u\n",
+ d, arg);
+
+ if ( current->domain != d )
+ domain_pause(d);
+
+ rc = hvm_debug_posted_intr(d, arg);
+
+ if ( current->domain != d )
+ domain_unpause(d);
+
+ break;
+
default:
return -ENOSYS;
}
diff --git a/xen/arch/x86/hvm/svm/avic.c b/xen/arch/x86/hvm/svm/avic.c
index 4dcd2c94ea87..ca779be22eea 100644
--- a/xen/arch/x86/hvm/svm/avic.c
+++ b/xen/arch/x86/hvm/svm/avic.c
@@ -729,6 +729,81 @@ void cf_check svm_avic_hvm_deliver_posted_intr(struct vcpu
*v, uint8_t vector)
}
}
+static void avic_domain_noaccel_state_sync(struct domain *d)
+{
+ struct svm_domain *sd = &d->arch.hvm.svm;
+ struct vcpu *v;
+
+ memset(sd->avic_logical_id_table, 0, PAGE_SIZE);
+
+ for_each_vcpu ( d, v )
+ {
+ struct svm_vcpu *sv = &v->arch.hvm.svm;
+ uint32_t ldr = vlapic_reg_read(v, APIC_LDR);
+ uint32_t dfr = vlapic_reg_read(v, APIC_DFR);
+ uint32_t id = GET_xAPIC_ID(vlapic_reg_read(v, APIC_ID));
+
+ sv->avic_ldr = ldr;
+ sv->avic_dfr = dfr;
+
+ avic_ldr_write(v, id, ldr);
+ }
+}
+
+static void avic_domain_enable(struct domain *d)
+{
+ struct vcpu *v;
+ int rc;
+
+ rc = avic_set_mmio_p2m_entry(d);
+ if ( rc )
+ goto out;
+
+ /* Re-load LDR/DFR from vLAPIC */
+ avic_domain_noaccel_state_sync(d);
+
+ for_each_vcpu ( d, v )
+ {
+ /* VINTR=0 */
+ svm_clear_intr_window(v);
+
+ /* VMCB.avic_enable=1 */
+ avic_vcpu_enable(v, true);
+ }
+
+ return;
+
+ out:
+ gdprintk(XENLOG_INFO,
+ "%pd: AVIC: failed to enable APIC MMIO access: %d\n",
+ d, rc);
+}
+
+static void avic_domain_disable(struct domain *d)
+{
+ struct vcpu *v;
+ int rc;
+
+ for_each_vcpu ( d, v )
+ {
+ /* IsRunning=0 */
+ avic_vcpu_clear_running(v);
+
+ /* VMCB.avic_enable=0 */
+ avic_vcpu_enable(v, false);
+
+ avic_stats_reset(v);
+ }
+
+ rc = avic_clear_mmio_p2m_entry(d);
+ if ( !rc )
+ return;
+
+ gdprintk(XENLOG_INFO,
+ "%pd: AVIC: failed to disable APIC MMIO access: %d\n",
+ d, rc);
+}
+
void cf_check svm_avic_hvm_dump_posted_intr(const struct vcpu *v)
{
const struct svm_vcpu *sv = &v->arch.hvm.svm;
@@ -752,6 +827,63 @@ void cf_check svm_avic_hvm_dump_posted_intr(const struct
vcpu *v)
sv->avic_cnt_kick);
}
+static void avic_domain_dump_stats(struct domain *d)
+{
+ struct vcpu *v;
+
+ for_each_vcpu ( d, v )
+ {
+ svm_avic_hvm_dump_posted_intr(v);
+ avic_stats_reset(v);
+ }
+}
+
+/* Interrupt acceleration control operations. */
+enum {
+ POSTED_INTR_DISABLE = 0,
+ POSTED_INTR_ENABLE = 1,
+ POSTED_INTR_DUMP_STATS = 2,
+};
+
+void cf_check svm_avic_hvm_debug_posted_intr(struct domain *d,
+ unsigned int arg)
+{
+ struct vcpu *v;
+
+ /* Ensure no vCPU can VMRUN while updating VMCB for AVIC. */
+ for_each_vcpu ( d, v )
+ {
+ if ( !avic_vcpu_supported(v) )
+ goto out;
+
+ if ( v != current )
+ vcpu_pause(v);
+ }
+
+ switch ( arg ) {
+ case POSTED_INTR_DISABLE:
+ avic_domain_disable(d);
+ break;
+
+ case POSTED_INTR_ENABLE:
+ avic_domain_enable(d);
+ break;
+
+ case POSTED_INTR_DUMP_STATS:
+ avic_domain_dump_stats(d);
+ break;
+
+ default:
+ ASSERT_UNREACHABLE();
+ break;
+ }
+
+ out:
+ for_each_vcpu ( d, v )
+ if ( v != current )
+ vcpu_unpause(v);
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/arch/x86/hvm/svm/avic.h b/xen/arch/x86/hvm/svm/avic.h
index 24d5fab59b29..e40aa77264ad 100644
--- a/xen/arch/x86/hvm/svm/avic.h
+++ b/xen/arch/x86/hvm/svm/avic.h
@@ -34,5 +34,7 @@ void svm_avic_vcpu_switch_from(struct vcpu *v);
void cf_check svm_avic_hvm_deliver_posted_intr(struct vcpu *v, uint8_t vector);
void cf_check svm_avic_hvm_dump_posted_intr(const struct vcpu *v);
+void cf_check svm_avic_hvm_debug_posted_intr(struct domain *d,
+ unsigned int arg);
#endif /* __SVM_AVIC_H__ */
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 83977d411b0a..f2eb01799c63 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -2520,6 +2520,7 @@ static void __init svm_avic_start(void)
svm_function_table.deliver_posted_intr = svm_avic_hvm_deliver_posted_intr;
svm_function_table.dump_posted_intr = svm_avic_hvm_dump_posted_intr;
+ svm_function_table.debug_posted_intr = svm_avic_hvm_debug_posted_intr;
svm_function_table.caps.virtual_intr_delivery = true;
}
diff --git a/xen/arch/x86/include/asm/hvm/hvm.h
b/xen/arch/x86/include/asm/hvm/hvm.h
index 6efc533b35df..d44f136fae8f 100644
--- a/xen/arch/x86/include/asm/hvm/hvm.h
+++ b/xen/arch/x86/include/asm/hvm/hvm.h
@@ -218,6 +218,7 @@ struct hvm_function_table {
void (*process_isr)(int isr, struct vcpu *v);
void (*deliver_posted_intr)(struct vcpu *v, u8 vector);
void (*dump_posted_intr)(const struct vcpu *v);
+ void (*debug_posted_intr)(struct domain *d, unsigned int arg);
void (*sync_pir_to_irr)(struct vcpu *v);
bool (*test_pir)(const struct vcpu *v, uint8_t vector);
void (*handle_eoi)(uint8_t vector, int isr);
@@ -859,6 +860,16 @@ static inline void hvm_dump_posted_intr(const struct vcpu
*v)
alternative_vcall(hvm_funcs.dump_posted_intr, v);
}
+static inline int hvm_debug_posted_intr(struct domain *d, unsigned int arg)
+{
+ if ( !hvm_funcs.debug_posted_intr )
+ return -ENOSYS;
+
+ alternative_vcall(hvm_funcs.debug_posted_intr, d, arg);
+
+ return 0;
+}
+
#else /* CONFIG_HVM */
#define hvm_enabled false
@@ -971,6 +982,12 @@ static inline void hvm_dump_posted_intr(const struct vcpu
*v)
ASSERT_UNREACHABLE();
}
+static inline int hvm_debug_posted_intr(struct domain *d, unsigned int arg)
+{
+ ASSERT_UNREACHABLE();
+ return -EOPNOTSUPP;
+}
+
#define is_viridian_domain(d) ((void)(d), false)
#define is_viridian_vcpu(v) ((void)(v), false)
#define has_viridian_time_ref_count(d) ((void)(d), false)
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 546d9a8ac9c0..b72164f61ce2 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -765,6 +765,7 @@ struct xen_domctl_subscribe {
/* XEN_DOMCTL_debug_op */
#define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF 0
#define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON 1
+#define XEN_DOMCTL_DEBUG_OP_POSTED_INTR 3
struct xen_domctl_debug_op {
uint32_t op; /* IN */
uint32_t vcpu; /* IN */
--
2.55.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |