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 181 // When mask a msi irq, entry.masked is set to be true, 182 // and the gsi will not be passed to KVM through KVM_SET_GSI_ROUTING. 183 // So it's required to call disable() (which deassign KVM_IRQFD) before 184 // set_gsi_routes() to avoid kernel panic (see #3827) 185 if masked { 186 route.disable(&self.vm)?; 187 } 188 189 let mut routes = self.gsi_msi_routes.lock().unwrap(); 190 routes.insert(route.gsi, entry); 191 if set_gsi { 192 self.set_gsi_routes(&routes)?; 193 } 194 195 // Assign KVM_IRQFD after KVM_SET_GSI_ROUTING to avoid 196 // panic on kernel which not have commit a80ced6ea514 197 // (KVM: SVM: fix panic on out-of-bounds guest IRQ). 198 if !masked { 199 route.enable(&self.vm)?; 200 } 201 202 return Ok(()); 203 } 204 205 Err(io::Error::new( 206 io::ErrorKind::Other, 207 format!("update: Invalid interrupt index {index}"), 208 )) 209 } 210 211 fn set_gsi(&self) -> Result<()> { 212 let routes = self.gsi_msi_routes.lock().unwrap(); 213 self.set_gsi_routes(&routes) 214 } 215 } 216 217 pub struct LegacyUserspaceInterruptGroup { 218 ioapic: Arc<Mutex<dyn InterruptController>>, 219 irq: u32, 220 } 221 222 impl LegacyUserspaceInterruptGroup { 223 fn new(ioapic: Arc<Mutex<dyn InterruptController>>, irq: u32) -> Self { 224 LegacyUserspaceInterruptGroup { ioapic, irq } 225 } 226 } 227 228 impl InterruptSourceGroup for LegacyUserspaceInterruptGroup { 229 fn trigger(&self, _index: InterruptIndex) -> Result<()> { 230 self.ioapic 231 .lock() 232 .unwrap() 233 .service_irq(self.irq as usize) 234 .map_err(|e| { 235 io::Error::new( 236 io::ErrorKind::Other, 237 format!("failed to inject IRQ #{}: {:?}", self.irq, e), 238 ) 239 }) 240 } 241 242 fn update( 243 &self, 244 _index: InterruptIndex, 245 _config: InterruptSourceConfig, 246 _masked: bool, 247 _set_gsi: bool, 248 ) -> Result<()> { 249 Ok(()) 250 } 251 252 fn set_gsi(&self) -> Result<()> { 253 Ok(()) 254 } 255 256 fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> { 257 self.ioapic.lock().unwrap().notifier(self.irq as usize) 258 } 259 } 260 261 pub struct LegacyUserspaceInterruptManager { 262 ioapic: Arc<Mutex<dyn InterruptController>>, 263 } 264 265 pub struct MsiInterruptManager { 266 allocator: Arc<Mutex<SystemAllocator>>, 267 vm: Arc<dyn hypervisor::Vm>, 268 gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry>>>, 269 } 270 271 impl LegacyUserspaceInterruptManager { 272 pub fn new(ioapic: Arc<Mutex<dyn InterruptController>>) -> Self { 273 LegacyUserspaceInterruptManager { ioapic } 274 } 275 } 276 277 impl MsiInterruptManager { 278 pub fn new(allocator: Arc<Mutex<SystemAllocator>>, vm: Arc<dyn hypervisor::Vm>) -> Self { 279 // Create a shared list of GSI that can be shared through all PCI 280 // devices. This way, we can maintain the full list of used GSI, 281 // preventing one device from overriding interrupts setting from 282 // another one. 283 let gsi_msi_routes = Arc::new(Mutex::new(HashMap::new())); 284 285 MsiInterruptManager { 286 allocator, 287 vm, 288 gsi_msi_routes, 289 } 290 } 291 } 292 293 impl InterruptManager for LegacyUserspaceInterruptManager { 294 type GroupConfig = LegacyIrqGroupConfig; 295 296 fn create_group(&self, config: Self::GroupConfig) -> Result<Arc<dyn InterruptSourceGroup>> { 297 Ok(Arc::new(LegacyUserspaceInterruptGroup::new( 298 self.ioapic.clone(), 299 config.irq, 300 ))) 301 } 302 303 fn destroy_group(&self, _group: Arc<dyn InterruptSourceGroup>) -> Result<()> { 304 Ok(()) 305 } 306 } 307 308 impl InterruptManager for MsiInterruptManager { 309 type GroupConfig = MsiIrqGroupConfig; 310 311 fn create_group(&self, config: Self::GroupConfig) -> Result<Arc<dyn InterruptSourceGroup>> { 312 let mut allocator = self.allocator.lock().unwrap(); 313 let mut irq_routes: HashMap<InterruptIndex, InterruptRoute> = 314 HashMap::with_capacity(config.count as usize); 315 for i in config.base..config.base + config.count { 316 irq_routes.insert(i, InterruptRoute::new(&mut allocator)?); 317 } 318 319 Ok(Arc::new(MsiInterruptGroup::new( 320 self.vm.clone(), 321 self.gsi_msi_routes.clone(), 322 irq_routes, 323 ))) 324 } 325 326 fn destroy_group(&self, _group: Arc<dyn InterruptSourceGroup>) -> Result<()> { 327 Ok(()) 328 } 329 } 330