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