aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoffer Dall <cdall@cs.columbia.edu>2013-01-20 18:28:08 -0500
committerChristoffer Dall <c.dall@virtualopensystems.com>2013-01-23 13:29:12 -0500
commit86ce85352f0da7e1431ad8efcb04323819a620e7 (patch)
tree0f5a0a971b0092c9cfd74659254f76a4c7117294
parentd5d8184d35c990b1324d9b30bcd0e4e8aa08f56d (diff)
KVM: ARM: Inject IRQs and FIQs from userspace
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. Reviewed-by: Will Deacon <will.deacon@arm.com> Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
-rw-r--r--Documentation/virtual/kvm/api.txt25
-rw-r--r--arch/arm/include/asm/kvm_arm.h1
-rw-r--r--arch/arm/include/uapi/asm/kvm.h21
-rw-r--r--arch/arm/kvm/arm.c65
-rw-r--r--arch/arm/kvm/trace.h25
-rw-r--r--include/uapi/linux/kvm.h1
6 files changed, 134 insertions, 4 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 4237c27ea612..505049299298 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -615,15 +615,32 @@ created.
6154.25 KVM_IRQ_LINE 6154.25 KVM_IRQ_LINE
616 616
617Capability: KVM_CAP_IRQCHIP 617Capability: KVM_CAP_IRQCHIP
618Architectures: x86, ia64 618Architectures: x86, ia64, arm
619Type: vm ioctl 619Type: vm ioctl
620Parameters: struct kvm_irq_level 620Parameters: struct kvm_irq_level
621Returns: 0 on success, -1 on error 621Returns: 0 on success, -1 on error
622 622
623Sets the level of a GSI input to the interrupt controller model in the kernel. 623Sets the level of a GSI input to the interrupt controller model in the kernel.
624Requires that an interrupt controller model has been previously created with 624On some architectures it is required that an interrupt controller model has
625KVM_CREATE_IRQCHIP. Note that edge-triggered interrupts require the level 625been previously created with KVM_CREATE_IRQCHIP. Note that edge-triggered
626to be set to 1 and then back to 0. 626interrupts require the level to be set to 1 and then back to 0.
627
628ARM can signal an interrupt either at the CPU level, or at the in-kernel irqchip
629(GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for
630specific cpus. The irq field is interpreted like this:
631
632  bits: | 31 ... 24 | 23 ... 16 | 15 ... 0 |
633 field: | irq_type | vcpu_index | irq_id |
634
635The irq_type field has the following values:
636- irq_type[0]: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
637- irq_type[1]: in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.)
638 (the vcpu_index field is ignored)
639- irq_type[2]: in-kernel GIC: PPI, irq_id between 16 and 31 (incl.)
640
641(The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
642
643In both cases, level is used to raise/lower the line.
627 644
628struct kvm_irq_level { 645struct kvm_irq_level {
629 union { 646 union {
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index 8875b3f605a7..d64b5250ad4e 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -68,6 +68,7 @@
68#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \ 68#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
69 HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \ 69 HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
70 HCR_SWIO | HCR_TIDCP) 70 HCR_SWIO | HCR_TIDCP)
71#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
71 72
72/* Hyp System Control Register (HSCTLR) bits */ 73/* Hyp System Control Register (HSCTLR) bits */
73#define HSCTLR_TE (1 << 30) 74#define HSCTLR_TE (1 << 30)
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 1083327b5fcd..53f45f146875 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -23,6 +23,7 @@
23#include <asm/ptrace.h> 23#include <asm/ptrace.h>
24 24
25#define __KVM_HAVE_GUEST_DEBUG 25#define __KVM_HAVE_GUEST_DEBUG
26#define __KVM_HAVE_IRQ_LINE
26 27
27#define KVM_REG_SIZE(id) \ 28#define KVM_REG_SIZE(id) \
28 (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) 29 (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
@@ -103,4 +104,24 @@ struct kvm_arch_memory_slot {
103#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) 104#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
104#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) 105#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4)
105 106
107/* KVM_IRQ_LINE irq field index values */
108#define KVM_ARM_IRQ_TYPE_SHIFT 24
109#define KVM_ARM_IRQ_TYPE_MASK 0xff
110#define KVM_ARM_IRQ_VCPU_SHIFT 16
111#define KVM_ARM_IRQ_VCPU_MASK 0xff
112#define KVM_ARM_IRQ_NUM_SHIFT 0
113#define KVM_ARM_IRQ_NUM_MASK 0xffff
114
115/* irq_type field */
116#define KVM_ARM_IRQ_TYPE_CPU 0
117#define KVM_ARM_IRQ_TYPE_SPI 1
118#define KVM_ARM_IRQ_TYPE_PPI 2
119
120/* out-of-kernel GIC cpu interrupt injection irq_number field */
121#define KVM_ARM_IRQ_CPU_IRQ 0
122#define KVM_ARM_IRQ_CPU_FIQ 1
123
124/* Highest supported SPI, from VGIC_NR_IRQS */
125#define KVM_ARM_IRQ_GIC_MAX 127
126
106#endif /* __ARM_KVM_H__ */ 127#endif /* __ARM_KVM_H__ */
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index d810afb6cb84..2101152c3a4b 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -24,6 +24,7 @@
24#include <linux/fs.h> 24#include <linux/fs.h>
25#include <linux/mman.h> 25#include <linux/mman.h>
26#include <linux/sched.h> 26#include <linux/sched.h>
27#include <linux/kvm.h>
27#include <trace/events/kvm.h> 28#include <trace/events/kvm.h>
28 29
29#define CREATE_TRACE_POINTS 30#define CREATE_TRACE_POINTS
@@ -284,6 +285,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
284 285
285void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) 286void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
286{ 287{
288 vcpu->cpu = cpu;
287} 289}
288 290
289void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) 291void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
@@ -319,6 +321,69 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
319 return -EINVAL; 321 return -EINVAL;
320} 322}
321 323
324static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level)
325{
326 int bit_index;
327 bool set;
328 unsigned long *ptr;
329
330 if (number == KVM_ARM_IRQ_CPU_IRQ)
331 bit_index = __ffs(HCR_VI);
332 else /* KVM_ARM_IRQ_CPU_FIQ */
333 bit_index = __ffs(HCR_VF);
334
335 ptr = (unsigned long *)&vcpu->arch.irq_lines;
336 if (level)
337 set = test_and_set_bit(bit_index, ptr);
338 else
339 set = test_and_clear_bit(bit_index, ptr);
340
341 /*
342 * If we didn't change anything, no need to wake up or kick other CPUs
343 */
344 if (set == level)
345 return 0;
346
347 /*
348 * The vcpu irq_lines field was updated, wake up sleeping VCPUs and
349 * trigger a world-switch round on the running physical CPU to set the
350 * virtual IRQ/FIQ fields in the HCR appropriately.
351 */
352 kvm_vcpu_kick(vcpu);
353
354 return 0;
355}
356
357int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level)
358{
359 u32 irq = irq_level->irq;
360 unsigned int irq_type, vcpu_idx, irq_num;
361 int nrcpus = atomic_read(&kvm->online_vcpus);
362 struct kvm_vcpu *vcpu = NULL;
363 bool level = irq_level->level;
364
365 irq_type = (irq >> KVM_ARM_IRQ_TYPE_SHIFT) & KVM_ARM_IRQ_TYPE_MASK;
366 vcpu_idx = (irq >> KVM_ARM_IRQ_VCPU_SHIFT) & KVM_ARM_IRQ_VCPU_MASK;
367 irq_num = (irq >> KVM_ARM_IRQ_NUM_SHIFT) & KVM_ARM_IRQ_NUM_MASK;
368
369 trace_kvm_irq_line(irq_type, vcpu_idx, irq_num, irq_level->level);
370
371 if (irq_type != KVM_ARM_IRQ_TYPE_CPU)
372 return -EINVAL;
373
374 if (vcpu_idx >= nrcpus)
375 return -EINVAL;
376
377 vcpu = kvm_get_vcpu(kvm, vcpu_idx);
378 if (!vcpu)
379 return -EINVAL;
380
381 if (irq_num > KVM_ARM_IRQ_CPU_FIQ)
382 return -EINVAL;
383
384 return vcpu_interrupt_line(vcpu, irq_num, level);
385}
386
322long kvm_arch_vcpu_ioctl(struct file *filp, 387long kvm_arch_vcpu_ioctl(struct file *filp,
323 unsigned int ioctl, unsigned long arg) 388 unsigned int ioctl, unsigned long arg)
324{ 389{
diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h
index 862b2cc12fbe..105d1f79909a 100644
--- a/arch/arm/kvm/trace.h
+++ b/arch/arm/kvm/trace.h
@@ -39,6 +39,31 @@ TRACE_EVENT(kvm_exit,
39 TP_printk("PC: 0x%08lx", __entry->vcpu_pc) 39 TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
40); 40);
41 41
42TRACE_EVENT(kvm_irq_line,
43 TP_PROTO(unsigned int type, int vcpu_idx, int irq_num, int level),
44 TP_ARGS(type, vcpu_idx, irq_num, level),
45
46 TP_STRUCT__entry(
47 __field( unsigned int, type )
48 __field( int, vcpu_idx )
49 __field( int, irq_num )
50 __field( int, level )
51 ),
52
53 TP_fast_assign(
54 __entry->type = type;
55 __entry->vcpu_idx = vcpu_idx;
56 __entry->irq_num = irq_num;
57 __entry->level = level;
58 ),
59
60 TP_printk("Inject %s interrupt (%d), vcpu->idx: %d, num: %d, level: %d",
61 (__entry->type == KVM_ARM_IRQ_TYPE_CPU) ? "CPU" :
62 (__entry->type == KVM_ARM_IRQ_TYPE_PPI) ? "VGIC PPI" :
63 (__entry->type == KVM_ARM_IRQ_TYPE_SPI) ? "VGIC SPI" : "UNKNOWN",
64 __entry->type, __entry->vcpu_idx, __entry->irq_num, __entry->level)
65);
66
42TRACE_EVENT(kvm_unmap_hva, 67TRACE_EVENT(kvm_unmap_hva,
43 TP_PROTO(unsigned long hva), 68 TP_PROTO(unsigned long hva),
44 TP_ARGS(hva), 69 TP_ARGS(hva),
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 24978d525c6e..dc63665e73ad 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -115,6 +115,7 @@ struct kvm_irq_level {
115 * ACPI gsi notion of irq. 115 * ACPI gsi notion of irq.
116 * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47.. 116 * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
117 * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23.. 117 * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
118 * For ARM: See Documentation/virtual/kvm/api.txt
118 */ 119 */
119 union { 120 union {
120 __u32 irq; 121 __u32 irq;