xref: /openbmc/linux/arch/x86/kvm/irq.c (revision b3646477d458fbe7694a15b9c78fbe2fa426b703)
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"
17edf88417SAvi Kivity 
18edf88417SAvi Kivity /*
193d80840dSMarcelo Tosatti  * check if there are pending timer events
203d80840dSMarcelo Tosatti  * to be processed.
213d80840dSMarcelo Tosatti  */
223d80840dSMarcelo Tosatti int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
233d80840dSMarcelo Tosatti {
241e3161b4SPaolo Bonzini 	if (lapic_in_kernel(vcpu))
2523e7a794SJason Wang 		return apic_has_pending_timer(vcpu);
261e3161b4SPaolo Bonzini 
271e3161b4SPaolo Bonzini 	return 0;
283d80840dSMarcelo Tosatti }
293d80840dSMarcelo Tosatti EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
303d80840dSMarcelo Tosatti 
313d80840dSMarcelo Tosatti /*
321c1a9ce9SSteve Rutherford  * check if there is a pending userspace external interrupt
331c1a9ce9SSteve Rutherford  */
341c1a9ce9SSteve Rutherford static int pending_userspace_extint(struct kvm_vcpu *v)
351c1a9ce9SSteve Rutherford {
361c1a9ce9SSteve Rutherford 	return v->arch.pending_external_vector != -1;
371c1a9ce9SSteve Rutherford }
381c1a9ce9SSteve Rutherford 
391c1a9ce9SSteve Rutherford /*
40c7c9c56cSYang Zhang  * check if there is pending interrupt from
41c7c9c56cSYang Zhang  * non-APIC source without intack.
42c7c9c56cSYang Zhang  */
4371cc849bSPaolo Bonzini int kvm_cpu_has_extint(struct kvm_vcpu *v)
44c7c9c56cSYang Zhang {
45c7c9c56cSYang Zhang 	/*
4672c3bcdcSPaolo Bonzini 	 * FIXME: interrupt.injected represents an interrupt whose
4704140b41SLiran Alon 	 * side-effects have already been applied (e.g. bit from IRR
4804140b41SLiran Alon 	 * already moved to ISR). Therefore, it is incorrect to rely
4904140b41SLiran Alon 	 * on interrupt.injected to know if there is a pending
5004140b41SLiran Alon 	 * interrupt in the user-mode LAPIC.
5104140b41SLiran Alon 	 * This leads to nVMX/nSVM not be able to distinguish
5204140b41SLiran Alon 	 * if it should exit from L2 to L1 on EXTERNAL_INTERRUPT on
5304140b41SLiran Alon 	 * pending interrupt or should re-inject an injected
5404140b41SLiran Alon 	 * interrupt.
5504140b41SLiran Alon 	 */
5635754c98SPaolo Bonzini 	if (!lapic_in_kernel(v))
5704140b41SLiran Alon 		return v->arch.interrupt.injected;
58c7c9c56cSYang Zhang 
5972c3bcdcSPaolo Bonzini 	if (!kvm_apic_accept_pic_intr(v))
6072c3bcdcSPaolo Bonzini 		return 0;
6172c3bcdcSPaolo Bonzini 
6272c3bcdcSPaolo Bonzini 	if (irqchip_split(v->kvm))
6372c3bcdcSPaolo Bonzini 		return pending_userspace_extint(v);
6472c3bcdcSPaolo Bonzini 	else
6572c3bcdcSPaolo Bonzini 		return v->kvm->arch.vpic->output;
6672c3bcdcSPaolo Bonzini }
6772c3bcdcSPaolo Bonzini 
6872c3bcdcSPaolo Bonzini /*
6972c3bcdcSPaolo Bonzini  * check if there is injectable interrupt:
7072c3bcdcSPaolo Bonzini  * when virtual interrupt delivery enabled,
7172c3bcdcSPaolo Bonzini  * interrupt from apic will handled by hardware,
7272c3bcdcSPaolo Bonzini  * we don't need to check it here.
7372c3bcdcSPaolo Bonzini  */
7472c3bcdcSPaolo Bonzini int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
7572c3bcdcSPaolo Bonzini {
76c7c9c56cSYang Zhang 	if (kvm_cpu_has_extint(v))
77c7c9c56cSYang Zhang 		return 1;
78c7c9c56cSYang Zhang 
79851c1a18SLiran Alon 	if (!is_guest_mode(v) && kvm_vcpu_apicv_active(v))
80c7c9c56cSYang Zhang 		return 0;
81c7c9c56cSYang Zhang 
82c7c9c56cSYang Zhang 	return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
83c7c9c56cSYang Zhang }
84ffdf7f9eSPaolo Bonzini EXPORT_SYMBOL_GPL(kvm_cpu_has_injectable_intr);
85c7c9c56cSYang Zhang 
86c7c9c56cSYang Zhang /*
87edf88417SAvi Kivity  * check if there is pending interrupt without
88edf88417SAvi Kivity  * intack.
89edf88417SAvi Kivity  */
90edf88417SAvi Kivity int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
91edf88417SAvi Kivity {
92c7c9c56cSYang Zhang 	if (kvm_cpu_has_extint(v))
93c7c9c56cSYang Zhang 		return 1;
94f3200d00SGleb Natapov 
95f3200d00SGleb Natapov 	return kvm_apic_has_interrupt(v) != -1;	/* LAPIC */
96edf88417SAvi Kivity }
97edf88417SAvi Kivity EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
98edf88417SAvi Kivity 
99edf88417SAvi Kivity /*
100c7c9c56cSYang Zhang  * Read pending interrupt(from non-APIC source)
101c7c9c56cSYang Zhang  * vector and intack.
102c7c9c56cSYang Zhang  */
103c7c9c56cSYang Zhang static int kvm_cpu_get_extint(struct kvm_vcpu *v)
104c7c9c56cSYang Zhang {
10572c3bcdcSPaolo Bonzini 	if (!kvm_cpu_has_extint(v)) {
10672c3bcdcSPaolo Bonzini 		WARN_ON(!lapic_in_kernel(v));
10772c3bcdcSPaolo Bonzini 		return -1;
10872c3bcdcSPaolo Bonzini 	}
10972c3bcdcSPaolo Bonzini 
11072c3bcdcSPaolo Bonzini 	if (!lapic_in_kernel(v))
11172c3bcdcSPaolo Bonzini 		return v->arch.interrupt.nr;
11272c3bcdcSPaolo Bonzini 
1131c1a9ce9SSteve Rutherford 	if (irqchip_split(v->kvm)) {
1141c1a9ce9SSteve Rutherford 		int vector = v->arch.pending_external_vector;
1151c1a9ce9SSteve Rutherford 
1161c1a9ce9SSteve Rutherford 		v->arch.pending_external_vector = -1;
1171c1a9ce9SSteve Rutherford 		return vector;
1181c1a9ce9SSteve Rutherford 	} else
119c7c9c56cSYang Zhang 		return kvm_pic_read_irq(v->kvm); /* PIC */
120c7c9c56cSYang Zhang }
121c7c9c56cSYang Zhang 
122c7c9c56cSYang Zhang /*
123edf88417SAvi Kivity  * Read pending interrupt vector and intack.
124edf88417SAvi Kivity  */
125edf88417SAvi Kivity int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
126edf88417SAvi Kivity {
12772c3bcdcSPaolo Bonzini 	int vector = kvm_cpu_get_extint(v);
12856cc2406SWanpeng Li 	if (vector != -1)
129c7c9c56cSYang Zhang 		return vector;			/* PIC */
130f3200d00SGleb Natapov 
131f3200d00SGleb Natapov 	return kvm_get_apic_interrupt(v);	/* APIC */
132edf88417SAvi Kivity }
13377b0f5d6SBandan Das EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
134edf88417SAvi Kivity 
135edf88417SAvi Kivity void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
136edf88417SAvi Kivity {
1371e3161b4SPaolo Bonzini 	if (lapic_in_kernel(vcpu))
138edf88417SAvi Kivity 		kvm_inject_apic_timer_irqs(vcpu);
139edf88417SAvi Kivity }
140edf88417SAvi Kivity EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
141edf88417SAvi Kivity 
1422f599714SMarcelo Tosatti void __kvm_migrate_timers(struct kvm_vcpu *vcpu)
1432f599714SMarcelo Tosatti {
1442f599714SMarcelo Tosatti 	__kvm_migrate_apic_timer(vcpu);
1452f599714SMarcelo Tosatti 	__kvm_migrate_pit_timer(vcpu);
146*b3646477SJason Baron 	static_call_cond(kvm_x86_migrate_timers)(vcpu);
1472f599714SMarcelo Tosatti }
148654f1f13SPeter Xu 
149654f1f13SPeter Xu bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args)
150654f1f13SPeter Xu {
151654f1f13SPeter Xu 	bool resample = args->flags & KVM_IRQFD_FLAG_RESAMPLE;
152654f1f13SPeter Xu 
153654f1f13SPeter Xu 	return resample ? irqchip_kernel(kvm) : irqchip_in_kernel(kvm);
154654f1f13SPeter Xu }
155