[Xen-devel,RFC,26/49] ARM: new VGIC: Implement vgic_vcpu_pending_irq

Message ID 20180209143937.28866-27-andre.przywara@linaro.org
State New
Headers show
Series
  • New VGIC(-v2) implementation
Related show

Commit Message

Andre Przywara Feb. 9, 2018, 2:39 p.m.
Tell Xen whether a particular VCPU has an IRQ that needs handling
in the guest. This is used to decide whether a VCPU is runnable.

This is based on Linux commit 90eee56c5f90, written by Eric Auger.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
 xen/arch/arm/vgic/vgic.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

Comments

Julien Grall Feb. 13, 2018, 4:35 p.m. | #1
Hi,

On 09/02/18 14:39, Andre Przywara wrote:
> Tell Xen whether a particular VCPU has an IRQ that needs handling
> in the guest. This is used to decide whether a VCPU is runnable.
> 
> This is based on Linux commit 90eee56c5f90, written by Eric Auger.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
>   xen/arch/arm/vgic/vgic.c | 32 ++++++++++++++++++++++++++++++++
>   1 file changed, 32 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index f4f2a04a60..9e7fb1edcb 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -646,6 +646,38 @@ void gic_inject(void)
>       vgic_restore_state(current);
>   }
>   
> +static int vgic_vcpu_pending_irq(struct vcpu *vcpu)
> +{
> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +    struct vgic_irq *irq;
> +    bool pending = false;
> +    unsigned long flags;
> +
> +    if ( !vcpu->domain->arch.vgic.enabled )
> +        return false;
> +
> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
> +
> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
> +    {
> +        spin_lock(&irq->irq_lock);
> +        pending = irq_is_pending(irq) && irq->enabled;
> +        spin_unlock(&irq->irq_lock);
> +
> +        if ( pending )
> +            break;
> +    }
> +
> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
> +
> +    return pending;
> +}
> +
> +int gic_events_need_delivery(void)

You probably want to rename that function or just expose 
vgic_vcpu_pending_irq().

Cheers,
Julien Grall Feb. 13, 2018, 4:36 p.m. | #2
On 13/02/18 16:35, Julien Grall wrote:
> Hi,
> 
> On 09/02/18 14:39, Andre Przywara wrote:
>> Tell Xen whether a particular VCPU has an IRQ that needs handling
>> in the guest. This is used to decide whether a VCPU is runnable.

I forgot to mention one thing. This is not the main usage of this 
function in Xen. That function will mostly be used to check whether we 
need to preempt an hypercall to run interrupt.

Please update the commit message accordingly.

>>
>> This is based on Linux commit 90eee56c5f90, written by Eric Auger.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> ---
>>   xen/arch/arm/vgic/vgic.c | 32 ++++++++++++++++++++++++++++++++
>>   1 file changed, 32 insertions(+)
>>
>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>> index f4f2a04a60..9e7fb1edcb 100644
>> --- a/xen/arch/arm/vgic/vgic.c
>> +++ b/xen/arch/arm/vgic/vgic.c
>> @@ -646,6 +646,38 @@ void gic_inject(void)
>>       vgic_restore_state(current);
>>   }
>> +static int vgic_vcpu_pending_irq(struct vcpu *vcpu)
>> +{
>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +    struct vgic_irq *irq;
>> +    bool pending = false;
>> +    unsigned long flags;
>> +
>> +    if ( !vcpu->domain->arch.vgic.enabled )
>> +        return false;
>> +
>> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
>> +
>> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
>> +    {
>> +        spin_lock(&irq->irq_lock);
>> +        pending = irq_is_pending(irq) && irq->enabled;
>> +        spin_unlock(&irq->irq_lock);
>> +
>> +        if ( pending )
>> +            break;
>> +    }
>> +
>> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
>> +
>> +    return pending;
>> +}
>> +
>> +int gic_events_need_delivery(void)
> 
> You probably want to rename that function or just expose 
> vgic_vcpu_pending_irq().
> 
> Cheers,
>
Andre Przywara Feb. 26, 2018, 3:29 p.m. | #3
Hi,

