xref: /cloud-hypervisor/vmm/src/interrupt.rs (revision 3ce0fef7fd546467398c914dbc74d8542e45cf6f)
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             if masked {
181                 route.disable(&self.vm)?;
182             } else {
183                 route.enable(&self.vm)?;
184             }
185             let mut routes = self.gsi_msi_routes.lock().unwrap();
186             routes.insert(route.gsi, entry);
187             if set_gsi {
188                 return self.set_gsi_routes(&routes);
189             } else {
190                 return Ok(());
191             }
192         }
193 
194         Err(io::Error::new(
195             io::ErrorKind::Other,
196             format!("update: Invalid interrupt index {index}"),
197         ))
198     }
199 
200     fn set_gsi(&self) -> Result<()> {
201         let routes = self.gsi_msi_routes.lock().unwrap();
202         self.set_gsi_routes(&routes)
203     }
204 }
205 
206 pub struct LegacyUserspaceInterruptGroup {
207     ioapic: Arc<Mutex<dyn InterruptController>>,
208     irq: u32,
209 }
210 
211 impl LegacyUserspaceInterruptGroup {
212     fn new(ioapic: Arc<Mutex<dyn InterruptController>>, irq: u32) -> Self {
213         LegacyUserspaceInterruptGroup { ioapic, irq }
214     }
215 }
216 
217 impl InterruptSourceGroup for LegacyUserspaceInterruptGroup {
218     fn trigger(&self, _index: InterruptIndex) -> Result<()> {
219         self.ioapic
220             .lock()
221             .unwrap()
222             .service_irq(self.irq as usize)
223             .map_err(|e| {
224                 io::Error::new(
225                     io::ErrorKind::Other,
226                     format!("failed to inject IRQ #{}: {:?}", self.irq, e),
227                 )
228             })
229     }
230 
231     fn update(
232         &self,
233         _index: InterruptIndex,
234         _config: InterruptSourceConfig,
235         _masked: bool,
236         _set_gsi: bool,
237     ) -> Result<()> {
238         Ok(())
239     }
240 
241     fn set_gsi(&self) -> Result<()> {
242         Ok(())
243     }
244 
245     fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
246         self.ioapic.lock().unwrap().notifier(self.irq as usize)
247     }
248 }
249 
250 pub struct LegacyUserspaceInterruptManager {
251     ioapic: Arc<Mutex<dyn InterruptController>>,
252 }
253 
254 pub struct MsiInterruptManager {
255     allocator: Arc<Mutex<SystemAllocator>>,
256     vm: Arc<dyn hypervisor::Vm>,
257     gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry>>>,
258 }
259 
260 impl LegacyUserspaceInterruptManager {
261     pub fn new(ioapic: Arc<Mutex<dyn InterruptController>>) -> Self {
262         LegacyUserspaceInterruptManager { ioapic }
263     }
264 }
265 
266 impl MsiInterruptManager {
267     pub fn new(allocator: Arc<Mutex<SystemAllocator>>, vm: Arc<dyn hypervisor::Vm>) -> Self {
268         // Create a shared list of GSI that can be shared through all PCI
269         // devices. This way, we can maintain the full list of used GSI,
270         // preventing one device from overriding interrupts setting from
271         // another one.
272         let gsi_msi_routes = Arc::new(Mutex::new(HashMap::new()));
273 
274         MsiInterruptManager {
275             allocator,
276             vm,
277             gsi_msi_routes,
278         }
279     }
280 }
281 
282 impl InterruptManager for LegacyUserspaceInterruptManager {
283     type GroupConfig = LegacyIrqGroupConfig;
284 
285     fn create_group(&self, config: Self::GroupConfig) -> Result<Arc<dyn InterruptSourceGroup>> {
286         Ok(Arc::new(LegacyUserspaceInterruptGroup::new(
287             self.ioapic.clone(),
288             config.irq,
289         )))
290     }
291 
292     fn destroy_group(&self, _group: Arc<dyn InterruptSourceGroup>) -> Result<()> {
293         Ok(())
294     }
295 }
296 
297 impl InterruptManager for MsiInterruptManager {
298     type GroupConfig = MsiIrqGroupConfig;
299 
300     fn create_group(&self, config: Self::GroupConfig) -> Result<Arc<dyn InterruptSourceGroup>> {
301         let mut allocator = self.allocator.lock().unwrap();
302         let mut irq_routes: HashMap<InterruptIndex, InterruptRoute> =
303             HashMap::with_capacity(config.count as usize);
304         for i in config.base..config.base + config.count {
305             irq_routes.insert(i, InterruptRoute::new(&mut allocator)?);
306         }
307 
308         Ok(Arc::new(MsiInterruptGroup::new(
309             self.vm.clone(),
310             self.gsi_msi_routes.clone(),
311             irq_routes,
312         )))
313     }
314 
315     fn destroy_group(&self, _group: Arc<dyn InterruptSourceGroup>) -> Result<()> {
316         Ok(())
317     }
318 }
319