1use std::any::Any;
6use std::sync::Arc;
7
8use anyhow::anyhow;
9use anyhow::Context;
10use base::error;
11#[cfg(not(test))]
12use base::Clock;
13use base::Error;
14use base::Event;
15#[cfg(test)]
16use base::FakeClock as Clock;
17use base::Result;
18use base::Tube;
19use hypervisor::kvm::KvmCap;
20use hypervisor::kvm::KvmVcpu;
21use hypervisor::kvm::KvmVm;
22use hypervisor::IoapicState;
23use hypervisor::IrqRoute;
24use hypervisor::IrqSource;
25use hypervisor::IrqSourceChip;
26use hypervisor::LapicState;
27use hypervisor::MPState;
28use hypervisor::PicSelect;
29use hypervisor::PicState;
30use hypervisor::PitState;
31use hypervisor::Vcpu;
32use hypervisor::VcpuArch;
33use kvm_sys::*;
34use resources::SystemAllocator;
35use serde::Deserialize;
36use serde::Serialize;
37use snapshot::AnySnapshot;
38use sync::Mutex;
39
40use crate::irqchip::Ioapic;
41use crate::irqchip::IrqEvent;
42use crate::irqchip::IrqEventIndex;
43use crate::irqchip::Pic;
44use crate::irqchip::VcpuRunState;
45use crate::irqchip::IOAPIC_BASE_ADDRESS;
46use crate::irqchip::IOAPIC_MEM_LENGTH_BYTES;
47use crate::Bus;
48use crate::IrqChip;
49use crate::IrqChipCap;
50use crate::IrqChipX86_64;
51use crate::IrqEdgeEvent;
52use crate::IrqEventSource;
53use crate::IrqLevelEvent;
54use crate::Pit;
55use crate::PitError;
56
57const PIT_CHANNEL0_IRQ: u32 = 0;
59
60fn kvm_default_irq_routing_table(ioapic_pins: usize) -> Vec<IrqRoute> {
63 let mut routes: Vec<IrqRoute> = Vec::new();
64
65 for i in 0..8 {
66 routes.push(IrqRoute::pic_irq_route(IrqSourceChip::PicPrimary, i));
67 routes.push(IrqRoute::ioapic_irq_route(i));
68 }
69 for i in 8..16 {
70 routes.push(IrqRoute::pic_irq_route(IrqSourceChip::PicSecondary, i));
71 routes.push(IrqRoute::ioapic_irq_route(i));
72 }
73 for i in 16..ioapic_pins as u32 {
74 routes.push(IrqRoute::ioapic_irq_route(i));
75 }
76
77 routes
78}
79
80pub struct KvmKernelIrqChip {
84 pub(super) vm: Arc<KvmVm>,
85 pub(super) vcpus: Mutex<Vec<Option<Arc<KvmVcpu>>>>,
86 pub(super) routes: Mutex<Vec<IrqRoute>>,
87}
88
89#[derive(Serialize, Deserialize)]
90struct KvmKernelIrqChipSnapshot {
91 routes: Vec<IrqRoute>,
92 apic_base: Vec<u64>,
96 interrupt_bitmap: Vec<[u64; 4usize]>,
97}
98
99impl KvmKernelIrqChip {
100 pub fn new(vm: Arc<KvmVm>, num_vcpus: usize) -> Result<KvmKernelIrqChip> {
102 vm.create_irq_chip()?;
103 vm.create_pit()?;
104 let ioapic_pins = vm.get_ioapic_num_pins()?;
105
106 Ok(KvmKernelIrqChip {
107 vm,
108 vcpus: Mutex::new((0..num_vcpus).map(|_| None).collect()),
109 routes: Mutex::new(kvm_default_irq_routing_table(ioapic_pins)),
110 })
111 }
112}
113
114impl IrqChipX86_64 for KvmKernelIrqChip {
115 fn get_pic_state(&self, select: PicSelect) -> Result<PicState> {
117 Ok(PicState::from(&self.vm.get_pic_state(select)?))
118 }
119
120 fn set_pic_state(&self, select: PicSelect, state: &PicState) -> Result<()> {
122 self.vm.set_pic_state(select, &kvm_pic_state::from(state))
123 }
124
125 fn get_ioapic_state(&self) -> Result<IoapicState> {
127 Ok(IoapicState::from(&self.vm.get_ioapic_state()?))
128 }
129
130 fn set_ioapic_state(&self, state: &IoapicState) -> Result<()> {
132 self.vm.set_ioapic_state(&kvm_ioapic_state::from(state))
133 }
134
135 fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState> {
137 match self.vcpus.lock().get(vcpu_id) {
138 Some(Some(vcpu)) => Ok(LapicState::from(&vcpu.get_lapic()?)),
139 _ => Err(Error::new(libc::ENOENT)),
140 }
141 }
142
143 fn set_lapic_state(&self, vcpu_id: usize, state: &LapicState) -> Result<()> {
145 match self.vcpus.lock().get(vcpu_id) {
146 Some(Some(vcpu)) => vcpu.set_lapic(&kvm_lapic_state::from(state)),
147 _ => Err(Error::new(libc::ENOENT)),
148 }
149 }
150
151 fn lapic_frequency(&self) -> u32 {
153 1_000_000_000
155 }
156
157 fn get_pit(&self) -> Result<PitState> {
159 Ok(PitState::from(&self.vm.get_pit_state()?))
160 }
161
162 fn set_pit(&self, state: &PitState) -> Result<()> {
164 self.vm.set_pit_state(&kvm_pit_state2::from(state))
165 }
166
167 fn pit_uses_speaker_port(&self) -> bool {
170 false
171 }
172
173 fn snapshot_chip_specific(&self) -> anyhow::Result<AnySnapshot> {
174 let mut apics: Vec<u64> = Vec::new();
175 let mut interrupt_bitmaps: Vec<[u64; 4usize]> = Vec::new();
176 {
177 let vcpus_lock = self.vcpus.lock();
178 for vcpu in (*vcpus_lock).iter().flatten() {
179 apics.push(vcpu.get_apic_base()?);
180 interrupt_bitmaps.push(vcpu.get_interrupt_bitmap()?);
181 }
182 }
183 AnySnapshot::to_any(KvmKernelIrqChipSnapshot {
184 routes: self.routes.lock().clone(),
185 apic_base: apics,
186 interrupt_bitmap: interrupt_bitmaps,
187 })
188 .context("failed to serialize KvmKernelIrqChip")
189 }
190
191 fn restore_chip_specific(&self, data: AnySnapshot) -> anyhow::Result<()> {
192 let deser: KvmKernelIrqChipSnapshot =
193 AnySnapshot::from_any(data).context("failed to deserialize data")?;
194 self.set_irq_routes(&deser.routes)?;
195 let vcpus_lock = self.vcpus.lock();
196 assert_eq!(deser.interrupt_bitmap.len(), vcpus_lock.len());
197 assert_eq!(deser.apic_base.len(), vcpus_lock.len());
198 for (i, vcpu) in vcpus_lock.iter().enumerate() {
199 if let Some(vcpu) = vcpu {
200 vcpu.set_apic_base(*deser.apic_base.get(i).unwrap())?;
201 vcpu.set_interrupt_bitmap(*deser.interrupt_bitmap.get(i).unwrap())?;
202 } else {
203 return Err(anyhow!(
204 "Received None instead of Vcpu while restoring apic_base and interrupt_bitmap"
205 ));
206 }
207 }
208 Ok(())
209 }
210}
211
212pub struct KvmSplitIrqChip {
217 vm: Arc<KvmVm>,
218 vcpus: Arc<Mutex<Vec<Option<Arc<KvmVcpu>>>>>,
219 routes: Arc<Mutex<Vec<IrqRoute>>>,
220 pit: Arc<Mutex<Pit>>,
221 pic: Arc<Mutex<Pic>>,
222 ioapic: Arc<Mutex<Ioapic>>,
223 ioapic_pins: usize,
224 delayed_ioapic_irq_events: Arc<Mutex<Vec<usize>>>,
229 delayed_ioapic_irq_trigger: Event,
231 irq_events: Arc<Mutex<Vec<Option<IrqEvent>>>>,
233}
234
235fn kvm_dummy_msi_routes(ioapic_pins: usize) -> Vec<IrqRoute> {
236 let mut routes: Vec<IrqRoute> = Vec::new();
237 for i in 0..ioapic_pins {
238 routes.push(
239 IrqRoute {
241 gsi: i as u32,
242 source: IrqSource::Msi {
243 address: 0,
244 data: 0,
245 },
246 },
247 );
248 }
249 routes
250}
251
252impl KvmSplitIrqChip {
253 pub fn new(
255 vm: Arc<KvmVm>,
256 num_vcpus: usize,
257 irq_tube: Tube,
258 ioapic_pins: Option<usize>,
259 ) -> Result<Self> {
260 let ioapic_pins = ioapic_pins.unwrap_or(vm.get_ioapic_num_pins()?);
261 vm.enable_split_irqchip(ioapic_pins)?;
262 let pit_evt = IrqEdgeEvent::new()?;
263 let pit = Pit::new(pit_evt.try_clone()?, Arc::new(Mutex::new(Clock::new()))).map_err(
264 |e| match e {
265 PitError::CloneEvent(err) => err,
266 PitError::CreateEvent(err) => err,
267 PitError::CreateWaitContext(err) => err,
268 PitError::WaitError(err) => err,
269 PitError::TimerCreateError(err) => err,
270 PitError::SpawnThread(_) => Error::new(libc::EIO),
271 },
272 )?;
273
274 let pit_event_source = IrqEventSource::from_device(&pit);
275
276 let chip = KvmSplitIrqChip {
277 vm,
278 vcpus: Arc::new(Mutex::new((0..num_vcpus).map(|_| None).collect())),
279 routes: Arc::new(Mutex::new(Vec::new())),
280 pit: Arc::new(Mutex::new(pit)),
281 pic: Arc::new(Mutex::new(Pic::new())),
282 ioapic: Arc::new(Mutex::new(Ioapic::new(irq_tube, ioapic_pins)?)),
283 ioapic_pins,
284 delayed_ioapic_irq_events: Arc::new(Mutex::new(Vec::new())),
285 delayed_ioapic_irq_trigger: Event::new()?,
286 irq_events: Arc::new(Mutex::new(Default::default())),
287 };
288
289 let mut routes = kvm_default_irq_routing_table(ioapic_pins);
291 routes.append(&mut kvm_dummy_msi_routes(ioapic_pins));
293
294 chip.set_irq_routes(&routes)?;
296
297 chip.register_edge_irq_event(PIT_CHANNEL0_IRQ, &pit_evt, pit_event_source)?;
298 Ok(chip)
299 }
300}
301
302impl KvmSplitIrqChip {
303 fn routes_to_chips(&self, irq: u32) -> Vec<(IrqSourceChip, u32)> {
305 let mut chips = Vec::new();
306 for route in self.routes.lock().iter() {
307 match route {
308 IrqRoute {
309 gsi,
310 source: IrqSource::Irqchip { chip, pin },
311 } if *gsi == irq => match chip {
312 IrqSourceChip::PicPrimary
313 | IrqSourceChip::PicSecondary
314 | IrqSourceChip::Ioapic => chips.push((*chip, *pin)),
315 IrqSourceChip::Gic => {
316 error!("gic irq should not be possible on a KvmSplitIrqChip")
317 }
318 IrqSourceChip::Aia => {
319 error!("Aia irq should not be possible on x86_64")
320 }
321 },
322 _ => {}
324 }
325 }
326 chips
327 }
328
329 pub fn interrupt_requested(&self, vcpu_id: usize) -> bool {
332 if vcpu_id != 0 {
334 return false;
335 }
336 self.pic.lock().interrupt_requested()
337 }
338
339 pub fn get_external_interrupt(&self, vcpu_id: usize) -> Option<u8> {
343 if vcpu_id != 0 {
345 return None;
346 }
347 self.pic.lock().get_external_interrupt()
348 }
349
350 fn register_irq_event(
352 &self,
353 irq: u32,
354 irq_event: &Event,
355 resample_event: Option<&Event>,
356 source: IrqEventSource,
357 ) -> Result<Option<IrqEventIndex>> {
358 if irq < self.ioapic_pins as u32 {
359 let mut evt = IrqEvent {
360 gsi: irq,
361 event: irq_event.try_clone()?,
362 resample_event: None,
363 source,
364 };
365
366 if let Some(resample_event) = resample_event {
367 evt.resample_event = Some(resample_event.try_clone()?);
368 }
369
370 let mut irq_events = self.irq_events.lock();
371 let index = irq_events.len();
372 irq_events.push(Some(evt));
373 Ok(Some(index))
374 } else {
375 self.vm.register_irqfd(irq, irq_event, resample_event)?;
376 Ok(None)
377 }
378 }
379
380 fn unregister_irq_event(&self, irq: u32, irq_event: &Event) -> Result<()> {
382 if irq < self.ioapic_pins as u32 {
383 let mut irq_events = self.irq_events.lock();
384 for (index, evt) in irq_events.iter().enumerate() {
385 if let Some(evt) = evt {
386 if evt.gsi == irq && irq_event.eq(&evt.event) {
387 irq_events[index] = None;
388 break;
389 }
390 }
391 }
392 Ok(())
393 } else {
394 self.vm.unregister_irqfd(irq, irq_event)
395 }
396 }
397}
398
399fn routes_conflict(route: &IrqRoute, other: &IrqRoute) -> bool {
402 if route.gsi != other.gsi {
404 return false;
405 }
406
407 if let (IrqSource::Msi { .. }, IrqSource::Msi { .. }) = (route.source, other.source) {
409 return true;
410 }
411
412 if let (
414 IrqSource::Irqchip {
415 chip: route_chip, ..
416 },
417 IrqSource::Irqchip {
418 chip: other_chip, ..
419 },
420 ) = (route.source, other.source)
421 {
422 return route_chip == other_chip;
423 }
424
425 false
427}
428
429impl IrqChip for KvmSplitIrqChip {
431 fn add_vcpu(&self, vcpu_id: usize, vcpu: Arc<dyn VcpuArch>) -> Result<()> {
433 let vcpu = Arc::downcast(vcpu)
434 .map_err(|_| ())
435 .expect("KvmSplitIrqChip::add_vcpu called with non-KvmVcpu");
436 self.vcpus.lock()[vcpu_id] = Some(vcpu);
437 Ok(())
438 }
439
440 fn register_edge_irq_event(
442 &self,
443 irq: u32,
444 irq_event: &IrqEdgeEvent,
445 source: IrqEventSource,
446 ) -> Result<Option<IrqEventIndex>> {
447 self.register_irq_event(irq, irq_event.get_trigger(), None, source)
448 }
449
450 fn unregister_edge_irq_event(&self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()> {
451 self.unregister_irq_event(irq, irq_event.get_trigger())
452 }
453
454 fn register_level_irq_event(
455 &self,
456 irq: u32,
457 irq_event: &IrqLevelEvent,
458 source: IrqEventSource,
459 ) -> Result<Option<IrqEventIndex>> {
460 self.register_irq_event(
461 irq,
462 irq_event.get_trigger(),
463 Some(irq_event.get_resample()),
464 source,
465 )
466 }
467
468 fn unregister_level_irq_event(&self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()> {
469 self.unregister_irq_event(irq, irq_event.get_trigger())
470 }
471
472 fn route_irq(&self, route: IrqRoute) -> Result<()> {
474 let mut routes = self.routes.lock();
475 routes.retain(|r| !routes_conflict(r, &route));
476
477 routes.push(route);
478
479 let mut msi_routes = routes.clone();
481 msi_routes.retain(|r| matches!(r.source, IrqSource::Msi { .. }));
482
483 self.vm.set_gsi_routing(&msi_routes)
484 }
485
486 fn set_irq_routes(&self, routes: &[IrqRoute]) -> Result<()> {
488 let mut current_routes = self.routes.lock();
489 *current_routes = routes.to_vec();
490
491 let mut msi_routes = routes.to_vec();
493 msi_routes.retain(|r| matches!(r.source, IrqSource::Msi { .. }));
494
495 self.vm.set_gsi_routing(&msi_routes)
496 }
497
498 fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>> {
501 let mut tokens = vec![];
502 for (index, evt) in self.irq_events.lock().iter().enumerate() {
503 if let Some(evt) = evt {
504 tokens.push((index, evt.source.clone(), evt.event.try_clone()?));
505 }
506 }
507 Ok(tokens)
508 }
509
510 fn service_irq(&self, irq: u32, level: bool) -> Result<()> {
513 let chips = self.routes_to_chips(irq);
514 for (chip, pin) in chips {
515 match chip {
516 IrqSourceChip::PicPrimary | IrqSourceChip::PicSecondary => {
517 self.pic.lock().service_irq(pin as u8, level);
518 }
519 IrqSourceChip::Ioapic => {
520 self.ioapic.lock().service_irq(pin as usize, level);
521 }
522 _ => {}
523 }
524 }
525 Ok(())
526 }
527
528 fn service_irq_event(&self, event_index: IrqEventIndex) -> Result<()> {
537 if let Some(evt) = &self.irq_events.lock()[event_index] {
538 evt.event.wait()?;
539 let chips = self.routes_to_chips(evt.gsi);
540
541 for (chip, pin) in chips {
542 match chip {
543 IrqSourceChip::PicPrimary | IrqSourceChip::PicSecondary => {
544 let mut pic = self.pic.lock();
545 pic.service_irq(pin as u8, true);
546 if evt.resample_event.is_none() {
547 pic.service_irq(pin as u8, false);
548 }
549 }
550 IrqSourceChip::Ioapic => {
551 if let Ok(mut ioapic) = self.ioapic.try_lock() {
552 ioapic.service_irq(pin as usize, true);
553 if evt.resample_event.is_none() {
554 ioapic.service_irq(pin as usize, false);
555 }
556 } else {
557 self.delayed_ioapic_irq_events.lock().push(event_index);
558 self.delayed_ioapic_irq_trigger.signal().unwrap();
559 }
560 }
561 _ => {}
562 }
563 }
564 }
565
566 Ok(())
567 }
568
569 fn broadcast_eoi(&self, vector: u8) -> Result<()> {
571 self.ioapic.lock().end_of_interrupt(vector);
572 Ok(())
573 }
574
575 fn inject_interrupts(&self, vcpu: &dyn VcpuArch) -> Result<()> {
578 let vcpu: &KvmVcpu = <dyn Any>::downcast_ref(vcpu)
579 .expect("KvmSplitIrqChip::add_vcpu called with non-KvmVcpu");
580
581 let vcpu_id = vcpu.id();
582 if !self.interrupt_requested(vcpu_id) || !vcpu.ready_for_interrupt() {
583 return Ok(());
584 }
585
586 if let Some(vector) = self.get_external_interrupt(vcpu_id) {
587 vcpu.interrupt(vector)?;
588 }
589
590 if self.interrupt_requested(vcpu_id) {
593 vcpu.set_interrupt_window_requested(true);
594 }
595 Ok(())
596 }
597
598 fn halted(&self, _vcpu_id: usize) {}
601
602 fn wait_until_runnable(&self, _vcpu: &dyn VcpuArch) -> Result<VcpuRunState> {
608 Ok(VcpuRunState::Runnable)
609 }
610
611 fn kick_halted_vcpus(&self) {}
614
615 fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState> {
617 match self.vcpus.lock().get(vcpu_id) {
618 Some(Some(vcpu)) => Ok(MPState::from(&vcpu.get_mp_state()?)),
619 _ => Err(Error::new(libc::ENOENT)),
620 }
621 }
622
623 fn set_mp_state(&self, vcpu_id: usize, state: &MPState) -> Result<()> {
625 match self.vcpus.lock().get(vcpu_id) {
626 Some(Some(vcpu)) => vcpu.set_mp_state(&kvm_mp_state::from(state)),
627 _ => Err(Error::new(libc::ENOENT)),
628 }
629 }
630
631 fn finalize_devices(
634 self: Arc<Self>,
635 resources: &mut SystemAllocator,
636 io_bus: &Bus,
637 mmio_bus: &Bus,
638 ) -> Result<()> {
639 io_bus.insert(self.pit.clone(), 0x040, 0x8).unwrap();
641 io_bus.insert(self.pit.clone(), 0x061, 0x1).unwrap();
642
643 io_bus.insert(self.pic.clone(), 0x20, 0x2).unwrap();
645 io_bus.insert(self.pic.clone(), 0xa0, 0x2).unwrap();
646 io_bus.insert(self.pic.clone(), 0x4d0, 0x2).unwrap();
647
648 mmio_bus
650 .insert(
651 self.ioapic.clone(),
652 IOAPIC_BASE_ADDRESS,
653 IOAPIC_MEM_LENGTH_BYTES,
654 )
655 .unwrap();
656
657 let mut ioapic_resample_events: Vec<Vec<Event>> =
660 (0..self.ioapic_pins).map(|_| Vec::new()).collect();
661 let mut pic_resample_events: Vec<Vec<Event>> =
662 (0..self.ioapic_pins).map(|_| Vec::new()).collect();
663
664 for evt in self.irq_events.lock().iter().flatten() {
665 if (evt.gsi as usize) >= self.ioapic_pins {
666 continue;
667 }
668 if let Some(resample_evt) = &evt.resample_event {
669 ioapic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?);
670 pic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?);
671 }
672 }
673
674 self.ioapic
676 .lock()
677 .register_resample_events(ioapic_resample_events);
678 self.pic
680 .lock()
681 .register_resample_events(pic_resample_events);
682
683 let mut irq_num = resources.allocate_irq().unwrap();
685 while irq_num < self.ioapic_pins as u32 {
686 irq_num = resources.allocate_irq().unwrap();
687 }
688
689 Ok(())
690 }
691
692 fn process_delayed_irq_events(&self) -> Result<()> {
700 self.delayed_ioapic_irq_events
701 .lock()
702 .retain(|&event_index| {
703 if let Some(evt) = &self.irq_events.lock()[event_index] {
704 if let Ok(mut ioapic) = self.ioapic.try_lock() {
705 ioapic.service_irq(evt.gsi as usize, true);
706 if evt.resample_event.is_none() {
707 ioapic.service_irq(evt.gsi as usize, false);
708 }
709
710 false
711 } else {
712 true
713 }
714 } else {
715 true
716 }
717 });
718
719 if self.delayed_ioapic_irq_events.lock().is_empty() {
720 self.delayed_ioapic_irq_trigger.wait()?;
721 }
722
723 Ok(())
724 }
725
726 fn irq_delayed_event_token(&self) -> Result<Option<Event>> {
727 Ok(Some(self.delayed_ioapic_irq_trigger.try_clone()?))
728 }
729
730 fn check_capability(&self, c: IrqChipCap) -> bool {
731 match c {
732 IrqChipCap::TscDeadlineTimer => self.vm.check_raw_capability(KvmCap::TscDeadlineTimer),
733 IrqChipCap::X2Apic => true,
734 IrqChipCap::MpStateGetSet => true,
735 }
736 }
737}
738
739#[derive(Serialize, Deserialize)]
740struct KvmSplitIrqChipSnapshot {
741 routes: Vec<IrqRoute>,
742}
743
744impl IrqChipX86_64 for KvmSplitIrqChip {
745 fn get_pic_state(&self, select: PicSelect) -> Result<PicState> {
747 Ok(self.pic.lock().get_pic_state(select))
748 }
749
750 fn set_pic_state(&self, select: PicSelect, state: &PicState) -> Result<()> {
752 self.pic.lock().set_pic_state(select, state);
753 Ok(())
754 }
755
756 fn get_ioapic_state(&self) -> Result<IoapicState> {
758 Ok(self.ioapic.lock().get_ioapic_state())
759 }
760
761 fn set_ioapic_state(&self, state: &IoapicState) -> Result<()> {
763 self.ioapic.lock().set_ioapic_state(state);
764 Ok(())
765 }
766
767 fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState> {
769 match self.vcpus.lock().get(vcpu_id) {
770 Some(Some(vcpu)) => Ok(LapicState::from(&vcpu.get_lapic()?)),
771 _ => Err(Error::new(libc::ENOENT)),
772 }
773 }
774
775 fn set_lapic_state(&self, vcpu_id: usize, state: &LapicState) -> Result<()> {
777 match self.vcpus.lock().get(vcpu_id) {
778 Some(Some(vcpu)) => vcpu.set_lapic(&kvm_lapic_state::from(state)),
779 _ => Err(Error::new(libc::ENOENT)),
780 }
781 }
782
783 fn lapic_frequency(&self) -> u32 {
785 1_000_000_000
787 }
788
789 fn get_pit(&self) -> Result<PitState> {
791 Ok(self.pit.lock().get_pit_state())
792 }
793
794 fn set_pit(&self, state: &PitState) -> Result<()> {
796 self.pit.lock().set_pit_state(state);
797 Ok(())
798 }
799
800 fn pit_uses_speaker_port(&self) -> bool {
803 true
804 }
805
806 fn snapshot_chip_specific(&self) -> anyhow::Result<AnySnapshot> {
807 AnySnapshot::to_any(KvmSplitIrqChipSnapshot {
808 routes: self.routes.lock().clone(),
809 })
810 .context("failed to serialize KvmSplitIrqChip")
811 }
812
813 fn restore_chip_specific(&self, data: AnySnapshot) -> anyhow::Result<()> {
814 let deser: KvmSplitIrqChipSnapshot =
815 AnySnapshot::from_any(data).context("failed to deserialize KvmSplitIrqChip")?;
816 self.set_irq_routes(&deser.routes)?;
817 Ok(())
818 }
819}