On 13/02/18 16:35, Julien Grall wrote:
> Hi,
> 
> On 09/02/18 14:39, Andre Przywara wrote:
>> Tell Xen whether a particular VCPU has an IRQ that needs handling
>> in the guest. This is used to decide whether a VCPU is runnable.
>>
>> This is based on Linux commit 90eee56c5f90, written by Eric Auger.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> ---
>>   xen/arch/arm/vgic/vgic.c | 32 ++++++++++++++++++++++++++++++++
>>   1 file changed, 32 insertions(+)
>>
>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>> index f4f2a04a60..9e7fb1edcb 100644
>> --- a/xen/arch/arm/vgic/vgic.c
>> +++ b/xen/arch/arm/vgic/vgic.c
>> @@ -646,6 +646,38 @@ void gic_inject(void)
>>       vgic_restore_state(current);
>>   }
>>   +static int vgic_vcpu_pending_irq(struct vcpu *vcpu)
>> +{
>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +    struct vgic_irq *irq;
>> +    bool pending = false;
>> +    unsigned long flags;
>> +
>> +    if ( !vcpu->domain->arch.vgic.enabled )
>> +        return false;
>> +
>> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
>> +
>> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
>> +    {
>> +        spin_lock(&irq->irq_lock);
>> +        pending = irq_is_pending(irq) && irq->enabled;
>> +        spin_unlock(&irq->irq_lock);
>> +
>> +        if ( pending )
>> +            break;
>> +    }
>> +
>> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
>> +
>> +    return pending;
>> +}
>> +
>> +int gic_events_need_delivery(void)
> 
> You probably want to rename that function or just expose
> vgic_vcpu_pending_irq().

Rename to what? I need both functions: vgic_vcpu_pending_irq() is also
called by vgic_kick_vcpus() (later in the series).
And gic_events_need_delivery(void) is the interface that the arch code
expects. Shall I rename this there? To what?

Cheers,
Andre.
Julien Grall Feb. 26, 2018, 3:55 p.m. | #4
Hi,

On 02/26/2018 03:29 PM, Andre Przywara wrote:
> On 13/02/18 16:35, Julien Grall wrote:
>>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>>> index f4f2a04a60..9e7fb1edcb 100644
>>> --- a/xen/arch/arm/vgic/vgic.c
>>> +++ b/xen/arch/arm/vgic/vgic.c
>>> @@ -646,6 +646,38 @@ void gic_inject(void)
>>>        vgic_restore_state(current);
>>>    }
>>>    +static int vgic_vcpu_pending_irq(struct vcpu *vcpu)
>>> +{
>>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>> +    struct vgic_irq *irq;
>>> +    bool pending = false;
>>> +    unsigned long flags;
>>> +
>>> +    if ( !vcpu->domain->arch.vgic.enabled )
>>> +        return false;
>>> +
>>> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
>>> +
>>> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
>>> +    {
>>> +        spin_lock(&irq->irq_lock);
>>> +        pending = irq_is_pending(irq) && irq->enabled;
>>> +        spin_unlock(&irq->irq_lock);
>>> +
>>> +        if ( pending )
>>> +            break;
>>> +    }
>>> +
>>> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
>>> +
>>> +    return pending;
>>> +}
>>> +
>>> +int gic_events_need_delivery(void)
>>
>> You probably want to rename that function or just expose
>> vgic_vcpu_pending_irq().
> 
> Rename to what? I need both functions: vgic_vcpu_pending_irq() is also
> called by vgic_kick_vcpus() (later in the series).
> And gic_events_need_delivery(void) is the interface that the arch code
> expects. Shall I rename this there? To what?

Let me start with it is a bit odd to have a function name 'gic_*' in the 
virtual GIC code. So at least renaming to vgic_events_need_delivery 
would be an improvement.

Regarding the interface itself, it is ARM specific and not set in stone. 
It would not be too bad to use vgic_vcpu_pending_irq(current). Is there 
any reason for not doing that?

Cheers,
Andre Przywara Feb. 26, 2018, 4:25 p.m. | #5
Hi,

