Propagate virtual timer interrupts to userspace
Subsystems (2)
cover Propagate virtual timer interrupts to userspace
This patchset allows virtual timer to function without vGIC. In this case the interrupt should be handled by userspace GIC emulation.
In order to signal an interrupt a VM exit is performed with KVM_EXIT_IRQ return code. Together with the code, IRQ number and level is returned.
'level' is actually reserved for possible future level-sensitive interrupts. For them KVM_EXIT_IRQ code would be generated upon line state transition to the specified level. For edge-sensitive interrupts actually only 'irq' number is meaningful, signalling trigger condition on the specified IRQ. However, 'level' still denotes active state (1 for low-to-high edge or 0 for high-to-low edge).
Currently there's no additional API to specify how to treate particular IRQs in the userspace. The userspace is assumed just to know it. On ARM architecture all interrupts are processed by KVM as if they were edge-sensitive, therefore timer interrupt as signalled as edge-sensitive, active high.
This patch set is to be applied on top of "Allow to use KVM without in-kernel irqchip" one.
Pavel Fedin (2):
Introduce KVM_EXIT_IRQ
Send KVM_EXIT_IRQ from timer if irqchip is not used
arch/arm/kvm/arm.c | 18 +++++++++++------- include/linux/kvm_host.h | 7 +++++++ include/uapi/linux/kvm.h | 3 +++ virt/kvm/arm/arch_timer.c | 6 ++++++ 4 files changed, 27 insertions(+), 7 deletions(-)
Signature · 1 line
2.4.4
RFC 1/2 Introduce KVM_EXIT_IRQ
This exit code means that this vCPU wants to inject an interrupt using userspace-emulated controller.
The code is designed to be as much arch-agnostic as possible. Therefore, it has IRQ number and level as parameters (encoded in struct kvm_irq_level).
Currently it will be used only by ARM architecture, whose implementation of virtual timer works as if it was edge-sensitive (despite on real hardware timer IRQ is level-sensitive). Therefore, level value is actually reserved for implementing hypothetical level-sensitive IRQs. In this case this exit code would indicate transition of the line to the specified level.
--- include/uapi/linux/kvm.h | 3 +++ 1 file changed, 3 insertions(+)
include/uapi/linux/kvm.h +3 -0
@@ -183,6 +183,7 @@ struct kvm_s390_skeys {#define KVM_EXIT_EPR 23#define KVM_EXIT_SYSTEM_EVENT 24#define KVM_EXIT_S390_STSI 25 +#define KVM_EXIT_IRQ 26/* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */
@@ -329,6 +330,8 @@ struct kvm_run {__u8 sel1;__u16 sel2; } s390_stsi; +/* KVM_EXIT_IRQ */ +struct kvm_irq_level irq;/* Fix the size of the union. */ char padding[256 ]; };
Signature · 1 line
2.4.4
RFC 2/2 Send KVM_EXIT_IRQ from timer if irqchip is not used
In reply to Pavel Fedin--- arch/arm/kvm/arm.c | 18 +++++++++++------- include/linux/kvm_host.h | 7 +++++++ virt/kvm/arm/arch_timer.c | 6 ++++++ 3 files changed, 24 insertions(+), 7 deletions(-)
arch/arm/kvm/arm.c +11 -7
@@ -461,13 +461,7 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)return ret; } -/* -* Enable the arch timers only if we have an in-kernel VGIC -* and it has been properly initialized, since we cannot handle -* interrupts from the virtual timer with a userspace gic. -*/ -if (irqchip_in_kernel (kvm) &&vgic_initialized (kvm)) -kvm_timer_enable (kvm); +kvm_timer_enable (kvm);return 0 ; }
@@ -547,6 +541,16 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) run->exit_reason =KVM_EXIT_INTR ; } +if (vcpu->irq) { + ret =0 ; + run->exit_reason =KVM_EXIT_IRQ ; + run->irq.irq = vcpu->irq->irq; + run->irq.level = vcpu->irq->level; + + vcpu->irq =NULL ; +continue ; + } +if (ret <=0 ||need_new_vmid_gen (vcpu->kvm)) {local_irq_enable ();kvm_timer_sync_hwstate (vcpu);
include/linux/kvm_host.h +7 -0
@@ -267,6 +267,13 @@ struct kvm_vcpu { } spin_loop;#endif bool preempted; + +/* +* IRQ pending to the userspace on this CPU. +* Currently we support only one slot, used only by ARM architecture. +*/ +const struct kvm_irq_level *irq; +struct kvm_vcpu_arch arch; };
virt/kvm/arm/arch_timer.c +6 -0
@@ -65,6 +65,12 @@ static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu)struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; timer->cntv_ctl |=ARCH_TIMER_CTRL_IT_MASK ; + +if (!irqchip_in_kernel (vcpu->kvm)) { + vcpu->irq = timer->irq; +return ; + } + ret =kvm_vgic_inject_irq (vcpu->kvm, vcpu->vcpu_id, timer->irq->irq, timer->irq->level);
Signature · 1 line
2.4.4