Re: [PATCH v4 02/12] x86/vlapic: introduce an EOI callback mechanism

2021-04-29 Thread Jan Beulich
On 20.04.2021 16:07, Roger Pau Monne wrote:
> Add a new vlapic_set_irq_callback helper in order to inject a vector
> and set a callback to be executed when the guest performs the end of
> interrupt acknowledgment.
> 
> Such functionality will be used to migrate the current ad hoc handling
> done in vlapic_handle_EOI for the vectors that require some logic to
> be executed when the end of interrupt is performed.
> 
> The setter of the callback will be in charge for setting the callback
> again on guest restore, as callbacks are not saved as part of the
> vlapic state. That is the reason why vlapic_set_callback is not a
> static function.
> 
> No current users are migrated to use this new functionality yet, so no
> functional change expected as a result.
> 
> Signed-off-by: Roger Pau Monné 

Reviewed-by: Jan Beulich 



[PATCH v4 02/12] x86/vlapic: introduce an EOI callback mechanism

2021-04-20 Thread Roger Pau Monne
Add a new vlapic_set_irq_callback helper in order to inject a vector
and set a callback to be executed when the guest performs the end of
interrupt acknowledgment.

Such functionality will be used to migrate the current ad hoc handling
done in vlapic_handle_EOI for the vectors that require some logic to
be executed when the end of interrupt is performed.

The setter of the callback will be in charge for setting the callback
again on guest restore, as callbacks are not saved as part of the
vlapic state. That is the reason why vlapic_set_callback is not a
static function.

No current users are migrated to use this new functionality yet, so no
functional change expected as a result.

Signed-off-by: Roger Pau Monné 
---
Changes since v3:
 - Use xzalloc.
 - Drop printk on ENOMEM.
 - Add vcpu parameter to vlapic EOI callback.
 - Check that the vector is pending in ISR or IRR when printing a
   warning message because of an overriding callback.
 - Fix commit message regarding resume mention.

Changes since v2:
 - Fix commit message typo.
 - Expand commit message.
 - Also print a warning if the callback data is overridden.
 - Properly free memory in case of error in vlapic_init.

Changes since v1:
 - Make vlapic_set_irq an inline function on the header.
 - Clear the callback hook in vlapic_handle_EOI.
 - Introduce a helper to set the callback without injecting a vector.
 - Remove unneeded parentheses.
 - Reduce callback table by 16.
 - Use %pv to print domain/vcpu ID.
---
 xen/arch/x86/hvm/vlapic.c| 62 ++--
 xen/include/asm-x86/hvm/vlapic.h | 19 +-
 2 files changed, 78 insertions(+), 3 deletions(-)

diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index 5e21fb4937d..4465beaeec1 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -144,7 +144,37 @@ bool vlapic_test_irq(const struct vlapic *vlapic, uint8_t 
vec)
 return vlapic_test_vector(vec, >regs->data[APIC_IRR]);
 }
 
-void vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig)
+void vlapic_set_callback(struct vlapic *vlapic, unsigned int vec,
+ vlapic_eoi_callback_t *callback, void *data)
+{
+unsigned long flags;
+unsigned int index = vec - 16;
+
+if ( !callback || vec < 16 || vec >= X86_NR_VECTORS )
+{
+ASSERT_UNREACHABLE();
+return;
+}
+
+spin_lock_irqsave(>callback_lock, flags);
+if ( vlapic->callbacks[index].callback &&
+ (vlapic->callbacks[index].callback != callback ||
+  vlapic->callbacks[index].data != data) &&
+ (vlapic_test_vector(vec, >regs->data[APIC_IRR]) ||
+  vlapic_test_vector(vec, >regs->data[APIC_ISR])) )
+printk(XENLOG_G_WARNING
+   "%pv overriding vector %#x callback %ps (%p) data %p "
+   "with %ps (%p) data %p\n",
+   vlapic_vcpu(vlapic), vec, vlapic->callbacks[index].callback,
+   vlapic->callbacks[index].callback, 
vlapic->callbacks[index].data,
+   callback, callback, data);
+vlapic->callbacks[index].callback = callback;
+vlapic->callbacks[index].data = data;
+spin_unlock_irqrestore(>callback_lock, flags);
+}
+
+void vlapic_set_irq_callback(struct vlapic *vlapic, uint8_t vec, uint8_t trig,
+ vlapic_eoi_callback_t *callback, void *data)
 {
 struct vcpu *target = vlapic_vcpu(vlapic);
 
@@ -159,8 +189,12 @@ void vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, 
uint8_t trig)
 else
 vlapic_clear_vector(vec, >regs->data[APIC_TMR]);
 
+if ( callback )
+vlapic_set_callback(vlapic, vec, callback, data);
+
 if ( hvm_funcs.update_eoi_exit_bitmap )
-alternative_vcall(hvm_funcs.update_eoi_exit_bitmap, target, vec, trig);
+alternative_vcall(hvm_funcs.update_eoi_exit_bitmap, target, vec,
+  trig || callback);
 
 if ( hvm_funcs.deliver_posted_intr )
 alternative_vcall(hvm_funcs.deliver_posted_intr, target, vec);
@@ -461,11 +495,24 @@ void vlapic_handle_EOI(struct vlapic *vlapic, u8 vector)
 {
 struct vcpu *v = vlapic_vcpu(vlapic);
 struct domain *d = v->domain;
+vlapic_eoi_callback_t *callback;
+void *data;
+unsigned long flags;
+unsigned int index = vector - 16;
 
 if ( vlapic_test_vector(vector, >regs->data[APIC_TMR]) )
 vioapic_update_EOI(d, vector);
 
 hvm_dpci_msi_eoi(d, vector);
+
+spin_lock_irqsave(>callback_lock, flags);
+callback = vlapic->callbacks[index].callback;
+vlapic->callbacks[index].callback = NULL;
+data = vlapic->callbacks[index].data;
+spin_unlock_irqrestore(>callback_lock, flags);
+
+if ( callback )
+callback(v, vector, data);
 }
 
 static bool_t is_multicast_dest(struct vlapic *vlapic, unsigned int short_hand,
@@ -1623,9 +1670,19 @@ int vlapic_init(struct vcpu *v)
 
 clear_page(vlapic->regs);
 
+vlapic->callbacks = xzalloc_array(typeof(*vlapic->callbacks),
+