On 26/02/18 15:55, Julien Grall wrote:
> Hi,
> 
> On 02/26/2018 03:29 PM, Andre Przywara wrote:
>> On 13/02/18 16:35, Julien Grall wrote:
>>>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>>>> index f4f2a04a60..9e7fb1edcb 100644
>>>> --- a/xen/arch/arm/vgic/vgic.c
>>>> +++ b/xen/arch/arm/vgic/vgic.c
>>>> @@ -646,6 +646,38 @@ void gic_inject(void)
>>>>        vgic_restore_state(current);
>>>>    }
>>>>    +static int vgic_vcpu_pending_irq(struct vcpu *vcpu)
>>>> +{
>>>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>>> +    struct vgic_irq *irq;
>>>> +    bool pending = false;
>>>> +    unsigned long flags;
>>>> +
>>>> +    if ( !vcpu->domain->arch.vgic.enabled )
>>>> +        return false;
>>>> +
>>>> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
>>>> +
>>>> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
>>>> +    {
>>>> +        spin_lock(&irq->irq_lock);
>>>> +        pending = irq_is_pending(irq) && irq->enabled;
>>>> +        spin_unlock(&irq->irq_lock);
>>>> +
>>>> +        if ( pending )
>>>> +            break;
>>>> +    }
>>>> +
>>>> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
>>>> +
>>>> +    return pending;
>>>> +}
>>>> +
>>>> +int gic_events_need_delivery(void)
>>>
>>> You probably want to rename that function or just expose
>>> vgic_vcpu_pending_irq().
>>
>> Rename to what? I need both functions: vgic_vcpu_pending_irq() is also
>> called by vgic_kick_vcpus() (later in the series).
>> And gic_events_need_delivery(void) is the interface that the arch code
>> expects. Shall I rename this there? To what?
> 
> Let me start with it is a bit odd to have a function name 'gic_*' in the
> virtual GIC code. So at least renaming to vgic_events_need_delivery
> would be an improvement.
> 
> Regarding the interface itself, it is ARM specific and not set in stone.
> It would not be too bad to use vgic_vcpu_pending_irq(current). Is there
> any reason for not doing that?

Not really, but I am a bit reluctant to change too much original Xen
code, don't want to step on anyone's toes ;-)

But if that's fine with you, I am OK with the renaming - though it adds
yet another patch ;-)

Cheers,
Andre.
Julien Grall Feb. 26, 2018, 4:30 p.m. | #6
On 02/26/2018 04:25 PM, Andre Przywara wrote:
> Hi,
> 
> On 26/02/18 15:55, Julien Grall wrote:
>> Hi,
>>
>> On 02/26/2018 03:29 PM, Andre Przywara wrote:
>>> On 13/02/18 16:35, Julien Grall wrote:
>>>>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>>>>> index f4f2a04a60..9e7fb1edcb 100644
>>>>> --- a/xen/arch/arm/vgic/vgic.c
>>>>> +++ b/xen/arch/arm/vgic/vgic.c
>>>>> @@ -646,6 +646,38 @@ void gic_inject(void)
>>>>>         vgic_restore_state(current);
>>>>>     }
>>>>>     +static int vgic_vcpu_pending_irq(struct vcpu *vcpu)
>>>>> +{
>>>>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>>>> +    struct vgic_irq *irq;
>>>>> +    bool pending = false;
>>>>> +    unsigned long flags;
>>>>> +
>>>>> +    if ( !vcpu->domain->arch.vgic.enabled )
>>>>> +        return false;
>>>>> +
>>>>> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
>>>>> +
>>>>> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
>>>>> +    {
>>>>> +        spin_lock(&irq->irq_lock);
>>>>> +        pending = irq_is_pending(irq) && irq->enabled;
>>>>> +        spin_unlock(&irq->irq_lock);
>>>>> +
>>>>> +        if ( pending )
>>>>> +            break;
>>>>> +    }
>>>>> +
>>>>> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
>>>>> +
>>>>> +    return pending;
>>>>> +}
>>>>> +
>>>>> +int gic_events_need_delivery(void)
>>>>
>>>> You probably want to rename that function or just expose
>>>> vgic_vcpu_pending_irq().
>>>
>>> Rename to what? I need both functions: vgic_vcpu_pending_irq() is also
>>> called by vgic_kick_vcpus() (later in the series).
>>> And gic_events_need_delivery(void) is the interface that the arch code
>>> expects. Shall I rename this there? To what?
>>
>> Let me start with it is a bit odd to have a function name 'gic_*' in the
>> virtual GIC code. So at least renaming to vgic_events_need_delivery
>> would be an improvement.
>>
>> Regarding the interface itself, it is ARM specific and not set in stone.
>> It would not be too bad to use vgic_vcpu_pending_irq(current). Is there
>> any reason for not doing that?
> 
> Not really, but I am a bit reluctant to change too much original Xen
> code, don't want to step on anyone's toes ;-)

The original code is going to get kill at some point. So better use name 
that makes sense in the new context. It is quite similar to the 
gic_inject change.

> 
> But if that's fine with you, I am OK with the renaming - though it adds
> yet another patch ;-)

