xref: /openbmc/linux/arch/x86/kvm/irq.c (revision 536395260582be7443b0b35b0bbb89ffe3947f62)
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  */
10edf88417SAvi Kivity 
111767e931SPaul Gortmaker #include <linux/export.h>
12edf88417SAvi Kivity #include <linux/kvm_host.h>
13edf88417SAvi Kivity 
14edf88417SAvi Kivity #include "irq.h"
157837699fSSheng Yang #include "i8254.h"
168061823aSGleb Natapov #include "x86.h"
1740da8ccdSDavid Woodhouse #include "xen.h"
18edf88417SAvi Kivity 
19edf88417SAvi Kivity /*
203d80840dSMarcelo Tosatti  * check if there are pending timer events
213d80840dSMarcelo Tosatti  * to be processed.
223d80840dSMarcelo Tosatti  */
233d80840dSMarcelo Tosatti int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
243d80840dSMarcelo Tosatti {
25*53639526SJoao Martins 	int r = 0;
261e3161b4SPaolo Bonzini 
27*53639526SJoao Martins 	if (lapic_in_kernel(vcpu))
28*53639526SJoao Martins 		r = apic_has_pending_timer(vcpu);
29*53639526SJoao Martins 	if (kvm_xen_timer_enabled(vcpu))
30*53639526SJoao Martins 		r += kvm_xen_has_pending_timer(vcpu);
31*53639526SJoao Martins 
32*53639526SJoao Martins 	return r;
333d80840dSMarcelo Tosatti }
343d80840dSMarcelo Tosatti EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
353d80840dSMarcelo Tosatti 
363d80840dSMarcelo Tosatti /*
371c1a9ce9SSteve Rutherford  * check if there is a pending userspace external interrupt
381c1a9ce9SSteve Rutherford  */
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  */
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  */
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  */
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  */
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  */
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 
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);
150*53639526SJoao Martins 	if (kvm_xen_timer_enabled(vcpu))
151*53639526SJoao Martins 		kvm_xen_inject_timer_irqs(vcpu);
152edf88417SAvi Kivity }
153edf88417SAvi Kivity EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
154edf88417SAvi Kivity 
1552f599714SMarcelo Tosatti void __kvm_migrate_timers(struct kvm_vcpu *vcpu)
1562f599714SMarcelo Tosatti {
1572f599714SMarcelo Tosatti 	__kvm_migrate_apic_timer(vcpu);
1582f599714SMarcelo Tosatti 	__kvm_migrate_pit_timer(vcpu);
159b3646477SJason Baron 	static_call_cond(kvm_x86_migrate_timers)(vcpu);
1602f599714SMarcelo Tosatti }
161654f1f13SPeter Xu 
162654f1f13SPeter Xu bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args)
163654f1f13SPeter Xu {
164654f1f13SPeter Xu 	bool resample = args->flags & KVM_IRQFD_FLAG_RESAMPLE;
165654f1f13SPeter Xu 
166654f1f13SPeter Xu 	return resample ? irqchip_kernel(kvm) : irqchip_in_kernel(kvm);
167654f1f13SPeter Xu }
168