1 // Copyright 2021 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::convert::TryFrom; 6 use std::sync::Arc; 7 8 use anyhow::Context; 9 use serde::Deserialize; 10 use serde::Serialize; 11 use sync::Mutex; 12 13 cfg_if::cfg_if! { 14 if #[cfg(test)] { 15 use base::FakeClock as Clock; 16 } else { 17 use base::Clock; 18 } 19 } 20 use base::error; 21 use base::Error; 22 use base::Event; 23 use base::Result; 24 use base::Tube; 25 use hypervisor::whpx::WhpxVcpu; 26 use hypervisor::whpx::WhpxVm; 27 use hypervisor::IoapicState; 28 use hypervisor::IrqRoute; 29 use hypervisor::IrqSource; 30 use hypervisor::IrqSourceChip; 31 use hypervisor::LapicState; 32 use hypervisor::MPState; 33 use hypervisor::MsiAddressMessage; 34 use hypervisor::MsiDataMessage; 35 use hypervisor::PicSelect; 36 use hypervisor::PicState; 37 use hypervisor::PitState; 38 use hypervisor::Vcpu; 39 use hypervisor::VcpuX86_64; 40 use hypervisor::Vm; 41 use resources::SystemAllocator; 42 43 use crate::irqchip::DelayedIoApicIrqEvents; 44 use crate::irqchip::InterruptData; 45 use crate::irqchip::InterruptDestination; 46 use crate::irqchip::Ioapic; 47 use crate::irqchip::IrqEvent; 48 use crate::irqchip::IrqEventIndex; 49 use crate::irqchip::Pic; 50 use crate::irqchip::Routes; 51 use crate::irqchip::VcpuRunState; 52 use crate::irqchip::IOAPIC_BASE_ADDRESS; 53 use crate::irqchip::IOAPIC_MEM_LENGTH_BYTES; 54 use crate::Bus; 55 use crate::IrqChip; 56 use crate::IrqChipCap; 57 use crate::IrqChipX86_64; 58 use crate::IrqEdgeEvent; 59 use crate::IrqEventSource; 60 use crate::IrqLevelEvent; 61 use crate::Pit; 62 use crate::PitError; 63 64 /// PIT channel 0 timer is connected to IRQ 0 65 const PIT_CHANNEL0_IRQ: u32 = 0; 66 /// TODO(b/187464379): we don't know what the right frequency is here, but 100MHz gives 67 /// us better results than the frequency that WSL seems to use, which is 500MHz. 68 const WHPX_LOCAL_APIC_EMULATION_APIC_FREQUENCY: u32 = 100_000_000; 69 70 /// The WhpxSplitIrqChip supports 71 pub struct WhpxSplitIrqChip { 72 vm: WhpxVm, 73 routes: Arc<Mutex<Routes>>, 74 pit: Arc<Mutex<Pit>>, 75 pic: Arc<Mutex<Pic>>, 76 ioapic: Arc<Mutex<Ioapic>>, 77 ioapic_pins: usize, 78 /// Delayed ioapic irq object, that contains the delayed events because the ioapic was locked 79 /// when service_irq was called on the irqchip. This prevents deadlocks when a Vcpu thread has 80 /// locked the ioapic and the ioapic sends a AddMsiRoute signal to the main thread (which 81 /// itself may be busy trying to call service_irq). 82 /// 83 /// ## Note: 84 /// This lock may be locked by itself to access the `DelayedIoApicIrqEvents`. If accessed in 85 /// conjunction with the `irq_events` field, that lock should be taken first to prevent 86 /// deadlocks stemming from lock-ordering issues. 87 delayed_ioapic_irq_events: Arc<Mutex<DelayedIoApicIrqEvents>>, 88 /// Array of Events that devices will use to assert ioapic pins. 89 irq_events: Arc<Mutex<Vec<Option<IrqEvent>>>>, 90 } 91 92 impl WhpxSplitIrqChip { 93 /// Construct a new WhpxSplitIrqChip. new(vm: WhpxVm, irq_tube: Tube, ioapic_pins: Option<usize>) -> Result<Self>94 pub fn new(vm: WhpxVm, irq_tube: Tube, ioapic_pins: Option<usize>) -> Result<Self> { 95 let pit_evt = IrqEdgeEvent::new()?; 96 let pit = Pit::new(pit_evt.try_clone()?, Arc::new(Mutex::new(Clock::new()))).map_err( 97 |e| match e { 98 PitError::CloneEvent(err) => err, 99 PitError::CreateEvent(err) => err, 100 PitError::CreateWaitContext(err) => err, 101 PitError::WaitError(err) => err, 102 PitError::TimerCreateError(err) => err, 103 PitError::SpawnThread(_) => Error::new(libc::EIO), 104 }, 105 )?; 106 107 let pit_event_source = IrqEventSource::from_device(&pit); 108 109 let ioapic_pins = ioapic_pins.unwrap_or(hypervisor::NUM_IOAPIC_PINS); 110 let ioapic = Ioapic::new(irq_tube, ioapic_pins)?; 111 112 let mut chip = WhpxSplitIrqChip { 113 vm, 114 routes: Arc::new(Mutex::new(Routes::new())), 115 pit: Arc::new(Mutex::new(pit)), 116 pic: Arc::new(Mutex::new(Pic::new())), 117 ioapic: Arc::new(Mutex::new(ioapic)), 118 ioapic_pins, 119 delayed_ioapic_irq_events: Arc::new(Mutex::new(DelayedIoApicIrqEvents::new()?)), 120 irq_events: Arc::new(Mutex::new(Vec::new())), 121 }; 122 123 // This is equivalent to setting this in the blank Routes object above because 124 // WhpxSplitIrqChip doesn't interact with the WHPX API when setting routes, but in case 125 // that changes we do it this way. 126 chip.set_irq_routes(&Routes::default_pic_ioapic_routes(ioapic_pins))?; 127 128 // Add the pit 129 chip.register_edge_irq_event(PIT_CHANNEL0_IRQ, &pit_evt, pit_event_source)?; 130 Ok(chip) 131 } 132 133 /// Sends a Message Signaled Interrupt to one or more APICs. The WHPX API does not accept the 134 /// MSI address and data directly, so we must parse them and supply WHPX with the vector, 135 /// destination id, destination mode, trigger mode, and delivery mode (aka interrupt type). send_msi(&self, addr: u32, data: u32) -> Result<()>136 fn send_msi(&self, addr: u32, data: u32) -> Result<()> { 137 let mut msi_addr = MsiAddressMessage::new(); 138 msi_addr.set(0, 32, addr as u64); 139 let dest = InterruptDestination::try_from(&msi_addr).or(Err(Error::new(libc::EINVAL)))?; 140 141 let mut msi_data = MsiDataMessage::new(); 142 msi_data.set(0, 32, data as u64); 143 let data = InterruptData::from(&msi_data); 144 145 self.vm.request_interrupt( 146 data.vector, 147 dest.dest_id, 148 dest.mode, 149 data.trigger, 150 data.delivery, 151 ) 152 } 153 154 /// Return true if there is a pending interrupt for the specified vcpu. For WhpxSplitIrqChip 155 /// this calls interrupt_requested on the pic. interrupt_requested(&self, vcpu_id: usize) -> bool156 pub fn interrupt_requested(&self, vcpu_id: usize) -> bool { 157 // Pic interrupts for the split irqchip only go to vcpu 0 158 if vcpu_id != 0 { 159 return false; 160 } 161 self.pic.lock().interrupt_requested() 162 } 163 164 /// Check if the specified vcpu has any pending interrupts. Returns [`None`] for no interrupts, 165 /// otherwise [`Some::<u8>`] should be the injected interrupt vector. For [`WhpxSplitIrqChip`] 166 /// this calls `get_external_interrupt` on the pic. get_external_interrupt(&self, vcpu_id: usize) -> Result<Option<u8>>167 pub fn get_external_interrupt(&self, vcpu_id: usize) -> Result<Option<u8>> { 168 // Pic interrupts for the split irqchip only go to vcpu 0 169 if vcpu_id != 0 { 170 return Ok(None); 171 } 172 if let Some(vector) = self.pic.lock().get_external_interrupt() { 173 Ok(Some(vector)) 174 } else { 175 Ok(None) 176 } 177 } 178 } 179 180 impl WhpxSplitIrqChip { register_irq_event( &mut self, irq: u32, irq_event: &Event, resample_event: Option<&Event>, source: IrqEventSource, ) -> Result<Option<usize>>181 fn register_irq_event( 182 &mut self, 183 irq: u32, 184 irq_event: &Event, 185 resample_event: Option<&Event>, 186 source: IrqEventSource, 187 ) -> Result<Option<usize>> { 188 let mut evt = IrqEvent { 189 gsi: irq, 190 event: irq_event.try_clone()?, 191 resample_event: None, 192 source, 193 }; 194 195 if let Some(resample_event) = resample_event { 196 evt.resample_event = Some(resample_event.try_clone()?); 197 } 198 199 let mut irq_events = self.irq_events.lock(); 200 let index = irq_events.len(); 201 irq_events.push(Some(evt)); 202 Ok(Some(index)) 203 } 204 unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()>205 fn unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()> { 206 let mut irq_events = self.irq_events.lock(); 207 for (index, evt) in irq_events.iter().enumerate() { 208 if let Some(evt) = evt { 209 if evt.gsi == irq && irq_event.eq(&evt.event) { 210 irq_events[index] = None; 211 break; 212 } 213 } 214 } 215 Ok(()) 216 } 217 } 218 219 /// This IrqChip only works with Whpx so we only implement it for WhpxVcpu. 220 impl IrqChip for WhpxSplitIrqChip { add_vcpu(&mut self, _vcpu_id: usize, _vcpu: &dyn Vcpu) -> Result<()>221 fn add_vcpu(&mut self, _vcpu_id: usize, _vcpu: &dyn Vcpu) -> Result<()> { 222 // The WHPX API acts entirely on the VM partition, so we don't need to keep references to 223 // the vcpus. 224 Ok(()) 225 } 226 register_edge_irq_event( &mut self, irq: u32, irq_event: &IrqEdgeEvent, source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>227 fn register_edge_irq_event( 228 &mut self, 229 irq: u32, 230 irq_event: &IrqEdgeEvent, 231 source: IrqEventSource, 232 ) -> Result<Option<IrqEventIndex>> { 233 self.register_irq_event(irq, irq_event.get_trigger(), None, source) 234 } 235 unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>236 fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()> { 237 self.unregister_irq_event(irq, irq_event.get_trigger()) 238 } 239 register_level_irq_event( &mut self, irq: u32, irq_event: &IrqLevelEvent, source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>240 fn register_level_irq_event( 241 &mut self, 242 irq: u32, 243 irq_event: &IrqLevelEvent, 244 source: IrqEventSource, 245 ) -> Result<Option<IrqEventIndex>> { 246 self.register_irq_event( 247 irq, 248 irq_event.get_trigger(), 249 Some(irq_event.get_resample()), 250 source, 251 ) 252 } 253 unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>254 fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()> { 255 self.unregister_irq_event(irq, irq_event.get_trigger()) 256 } 257 route_irq(&mut self, route: IrqRoute) -> Result<()>258 fn route_irq(&mut self, route: IrqRoute) -> Result<()> { 259 self.routes.lock().add(route) 260 } 261 set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>262 fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()> { 263 self.routes.lock().replace_all(routes) 264 } 265 irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>>266 fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>> { 267 let mut tokens: Vec<(IrqEventIndex, IrqEventSource, Event)> = Vec::new(); 268 for (index, evt) in self.irq_events.lock().iter().enumerate() { 269 if let Some(evt) = evt { 270 tokens.push((index, evt.source.clone(), evt.event.try_clone()?)); 271 } 272 } 273 Ok(tokens) 274 } 275 service_irq(&mut self, irq: u32, level: bool) -> Result<()>276 fn service_irq(&mut self, irq: u32, level: bool) -> Result<()> { 277 for route in self.routes.lock()[irq as usize].iter() { 278 match *route { 279 IrqSource::Irqchip { 280 chip: IrqSourceChip::PicPrimary, 281 pin, 282 } 283 | IrqSource::Irqchip { 284 chip: IrqSourceChip::PicSecondary, 285 pin, 286 } => { 287 self.pic.lock().service_irq(pin as u8, level); 288 } 289 IrqSource::Irqchip { 290 chip: IrqSourceChip::Ioapic, 291 pin, 292 } => { 293 self.ioapic.lock().service_irq(pin as usize, level); 294 } 295 // service_irq's level parameter is ignored for MSIs. MSI data specifies the level. 296 IrqSource::Msi { address, data } => self.send_msi(address as u32, data)?, 297 _ => { 298 error!("Unexpected route source {:?}", route); 299 return Err(Error::new(libc::EINVAL)); 300 } 301 } 302 } 303 Ok(()) 304 } 305 306 /// Services an IRQ event by asserting then deasserting an IRQ line. The associated Event 307 /// that triggered the irq event will be read from. If the irq is associated with a resample 308 /// Event, then the deassert will only happen after an EOI is broadcast for a vector 309 /// associated with the irq line. 310 /// For WhpxSplitIrqChip, this function identifies the destination(s) of the irq: PIC, IOAPIC, 311 /// or APIC (MSI). If it's a PIC or IOAPIC route, we attempt to call service_irq on those 312 /// chips. If the IOAPIC is unable to be immediately locked, we add the irq to the 313 /// delayed_ioapic_irq_events (though we still read from the Event that triggered the irq 314 /// event). If it's an MSI route, we call send_msi to decode the MSI and send the interrupt 315 /// to WHPX. service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>316 fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()> { 317 let irq_events = self.irq_events.lock(); 318 let evt = if let Some(evt) = &irq_events[event_index] { 319 evt 320 } else { 321 return Ok(()); 322 }; 323 evt.event.wait()?; 324 325 for route in self.routes.lock()[evt.gsi as usize].iter() { 326 match *route { 327 IrqSource::Irqchip { 328 chip: IrqSourceChip::PicPrimary, 329 pin, 330 } 331 | IrqSource::Irqchip { 332 chip: IrqSourceChip::PicSecondary, 333 pin, 334 } => { 335 let mut pic = self.pic.lock(); 336 if evt.resample_event.is_some() { 337 pic.service_irq(pin as u8, true); 338 } else { 339 pic.service_irq(pin as u8, true); 340 pic.service_irq(pin as u8, false); 341 } 342 } 343 IrqSource::Irqchip { 344 chip: IrqSourceChip::Ioapic, 345 pin, 346 } => { 347 if let Ok(mut ioapic) = self.ioapic.try_lock() { 348 if evt.resample_event.is_some() { 349 ioapic.service_irq(pin as usize, true); 350 } else { 351 ioapic.service_irq(pin as usize, true); 352 ioapic.service_irq(pin as usize, false); 353 } 354 } else { 355 let mut delayed_events = self.delayed_ioapic_irq_events.lock(); 356 delayed_events.events.push(event_index); 357 delayed_events.trigger.signal()?; 358 } 359 } 360 IrqSource::Msi { address, data } => self.send_msi(address as u32, data)?, 361 _ => { 362 error!("Unexpected route source {:?}", route); 363 return Err(Error::new(libc::EINVAL)); 364 } 365 } 366 } 367 368 Ok(()) 369 } 370 371 /// Broadcasts an end of interrupt. For WhpxSplitIrqChip this sends the EOI to the Ioapic. broadcast_eoi(&self, vector: u8) -> Result<()>372 fn broadcast_eoi(&self, vector: u8) -> Result<()> { 373 self.ioapic.lock().end_of_interrupt(vector); 374 Ok(()) 375 } 376 377 /// Injects any pending interrupts for `vcpu`. 378 /// For WhpxSplitIrqChip this injects any PIC interrupts on vcpu_id 0. inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>379 fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()> { 380 let vcpu: &WhpxVcpu = vcpu 381 .downcast_ref() 382 .expect("WhpxSplitIrqChip::add_vcpu called with non-WhpxVcpu"); 383 let vcpu_id = vcpu.id(); 384 if !self.interrupt_requested(vcpu_id) || !vcpu.ready_for_interrupt() { 385 return Ok(()); 386 } 387 388 if let Some(vector) = self.get_external_interrupt(vcpu_id)? { 389 vcpu.interrupt(vector)?; 390 } 391 392 // The second interrupt request should be handled immediately, so ask vCPU to exit as soon 393 // as possible. 394 if self.interrupt_requested(vcpu_id) { 395 vcpu.set_interrupt_window_requested(true); 396 } 397 Ok(()) 398 } 399 400 /// Notifies the irq chip that the specified VCPU has executed a halt instruction. 401 /// For WhpxSplitIrqChip this is a no-op because Whpx handles VCPU blocking. halted(&self, _vcpu_id: usize)402 fn halted(&self, _vcpu_id: usize) {} 403 404 /// Blocks until `vcpu` is in a runnable state or until interrupted by 405 /// `IrqChip::kick_halted_vcpus`. Returns `VcpuRunState::Runnable if vcpu is runnable, or 406 /// `VcpuRunState::Interrupted` if the wait was interrupted. 407 /// For WhpxSplitIrqChip this is a no-op and always returns Runnable because Whpx handles VCPU 408 /// blocking. wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState>409 fn wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState> { 410 Ok(VcpuRunState::Runnable) 411 } 412 413 /// Makes unrunnable VCPUs return immediately from `wait_until_runnable`. 414 /// For WhpxSplitIrqChip this is a no-op because Whpx handles VCPU blocking. kick_halted_vcpus(&self)415 fn kick_halted_vcpus(&self) {} 416 get_mp_state(&self, _vcpu_id: usize) -> Result<MPState>417 fn get_mp_state(&self, _vcpu_id: usize) -> Result<MPState> { 418 // WHPX does not seem to have an API for this, but luckily this API isn't used anywhere 419 // except the plugin. 420 Err(Error::new(libc::ENXIO)) 421 } 422 set_mp_state(&mut self, _vcpu_id: usize, _state: &MPState) -> Result<()>423 fn set_mp_state(&mut self, _vcpu_id: usize, _state: &MPState) -> Result<()> { 424 // WHPX does not seem to have an API for this, but luckily this API isn't used anywhere 425 // except the plugin. 426 Err(Error::new(libc::ENXIO)) 427 } 428 try_clone(&self) -> Result<Self> where Self: Sized,429 fn try_clone(&self) -> Result<Self> 430 where 431 Self: Sized, 432 { 433 Ok(WhpxSplitIrqChip { 434 vm: self.vm.try_clone()?, 435 routes: self.routes.clone(), 436 pit: self.pit.clone(), 437 pic: self.pic.clone(), 438 ioapic: self.ioapic.clone(), 439 ioapic_pins: self.ioapic_pins, 440 delayed_ioapic_irq_events: self.delayed_ioapic_irq_events.clone(), 441 irq_events: self.irq_events.clone(), 442 }) 443 } 444 finalize_devices( &mut self, resources: &mut SystemAllocator, io_bus: &Bus, mmio_bus: &Bus, ) -> Result<()>445 fn finalize_devices( 446 &mut self, 447 resources: &mut SystemAllocator, 448 io_bus: &Bus, 449 mmio_bus: &Bus, 450 ) -> Result<()> { 451 // Insert pit into io_bus 452 io_bus.insert(self.pit.clone(), 0x040, 0x8).unwrap(); 453 io_bus.insert(self.pit.clone(), 0x061, 0x1).unwrap(); 454 455 // Insert pic into io_bus 456 io_bus.insert(self.pic.clone(), 0x20, 0x2).unwrap(); 457 io_bus.insert(self.pic.clone(), 0xa0, 0x2).unwrap(); 458 io_bus.insert(self.pic.clone(), 0x4d0, 0x2).unwrap(); 459 460 // Insert ioapic into mmio_bus 461 mmio_bus 462 .insert( 463 self.ioapic.clone(), 464 IOAPIC_BASE_ADDRESS, 465 IOAPIC_MEM_LENGTH_BYTES, 466 ) 467 .unwrap(); 468 469 // At this point, all of our devices have been created and they have registered their 470 // irq events, so we can clone our resample events 471 let mut ioapic_resample_events: Vec<Vec<Event>> = 472 (0..self.ioapic_pins).map(|_| Vec::new()).collect(); 473 let mut pic_resample_events: Vec<Vec<Event>> = 474 (0..self.ioapic_pins).map(|_| Vec::new()).collect(); 475 476 for evt in self.irq_events.lock().iter().flatten() { 477 if (evt.gsi as usize) >= self.ioapic_pins { 478 continue; 479 } 480 if let Some(resample_evt) = &evt.resample_event { 481 ioapic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?); 482 pic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?); 483 } 484 } 485 486 // Register resample events with the ioapic 487 self.ioapic 488 .lock() 489 .register_resample_events(ioapic_resample_events); 490 // Register resample events with the pic 491 self.pic 492 .lock() 493 .register_resample_events(pic_resample_events); 494 495 // Make sure all future irq numbers are >= self.ioapic_pins 496 let mut irq_num = resources.allocate_irq().unwrap(); 497 while irq_num < self.ioapic_pins as u32 { 498 irq_num = resources.allocate_irq().unwrap(); 499 } 500 501 Ok(()) 502 } 503 process_delayed_irq_events(&mut self) -> Result<()>504 fn process_delayed_irq_events(&mut self) -> Result<()> { 505 let irq_events = self.irq_events.lock(); 506 let mut delayed_events = self.delayed_ioapic_irq_events.lock(); 507 delayed_events.events.retain(|&event_index| { 508 if let Some(evt) = &irq_events[event_index] { 509 if let Ok(mut ioapic) = self.ioapic.try_lock() { 510 if evt.resample_event.is_some() { 511 ioapic.service_irq(evt.gsi as usize, true); 512 } else { 513 ioapic.service_irq(evt.gsi as usize, true); 514 ioapic.service_irq(evt.gsi as usize, false); 515 } 516 517 false 518 } else { 519 true 520 } 521 } else { 522 true 523 } 524 }); 525 526 if delayed_events.events.is_empty() { 527 delayed_events.trigger.wait()?; 528 } 529 Ok(()) 530 } 531 irq_delayed_event_token(&self) -> Result<Option<Event>>532 fn irq_delayed_event_token(&self) -> Result<Option<Event>> { 533 Ok(Some( 534 self.delayed_ioapic_irq_events.lock().trigger.try_clone()?, 535 )) 536 } 537 check_capability(&self, c: IrqChipCap) -> bool538 fn check_capability(&self, c: IrqChipCap) -> bool { 539 match c { 540 // It appears as though WHPX does not have tsc deadline support because we get guest 541 // MSR write failures if we enable it. 542 IrqChipCap::TscDeadlineTimer => false, 543 // TODO(b/180966070): Figure out how to query x2apic support. 544 IrqChipCap::X2Apic => false, 545 IrqChipCap::MpStateGetSet => false, 546 } 547 } 548 } 549 550 #[derive(Serialize, Deserialize)] 551 struct WhpxSplitIrqChipSnapshot { 552 routes: Vec<IrqRoute>, 553 } 554 555 impl IrqChipX86_64 for WhpxSplitIrqChip { try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>>556 fn try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>> { 557 Ok(Box::new(self.try_clone()?)) 558 } 559 as_irq_chip(&self) -> &dyn IrqChip560 fn as_irq_chip(&self) -> &dyn IrqChip { 561 self 562 } 563 as_irq_chip_mut(&mut self) -> &mut dyn IrqChip564 fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip { 565 self 566 } 567 568 /// Get the current state of the PIC get_pic_state(&self, select: PicSelect) -> Result<PicState>569 fn get_pic_state(&self, select: PicSelect) -> Result<PicState> { 570 Ok(self.pic.lock().get_pic_state(select)) 571 } 572 573 /// Set the current state of the PIC set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>574 fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()> { 575 self.pic.lock().set_pic_state(select, state); 576 Ok(()) 577 } 578 579 /// Get the current state of the IOAPIC get_ioapic_state(&self) -> Result<IoapicState>580 fn get_ioapic_state(&self) -> Result<IoapicState> { 581 Ok(self.ioapic.lock().get_ioapic_state()) 582 } 583 584 /// Set the current state of the IOAPIC set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>585 fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()> { 586 self.ioapic.lock().set_ioapic_state(state); 587 Ok(()) 588 } 589 590 /// Get the current state of the specified VCPU's local APIC get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>591 fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState> { 592 self.vm.get_vcpu_lapic_state(vcpu_id) 593 } 594 595 /// Set the current state of the specified VCPU's local APIC set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>596 fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()> { 597 self.vm.set_vcpu_lapic_state(vcpu_id, state) 598 } 599 lapic_frequency(&self) -> u32600 fn lapic_frequency(&self) -> u32 { 601 WHPX_LOCAL_APIC_EMULATION_APIC_FREQUENCY 602 } 603 604 /// Retrieves the state of the PIT. get_pit(&self) -> Result<PitState>605 fn get_pit(&self) -> Result<PitState> { 606 Ok(self.pit.lock().get_pit_state()) 607 } 608 609 /// Sets the state of the PIT. set_pit(&mut self, state: &PitState) -> Result<()>610 fn set_pit(&mut self, state: &PitState) -> Result<()> { 611 self.pit.lock().set_pit_state(state); 612 Ok(()) 613 } 614 615 /// Returns true if the PIT uses port 0x61 for the PC speaker, false if 0x61 is unused. 616 /// devices::Pit uses 0x61. pit_uses_speaker_port(&self) -> bool617 fn pit_uses_speaker_port(&self) -> bool { 618 true 619 } 620 snapshot_chip_specific(&self) -> anyhow::Result<serde_json::Value>621 fn snapshot_chip_specific(&self) -> anyhow::Result<serde_json::Value> { 622 serde_json::to_value(&WhpxSplitIrqChipSnapshot { 623 routes: self.routes.lock().get_routes(), 624 }) 625 .context("failed to snapshot WhpxSplitIrqChip") 626 } 627 restore_chip_specific(&mut self, data: serde_json::Value) -> anyhow::Result<()>628 fn restore_chip_specific(&mut self, data: serde_json::Value) -> anyhow::Result<()> { 629 let mut deser: WhpxSplitIrqChipSnapshot = 630 serde_json::from_value(data).context("failed to deserialize WhpxSplitIrqChip")?; 631 self.set_irq_routes(deser.routes.as_slice())?; 632 Ok(()) 633 } 634 } 635