xref: /openbmc/linux/arch/x86/kvm/irq.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
13b20eb23SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2edf88417SAvi Kivity /*
3edf88417SAvi Kivity  * irq.c: API for in kernel interrupt controller
4edf88417SAvi Kivity  * Copyright (c) 2007, Intel Corporation.
59611c187SNicolas Kaiser  * Copyright 2009 Red Hat, Inc. and/or its affiliates.
6edf88417SAvi Kivity  *
7edf88417SAvi Kivity  * Authors:
8edf88417SAvi Kivity  *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
9edf88417SAvi Kivity  */
10*8d20bd63SSean Christopherson #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11edf88417SAvi Kivity 
121767e931SPaul Gortmaker #include <linux/export.h>
13edf88417SAvi Kivity #include <linux/kvm_host.h>
14edf88417SAvi Kivity 
15edf88417SAvi Kivity #include "irq.h"
167837699fSSheng Yang #include "i8254.h"
178061823aSGleb Natapov #include "x86.h"
1840da8ccdSDavid Woodhouse #include "xen.h"
19edf88417SAvi Kivity 
20edf88417SAvi Kivity /*
213d80840dSMarcelo Tosatti  * check if there are pending timer events
223d80840dSMarcelo Tosatti  * to be processed.
233d80840dSMarcelo Tosatti  */
kvm_cpu_has_pending_timer(struct kvm_vcpu * vcpu)243d80840dSMarcelo Tosatti int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
253d80840dSMarcelo Tosatti {
2653639526SJoao Martins 	int r = 0;
271e3161b4SPaolo Bonzini 
2853639526SJoao Martins 	if (lapic_in_kernel(vcpu))
2953639526SJoao Martins 		r = apic_has_pending_timer(vcpu);
3053639526SJoao Martins 	if (kvm_xen_timer_enabled(vcpu))
3153639526SJoao Martins 		r += kvm_xen_has_pending_timer(vcpu);
3253639526SJoao Martins 
3353639526SJoao Martins 	return r;
343d80840dSMarcelo Tosatti }
353d80840dSMarcelo Tosatti 
363d80840dSMarcelo Tosatti /*
371c1a9ce9SSteve Rutherford  * check if there is a pending userspace external interrupt
381c1a9ce9SSteve Rutherford  */
pending_userspace_extint(struct kvm_vcpu * v)391c1a9ce9SSteve Rutherford static int pending_userspace_extint(struct kvm_vcpu *v)
401c1a9ce9SSteve Rutherford {
411c1a9ce9SSteve Rutherford 	return v->arch.pending_external_vector != -1;
421c1a9ce9SSteve Rutherford }
431c1a9ce9SSteve Rutherford 
441c1a9ce9SSteve Rutherford /*
45c7c9c56cSYang Zhang  * check if there is pending interrupt from
46c7c9c56cSYang Zhang  * non-APIC source without intack.
47c7c9c56cSYang Zhang  */
kvm_cpu_has_extint(struct kvm_vcpu * v)4871cc849bSPaolo Bonzini int kvm_cpu_has_extint(struct kvm_vcpu *v)
49c7c9c56cSYang Zhang {
50c7c9c56cSYang Zhang 	/*
5172c3bcdcSPaolo Bonzini 	 * FIXME: interrupt.injected represents an interrupt whose
5204140b41SLiran Alon 	 * side-effects have already been applied (e.g. bit from IRR
5304140b41SLiran Alon 	 * already moved to ISR). Therefore, it is incorrect to rely
5404140b41SLiran Alon 	 * on interrupt.injected to know if there is a pending
5504140b41SLiran Alon 	 * interrupt in the user-mode LAPIC.
5604140b41SLiran Alon 	 * This leads to nVMX/nSVM not be able to distinguish
5704140b41SLiran Alon 	 * if it should exit from L2 to L1 on EXTERNAL_INTERRUPT on
5804140b41SLiran Alon 	 * pending interrupt or should re-inject an injected
5904140b41SLiran Alon 	 * interrupt.
6004140b41SLiran Alon 	 */
6135754c98SPaolo Bonzini 	if (!lapic_in_kernel(v))
6204140b41SLiran Alon 		return v->arch.interrupt.injected;
63c7c9c56cSYang Zhang 
6440da8ccdSDavid Woodhouse 	if (kvm_xen_has_interrupt(v))
6540da8ccdSDavid Woodhouse 		return 1;
6640da8ccdSDavid Woodhouse 
6772c3bcdcSPaolo Bonzini 	if (!kvm_apic_accept_pic_intr(v))
6872c3bcdcSPaolo Bonzini 		return 0;
6972c3bcdcSPaolo Bonzini 
7072c3bcdcSPaolo Bonzini 	if (irqchip_split(v->kvm))
7172c3bcdcSPaolo Bonzini 		return pending_userspace_extint(v);
7272c3bcdcSPaolo Bonzini 	else
7372c3bcdcSPaolo Bonzini 		return v->kvm->arch.vpic->output;
7472c3bcdcSPaolo Bonzini }
7572c3bcdcSPaolo Bonzini 
7672c3bcdcSPaolo Bonzini /*
7772c3bcdcSPaolo Bonzini  * check if there is injectable interrupt:
7872c3bcdcSPaolo Bonzini  * when virtual interrupt delivery enabled,
7972c3bcdcSPaolo Bonzini  * interrupt from apic will handled by hardware,
8072c3bcdcSPaolo Bonzini  * we don't need to check it here.
8172c3bcdcSPaolo Bonzini  */
kvm_cpu_has_injectable_intr(struct kvm_vcpu * v)8272c3bcdcSPaolo Bonzini int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
8372c3bcdcSPaolo Bonzini {
84c7c9c56cSYang Zhang 	if (kvm_cpu_has_extint(v))
85c7c9c56cSYang Zhang 		return 1;
86c7c9c56cSYang Zhang 
87851c1a18SLiran Alon 	if (!is_guest_mode(v) && kvm_vcpu_apicv_active(v))
88c7c9c56cSYang Zhang 		return 0;
89c7c9c56cSYang Zhang 
90c7c9c56cSYang Zhang 	return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
91c7c9c56cSYang Zhang }
92ffdf7f9eSPaolo Bonzini EXPORT_SYMBOL_GPL(kvm_cpu_has_injectable_intr);
93c7c9c56cSYang Zhang 
94c7c9c56cSYang Zhang /*
95edf88417SAvi Kivity  * check if there is pending interrupt without
96edf88417SAvi Kivity  * intack.
97edf88417SAvi Kivity  */
kvm_cpu_has_interrupt(struct kvm_vcpu * v)98edf88417SAvi Kivity int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
99edf88417SAvi Kivity {
100c7c9c56cSYang Zhang 	if (kvm_cpu_has_extint(v))
101c7c9c56cSYang Zhang 		return 1;
102f3200d00SGleb Natapov 
103f3200d00SGleb Natapov 	return kvm_apic_has_interrupt(v) != -1;	/* LAPIC */
104edf88417SAvi Kivity }
105edf88417SAvi Kivity EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
106edf88417SAvi Kivity 
107edf88417SAvi Kivity /*
108c7c9c56cSYang Zhang  * Read pending interrupt(from non-APIC source)
109c7c9c56cSYang Zhang  * vector and intack.
110c7c9c56cSYang Zhang  */
kvm_cpu_get_extint(struct kvm_vcpu * v)111c7c9c56cSYang Zhang static int kvm_cpu_get_extint(struct kvm_vcpu *v)
112c7c9c56cSYang Zhang {
11372c3bcdcSPaolo Bonzini 	if (!kvm_cpu_has_extint(v)) {
11472c3bcdcSPaolo Bonzini 		WARN_ON(!lapic_in_kernel(v));
11572c3bcdcSPaolo Bonzini 		return -1;
11672c3bcdcSPaolo Bonzini 	}
11772c3bcdcSPaolo Bonzini 
11872c3bcdcSPaolo Bonzini 	if (!lapic_in_kernel(v))
11972c3bcdcSPaolo Bonzini 		return v->arch.interrupt.nr;
12072c3bcdcSPaolo Bonzini 
12140da8ccdSDavid Woodhouse 	if (kvm_xen_has_interrupt(v))
12240da8ccdSDavid Woodhouse 		return v->kvm->arch.xen.upcall_vector;
12340da8ccdSDavid Woodhouse 
1241c1a9ce9SSteve Rutherford 	if (irqchip_split(v->kvm)) {
1251c1a9ce9SSteve Rutherford 		int vector = v->arch.pending_external_vector;
1261c1a9ce9SSteve Rutherford 
1271c1a9ce9SSteve Rutherford 		v->arch.pending_external_vector = -1;
1281c1a9ce9SSteve Rutherford 		return vector;
1291c1a9ce9SSteve Rutherford 	} else
130c7c9c56cSYang Zhang 		return kvm_pic_read_irq(v->kvm); /* PIC */
131c7c9c56cSYang Zhang }
132c7c9c56cSYang Zhang 
133c7c9c56cSYang Zhang /*
134edf88417SAvi Kivity  * Read pending interrupt vector and intack.
135edf88417SAvi Kivity  */
kvm_cpu_get_interrupt(struct kvm_vcpu * v)136edf88417SAvi Kivity int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
137edf88417SAvi Kivity {
13872c3bcdcSPaolo Bonzini 	int vector = kvm_cpu_get_extint(v);
13956cc2406SWanpeng Li 	if (vector != -1)
140c7c9c56cSYang Zhang 		return vector;			/* PIC */
141f3200d00SGleb Natapov 
142f3200d00SGleb Natapov 	return kvm_get_apic_interrupt(v);	/* APIC */
143edf88417SAvi Kivity }
14477b0f5d6SBandan Das EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
145edf88417SAvi Kivity 
kvm_inject_pending_timer_irqs(struct kvm_vcpu * vcpu)146edf88417SAvi Kivity void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
147edf88417SAvi Kivity {
1481e3161b4SPaolo Bonzini 	if (lapic_in_kernel(vcpu))
149edf88417SAvi Kivity 		kvm_inject_apic_timer_irqs(vcpu);
15053639526SJoao Martins 	if (kvm_xen_timer_enabled(vcpu))
15153639526SJoao Martins 		kvm_xen_inject_timer_irqs(vcpu);
152edf88417SAvi Kivity }
153edf88417SAvi Kivity 
__kvm_migrate_timers(struct kvm_vcpu * vcpu)1542f599714SMarcelo Tosatti void __kvm_migrate_timers(struct kvm_vcpu *vcpu)
1552f599714SMarcelo Tosatti {
1562f599714SMarcelo Tosatti 	__kvm_migrate_apic_timer(vcpu);
1572f599714SMarcelo Tosatti 	__kvm_migrate_pit_timer(vcpu);
158b3646477SJason Baron 	static_call_cond(kvm_x86_migrate_timers)(vcpu);
1592f599714SMarcelo Tosatti }
160654f1f13SPeter Xu 
kvm_arch_irqfd_allowed(struct kvm * kvm,struct kvm_irqfd * args)161654f1f13SPeter Xu bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args)
162654f1f13SPeter Xu {
163654f1f13SPeter Xu 	bool resample = args->flags & KVM_IRQFD_FLAG_RESAMPLE;
164654f1f13SPeter Xu 
165654f1f13SPeter Xu 	return resample ? irqchip_kernel(kvm) : irqchip_in_kernel(kvm);
166654f1f13SPeter Xu }
167d663b8a2SPaolo Bonzini 
kvm_arch_irqchip_in_kernel(struct kvm * kvm)168d663b8a2SPaolo Bonzini bool kvm_arch_irqchip_in_kernel(struct kvm *kvm)
169d663b8a2SPaolo Bonzini {
170d663b8a2SPaolo Bonzini 	return irqchip_in_kernel(kvm);
171d663b8a2SPaolo Bonzini }
172