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