aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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 /arch
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>
Diffstat (limited to 'arch')
-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
4 files changed, 112 insertions, 0 deletions
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),