xref: /cloud-hypervisor/vmm/src/interrupt.rs (revision 9af2968a7dc47b89bf07ea9dc5e735084efcfa3a)
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<IrqRoutingEntry> {
88     route: IrqRoutingEntry,
89     masked: bool,
90 }
91 
92 pub struct MsiInterruptGroup<IrqRoutingEntry> {
93     vm: Arc<dyn hypervisor::Vm>,
94     gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry<IrqRoutingEntry>>>>,
95     irq_routes: HashMap<InterruptIndex, InterruptRoute>,
96 }
97 
98 impl MsiInterruptGroup<IrqRoutingEntry> {
99     fn set_gsi_routes(&self, routes: &HashMap<u32, RoutingEntry<IrqRoutingEntry>>) -> 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<IrqRoutingEntry> {
119     fn new(
120         vm: Arc<dyn hypervisor::Vm>,
121         gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry<IrqRoutingEntry>>>>,
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<IrqRoutingEntry> {
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(&self, index: InterruptIndex, config: InterruptSourceConfig) -> Result<()> {
169         if let Some(route) = self.irq_routes.get(&index) {
170             let entry = RoutingEntry::<_>::make_entry(&self.vm, route.gsi, &config)?;
171             let mut routes = self.gsi_msi_routes.lock().unwrap();
172             routes.insert(route.gsi, *entry);
173             return self.set_gsi_routes(&routes);
174         }
175 
176         Err(io::Error::new(
177             io::ErrorKind::Other,
178             format!("update: Invalid interrupt index {}", index),
179         ))
180     }
181 
182     fn mask(&self, index: InterruptIndex) -> Result<()> {
183         if let Some(route) = self.irq_routes.get(&index) {
184             let mut routes = self.gsi_msi_routes.lock().unwrap();
185             if let Some(entry) = routes.get_mut(&route.gsi) {
186                 entry.masked = true;
187             } else {
188                 return Err(io::Error::new(
189                     io::ErrorKind::Other,
190                     format!("mask: No existing route for interrupt index {}", index),
191                 ));
192             }
193             self.set_gsi_routes(&routes)?;
194             return route.disable(&self.vm);
195         }
196 
197         Err(io::Error::new(
198             io::ErrorKind::Other,
199             format!("mask: Invalid interrupt index {}", index),
200         ))
201     }
202 
203     fn unmask(&self, index: InterruptIndex) -> Result<()> {
204         if let Some(route) = self.irq_routes.get(&index) {
205             let mut routes = self.gsi_msi_routes.lock().unwrap();
206             if let Some(entry) = routes.get_mut(&route.gsi) {
207                 entry.masked = false;
208             } else {
209                 return Err(io::Error::new(
210                     io::ErrorKind::Other,
211                     format!("mask: No existing route for interrupt index {}", index),
212                 ));
213             }
214             self.set_gsi_routes(&routes)?;
215             return route.enable(&self.vm);
216         }
217 
218         Err(io::Error::new(
219             io::ErrorKind::Other,
220             format!("unmask: Invalid interrupt index {}", index),
221         ))
222     }
223 }
224 
225 pub struct LegacyUserspaceInterruptGroup {
226     ioapic: Arc<Mutex<dyn InterruptController>>,
227     irq: u32,
228 }
229 
230 impl LegacyUserspaceInterruptGroup {
231     fn new(ioapic: Arc<Mutex<dyn InterruptController>>, irq: u32) -> Self {
232         LegacyUserspaceInterruptGroup { ioapic, irq }
233     }
234 }
235 
236 impl InterruptSourceGroup for LegacyUserspaceInterruptGroup {
237     fn trigger(&self, _index: InterruptIndex) -> Result<()> {
238         self.ioapic
239             .lock()
240             .unwrap()
241             .service_irq(self.irq as usize)
242             .map_err(|e| {
243                 io::Error::new(
244                     io::ErrorKind::Other,
245                     format!("failed to inject IRQ #{}: {:?}", self.irq, e),
246                 )
247             })
248     }
249 
250     fn update(&self, _index: InterruptIndex, _config: InterruptSourceConfig) -> Result<()> {
251         Ok(())
252     }
253 
254     fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
255         self.ioapic.lock().unwrap().notifier(self.irq as usize)
256     }
257 }
258 
259 pub struct LegacyUserspaceInterruptManager {
260     ioapic: Arc<Mutex<dyn InterruptController>>,
261 }
262 
263 pub struct MsiInterruptManager<IrqRoutingEntry> {
264     allocator: Arc<Mutex<SystemAllocator>>,
265     vm: Arc<dyn hypervisor::Vm>,
266     gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry<IrqRoutingEntry>>>>,
267 }
268 
269 impl LegacyUserspaceInterruptManager {
270     pub fn new(ioapic: Arc<Mutex<dyn InterruptController>>) -> Self {
271         LegacyUserspaceInterruptManager { ioapic }
272     }
273 }
274 
275 impl MsiInterruptManager<IrqRoutingEntry> {
276     pub fn new(allocator: Arc<Mutex<SystemAllocator>>, vm: Arc<dyn hypervisor::Vm>) -> Self {
277         // Create a shared list of GSI that can be shared through all PCI
278         // devices. This way, we can maintain the full list of used GSI,
279         // preventing one device from overriding interrupts setting from
280         // another one.
281         let gsi_msi_routes = Arc::new(Mutex::new(HashMap::new()));
282 
283         MsiInterruptManager {
284             allocator,
285             vm,
286             gsi_msi_routes,
287         }
288     }
289 }
290 
291 impl InterruptManager for LegacyUserspaceInterruptManager {
292     type GroupConfig = LegacyIrqGroupConfig;
293 
294     fn create_group(
295         &self,
296         config: Self::GroupConfig,
297     ) -> Result<Arc<Box<dyn InterruptSourceGroup>>> {
298         Ok(Arc::new(Box::new(LegacyUserspaceInterruptGroup::new(
299             self.ioapic.clone(),
300             config.irq as u32,
301         ))))
302     }
303 
304     fn destroy_group(&self, _group: Arc<Box<dyn InterruptSourceGroup>>) -> Result<()> {
305         Ok(())
306     }
307 }
308 
309 impl InterruptManager for MsiInterruptManager<IrqRoutingEntry> {
310     type GroupConfig = MsiIrqGroupConfig;
311 
312     fn create_group(
313         &self,
314         config: Self::GroupConfig,
315     ) -> Result<Arc<Box<dyn InterruptSourceGroup>>> {
316         let mut allocator = self.allocator.lock().unwrap();
317         let mut irq_routes: HashMap<InterruptIndex, InterruptRoute> =
318             HashMap::with_capacity(config.count as usize);
319         for i in config.base..config.base + config.count {
320             irq_routes.insert(i, InterruptRoute::new(&mut allocator)?);
321         }
322 
323         Ok(Arc::new(Box::new(MsiInterruptGroup::new(
324             self.vm.clone(),
325             self.gsi_msi_routes.clone(),
326             irq_routes,
327         ))))
328     }
329 
330     fn destroy_group(&self, _group: Arc<Box<dyn InterruptSourceGroup>>) -> Result<()> {
331         Ok(())
332     }
333 }
334 
335 #[cfg(feature = "kvm")]
336 pub mod kvm {
337     use super::*;
338     use hypervisor::kvm::KVM_MSI_VALID_DEVID;
339     use hypervisor::kvm::{kvm_irq_routing_entry, KVM_IRQ_ROUTING_IRQCHIP, KVM_IRQ_ROUTING_MSI};
340 
341     type KvmRoutingEntry = RoutingEntry<kvm_irq_routing_entry>;
342     pub type KvmMsiInterruptManager = MsiInterruptManager<kvm_irq_routing_entry>;
343 
344     impl KvmRoutingEntry {
345         pub fn make_entry(
346             vm: &Arc<dyn hypervisor::Vm>,
347             gsi: u32,
348             config: &InterruptSourceConfig,
349         ) -> Result<Box<Self>> {
350             if let InterruptSourceConfig::MsiIrq(cfg) = &config {
351                 let mut kvm_route = kvm_irq_routing_entry {
352                     gsi,
353                     type_: KVM_IRQ_ROUTING_MSI,
354                     ..Default::default()
355                 };
356 
357                 kvm_route.u.msi.address_lo = cfg.low_addr;
358                 kvm_route.u.msi.address_hi = cfg.high_addr;
359                 kvm_route.u.msi.data = cfg.data;
360 
361                 if vm.check_extension(hypervisor::Cap::MsiDevid) {
362                     kvm_route.flags = KVM_MSI_VALID_DEVID;
363                     kvm_route.u.msi.__bindgen_anon_1.devid = cfg.devid;
364                 }
365 
366                 let kvm_entry = KvmRoutingEntry {
367                     route: kvm_route,
368                     masked: false,
369                 };
370 
371                 return Ok(Box::new(kvm_entry));
372             } else if let InterruptSourceConfig::LegacyIrq(cfg) = &config {
373                 let mut kvm_route = kvm_irq_routing_entry {
374                     gsi,
375                     type_: KVM_IRQ_ROUTING_IRQCHIP,
376                     ..Default::default()
377                 };
378                 kvm_route.u.irqchip.irqchip = cfg.irqchip;
379                 kvm_route.u.irqchip.pin = cfg.pin;
380                 let kvm_entry = KvmRoutingEntry {
381                     route: kvm_route,
382                     masked: false,
383                 };
384 
385                 return Ok(Box::new(kvm_entry));
386             }
387 
388             Err(io::Error::new(
389                 io::ErrorKind::Other,
390                 "Interrupt config type not supported",
391             ))
392         }
393     }
394 }
395 
396 #[cfg(feature = "mshv")]
397 pub mod mshv {
398     use super::*;
399     use hypervisor::mshv::*;
400 
401     type MshvRoutingEntry = RoutingEntry<mshv_msi_routing_entry>;
402     pub type MshvMsiInterruptManager = MsiInterruptManager<mshv_msi_routing_entry>;
403 
404     impl MshvRoutingEntry {
405         pub fn make_entry(
406             _vm: &Arc<dyn hypervisor::Vm>,
407             gsi: u32,
408             config: &InterruptSourceConfig,
409         ) -> Result<Box<Self>> {
410             if let InterruptSourceConfig::MsiIrq(cfg) = &config {
411                 let route = mshv_msi_routing_entry {
412                     gsi,
413                     address_lo: cfg.low_addr,
414                     address_hi: cfg.high_addr,
415                     data: cfg.data,
416                 };
417                 let entry = MshvRoutingEntry {
418                     route,
419                     masked: false,
420                 };
421 
422                 return Ok(Box::new(entry));
423             }
424 
425             Err(io::Error::new(
426                 io::ErrorKind::Other,
427                 "Interrupt config type not supported",
428             ))
429         }
430     }
431 }
432 
433 #[cfg(target_arch = "aarch64")]
434 #[cfg(test)]
435 mod tests {
436     use arch::aarch64::gic::kvm::{create_gic, save_pending_tables};
437     use arch::aarch64::gic::{
438         get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs,
439     };
440 
441     #[test]
442     fn test_create_gic() {
443         let hv = hypervisor::new().unwrap();
444         let vm = hv.create_vm().unwrap();
445 
446         assert!(create_gic(&vm, 1).is_ok());
447     }
448 
449     #[test]
450     fn test_get_set_dist_regs() {
451         let hv = hypervisor::new().unwrap();
452         let vm = hv.create_vm().unwrap();
453         let _ = vm.create_vcpu(0, None).unwrap();
454         let gic = create_gic(&vm, 1).expect("Cannot create gic");
455 
456         let res = get_dist_regs(gic.device());
457         assert!(res.is_ok());
458         let state = res.unwrap();
459         assert_eq!(state.len(), 568);
460 
461         let res = set_dist_regs(gic.device(), &state);
462         assert!(res.is_ok());
463     }
464 
465     #[test]
466     fn test_get_set_redist_regs() {
467         let hv = hypervisor::new().unwrap();
468         let vm = hv.create_vm().unwrap();
469         let _ = vm.create_vcpu(0, None).unwrap();
470         let gic = create_gic(&vm, 1).expect("Cannot create gic");
471 
472         let gicr_typer = vec![123];
473         let res = get_redist_regs(gic.device(), &gicr_typer);
474         assert!(res.is_ok());
475         let state = res.unwrap();
476         println!("{}", state.len());
477         assert!(state.len() == 24);
478 
479         assert!(set_redist_regs(gic.device(), &gicr_typer, &state).is_ok());
480     }
481 
482     #[test]
483     fn test_get_set_icc_regs() {
484         let hv = hypervisor::new().unwrap();
485         let vm = hv.create_vm().unwrap();
486         let _ = vm.create_vcpu(0, None).unwrap();
487         let gic = create_gic(&vm, 1).expect("Cannot create gic");
488 
489         let gicr_typer = vec![123];
490         let res = get_icc_regs(gic.device(), &gicr_typer);
491         assert!(res.is_ok());
492         let state = res.unwrap();
493         println!("{}", state.len());
494         assert!(state.len() == 9);
495 
496         assert!(set_icc_regs(gic.device(), &gicr_typer, &state).is_ok());
497     }
498 
499     #[test]
500     fn test_save_pending_tables() {
501         let hv = hypervisor::new().unwrap();
502         let vm = hv.create_vm().unwrap();
503         let _ = vm.create_vcpu(0, None).unwrap();
504         let gic = create_gic(&vm, 1).expect("Cannot create gic");
505 
506         assert!(save_pending_tables(gic.device()).is_ok());
507     }
508 }
509