1 | // SPDX-License-Identifier: GPL-2.0-only |
---|---|
2 | /* |
3 | * irq.c: API for in kernel interrupt controller |
4 | * Copyright (c) 2007, Intel Corporation. |
5 | * Copyright 2009 Red Hat, Inc. and/or its affiliates. |
6 | * |
7 | * Authors: |
8 | * Yaozu (Eddie) Dong <Eddie.dong@intel.com> |
9 | */ |
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
11 | |
12 | #include <linux/export.h> |
13 | #include <linux/kvm_host.h> |
14 | |
15 | #include "irq.h" |
16 | #include "i8254.h" |
17 | #include "x86.h" |
18 | #include "xen.h" |
19 | |
20 | /* |
21 | * check if there are pending timer events |
22 | * to be processed. |
23 | */ |
24 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) |
25 | { |
26 | int r = 0; |
27 | |
28 | if (lapic_in_kernel(vcpu)) |
29 | r = apic_has_pending_timer(vcpu); |
30 | if (kvm_xen_timer_enabled(vcpu)) |
31 | r += kvm_xen_has_pending_timer(vcpu); |
32 | |
33 | return r; |
34 | } |
35 | |
36 | /* |
37 | * check if there is a pending userspace external interrupt |
38 | */ |
39 | static int pending_userspace_extint(struct kvm_vcpu *v) |
40 | { |
41 | return v->arch.pending_external_vector != -1; |
42 | } |
43 | |
44 | /* |
45 | * check if there is pending interrupt from |
46 | * non-APIC source without intack. |
47 | */ |
48 | int kvm_cpu_has_extint(struct kvm_vcpu *v) |
49 | { |
50 | /* |
51 | * FIXME: interrupt.injected represents an interrupt whose |
52 | * side-effects have already been applied (e.g. bit from IRR |
53 | * already moved to ISR). Therefore, it is incorrect to rely |
54 | * on interrupt.injected to know if there is a pending |
55 | * interrupt in the user-mode LAPIC. |
56 | * This leads to nVMX/nSVM not be able to distinguish |
57 | * if it should exit from L2 to L1 on EXTERNAL_INTERRUPT on |
58 | * pending interrupt or should re-inject an injected |
59 | * interrupt. |
60 | */ |
61 | if (!lapic_in_kernel(vcpu: v)) |
62 | return v->arch.interrupt.injected; |
63 | |
64 | if (kvm_xen_has_interrupt(vcpu: v)) |
65 | return 1; |
66 | |
67 | if (!kvm_apic_accept_pic_intr(vcpu: v)) |
68 | return 0; |
69 | |
70 | if (irqchip_split(kvm: v->kvm)) |
71 | return pending_userspace_extint(v); |
72 | else |
73 | return v->kvm->arch.vpic->output; |
74 | } |
75 | |
76 | /* |
77 | * check if there is injectable interrupt: |
78 | * when virtual interrupt delivery enabled, |
79 | * interrupt from apic will handled by hardware, |
80 | * we don't need to check it here. |
81 | */ |
82 | int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v) |
83 | { |
84 | if (kvm_cpu_has_extint(v)) |
85 | return 1; |
86 | |
87 | if (!is_guest_mode(vcpu: v) && kvm_vcpu_apicv_active(vcpu: v)) |
88 | return 0; |
89 | |
90 | return kvm_apic_has_interrupt(vcpu: v) != -1; /* LAPIC */ |
91 | } |
92 | EXPORT_SYMBOL_GPL(kvm_cpu_has_injectable_intr); |
93 | |
94 | /* |
95 | * check if there is pending interrupt without |
96 | * intack. |
97 | */ |
98 | int kvm_cpu_has_interrupt(struct kvm_vcpu *v) |
99 | { |
100 | if (kvm_cpu_has_extint(v)) |
101 | return 1; |
102 | |
103 | return kvm_apic_has_interrupt(vcpu: v) != -1; /* LAPIC */ |
104 | } |
105 | EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); |
106 | |
107 | /* |
108 | * Read pending interrupt(from non-APIC source) |
109 | * vector and intack. |
110 | */ |
111 | static int kvm_cpu_get_extint(struct kvm_vcpu *v) |
112 | { |
113 | if (!kvm_cpu_has_extint(v)) { |
114 | WARN_ON(!lapic_in_kernel(v)); |
115 | return -1; |
116 | } |
117 | |
118 | if (!lapic_in_kernel(vcpu: v)) |
119 | return v->arch.interrupt.nr; |
120 | |
121 | #ifdef CONFIG_KVM_XEN |
122 | if (kvm_xen_has_interrupt(vcpu: v)) |
123 | return v->kvm->arch.xen.upcall_vector; |
124 | #endif |
125 | |
126 | if (irqchip_split(kvm: v->kvm)) { |
127 | int vector = v->arch.pending_external_vector; |
128 | |
129 | v->arch.pending_external_vector = -1; |
130 | return vector; |
131 | } else |
132 | return kvm_pic_read_irq(kvm: v->kvm); /* PIC */ |
133 | } |
134 | |
135 | /* |
136 | * Read pending interrupt vector and intack. |
137 | */ |
138 | int kvm_cpu_get_interrupt(struct kvm_vcpu *v) |
139 | { |
140 | int vector = kvm_cpu_get_extint(v); |
141 | if (vector != -1) |
142 | return vector; /* PIC */ |
143 | |
144 | return kvm_get_apic_interrupt(vcpu: v); /* APIC */ |
145 | } |
146 | EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); |
147 | |
148 | void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) |
149 | { |
150 | if (lapic_in_kernel(vcpu)) |
151 | kvm_inject_apic_timer_irqs(vcpu); |
152 | if (kvm_xen_timer_enabled(vcpu)) |
153 | kvm_xen_inject_timer_irqs(vcpu); |
154 | } |
155 | |
156 | void __kvm_migrate_timers(struct kvm_vcpu *vcpu) |
157 | { |
158 | __kvm_migrate_apic_timer(vcpu); |
159 | __kvm_migrate_pit_timer(vcpu); |
160 | static_call_cond(kvm_x86_migrate_timers)(vcpu); |
161 | } |
162 | |
163 | bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args) |
164 | { |
165 | bool resample = args->flags & KVM_IRQFD_FLAG_RESAMPLE; |
166 | |
167 | return resample ? irqchip_kernel(kvm) : irqchip_in_kernel(kvm); |
168 | } |
169 | |
170 | bool kvm_arch_irqchip_in_kernel(struct kvm *kvm) |
171 | { |
172 | return irqchip_in_kernel(kvm); |
173 | } |
174 |