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