Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Christoffer Dall and committed by
Christoffer Dall
86ce8535 d5d8184d

+134 -4
+21 -4
Documentation/virtual/kvm/api.txt
··· 615 615 4.25 KVM_IRQ_LINE 616 616 617 617 Capability: KVM_CAP_IRQCHIP 618 - Architectures: x86, ia64 618 + Architectures: x86, ia64, arm 619 619 Type: vm ioctl 620 620 Parameters: struct kvm_irq_level 621 621 Returns: 0 on success, -1 on error 622 622 623 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 625 - KVM_CREATE_IRQCHIP. Note that edge-triggered interrupts require the level 626 - to be set to 1 and then back to 0. 624 + On some architectures it is required that an interrupt controller model has 625 + been previously created with KVM_CREATE_IRQCHIP. Note that edge-triggered 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 645 struct kvm_irq_level { 629 646 union {
+1
arch/arm/include/asm/kvm_arm.h
··· 68 68 #define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \ 69 69 HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \ 70 70 HCR_SWIO | HCR_TIDCP) 71 + #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF) 71 72 72 73 /* Hyp System Control Register (HSCTLR) bits */ 73 74 #define HSCTLR_TE (1 << 30)
+21
arch/arm/include/uapi/asm/kvm.h
··· 23 23 #include <asm/ptrace.h> 24 24 25 25 #define __KVM_HAVE_GUEST_DEBUG 26 + #define __KVM_HAVE_IRQ_LINE 26 27 27 28 #define KVM_REG_SIZE(id) \ 28 29 (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) ··· 103 102 /* Normal registers are mapped as coprocessor 16. */ 104 103 #define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) 105 104 #define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) 105 + 106 + /* KVM_IRQ_LINE irq field index values */ 107 + #define KVM_ARM_IRQ_TYPE_SHIFT 24 108 + #define KVM_ARM_IRQ_TYPE_MASK 0xff 109 + #define KVM_ARM_IRQ_VCPU_SHIFT 16 110 + #define KVM_ARM_IRQ_VCPU_MASK 0xff 111 + #define KVM_ARM_IRQ_NUM_SHIFT 0 112 + #define KVM_ARM_IRQ_NUM_MASK 0xffff 113 + 114 + /* irq_type field */ 115 + #define KVM_ARM_IRQ_TYPE_CPU 0 116 + #define KVM_ARM_IRQ_TYPE_SPI 1 117 + #define KVM_ARM_IRQ_TYPE_PPI 2 118 + 119 + /* out-of-kernel GIC cpu interrupt injection irq_number field */ 120 + #define KVM_ARM_IRQ_CPU_IRQ 0 121 + #define KVM_ARM_IRQ_CPU_FIQ 1 122 + 123 + /* Highest supported SPI, from VGIC_NR_IRQS */ 124 + #define KVM_ARM_IRQ_GIC_MAX 127 106 125 107 126 #endif /* __ARM_KVM_H__ */
+65
arch/arm/kvm/arm.c
··· 24 24 #include <linux/fs.h> 25 25 #include <linux/mman.h> 26 26 #include <linux/sched.h> 27 + #include <linux/kvm.h> 27 28 #include <trace/events/kvm.h> 28 29 29 30 #define CREATE_TRACE_POINTS ··· 285 284 286 285 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) 287 286 { 287 + vcpu->cpu = cpu; 288 288 } 289 289 290 290 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) ··· 319 317 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) 320 318 { 321 319 return -EINVAL; 320 + } 321 + 322 + static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level) 323 + { 324 + int bit_index; 325 + bool set; 326 + unsigned long *ptr; 327 + 328 + if (number == KVM_ARM_IRQ_CPU_IRQ) 329 + bit_index = __ffs(HCR_VI); 330 + else /* KVM_ARM_IRQ_CPU_FIQ */ 331 + bit_index = __ffs(HCR_VF); 332 + 333 + ptr = (unsigned long *)&vcpu->arch.irq_lines; 334 + if (level) 335 + set = test_and_set_bit(bit_index, ptr); 336 + else 337 + set = test_and_clear_bit(bit_index, ptr); 338 + 339 + /* 340 + * If we didn't change anything, no need to wake up or kick other CPUs 341 + */ 342 + if (set == level) 343 + return 0; 344 + 345 + /* 346 + * The vcpu irq_lines field was updated, wake up sleeping VCPUs and 347 + * trigger a world-switch round on the running physical CPU to set the 348 + * virtual IRQ/FIQ fields in the HCR appropriately. 349 + */ 350 + kvm_vcpu_kick(vcpu); 351 + 352 + return 0; 353 + } 354 + 355 + int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level) 356 + { 357 + u32 irq = irq_level->irq; 358 + unsigned int irq_type, vcpu_idx, irq_num; 359 + int nrcpus = atomic_read(&kvm->online_vcpus); 360 + struct kvm_vcpu *vcpu = NULL; 361 + bool level = irq_level->level; 362 + 363 + irq_type = (irq >> KVM_ARM_IRQ_TYPE_SHIFT) & KVM_ARM_IRQ_TYPE_MASK; 364 + vcpu_idx = (irq >> KVM_ARM_IRQ_VCPU_SHIFT) & KVM_ARM_IRQ_VCPU_MASK; 365 + irq_num = (irq >> KVM_ARM_IRQ_NUM_SHIFT) & KVM_ARM_IRQ_NUM_MASK; 366 + 367 + trace_kvm_irq_line(irq_type, vcpu_idx, irq_num, irq_level->level); 368 + 369 + if (irq_type != KVM_ARM_IRQ_TYPE_CPU) 370 + return -EINVAL; 371 + 372 + if (vcpu_idx >= nrcpus) 373 + return -EINVAL; 374 + 375 + vcpu = kvm_get_vcpu(kvm, vcpu_idx); 376 + if (!vcpu) 377 + return -EINVAL; 378 + 379 + if (irq_num > KVM_ARM_IRQ_CPU_FIQ) 380 + return -EINVAL; 381 + 382 + return vcpu_interrupt_line(vcpu, irq_num, level); 322 383 } 323 384 324 385 long kvm_arch_vcpu_ioctl(struct file *filp,
+25
arch/arm/kvm/trace.h
··· 39 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 67 TRACE_EVENT(kvm_unmap_hva, 43 68 TP_PROTO(unsigned long hva), 44 69 TP_ARGS(hva),
+1
include/uapi/linux/kvm.h
··· 115 115 * ACPI gsi notion of irq. 116 116 * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47.. 117 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 120 union { 120 121 __u32 irq;