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::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) 46 .map_err(|e| io::Error::other(format!("Failed registering irq_fd: {e}")))?; 47 48 // Update internals to track the irq_fd as "registered". 49 self.registered.store(true, Ordering::Release); 50 } 51 52 Ok(()) 53 } 54 55 pub fn disable(&self, vm: &Arc<dyn hypervisor::Vm>) -> Result<()> { 56 if self.registered.load(Ordering::Acquire) { 57 vm.unregister_irqfd(&self.irq_fd, self.gsi) 58 .map_err(|e| io::Error::other(format!("Failed unregistering irq_fd: {e}")))?; 59 60 // Update internals to track the irq_fd as "unregistered". 61 self.registered.store(false, Ordering::Release); 62 } 63 64 Ok(()) 65 } 66 67 pub fn trigger(&self) -> Result<()> { 68 self.irq_fd.write(1) 69 } 70 71 pub fn notifier(&self) -> Option<EventFd> { 72 Some( 73 self.irq_fd 74 .try_clone() 75 .expect("Failed cloning interrupt's EventFd"), 76 ) 77 } 78 } 79 80 pub struct RoutingEntry { 81 route: IrqRoutingEntry, 82 masked: bool, 83 } 84 85 pub struct MsiInterruptGroup { 86 vm: Arc<dyn hypervisor::Vm>, 87 gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry>>>, 88 irq_routes: HashMap<InterruptIndex, InterruptRoute>, 89 } 90 91 impl MsiInterruptGroup { 92 fn set_gsi_routes(&self, routes: &HashMap<u32, RoutingEntry>) -> Result<()> { 93 let mut entry_vec: Vec<IrqRoutingEntry> = Vec::new(); 94 for (_, entry) in routes.iter() { 95 if entry.masked { 96 continue; 97 } 98 99 entry_vec.push(entry.route); 100 } 101 102 self.vm 103 .set_gsi_routing(&entry_vec) 104 .map_err(|e| io::Error::other(format!("Failed setting GSI routing: {e}"))) 105 } 106 } 107 108 impl MsiInterruptGroup { 109 fn new( 110 vm: Arc<dyn hypervisor::Vm>, 111 gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry>>>, 112 irq_routes: HashMap<InterruptIndex, InterruptRoute>, 113 ) -> Self { 114 MsiInterruptGroup { 115 vm, 116 gsi_msi_routes, 117 irq_routes, 118 } 119 } 120 } 121 122 impl InterruptSourceGroup for MsiInterruptGroup { 123 fn enable(&self) -> Result<()> { 124 for (_, route) in self.irq_routes.iter() { 125 route.enable(&self.vm)?; 126 } 127 128 Ok(()) 129 } 130 131 fn disable(&self) -> Result<()> { 132 for (_, route) in self.irq_routes.iter() { 133 route.disable(&self.vm)?; 134 } 135 136 Ok(()) 137 } 138 139 fn trigger(&self, index: InterruptIndex) -> Result<()> { 140 if let Some(route) = self.irq_routes.get(&index) { 141 return route.trigger(); 142 } 143 144 Err(io::Error::other(format!( 145 "trigger: Invalid interrupt index {index}" 146 ))) 147 } 148 149 fn notifier(&self, index: InterruptIndex) -> Option<EventFd> { 150 if let Some(route) = self.irq_routes.get(&index) { 151 return route.notifier(); 152 } 153 154 None 155 } 156 157 fn update( 158 &self, 159 index: InterruptIndex, 160 config: InterruptSourceConfig, 161 masked: bool, 162 set_gsi: bool, 163 ) -> Result<()> { 164 if let Some(route) = self.irq_routes.get(&index) { 165 let entry = RoutingEntry { 166 route: self.vm.make_routing_entry(route.gsi, &config), 167 masked, 168 }; 169 170 // When mask a msi irq, entry.masked is set to be true, 171 // and the gsi will not be passed to KVM through KVM_SET_GSI_ROUTING. 172 // So it's required to call disable() (which deassign KVM_IRQFD) before 173 // set_gsi_routes() to avoid kernel panic (see #3827) 174 if masked { 175 route.disable(&self.vm)?; 176 } 177 178 let mut routes = self.gsi_msi_routes.lock().unwrap(); 179 routes.insert(route.gsi, entry); 180 if set_gsi { 181 self.set_gsi_routes(&routes)?; 182 } 183 184 // Assign KVM_IRQFD after KVM_SET_GSI_ROUTING to avoid 185 // panic on kernel which not have commit a80ced6ea514 186 // (KVM: SVM: fix panic on out-of-bounds guest IRQ). 187 if !masked { 188 route.enable(&self.vm)?; 189 } 190 191 return Ok(()); 192 } 193 194 Err(io::Error::other(format!( 195 "update: Invalid interrupt index {index}" 196 ))) 197 } 198 199 fn set_gsi(&self) -> Result<()> { 200 let routes = self.gsi_msi_routes.lock().unwrap(); 201 self.set_gsi_routes(&routes) 202 } 203 } 204 205 pub struct LegacyUserspaceInterruptGroup { 206 ioapic: Arc<Mutex<dyn InterruptController>>, 207 irq: u32, 208 } 209 210 impl LegacyUserspaceInterruptGroup { 211 fn new(ioapic: Arc<Mutex<dyn InterruptController>>, irq: u32) -> Self { 212 LegacyUserspaceInterruptGroup { ioapic, irq } 213 } 214 } 215 216 impl InterruptSourceGroup for LegacyUserspaceInterruptGroup { 217 fn trigger(&self, _index: InterruptIndex) -> Result<()> { 218 self.ioapic 219 .lock() 220 .unwrap() 221 .service_irq(self.irq as usize) 222 .map_err(|e| io::Error::other(format!("failed to inject IRQ #{}: {:?}", self.irq, e))) 223 } 224 225 fn update( 226 &self, 227 _index: InterruptIndex, 228 _config: InterruptSourceConfig, 229 _masked: bool, 230 _set_gsi: bool, 231 ) -> Result<()> { 232 Ok(()) 233 } 234 235 fn set_gsi(&self) -> Result<()> { 236 Ok(()) 237 } 238 239 fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> { 240 self.ioapic.lock().unwrap().notifier(self.irq as usize) 241 } 242 } 243 244 pub struct LegacyUserspaceInterruptManager { 245 ioapic: Arc<Mutex<dyn InterruptController>>, 246 } 247 248 pub struct MsiInterruptManager { 249 allocator: Arc<Mutex<SystemAllocator>>, 250 vm: Arc<dyn hypervisor::Vm>, 251 gsi_msi_routes: Arc<Mutex<HashMap<u32, RoutingEntry>>>, 252 } 253 254 impl LegacyUserspaceInterruptManager { 255 pub fn new(ioapic: Arc<Mutex<dyn InterruptController>>) -> Self { 256 LegacyUserspaceInterruptManager { ioapic } 257 } 258 } 259 260 impl MsiInterruptManager { 261 pub fn new(allocator: Arc<Mutex<SystemAllocator>>, vm: Arc<dyn hypervisor::Vm>) -> Self { 262 // Create a shared list of GSI that can be shared through all PCI 263 // devices. This way, we can maintain the full list of used GSI, 264 // preventing one device from overriding interrupts setting from 265 // another one. 266 let gsi_msi_routes = Arc::new(Mutex::new(HashMap::new())); 267 268 MsiInterruptManager { 269 allocator, 270 vm, 271 gsi_msi_routes, 272 } 273 } 274 } 275 276 impl InterruptManager for LegacyUserspaceInterruptManager { 277 type GroupConfig = LegacyIrqGroupConfig; 278 279 fn create_group(&self, config: Self::GroupConfig) -> Result<Arc<dyn InterruptSourceGroup>> { 280 Ok(Arc::new(LegacyUserspaceInterruptGroup::new( 281 self.ioapic.clone(), 282 config.irq, 283 ))) 284 } 285 286 fn destroy_group(&self, _group: Arc<dyn InterruptSourceGroup>) -> Result<()> { 287 Ok(()) 288 } 289 } 290 291 impl InterruptManager for MsiInterruptManager { 292 type GroupConfig = MsiIrqGroupConfig; 293 294 fn create_group(&self, config: Self::GroupConfig) -> Result<Arc<dyn InterruptSourceGroup>> { 295 let mut allocator = self.allocator.lock().unwrap(); 296 let mut irq_routes: HashMap<InterruptIndex, InterruptRoute> = 297 HashMap::with_capacity(config.count as usize); 298 for i in config.base..config.base + config.count { 299 irq_routes.insert(i, InterruptRoute::new(&mut allocator)?); 300 } 301 302 Ok(Arc::new(MsiInterruptGroup::new( 303 self.vm.clone(), 304 self.gsi_msi_routes.clone(), 305 irq_routes, 306 ))) 307 } 308 309 fn destroy_group(&self, _group: Arc<dyn InterruptSourceGroup>) -> Result<()> { 310 Ok(()) 311 } 312 } 313