The end goal is a better world, so the number of patches does not matter 
here :).

If you put them at the beginning, we can merge them right away.

Cheers,
Andre Przywara March 2, 2018, 1:53 p.m. | #7
Hi,

On 26/02/18 16:30, Julien Grall wrote:
> 
> 
> On 02/26/2018 04:25 PM, Andre Przywara wrote:
>> Hi,
>>
>> On 26/02/18 15:55, Julien Grall wrote:
>>> Hi,
>>>
>>> On 02/26/2018 03:29 PM, Andre Przywara wrote:
>>>> On 13/02/18 16:35, Julien Grall wrote:
>>>>>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>>>>>> index f4f2a04a60..9e7fb1edcb 100644
>>>>>> --- a/xen/arch/arm/vgic/vgic.c
>>>>>> +++ b/xen/arch/arm/vgic/vgic.c
>>>>>> @@ -646,6 +646,38 @@ void gic_inject(void)
>>>>>>         vgic_restore_state(current);
>>>>>>     }
>>>>>>     +static int vgic_vcpu_pending_irq(struct vcpu *vcpu)
>>>>>> +{
>>>>>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>>>>> +    struct vgic_irq *irq;
>>>>>> +    bool pending = false;
>>>>>> +    unsigned long flags;
>>>>>> +
>>>>>> +    if ( !vcpu->domain->arch.vgic.enabled )
>>>>>> +        return false;
>>>>>> +
>>>>>> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
>>>>>> +
>>>>>> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
>>>>>> +    {
>>>>>> +        spin_lock(&irq->irq_lock);
>>>>>> +        pending = irq_is_pending(irq) && irq->enabled;
>>>>>> +        spin_unlock(&irq->irq_lock);
>>>>>> +
>>>>>> +        if ( pending )
>>>>>> +            break;
>>>>>> +    }
>>>>>> +
>>>>>> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
>>>>>> +
>>>>>> +    return pending;
>>>>>> +}
>>>>>> +
>>>>>> +int gic_events_need_delivery(void)
>>>>>
>>>>> You probably want to rename that function or just expose
>>>>> vgic_vcpu_pending_irq().
>>>>
>>>> Rename to what? I need both functions: vgic_vcpu_pending_irq() is also
>>>> called by vgic_kick_vcpus() (later in the series).
>>>> And gic_events_need_delivery(void) is the interface that the arch code
>>>> expects. Shall I rename this there? To what?
>>>
>>> Let me start with it is a bit odd to have a function name 'gic_*' in the
>>> virtual GIC code. So at least renaming to vgic_events_need_delivery
>>> would be an improvement.
>>>
>>> Regarding the interface itself, it is ARM specific and not set in stone.
>>> It would not be too bad to use vgic_vcpu_pending_irq(current). Is there
>>> any reason for not doing that?

The two interfaces used for that purpose are different in the two VGICs:
- The old VGIC only works on the current VCPU, since it peeks into the
GICH_ register to learn the priority (regardless of whether this is
really needed or useful).
- The new VGIC can use this function for any VCPU, and we need this
functionality later on (when we iterate over all VCPUs).
So we can't use a function hardwiring "current", that would break
vgic_kick_vcpus() in the new VGIC. And we can't pass a VCPU parameter,
that would not work for the old VGIC.
So I believe having this small wrapper here is the easiest solution.
I will add a patch to rename this function to vgic_pending_irq(),
though, so this one here looks like:
int vgic_pending_irq(void)
{
    return vgic_vcpu_pending_irq(current);
}

We can clean this up when the old VGIC gets removed.

Cheers,
Andre.

>> Not really, but I am a bit reluctant to change too much original Xen
>> code, don't want to step on anyone's toes ;-)
> 
> The original code is going to get kill at some point. So better use name
> that makes sense in the new context. It is quite similar to the
> gic_inject change.
> 
>>
>> But if that's fine with you, I am OK with the renaming - though it adds
>> yet another patch ;-)
> 
> The end goal is a better world, so the number of patches does not matter
> here :).
> 
> If you put them at the beginning, we can merge them right away.
> 
> Cheers,
>
Julien Grall March 2, 2018, 1:58 p.m. | #8
On 02/03/18 13:53, Andre Przywara wrote:
> Hi,

Hi Andre,

