xref: /cloud-hypervisor/vmm/src/interrupt.rs (revision f6cd3bd86ded632da437b6dd6077f4237d2f71fe)
1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
4 //
5 
6 use devices::interrupt_controller::InterruptController;
7 use hypervisor::IrqRoutingEntry;
8 use std::collections::HashMap;
9 use std::io;
10 use std::sync::atomic::{AtomicBool, Ordering};
11 use std::sync::{Arc, Mutex};
12 use vm_allocator::SystemAllocator;
13 use vm_device::interrupt::{
14     InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
15     LegacyIrqGroupConfig, MsiIrqGroupConfig,
16 };
17 use vmm_sys_util::eventfd::EventFd;
18 
19 /// Reuse std::io::Result to simplify interoperability among crates.
20 pub type Result<T> = std::io::Result<T>;
21 
22 struct InterruptRoute {
23     gsi: u32,
24     irq_fd: EventFd,
25     registered: AtomicBool,
26 }
27 
28 impl InterruptRoute {
29     pub fn new(allocator: &mut SystemAllocator) -> Result<Self> {
30         let irq_fd = EventFd::new(libc::EFD_NONBLOCK)?;
31         let gsi = allocator
32             .allocate_gsi()
33             .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed allocating new GSI"))?;
34 
35         Ok(InterruptRoute {
36             gsi,
37             irq_fd,
38             registered: AtomicBool::new(false),
39         })
40     }
41 
42     pub fn enable(&self, vm: &Arc<dyn hypervisor::Vm>) -> Result<()> {
43         if !self.registered.load(Ordering::Acquire) {
44             vm.register_irqfd(&self.irq_fd, self.gsi).map_err(|e| {
45                 io::Error::new(
46                     io::ErrorKind::Other,
47                     format!("Failed registering irq_fd: {e}"),
48                 )
49             })?;
50 
51             // Update internals to track the irq_fd as "registered".
52             self.registered.store(true, Ordering::Release);
53         }
54 
55         Ok(())
56     }
57 
58     pub fn disable(&self, vm: &Arc<dyn hypervisor::Vm>) -> Result<()> {
59         if self.registered.load(Ordering::Acquire) {
60             vm.unregister_irqfd(&self.irq_fd, self.gsi).map_err(|e| {
61                 io::Error::new(
62                     io::ErrorKind::Other,
63                     format!("Failed unregistering irq_fd: {e}"),
64                 )
65             })?;
66 
67             // Update internals to track the irq_fd as "unregistered".
68             self.registered.store(false, Ordering::Release);
69         }
70 
71         Ok(())
72     }
73 
74     pub fn trigger(&self) -> Result<()> {
75         self.irq_fd.write(1)
76     }
77 
78     pub fn notifier(&self) -> Option<EventFd> {
79         Some(
80             self.irq_fd
81                 .try_clone()
82                 .expect("Failed cloning interrupt's EventFd"),
83         )
84     }
85 }
86 
87 pub struct RoutingEntry {
88     route: IrqRoutingEntry,
89     masked: bool,
90 }
91 
92 pub struct MsiInterruptGroup {
93     vm: Arc<dyn hypervisor::Vm>,
94     gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry>>>,
95     irq_routes: HashMap<InterruptIndex, InterruptRoute>,
96 }
97 
98 impl MsiInterruptGroup {
99     fn set_gsi_routes(&self, routes: &HashMap<u32, RoutingEntry>) -> Result<()> {
100         let mut entry_vec: Vec<IrqRoutingEntry> = Vec::new();
101         for (_, entry) in routes.iter() {
102             if entry.masked {
103                 continue;
104             }
105 
106             entry_vec.push(entry.route);
107         }
108 
109         self.vm.set_gsi_routing(&entry_vec).map_err(|e| {
110             io::Error::new(
111                 io::ErrorKind::Other,
112                 format!("Failed setting GSI routing: {e}"),
113             )
114         })
115     }
116 }
117 
118 impl MsiInterruptGroup {
119     fn new(
120         vm: Arc<dyn hypervisor::Vm>,
121         gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry>>>,
122         irq_routes: HashMap<InterruptIndex, InterruptRoute>,
123     ) -> Self {
124         MsiInterruptGroup {
125             vm,
126             gsi_msi_routes,
127             irq_routes,
128         }
129     }
130 }
131 
132 impl InterruptSourceGroup for MsiInterruptGroup {
133     fn enable(&self) -> Result<()> {
134         for (_, route) in self.irq_routes.iter() {
135             route.enable(&self.vm)?;
136         }
137 
138         Ok(())
139     }
140 
141     fn disable(&self) -> Result<()> {
142         for (_, route) in self.irq_routes.iter() {
143             route.disable(&self.vm)?;
144         }
145 
146         Ok(())
147     }
148 
149     fn trigger(&self, index: InterruptIndex) -> Result<()> {
150         if let Some(route) = self.irq_routes.get(&index) {
151             return route.trigger();
152         }
153 
154         Err(io::Error::new(
155             io::ErrorKind::Other,
156             format!("trigger: Invalid interrupt index {index}"),
157         ))
158     }
159 
160     fn notifier(&self, index: InterruptIndex) -> Option<EventFd> {
161         if let Some(route) = self.irq_routes.get(&index) {
162             return route.notifier();
163         }
164 
165         None
166     }
167 
168     fn update(
169         &self,
170         index: InterruptIndex,
171         config: InterruptSourceConfig,
172         masked: bool,
173         set_gsi: bool,
174     ) -> Result<()> {
175         if let Some(route) = self.irq_routes.get(&index) {
176             let entry = RoutingEntry {
177                 route: self.vm.make_routing_entry(route.gsi, &config),
178                 masked,
179             };
180 
181             // When mask a msi irq, entry.masked is set to be true,
182             // and the gsi will not be passed to KVM through KVM_SET_GSI_ROUTING.
183             // So it's required to call disable() (which deassign KVM_IRQFD) before
184             // set_gsi_routes() to avoid kernel panic (see #3827)
185             if masked {
186                 route.disable(&self.vm)?;
187             }
188 
189             let mut routes = self.gsi_msi_routes.lock().unwrap();
190             routes.insert(route.gsi, entry);
191             if set_gsi {
192                 self.set_gsi_routes(&routes)?;
193             }
194 
195             // Assign KVM_IRQFD after KVM_SET_GSI_ROUTING to avoid
196             // panic on kernel which not have commit a80ced6ea514
197             // (KVM: SVM: fix panic on out-of-bounds guest IRQ).
198             if !masked {
199                 route.enable(&self.vm)?;
200             }
201 
202             return Ok(());
203         }
204 
205         Err(io::Error::new(
206             io::ErrorKind::Other,
207             format!("update: Invalid interrupt index {index}"),
208         ))
209     }
210 
211     fn set_gsi(&self) -> Result<()> {
212         let routes = self.gsi_msi_routes.lock().unwrap();
213         self.set_gsi_routes(&routes)
214     }
215 }
216 
217 pub struct LegacyUserspaceInterruptGroup {
218     ioapic: Arc<Mutex<dyn InterruptController>>,
219     irq: u32,
220 }
221 
222 impl LegacyUserspaceInterruptGroup {
223     fn new(ioapic: Arc<Mutex<dyn InterruptController>>, irq: u32) -> Self {
224         LegacyUserspaceInterruptGroup { ioapic, irq }
225     }
226 }
227 
228 impl InterruptSourceGroup for LegacyUserspaceInterruptGroup {
229     fn trigger(&self, _index: InterruptIndex) -> Result<()> {
230         self.ioapic
231             .lock()
232             .unwrap()
233             .service_irq(self.irq as usize)
234             .map_err(|e| {
235                 io::Error::new(
236                     io::ErrorKind::Other,
237                     format!("failed to inject IRQ #{}: {:?}", self.irq, e),
238                 )
239             })
240     }
241 
242     fn update(
243         &self,
244         _index: InterruptIndex,
245         _config: InterruptSourceConfig,
246         _masked: bool,
247         _set_gsi: bool,
248     ) -> Result<()> {
249         Ok(())
250     }
251 
252     fn set_gsi(&self) -> Result<()> {
253         Ok(())
254     }
255 
256     fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
257         self.ioapic.lock().unwrap().notifier(self.irq as usize)
258     }
259 }
260 
261 pub struct LegacyUserspaceInterruptManager {
262     ioapic: Arc<Mutex<dyn InterruptController>>,
263 }
264 
265 pub struct MsiInterruptManager {
266     allocator: Arc<Mutex<SystemAllocator>>,
267     vm: Arc<dyn hypervisor::Vm>,
268     gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry>>>,
269 }
270 
271 impl LegacyUserspaceInterruptManager {
272     pub fn new(ioapic: Arc<Mutex<dyn InterruptController>>) -> Self {
273         LegacyUserspaceInterruptManager { ioapic }
274     }
275 }
276 
277 impl MsiInterruptManager {
278     pub fn new(allocator: Arc<Mutex<SystemAllocator>>, vm: Arc<dyn hypervisor::Vm>) -> Self {
279         // Create a shared list of GSI that can be shared through all PCI
280         // devices. This way, we can maintain the full list of used GSI,
281         // preventing one device from overriding interrupts setting from
282         // another one.
283         let gsi_msi_routes = Arc::new(Mutex::new(HashMap::new()));
284 
285         MsiInterruptManager {
286             allocator,
287             vm,
288             gsi_msi_routes,
289         }
290     }
291 }
292 
293 impl InterruptManager for LegacyUserspaceInterruptManager {
294     type GroupConfig = LegacyIrqGroupConfig;
295 
296     fn create_group(&self, config: Self::GroupConfig) -> Result<Arc<dyn InterruptSourceGroup>> {
297         Ok(Arc::new(LegacyUserspaceInterruptGroup::new(
298             self.ioapic.clone(),
299             config.irq,
300         )))
301     }
302 
303     fn destroy_group(&self, _group: Arc<dyn InterruptSourceGroup>) -> Result<()> {
304         Ok(())
305     }
306 }
307 
308 impl InterruptManager for MsiInterruptManager {
309     type GroupConfig = MsiIrqGroupConfig;
310 
311     fn create_group(&self, config: Self::GroupConfig) -> Result<Arc<dyn InterruptSourceGroup>> {
312         let mut allocator = self.allocator.lock().unwrap();
313         let mut irq_routes: HashMap<InterruptIndex, InterruptRoute> =
314             HashMap::with_capacity(config.count as usize);
315         for i in config.base..config.base + config.count {
316             irq_routes.insert(i, InterruptRoute::new(&mut allocator)?);
317         }
318 
319         Ok(Arc::new(MsiInterruptGroup::new(
320             self.vm.clone(),
321             self.gsi_msi_routes.clone(),
322             irq_routes,
323         )))
324     }
325 
326     fn destroy_group(&self, _group: Arc<dyn InterruptSourceGroup>) -> Result<()> {
327         Ok(())
328     }
329 }
330