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