diff mbox

[09/15] KVM: ARM: Inject IRQs and FIQs from userspace

Message ID 20120915153527.21241.61813.stgit@ubuntu
State New
Headers show

Commit Message

Christoffer Dall Sept. 15, 2012, 3:35 p.m. UTC
From: Christoffer Dall <cdall@cs.columbia.edu>

All interrupt injection is now based on the VM ioctl KVM_IRQ_LINE.  This
works semantically well for the GIC as we in fact raise/lower a line on
a machine component (the gic).  The IOCTL uses the follwing struct.

struct kvm_irq_level {
	union {
		__u32 irq;     /* GSI */
		__s32 status;  /* not used for KVM_IRQ_LEVEL */
	};
	__u32 level;           /* 0 or 1 */
};

ARM can signal an interrupt either at the CPU level, or at the in-kernel irqchip
(GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for
specific cpus.  The irq field is interpreted like this:

  bits:  | 31 ... 24 | 23  ... 16 | 15    ...    0 |
  field: | irq_type  | vcpu_index |   irq_number   |

The irq_type field has the following values:
- irq_type[0]: out-of-kernel GIC: irq_number 0 is IRQ, irq_number 1 is FIQ
- irq_type[1]: in-kernel GIC: SPI, irq_number between 32 and 1019 (incl.)
               (the vcpu_index field is ignored)
- irq_type[2]: in-kernel GIC: PPI, irq_number between 16 and 31 (incl.)

The irq_number thus corresponds to the irq ID in as in the GICv2 specs.

This is documented in Documentation/kvm/api.txt.

Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
---
 Documentation/virtual/kvm/api.txt |   25 +++++++++++--
 arch/arm/include/asm/kvm.h        |   21 +++++++++++
 arch/arm/include/asm/kvm_arm.h    |    1 +
 arch/arm/kvm/arm.c                |   70 +++++++++++++++++++++++++++++++++++++
 arch/arm/kvm/trace.h              |   23 ++++++++++++
 include/linux/kvm.h               |    1 +
 6 files changed, 137 insertions(+), 4 deletions(-)

Comments

Will Deacon Sept. 25, 2012, 3:55 p.m. UTC | #1
On Sat, Sep 15, 2012 at 04:35:27PM +0100, Christoffer Dall wrote:
> diff --git a/arch/arm/include/asm/kvm.h b/arch/arm/include/asm/kvm.h
> index a13b582..131e632 100644
> --- a/arch/arm/include/asm/kvm.h
> +++ b/arch/arm/include/asm/kvm.h
> @@ -22,6 +22,7 @@
>  #include <asm/types.h>
>  
>  #define __KVM_HAVE_GUEST_DEBUG
> +#define __KVM_HAVE_IRQ_LINE
>  
>  #define KVM_REG_SIZE(id)						\
>  	(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
> @@ -85,4 +86,24 @@ struct kvm_reg_list {
>  #define KVM_REG_ARM_CORE		(0x0010 << KVM_REG_ARM_COPROC_SHIFT)
>  #define KVM_REG_ARM_CORE_REG(name)	(offsetof(struct kvm_regs, name) / 4)
>  
> +/* KVM_IRQ_LINE irq field index values */
> +#define KVM_ARM_IRQ_TYPE_SHIFT		24
> +#define KVM_ARM_IRQ_TYPE_MASK		0xff
> +#define KVM_ARM_IRQ_VCPU_SHIFT		16
> +#define KVM_ARM_IRQ_VCPU_MASK		0xff
> +#define KVM_ARM_IRQ_NUM_SHIFT		0
> +#define KVM_ARM_IRQ_NUM_MASK		0xffff
> +
> +/* irq_type field */
> +#define KVM_ARM_IRQ_TYPE_CPU		0
> +#define KVM_ARM_IRQ_TYPE_SPI		1
> +#define KVM_ARM_IRQ_TYPE_PPI		2
> +
> +/* out-of-kernel GIC cpu interrupt injection irq_number field */
> +#define KVM_ARM_IRQ_CPU_IRQ		0
> +#define KVM_ARM_IRQ_CPU_FIQ		1
> +
> +/* Highest supported SPI, from VGIC_NR_IRQS */
> +#define KVM_ARM_IRQ_GIC_MAX		127

This define, and those referring to PPIs and SPIs sound highly GIC-specific.
Is that really appropriate for kvm.h? Do you mandate a single GIC as the
only interrupt controller?

> diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
> index 6e46541..0f641c1 100644
> --- a/arch/arm/include/asm/kvm_arm.h
> +++ b/arch/arm/include/asm/kvm_arm.h
> @@ -74,6 +74,7 @@
>  #define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
>  			HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
>  			HCR_SWIO | HCR_TIDCP)
> +#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
>  
>  /* Hyp System Control Register (HSCTLR) bits */
>  #define HSCTLR_TE	(1 << 30)
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index b97ebd0..8a87fc7 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -24,6 +24,7 @@
>  #include <linux/fs.h>
>  #include <linux/mman.h>
>  #include <linux/sched.h>
> +#include <linux/kvm.h>
>  #include <trace/events/kvm.h>
>  
>  #define CREATE_TRACE_POINTS
> @@ -271,6 +272,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
>  
>  void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>  {
> +	vcpu->cpu = cpu;
>  }
>  
>  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
> @@ -311,6 +313,74 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  	return -EINVAL;
>  }
>  
> +static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level)
> +{
> +	int bit_index;
> +	bool set;
> +	unsigned long *ptr;
> +
> +	if (number == KVM_ARM_IRQ_CPU_IRQ)
> +		bit_index = ffs(HCR_VI) - 1;
> +	else /* KVM_ARM_IRQ_CPU_FIQ */
> +		bit_index = ffs(HCR_VF) - 1;

__ffs

Will
Christoffer Dall Sept. 29, 2012, 3:50 p.m. UTC | #2
On Tue, Sep 25, 2012 at 11:55 AM, Will Deacon <will.deacon@arm.com> wrote:
> On Sat, Sep 15, 2012 at 04:35:27PM +0100, Christoffer Dall wrote:
>> diff --git a/arch/arm/include/asm/kvm.h b/arch/arm/include/asm/kvm.h
>> index a13b582..131e632 100644
>> --- a/arch/arm/include/asm/kvm.h
>> +++ b/arch/arm/include/asm/kvm.h
>> @@ -22,6 +22,7 @@
>>  #include <asm/types.h>
>>
>>  #define __KVM_HAVE_GUEST_DEBUG
>> +#define __KVM_HAVE_IRQ_LINE
>>
>>  #define KVM_REG_SIZE(id)                                             \
>>       (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
>> @@ -85,4 +86,24 @@ struct kvm_reg_list {
>>  #define KVM_REG_ARM_CORE             (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
>>  #define KVM_REG_ARM_CORE_REG(name)   (offsetof(struct kvm_regs, name) / 4)
>>
>> +/* KVM_IRQ_LINE irq field index values */
>> +#define KVM_ARM_IRQ_TYPE_SHIFT               24
>> +#define KVM_ARM_IRQ_TYPE_MASK                0xff
>> +#define KVM_ARM_IRQ_VCPU_SHIFT               16
>> +#define KVM_ARM_IRQ_VCPU_MASK                0xff
>> +#define KVM_ARM_IRQ_NUM_SHIFT                0
>> +#define KVM_ARM_IRQ_NUM_MASK         0xffff
>> +
>> +/* irq_type field */
>> +#define KVM_ARM_IRQ_TYPE_CPU         0
>> +#define KVM_ARM_IRQ_TYPE_SPI         1
>> +#define KVM_ARM_IRQ_TYPE_PPI         2
>> +
>> +/* out-of-kernel GIC cpu interrupt injection irq_number field */
>> +#define KVM_ARM_IRQ_CPU_IRQ          0
>> +#define KVM_ARM_IRQ_CPU_FIQ          1
>> +
>> +/* Highest supported SPI, from VGIC_NR_IRQS */
>> +#define KVM_ARM_IRQ_GIC_MAX          127
>
> This define, and those referring to PPIs and SPIs sound highly GIC-specific.
> Is that really appropriate for kvm.h? Do you mandate a single GIC as the
> only interrupt controller?
>

you can add a another gic with another in-kernel gic emulation if
someone makes such one that's different from the vgic specifications
by defining another irq type.

devices must interact with a gic available in the kernel, so I think
referring to PPIs and SPIs is very appropriate in kvm.h for a user
space device emulation that must inject either a PPI or an SPI.

We can call them TYPE_GIC_V2_XXX or something like that if you feel
this is cleaner.

>> diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
>> index 6e46541..0f641c1 100644
>> --- a/arch/arm/include/asm/kvm_arm.h
>> +++ b/arch/arm/include/asm/kvm_arm.h
>> @@ -74,6 +74,7 @@
>>  #define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
>>                       HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
>>                       HCR_SWIO | HCR_TIDCP)
>> +#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
>>
>>  /* Hyp System Control Register (HSCTLR) bits */
>>  #define HSCTLR_TE    (1 << 30)
>> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
>> index b97ebd0..8a87fc7 100644
>> --- a/arch/arm/kvm/arm.c
>> +++ b/arch/arm/kvm/arm.c
>> @@ -24,6 +24,7 @@
>>  #include <linux/fs.h>
>>  #include <linux/mman.h>
>>  #include <linux/sched.h>
>> +#include <linux/kvm.h>
>>  #include <trace/events/kvm.h>
>>
>>  #define CREATE_TRACE_POINTS
>> @@ -271,6 +272,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
>>
>>  void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>>  {
>> +     vcpu->cpu = cpu;
>>  }
>>
>>  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
>> @@ -311,6 +313,74 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>>       return -EINVAL;
>>  }
>>
>> +static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level)
>> +{
>> +     int bit_index;
>> +     bool set;
>> +     unsigned long *ptr;
>> +
>> +     if (number == KVM_ARM_IRQ_CPU_IRQ)
>> +             bit_index = ffs(HCR_VI) - 1;
>> +     else /* KVM_ARM_IRQ_CPU_FIQ */
>> +             bit_index = ffs(HCR_VF) - 1;
>
> __ffs
>
fixed


-Christoffer
Will Deacon Sept. 30, 2012, 12:48 p.m. UTC | #3
Hi Christoffer,

On Sat, Sep 29, 2012 at 04:50:25PM +0100, Christoffer Dall wrote:
> On Tue, Sep 25, 2012 at 11:55 AM, Will Deacon <will.deacon@arm.com> wrote:
> > On Sat, Sep 15, 2012 at 04:35:27PM +0100, Christoffer Dall wrote:
> >> diff --git a/arch/arm/include/asm/kvm.h b/arch/arm/include/asm/kvm.h
> >> index a13b582..131e632 100644
> >> --- a/arch/arm/include/asm/kvm.h
> >> +++ b/arch/arm/include/asm/kvm.h
> >> @@ -22,6 +22,7 @@
> >>  #include <asm/types.h>
> >>
> >>  #define __KVM_HAVE_GUEST_DEBUG
> >> +#define __KVM_HAVE_IRQ_LINE
> >>
> >>  #define KVM_REG_SIZE(id)                                             \
> >>       (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
> >> @@ -85,4 +86,24 @@ struct kvm_reg_list {
> >>  #define KVM_REG_ARM_CORE             (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
> >>  #define KVM_REG_ARM_CORE_REG(name)   (offsetof(struct kvm_regs, name) / 4)
> >>
> >> +/* KVM_IRQ_LINE irq field index values */
> >> +#define KVM_ARM_IRQ_TYPE_SHIFT               24
> >> +#define KVM_ARM_IRQ_TYPE_MASK                0xff
> >> +#define KVM_ARM_IRQ_VCPU_SHIFT               16
> >> +#define KVM_ARM_IRQ_VCPU_MASK                0xff
> >> +#define KVM_ARM_IRQ_NUM_SHIFT                0
> >> +#define KVM_ARM_IRQ_NUM_MASK         0xffff
> >> +
> >> +/* irq_type field */
> >> +#define KVM_ARM_IRQ_TYPE_CPU         0
> >> +#define KVM_ARM_IRQ_TYPE_SPI         1
> >> +#define KVM_ARM_IRQ_TYPE_PPI         2
> >> +
> >> +/* out-of-kernel GIC cpu interrupt injection irq_number field */
> >> +#define KVM_ARM_IRQ_CPU_IRQ          0
> >> +#define KVM_ARM_IRQ_CPU_FIQ          1
> >> +
> >> +/* Highest supported SPI, from VGIC_NR_IRQS */
> >> +#define KVM_ARM_IRQ_GIC_MAX          127
> >
> > This define, and those referring to PPIs and SPIs sound highly GIC-specific.
> > Is that really appropriate for kvm.h? Do you mandate a single GIC as the
> > only interrupt controller?
> >
> 
> you can add a another gic with another in-kernel gic emulation if
> someone makes such one that's different from the vgic specifications
> by defining another irq type.
> 
> devices must interact with a gic available in the kernel, so I think
> referring to PPIs and SPIs is very appropriate in kvm.h for a user
> space device emulation that must inject either a PPI or an SPI.
> 
> We can call them TYPE_GIC_V2_XXX or something like that if you feel
> this is cleaner.

It's more that the GIC isn't really part of the architecture, so it would be
cleaner to have the GIC-specifics separated out from the architectural part
of KVM. That will also make it easier when adding support for future
versions of the GIC.

If core KVM needs the concept of a per-cpu interrupt, just call it
IRQ_TYPE_PERCPU or something rather than PPI.

Will
Christoffer Dall Sept. 30, 2012, 2:34 p.m. UTC | #4
On Sun, Sep 30, 2012 at 8:48 AM, Will Deacon <will.deacon@arm.com> wrote:
> Hi Christoffer,
>
> On Sat, Sep 29, 2012 at 04:50:25PM +0100, Christoffer Dall wrote:
>> On Tue, Sep 25, 2012 at 11:55 AM, Will Deacon <will.deacon@arm.com> wrote:
>> > On Sat, Sep 15, 2012 at 04:35:27PM +0100, Christoffer Dall wrote:
>> >> diff --git a/arch/arm/include/asm/kvm.h b/arch/arm/include/asm/kvm.h
>> >> index a13b582..131e632 100644
>> >> --- a/arch/arm/include/asm/kvm.h
>> >> +++ b/arch/arm/include/asm/kvm.h
>> >> @@ -22,6 +22,7 @@
>> >>  #include <asm/types.h>
>> >>
>> >>  #define __KVM_HAVE_GUEST_DEBUG
>> >> +#define __KVM_HAVE_IRQ_LINE
>> >>
>> >>  #define KVM_REG_SIZE(id)                                             \
>> >>       (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
>> >> @@ -85,4 +86,24 @@ struct kvm_reg_list {
>> >>  #define KVM_REG_ARM_CORE             (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
>> >>  #define KVM_REG_ARM_CORE_REG(name)   (offsetof(struct kvm_regs, name) / 4)
>> >>
>> >> +/* KVM_IRQ_LINE irq field index values */
>> >> +#define KVM_ARM_IRQ_TYPE_SHIFT               24
>> >> +#define KVM_ARM_IRQ_TYPE_MASK                0xff
>> >> +#define KVM_ARM_IRQ_VCPU_SHIFT               16
>> >> +#define KVM_ARM_IRQ_VCPU_MASK                0xff
>> >> +#define KVM_ARM_IRQ_NUM_SHIFT                0
>> >> +#define KVM_ARM_IRQ_NUM_MASK         0xffff
>> >> +
>> >> +/* irq_type field */
>> >> +#define KVM_ARM_IRQ_TYPE_CPU         0
>> >> +#define KVM_ARM_IRQ_TYPE_SPI         1
>> >> +#define KVM_ARM_IRQ_TYPE_PPI         2
>> >> +
>> >> +/* out-of-kernel GIC cpu interrupt injection irq_number field */
>> >> +#define KVM_ARM_IRQ_CPU_IRQ          0
>> >> +#define KVM_ARM_IRQ_CPU_FIQ          1
>> >> +
>> >> +/* Highest supported SPI, from VGIC_NR_IRQS */
>> >> +#define KVM_ARM_IRQ_GIC_MAX          127
>> >
>> > This define, and those referring to PPIs and SPIs sound highly GIC-specific.
>> > Is that really appropriate for kvm.h? Do you mandate a single GIC as the
>> > only interrupt controller?
>> >
>>
>> you can add a another gic with another in-kernel gic emulation if
>> someone makes such one that's different from the vgic specifications
>> by defining another irq type.
>>
>> devices must interact with a gic available in the kernel, so I think
>> referring to PPIs and SPIs is very appropriate in kvm.h for a user
>> space device emulation that must inject either a PPI or an SPI.
>>
>> We can call them TYPE_GIC_V2_XXX or something like that if you feel
>> this is cleaner.
>
> It's more that the GIC isn't really part of the architecture, so it would be
> cleaner to have the GIC-specifics separated out from the architectural part
> of KVM. That will also make it easier when adding support for future
> versions of the GIC.
>
> If core KVM needs the concept of a per-cpu interrupt, just call it
> IRQ_TYPE_PERCPU or something rather than PPI.
>
that we have already, KVM_ARM_IRQ_TYPE_CPU

then how do you propose an interface for a user space emulation of a
board that uses the vgic where a device needs to inject a PPI to the
kernel that emulates the vgic?

I don't see the dire need for this separation: the API is extendable
and covers all the needs at this point.
diff mbox

Patch

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 67640c6..605986f 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -615,15 +615,32 @@  created.
 4.25 KVM_IRQ_LINE
 
 Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64
+Architectures: x86, ia64, arm
 Type: vm ioctl
 Parameters: struct kvm_irq_level
 Returns: 0 on success, -1 on error
 
 Sets the level of a GSI input to the interrupt controller model in the kernel.
-Requires that an interrupt controller model has been previously created with
-KVM_CREATE_IRQCHIP.  Note that edge-triggered interrupts require the level
-to be set to 1 and then back to 0.
+On some architectures it is required that an interrupt controller model has
+been previously created with KVM_CREATE_IRQCHIP.  Note that edge-triggered
+interrupts require the level to be set to 1 and then back to 0.
+
+ARM can signal an interrupt either at the CPU level, or at the in-kernel irqchip
+(GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for
+specific cpus.  The irq field is interpreted like this:
+
+  bits:  | 31 ... 24 | 23  ... 16 | 15    ...    0 |
+  field: | irq_type  | vcpu_index |     irq_id     |
+
+The irq_type field has the following values:
+- irq_type[0]: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
+- irq_type[1]: in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.)
+               (the vcpu_index field is ignored)
+- irq_type[2]: in-kernel GIC: PPI, irq_id between 16 and 31 (incl.)
+
+(The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
+
+In both cases, level is used to raise/lower the line.
 
 struct kvm_irq_level {
 	union {
diff --git a/arch/arm/include/asm/kvm.h b/arch/arm/include/asm/kvm.h
index a13b582..131e632 100644
--- a/arch/arm/include/asm/kvm.h
+++ b/arch/arm/include/asm/kvm.h
@@ -22,6 +22,7 @@ 
 #include <asm/types.h>
 
 #define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_IRQ_LINE
 
 #define KVM_REG_SIZE(id)						\
 	(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
@@ -85,4 +86,24 @@  struct kvm_reg_list {
 #define KVM_REG_ARM_CORE		(0x0010 << KVM_REG_ARM_COPROC_SHIFT)
 #define KVM_REG_ARM_CORE_REG(name)	(offsetof(struct kvm_regs, name) / 4)
 
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_TYPE_SHIFT		24
+#define KVM_ARM_IRQ_TYPE_MASK		0xff
+#define KVM_ARM_IRQ_VCPU_SHIFT		16
+#define KVM_ARM_IRQ_VCPU_MASK		0xff
+#define KVM_ARM_IRQ_NUM_SHIFT		0
+#define KVM_ARM_IRQ_NUM_MASK		0xffff
+
+/* irq_type field */
+#define KVM_ARM_IRQ_TYPE_CPU		0
+#define KVM_ARM_IRQ_TYPE_SPI		1
+#define KVM_ARM_IRQ_TYPE_PPI		2
+
+/* out-of-kernel GIC cpu interrupt injection irq_number field */
+#define KVM_ARM_IRQ_CPU_IRQ		0
+#define KVM_ARM_IRQ_CPU_FIQ		1
+
+/* Highest supported SPI, from VGIC_NR_IRQS */
+#define KVM_ARM_IRQ_GIC_MAX		127
+
 #endif /* __ARM_KVM_H__ */
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index 6e46541..0f641c1 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -74,6 +74,7 @@ 
 #define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
 			HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
 			HCR_SWIO | HCR_TIDCP)
+#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
 
 /* Hyp System Control Register (HSCTLR) bits */
 #define HSCTLR_TE	(1 << 30)
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index b97ebd0..8a87fc7 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -24,6 +24,7 @@ 
 #include <linux/fs.h>
 #include <linux/mman.h>
 #include <linux/sched.h>
+#include <linux/kvm.h>
 #include <trace/events/kvm.h>
 
 #define CREATE_TRACE_POINTS
@@ -271,6 +272,7 @@  void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
+	vcpu->cpu = cpu;
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
@@ -311,6 +313,74 @@  int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	return -EINVAL;
 }
 
+static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level)
+{
+	int bit_index;
+	bool set;
+	unsigned long *ptr;
+
+	if (number == KVM_ARM_IRQ_CPU_IRQ)
+		bit_index = ffs(HCR_VI) - 1;
+	else /* KVM_ARM_IRQ_CPU_FIQ */
+		bit_index = ffs(HCR_VF) - 1;
+
+	ptr = (unsigned long *)&vcpu->arch.irq_lines;
+	if (level)
+		set = test_and_set_bit(bit_index, ptr);
+	else
+		set = test_and_clear_bit(bit_index, ptr);
+
+	/*
+	 * If we didn't change anything, no need to wake up or kick other CPUs
+	 */
+	if (set == level)
+		return 0;
+
+	/*
+	 * The vcpu irq_lines field was updated, wake up sleeping VCPUs and
+	 * trigger a world-switch round on the running physical CPU to set the
+	 * virtual IRQ/FIQ fields in the HCR appropriately.
+	 */
+	kvm_vcpu_kick(vcpu);
+
+	return 0;
+}
+
+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level)
+{
+	u32 irq = irq_level->irq;
+	unsigned int irq_type, vcpu_idx, irq_num;
+	int nrcpus = atomic_read(&kvm->online_vcpus);
+	struct kvm_vcpu *vcpu = NULL;
+	bool level = irq_level->level;
+
+	irq_type = (irq >> KVM_ARM_IRQ_TYPE_SHIFT) & KVM_ARM_IRQ_TYPE_MASK;
+	vcpu_idx = (irq >> KVM_ARM_IRQ_VCPU_SHIFT) & KVM_ARM_IRQ_VCPU_MASK;
+	irq_num = (irq >> KVM_ARM_IRQ_NUM_SHIFT) & KVM_ARM_IRQ_NUM_MASK;
+
+	trace_kvm_irq_line(irq_type, vcpu_idx, irq_num, irq_level->level);
+
+	if (irq_type == KVM_ARM_IRQ_TYPE_CPU ||
+	    irq_type == KVM_ARM_IRQ_TYPE_PPI) {
+		if (vcpu_idx >= nrcpus)
+			return -EINVAL;
+
+		vcpu = kvm_get_vcpu(kvm, vcpu_idx);
+		if (!vcpu)
+			return -EINVAL;
+	}
+
+	switch (irq_type) {
+	case KVM_ARM_IRQ_TYPE_CPU:
+		if (irq_num > KVM_ARM_IRQ_CPU_FIQ)
+			return -EINVAL;
+
+		return vcpu_interrupt_line(vcpu, irq_num, level);
+	}
+
+	return -EINVAL;
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
 			 unsigned int ioctl, unsigned long arg)
 {
diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h
index f8869c1..a283eef 100644
--- a/arch/arm/kvm/trace.h
+++ b/arch/arm/kvm/trace.h
@@ -39,7 +39,30 @@  TRACE_EVENT(kvm_exit,
 	TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
 );
 
+TRACE_EVENT(kvm_irq_line,
+	TP_PROTO(unsigned int type, int vcpu_idx, int irq_num, int level),
+	TP_ARGS(type, vcpu_idx, irq_num, level),
 
+	TP_STRUCT__entry(
+		__field(	unsigned int,	type		)
+		__field(	int,		vcpu_idx	)
+		__field(	int,		irq_num		)
+		__field(	int,		level		)
+	),
+
+	TP_fast_assign(
+		__entry->type		= type;
+		__entry->vcpu_idx	= vcpu_idx;
+		__entry->irq_num	= irq_num;
+		__entry->level		= level;
+	),
+
+	TP_printk("Inject %s interrupt (%d), vcpu->idx: %d, num: %d, level: %d",
+		  (__entry->type == KVM_ARM_IRQ_TYPE_CPU) ? "CPU" :
+		  (__entry->type == KVM_ARM_IRQ_TYPE_PPI) ? "VGIC PPI" :
+		  (__entry->type == KVM_ARM_IRQ_TYPE_SPI) ? "VGIC SPI" : "UNKNOWN",
+		  __entry->type, __entry->vcpu_idx, __entry->irq_num, __entry->level)
+);
 
 #endif /* _TRACE_KVM_H */
 
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index a960f66..8091b1d 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -115,6 +115,7 @@  struct kvm_irq_level {
 	 * ACPI gsi notion of irq.
 	 * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
 	 * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
+	 * For ARM: IRQ: irq = (2*vcpu_index). FIQ: irq = (2*vcpu_indx + 1).
 	 */
 	union {
 		__u32 irq;