aboutsummaryrefslogtreecommitdiffstats
path: root/xen/include/asm-arm/event.h
diff options
context:
space:
mode:
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>2013-05-01 11:32:59 +0100
committerIan Campbell <ian.campbell@citrix.com>2013-05-08 11:01:45 +0100
commita780f750d7fc35ec23b7771516fe11a390d0aa07 (patch)
treeeda3b01d41ccb2b4fadc0dc69882669836395409 /xen/include/asm-arm/event.h
parent6f3059e0e05b72c3cc7246f3e6e81f80761b98cb (diff)
downloadxen-a780f750d7fc35ec23b7771516fe11a390d0aa07.tar.gz
xen-a780f750d7fc35ec23b7771516fe11a390d0aa07.tar.bz2
xen-a780f750d7fc35ec23b7771516fe11a390d0aa07.zip
xen/arm: trap guest WFI
Trap guest WFI, block the guest VCPU unless it has pending interrupts (WFI should return if any interrupts arrive even if interrupts are disabled). Awake the guest vcpu when a new interrupt for it arrives. Introduce gic_events_need_delivery: it checks whether the current vcpu has any interrupts that need to be delivered either on the lrs or in lr_pending. Properly implement local_events_need_delivery: check if the guest disabled interrupts, if they aren't disabled, return positive if gic_events_need_delivery returns positive. Otherwise we still need to check whether evtchn_upcall_pending is set but no VGIC_IRQ_EVTCHN_CALLBACK irqs are in flight: it could be the race described by commit db453468d92369e7182663fb13e14d83ec4ce456 "arm: vgic: fix race between evtchn upcall and evtchnop_send". If that is the case it means that an event needs to be injected. If all these tests are negative then no events need to be delivered. Implement local_event_delivery_enable by clearing PSR_IRQ_MASK. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com>
Diffstat (limited to 'xen/include/asm-arm/event.h')
-rw-r--r--xen/include/asm-arm/event.h41
1 files changed, 32 insertions, 9 deletions
diff --git a/xen/include/asm-arm/event.h b/xen/include/asm-arm/event.h
index 10f58af180..ed05901102 100644
--- a/xen/include/asm-arm/event.h
+++ b/xen/include/asm-arm/event.h
@@ -1,27 +1,50 @@
#ifndef __ASM_EVENT_H__
#define __ASM_EVENT_H__
+#include <asm/gic.h>
+#include <asm/domain.h>
+
void vcpu_kick(struct vcpu *v);
void vcpu_mark_events_pending(struct vcpu *v);
+static inline int local_events_need_delivery_nomask(void)
+{
+ struct pending_irq *p = irq_to_pending(current, VGIC_IRQ_EVTCHN_CALLBACK);
+
+ /* XXX: if the first interrupt has already been delivered, we should
+ * check whether any other interrupts with priority higher than the
+ * one in GICV_IAR are in the lr_pending queue or in the LR
+ * registers and return 1 only in that case.
+ * In practice the guest interrupt handler should run with
+ * interrupts disabled so this shouldn't be a problem in the general
+ * case.
+ */
+ if ( gic_events_need_delivery() )
+ return 1;
+
+ if ( vcpu_info(current, evtchn_upcall_pending) &&
+ list_empty(&p->inflight) )
+ return 1;
+
+ return 0;
+}
+
static inline int local_events_need_delivery(void)
{
- /* TODO
- * return (vcpu_info(v, evtchn_upcall_pending) &&
- !vcpu_info(v, evtchn_upcall_mask)); */
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
+
+ /* guest IRQs are masked */
+ if ( (regs->cpsr & PSR_IRQ_MASK) )
return 0;
+ return local_events_need_delivery_nomask();
}
int local_event_delivery_is_enabled(void);
-static inline void local_event_delivery_disable(void)
-{
- /* TODO current->vcpu_info->evtchn_upcall_mask = 1; */
-}
-
static inline void local_event_delivery_enable(void)
{
- /* TODO current->vcpu_info->evtchn_upcall_mask = 0; */
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
+ regs->cpsr &= ~PSR_IRQ_MASK;
}
/* No arch specific virq definition now. Default to global. */