> On 26/02/18 16:30, Julien Grall wrote:
>>
>>
>> On 02/26/2018 04:25 PM, Andre Przywara wrote:
>>> Hi,
>>>
>>> On 26/02/18 15:55, Julien Grall wrote:
>>>> Hi,
>>>>
>>>> On 02/26/2018 03:29 PM, Andre Przywara wrote:
>>>>> On 13/02/18 16:35, Julien Grall wrote:
>>>>>>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>>>>>>> index f4f2a04a60..9e7fb1edcb 100644
>>>>>>> --- a/xen/arch/arm/vgic/vgic.c
>>>>>>> +++ b/xen/arch/arm/vgic/vgic.c
>>>>>>> @@ -646,6 +646,38 @@ void gic_inject(void)
>>>>>>>          vgic_restore_state(current);
>>>>>>>      }
>>>>>>>      +static int vgic_vcpu_pending_irq(struct vcpu *vcpu)
>>>>>>> +{
>>>>>>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>>>>>>> +    struct vgic_irq *irq;
>>>>>>> +    bool pending = false;
>>>>>>> +    unsigned long flags;
>>>>>>> +
>>>>>>> +    if ( !vcpu->domain->arch.vgic.enabled )
>>>>>>> +        return false;
>>>>>>> +
>>>>>>> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
>>>>>>> +
>>>>>>> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
>>>>>>> +    {
>>>>>>> +        spin_lock(&irq->irq_lock);
>>>>>>> +        pending = irq_is_pending(irq) && irq->enabled;
>>>>>>> +        spin_unlock(&irq->irq_lock);
>>>>>>> +
>>>>>>> +        if ( pending )
>>>>>>> +            break;
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
>>>>>>> +
>>>>>>> +    return pending;
>>>>>>> +}
>>>>>>> +
>>>>>>> +int gic_events_need_delivery(void)
>>>>>>
>>>>>> You probably want to rename that function or just expose
>>>>>> vgic_vcpu_pending_irq().
>>>>>
>>>>> Rename to what? I need both functions: vgic_vcpu_pending_irq() is also
>>>>> called by vgic_kick_vcpus() (later in the series).
>>>>> And gic_events_need_delivery(void) is the interface that the arch code
>>>>> expects. Shall I rename this there? To what?
>>>>
>>>> Let me start with it is a bit odd to have a function name 'gic_*' in the
>>>> virtual GIC code. So at least renaming to vgic_events_need_delivery
>>>> would be an improvement.
>>>>
>>>> Regarding the interface itself, it is ARM specific and not set in stone.
>>>> It would not be too bad to use vgic_vcpu_pending_irq(current). Is there
>>>> any reason for not doing that?
> 
> The two interfaces used for that purpose are different in the two VGICs:
> - The old VGIC only works on the current VCPU, since it peeks into the
> GICH_ register to learn the priority (regardless of whether this is
> really needed or useful).
> - The new VGIC can use this function for any VCPU, and we need this
> functionality later on (when we iterate over all VCPUs).
> So we can't use a function hardwiring "current", that would break
> vgic_kick_vcpus() in the new VGIC. And we can't pass a VCPU parameter,
> that would not work for the old VGIC.
> So I believe having this small wrapper here is the easiest solution.
> I will add a patch to rename this function to vgic_pending_irq(),
> though, so this one here looks like:
> int vgic_pending_irq(void)
> {
>      return vgic_vcpu_pending_irq(current);
> }
> 
> We can clean this up when the old VGIC gets removed.

Likely no-one in the old vGIC are going to call that function with v != 
current. This would not be the only place in Xen where a vCPU is taken 
in parameter but effectively v can only be current. That's where 
ASSERT(v == current) comes into place.

Cheers,

Patch

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index f4f2a04a60..9e7fb1edcb 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -646,6 +646,38 @@  void gic_inject(void)
     vgic_restore_state(current);
 }
 
+static int vgic_vcpu_pending_irq(struct vcpu *vcpu)
+{
+    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+    struct vgic_irq *irq;
+    bool pending = false;
+    unsigned long flags;
+
+    if ( !vcpu->domain->arch.vgic.enabled )
+        return false;
+
+    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
+
+    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
+    {
+        spin_lock(&irq->irq_lock);
+        pending = irq_is_pending(irq) && irq->enabled;
+        spin_unlock(&irq->irq_lock);
+
+        if ( pending )
+            break;
+    }
+
+    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
+
+    return pending;
+}
+
+int gic_events_need_delivery(void)
+{
+    return vgic_vcpu_pending_irq(current);
+}
+
 /*
  * Local variables:
  * mode: C