diff options
author | Christoffer Dall <cdall@cs.columbia.edu> | 2013-01-20 18:28:08 -0500 |
---|---|---|
committer | Christoffer Dall <c.dall@virtualopensystems.com> | 2013-01-23 13:29:12 -0500 |
commit | 86ce85352f0da7e1431ad8efcb04323819a620e7 (patch) | |
tree | 0f5a0a971b0092c9cfd74659254f76a4c7117294 | |
parent | d5d8184d35c990b1324d9b30bcd0e4e8aa08f56d (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.txt | 25 | ||||
-rw-r--r-- | arch/arm/include/asm/kvm_arm.h | 1 | ||||
-rw-r--r-- | arch/arm/include/uapi/asm/kvm.h | 21 | ||||
-rw-r--r-- | arch/arm/kvm/arm.c | 65 | ||||
-rw-r--r-- | arch/arm/kvm/trace.h | 25 | ||||
-rw-r--r-- | include/uapi/linux/kvm.h | 1 |
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. | |||
615 | 4.25 KVM_IRQ_LINE | 615 | 4.25 KVM_IRQ_LINE |
616 | 616 | ||
617 | Capability: KVM_CAP_IRQCHIP | 617 | Capability: KVM_CAP_IRQCHIP |
618 | Architectures: x86, ia64 | 618 | Architectures: x86, ia64, arm |
619 | Type: vm ioctl | 619 | Type: vm ioctl |
620 | Parameters: struct kvm_irq_level | 620 | Parameters: struct kvm_irq_level |
621 | Returns: 0 on success, -1 on error | 621 | Returns: 0 on success, -1 on error |
622 | 622 | ||
623 | Sets the level of a GSI input to the interrupt controller model in the kernel. | 623 | Sets the level of a GSI input to the interrupt controller model in the kernel. |
624 | Requires that an interrupt controller model has been previously created with | 624 | On some architectures it is required that an interrupt controller model has |
625 | KVM_CREATE_IRQCHIP. Note that edge-triggered interrupts require the level | 625 | been previously created with KVM_CREATE_IRQCHIP. Note that edge-triggered |
626 | to be set to 1 and then back to 0. | 626 | interrupts require the level to be set to 1 and then back to 0. |
627 | |||
628 | ARM 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 | ||
630 | specific 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 | |||
635 | The 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 | |||
643 | In both cases, level is used to raise/lower the line. | ||
627 | 644 | ||
628 | struct kvm_irq_level { | 645 | struct 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 | ||
285 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | 286 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) |
286 | { | 287 | { |
288 | vcpu->cpu = cpu; | ||
287 | } | 289 | } |
288 | 290 | ||
289 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | 291 | void 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 | ||
324 | static 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 | |||
357 | int 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 | |||
322 | long kvm_arch_vcpu_ioctl(struct file *filp, | 387 | long 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 | ||
42 | TRACE_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 | |||
42 | TRACE_EVENT(kvm_unmap_hva, | 67 | TRACE_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; |