1 // Copyright 2022 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 #![cfg(target_arch = "x86_64")]
6
7 use std::collections::BTreeMap;
8 use std::sync::Arc;
9 use std::thread;
10 use std::time::Duration;
11 use std::time::Instant;
12
13 use base::Clock;
14 use base::EventWaitResult;
15 use base::Result;
16 use base::Tube;
17 use devices::Bus;
18 use devices::BusAccessInfo;
19 use devices::BusDeviceSync;
20 use devices::BusType;
21 use devices::CrosvmDeviceId;
22 use devices::DestinationShorthand;
23 use devices::DeviceId;
24 use devices::Interrupt;
25 use devices::InterruptData;
26 use devices::InterruptDestination;
27 use devices::IrqChip;
28 use devices::IrqChipX86_64;
29 use devices::IrqEdgeEvent;
30 use devices::IrqEventSource;
31 use devices::IrqLevelEvent;
32 use devices::UserspaceIrqChip;
33 use devices::VcpuRunState;
34 use devices::APIC_BASE_ADDRESS;
35 use devices::IOAPIC_BASE_ADDRESS;
36 use hypervisor::CpuId;
37 use hypervisor::CpuIdEntry;
38 use hypervisor::DebugRegs;
39 use hypervisor::DeliveryMode;
40 use hypervisor::DestinationMode;
41 use hypervisor::Fpu;
42 use hypervisor::IoParams;
43 use hypervisor::IoapicRedirectionTableEntry;
44 use hypervisor::IrqRoute;
45 use hypervisor::IrqSource;
46 use hypervisor::Level;
47 use hypervisor::PicSelect;
48 use hypervisor::PitRWMode;
49 use hypervisor::Regs;
50 use hypervisor::Sregs;
51 use hypervisor::TriggerMode;
52 use hypervisor::Vcpu;
53 use hypervisor::VcpuExit;
54 use hypervisor::VcpuSnapshot;
55 use hypervisor::VcpuX86_64;
56 use hypervisor::Xsave;
57 use resources::AddressRange;
58 use resources::SystemAllocator;
59 use resources::SystemAllocatorConfig;
60 use sync::Mutex;
61 use vm_memory::GuestAddress;
62
63 use crate::x86_64::test_get_ioapic;
64 use crate::x86_64::test_get_pit;
65 use crate::x86_64::test_route_irq;
66 use crate::x86_64::test_set_ioapic;
67 use crate::x86_64::test_set_pic;
68 use crate::x86_64::test_set_pit;
69
70 const APIC_ID: u64 = 0x20;
71 const TPR: u64 = 0x80;
72 const EOI: u64 = 0xB0;
73 const TEST_SLEEP_DURATION: Duration = Duration::from_millis(50);
74
75 /// Helper function for setting up a UserspaceIrqChip.
get_chip(num_vcpus: usize) -> UserspaceIrqChip<FakeVcpu>76 fn get_chip(num_vcpus: usize) -> UserspaceIrqChip<FakeVcpu> {
77 get_chip_with_clock(num_vcpus, Arc::new(Mutex::new(Clock::new())))
78 }
79
get_chip_with_clock(num_vcpus: usize, clock: Arc<Mutex<Clock>>) -> UserspaceIrqChip<FakeVcpu>80 fn get_chip_with_clock(num_vcpus: usize, clock: Arc<Mutex<Clock>>) -> UserspaceIrqChip<FakeVcpu> {
81 let (_, irq_tube) = Tube::pair().unwrap();
82 let mut chip = UserspaceIrqChip::<FakeVcpu>::new_with_clock(num_vcpus, irq_tube, None, clock)
83 .expect("failed to instantiate UserspaceIrqChip");
84
85 for i in 0..num_vcpus {
86 let vcpu = FakeVcpu {
87 id: i,
88 requested: Arc::new(Mutex::new(false)),
89 ready: Arc::new(Mutex::new(true)),
90 injected: Arc::new(Mutex::new(None)),
91 };
92 chip.add_vcpu(i, &vcpu).expect("failed to add vcpu");
93 chip.apics[i].lock().set_enabled(true);
94 }
95
96 chip
97 }
98
99 /// Helper function for cloning vcpus from a UserspaceIrqChip.
get_vcpus(chip: &UserspaceIrqChip<FakeVcpu>) -> Vec<FakeVcpu>100 fn get_vcpus(chip: &UserspaceIrqChip<FakeVcpu>) -> Vec<FakeVcpu> {
101 chip.vcpus
102 .lock()
103 .iter()
104 .map(|v| v.as_ref().unwrap().try_clone().unwrap())
105 .collect()
106 }
107
108 #[test]
set_pic()109 fn set_pic() {
110 test_set_pic(get_chip(1));
111 }
112
113 #[test]
get_ioapic()114 fn get_ioapic() {
115 test_get_ioapic(get_chip(1));
116 }
117
118 #[test]
set_ioapic()119 fn set_ioapic() {
120 test_set_ioapic(get_chip(1));
121 }
122
123 #[test]
get_pit()124 fn get_pit() {
125 test_get_pit(get_chip(1));
126 }
127
128 #[test]
set_pit()129 fn set_pit() {
130 test_set_pit(get_chip(1));
131 }
132
133 #[test]
route_irq()134 fn route_irq() {
135 test_route_irq(get_chip(1));
136 }
137
138 #[test]
pit_uses_speaker_port()139 fn pit_uses_speaker_port() {
140 let chip = get_chip(1);
141 assert!(chip.pit_uses_speaker_port());
142 }
143
144 #[test]
routes_conflict()145 fn routes_conflict() {
146 let mut chip = get_chip(1);
147 chip.route_irq(IrqRoute {
148 gsi: 32,
149 source: IrqSource::Msi {
150 address: 4276092928,
151 data: 0,
152 },
153 })
154 .expect("failed to set msi rout");
155 // this second route should replace the first
156 chip.route_irq(IrqRoute {
157 gsi: 32,
158 source: IrqSource::Msi {
159 address: 4276092928,
160 data: 32801,
161 },
162 })
163 .expect("failed to set msi rout");
164 }
165
166 #[test]
irq_event_tokens()167 fn irq_event_tokens() {
168 let mut chip = get_chip(1);
169 let tokens = chip
170 .irq_event_tokens()
171 .expect("could not get irq_event_tokens");
172
173 // there should be one token on a fresh split irqchip, for the pit
174 assert_eq!(tokens.len(), 1);
175 assert_eq!(tokens[0].1.device_name, "userspace PIT");
176
177 // register another irq event
178 let evt = IrqEdgeEvent::new().expect("failed to create eventfd");
179 let source = IrqEventSource {
180 device_id: CrosvmDeviceId::Cmos.into(),
181 queue_id: 0,
182 device_name: "test".to_owned(),
183 };
184 chip.register_edge_irq_event(6, &evt, source)
185 .expect("failed to register irq event");
186
187 let tokens = chip
188 .irq_event_tokens()
189 .expect("could not get irq_event_tokens");
190
191 // now there should be two tokens
192 assert_eq!(tokens.len(), 2);
193 assert_eq!(tokens[0].1.device_name, "userspace PIT");
194 assert_eq!(
195 tokens[1].1.device_id,
196 DeviceId::PlatformDeviceId(CrosvmDeviceId::Cmos)
197 );
198 assert_eq!(tokens[1].2, evt.get_trigger().try_clone().unwrap());
199 }
200
201 // TODO(srichman): Factor out of UserspaceIrqChip and KvmSplitIrqChip.
202 #[test]
finalize_devices()203 fn finalize_devices() {
204 let mut chip = get_chip(1);
205
206 let mmio_bus = Bus::new(BusType::Mmio);
207 let io_bus = Bus::new(BusType::Io);
208 let mut resources = SystemAllocator::new(
209 SystemAllocatorConfig {
210 io: Some(AddressRange {
211 start: 0xc000,
212 end: 0xFFFF,
213 }),
214 low_mmio: AddressRange {
215 start: 0,
216 end: 2047,
217 },
218 high_mmio: AddressRange {
219 start: 2048,
220 end: 6143,
221 },
222 platform_mmio: None,
223 first_irq: 5,
224 },
225 None,
226 &[],
227 )
228 .expect("failed to create SystemAllocator");
229
230 // Setup an event and a resample event for irq line 1.
231 let evt = IrqLevelEvent::new().expect("failed to create event");
232
233 let source = IrqEventSource {
234 device_id: CrosvmDeviceId::Cmos.into(),
235 device_name: "test".to_owned(),
236 queue_id: 0,
237 };
238
239 let evt_index = chip
240 .register_level_irq_event(1, &evt, source)
241 .expect("failed to register_level_irq_event")
242 .expect("register_level_irq_event should not return None");
243
244 // Once we finalize devices, the pic/pit/ioapic should be attached to io and mmio busses.
245 chip.finalize_devices(&mut resources, &io_bus, &mmio_bus)
246 .expect("failed to finalize devices");
247
248 // Should not be able to allocate an irq < 24 now.
249 assert!(resources.allocate_irq().expect("failed to allocate irq") >= 24);
250
251 // Set PIT counter 2 to "SquareWaveGen" (aka 3) mode and "Both" access mode.
252 io_bus.write(0x43, &[0b10110110]);
253
254 let state = chip.get_pit().expect("failed to get pit state");
255 assert_eq!(state.channels[2].mode, 3);
256 assert_eq!(state.channels[2].rw_mode, PitRWMode::Both);
257
258 // ICW1 0x11: Edge trigger, cascade mode, ICW4 needed.
259 // ICW2 0x08: Interrupt vector base address 0x08.
260 // ICW3 0xff: Value written does not matter.
261 // ICW4 0x13: Special fully nested mode, auto EOI.
262 io_bus.write(0x20, &[0x11]);
263 io_bus.write(0x21, &[0x08]);
264 io_bus.write(0x21, &[0xff]);
265 io_bus.write(0x21, &[0x13]);
266
267 let state = chip
268 .get_pic_state(PicSelect::Primary)
269 .expect("failed to get pic state");
270
271 // Auto eoi and special fully nested mode should be turned on.
272 assert!(state.auto_eoi);
273 assert!(state.special_fully_nested_mode);
274
275 // Need to write to the irq event before servicing it.
276 evt.trigger().expect("failed to write to eventfd");
277
278 // If we assert irq line one, and then get the resulting interrupt, an auto-eoi should occur
279 // and cause the resample_event to be written to.
280 chip.service_irq_event(evt_index)
281 .expect("failed to service irq");
282
283 let vcpu = get_vcpus(&chip).remove(0);
284 chip.inject_interrupts(&vcpu).unwrap();
285 assert_eq!(
286 vcpu.clear_injected(),
287 // Vector is 9 because the interrupt vector base address is 0x08 and this is irq line 1
288 // and 8+1 = 9.
289 Some(0x9)
290 );
291
292 assert_eq!(
293 evt.get_resample()
294 .wait_timeout(std::time::Duration::from_secs(1))
295 .expect("failed to read_timeout"),
296 EventWaitResult::Signaled
297 );
298
299 // Setup a ioapic redirection table entry 14.
300 let mut entry = IoapicRedirectionTableEntry::default();
301 entry.set_vector(44);
302
303 let irq_14_offset = 0x10 + 14 * 2;
304 mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_14_offset]);
305 mmio_bus.write(
306 IOAPIC_BASE_ADDRESS + 0x10,
307 &(entry.get(0, 32) as u32).to_ne_bytes(),
308 );
309 mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_14_offset + 1]);
310 mmio_bus.write(
311 IOAPIC_BASE_ADDRESS + 0x10,
312 &(entry.get(32, 32) as u32).to_ne_bytes(),
313 );
314
315 let state = chip.get_ioapic_state().expect("failed to get ioapic state");
316
317 // Redirection table entry 14 should have a vector of 44.
318 assert_eq!(state.redirect_table[14].get_vector(), 44);
319 }
320
321 #[test]
inject_pic_interrupt()322 fn inject_pic_interrupt() {
323 let mut chip = get_chip(2);
324 let vcpus = get_vcpus(&chip);
325
326 assert_eq!(vcpus[0].clear_injected(), None);
327 assert_eq!(vcpus[1].clear_injected(), None);
328
329 chip.service_irq(0, true).expect("failed to service irq");
330
331 // Should not inject PIC interrupt for vcpu_id != 0.
332 chip.inject_interrupts(&vcpus[1]).unwrap();
333 assert_eq!(vcpus[1].clear_injected(), None);
334
335 // Should inject Some interrupt.
336 chip.inject_interrupts(&vcpus[0]).unwrap();
337 assert_eq!(vcpus[0].clear_injected(), Some(0));
338
339 // Interrupt is not injected twice.
340 chip.inject_interrupts(&vcpus[0]).unwrap();
341 assert_eq!(vcpus[0].clear_injected(), None);
342 }
343
344 #[test]
inject_msi()345 fn inject_msi() {
346 let mut chip = get_chip(2);
347 let vcpus = get_vcpus(&chip);
348
349 let evt = IrqEdgeEvent::new().unwrap();
350 let source = IrqEventSource {
351 device_id: CrosvmDeviceId::Cmos.into(),
352 device_name: "test".to_owned(),
353 queue_id: 0,
354 };
355 let event_idx = chip
356 .register_edge_irq_event(30, &evt, source)
357 .unwrap()
358 .unwrap();
359 chip.route_irq(IrqRoute {
360 gsi: 30,
361 source: IrqSource::Msi {
362 address: 0xFEE01000, // physical addressing, send to apic 1
363 data: 0x000000F1, // edge-triggered, fixed interrupt, vector 0xF1
364 },
365 })
366 .unwrap();
367 evt.trigger().unwrap();
368
369 assert!(!vcpus[0].window_requested());
370 assert!(!vcpus[1].window_requested());
371 chip.service_irq_event(event_idx).unwrap();
372 assert!(!vcpus[0].window_requested());
373 assert!(vcpus[1].window_requested());
374
375 chip.inject_interrupts(&vcpus[0]).unwrap();
376 assert_eq!(vcpus[0].clear_injected(), None);
377
378 vcpus[1].set_ready(false);
379 chip.inject_interrupts(&vcpus[1]).unwrap();
380 assert_eq!(vcpus[1].clear_injected(), None);
381 vcpus[1].set_ready(true);
382 chip.inject_interrupts(&vcpus[1]).unwrap();
383 assert_eq!(vcpus[1].clear_injected(), Some(0xF1));
384 assert!(!vcpus[1].window_requested());
385 }
386
387 #[test]
lowest_priority_destination()388 fn lowest_priority_destination() {
389 let chip = get_chip(2);
390 let vcpus = get_vcpus(&chip);
391
392 // Make vcpu 0 higher priority.
393 chip.write(
394 BusAccessInfo {
395 id: 0,
396 address: APIC_BASE_ADDRESS + TPR,
397 offset: TPR,
398 },
399 &[0x10, 0, 0, 0],
400 );
401 chip.send_irq_to_apics(&Interrupt {
402 dest: InterruptDestination {
403 source_id: 0,
404 dest_id: 0,
405 shorthand: DestinationShorthand::All,
406 mode: DestinationMode::Physical,
407 },
408 data: InterruptData {
409 vector: 111,
410 delivery: DeliveryMode::Lowest,
411 trigger: TriggerMode::Edge,
412 level: Level::Deassert,
413 },
414 });
415 chip.inject_interrupts(&vcpus[0]).unwrap();
416 chip.inject_interrupts(&vcpus[1]).unwrap();
417 assert_eq!(vcpus[0].clear_injected(), None);
418 assert_eq!(vcpus[1].clear_injected(), Some(111));
419 chip.write(
420 BusAccessInfo {
421 id: 1,
422 address: APIC_BASE_ADDRESS + EOI,
423 offset: EOI,
424 },
425 &[0, 0, 0, 0],
426 );
427
428 // Make vcpu 1 higher priority.
429 chip.write(
430 BusAccessInfo {
431 id: 1,
432 address: APIC_BASE_ADDRESS + TPR,
433 offset: TPR,
434 },
435 &[0x20, 0, 0, 0],
436 );
437 chip.send_irq_to_apics(&Interrupt {
438 dest: InterruptDestination {
439 source_id: 0,
440 dest_id: 0,
441 shorthand: DestinationShorthand::All,
442 mode: DestinationMode::Physical,
443 },
444 data: InterruptData {
445 vector: 222,
446 delivery: DeliveryMode::Lowest,
447 trigger: TriggerMode::Edge,
448 level: Level::Deassert,
449 },
450 });
451 chip.inject_interrupts(&vcpus[0]).unwrap();
452 chip.inject_interrupts(&vcpus[1]).unwrap();
453 assert_eq!(vcpus[0].clear_injected(), Some(222));
454 assert_eq!(vcpus[1].clear_injected(), None);
455 }
456
457 // TODO(srichman): Factor out of UserspaceIrqChip and KvmSplitIrqChip.
458 #[test]
broadcast_eoi()459 fn broadcast_eoi() {
460 let mut chip = get_chip(1);
461
462 let mmio_bus = Bus::new(BusType::Mmio);
463 let io_bus = Bus::new(BusType::Io);
464 let mut resources = SystemAllocator::new(
465 SystemAllocatorConfig {
466 io: Some(AddressRange {
467 start: 0xc000,
468 end: 0xFFFF,
469 }),
470 low_mmio: AddressRange {
471 start: 0,
472 end: 2047,
473 },
474 high_mmio: AddressRange {
475 start: 2048,
476 end: 6143,
477 },
478 platform_mmio: None,
479 first_irq: 5,
480 },
481 None,
482 &[],
483 )
484 .expect("failed to create SystemAllocator");
485
486 // setup an event for irq line 1
487 let evt = IrqLevelEvent::new().expect("failed to create event");
488
489 let source = IrqEventSource {
490 device_id: CrosvmDeviceId::Cmos.into(),
491 device_name: "test".to_owned(),
492 queue_id: 0,
493 };
494
495 chip.register_level_irq_event(1, &evt, source)
496 .expect("failed to register_level_irq_event");
497
498 // Once we finalize devices, the pic/pit/ioapic should be attached to io and mmio busses
499 chip.finalize_devices(&mut resources, &io_bus, &mmio_bus)
500 .expect("failed to finalize devices");
501
502 // setup a ioapic redirection table entry 1 with a vector of 123
503 let mut entry = IoapicRedirectionTableEntry::default();
504 entry.set_vector(123);
505 entry.set_trigger_mode(TriggerMode::Level);
506
507 let irq_write_offset = 0x10 + 1 * 2;
508 mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_write_offset]);
509 mmio_bus.write(
510 IOAPIC_BASE_ADDRESS + 0x10,
511 &(entry.get(0, 32) as u32).to_ne_bytes(),
512 );
513 mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_write_offset + 1]);
514 mmio_bus.write(
515 IOAPIC_BASE_ADDRESS + 0x10,
516 &(entry.get(32, 32) as u32).to_ne_bytes(),
517 );
518
519 // Assert line 1
520 chip.service_irq(1, true).expect("failed to service irq");
521
522 // resample event should not be written to
523 assert_eq!(
524 evt.get_resample()
525 .wait_timeout(std::time::Duration::from_millis(10))
526 .expect("failed to read_timeout"),
527 EventWaitResult::TimedOut
528 );
529
530 // irq line 1 should be asserted
531 let state = chip.get_ioapic_state().expect("failed to get ioapic state");
532 assert_eq!(state.current_interrupt_level_bitmap, 1 << 1);
533
534 // Now broadcast an eoi for vector 123
535 chip.broadcast_eoi(123).expect("failed to broadcast eoi");
536
537 // irq line 1 should be deasserted
538 let state = chip.get_ioapic_state().expect("failed to get ioapic state");
539 assert_eq!(state.current_interrupt_level_bitmap, 0);
540
541 // resample event should be written to by ioapic
542 assert_eq!(
543 evt.get_resample()
544 .wait_timeout(std::time::Duration::from_millis(10))
545 .expect("failed to read_timeout"),
546 EventWaitResult::Signaled
547 );
548 }
549
550 #[test]
apic_mmio()551 fn apic_mmio() {
552 let chip = get_chip(2);
553 let mut data = [0u8; 4];
554 chip.read(
555 BusAccessInfo {
556 id: 0,
557 address: APIC_BASE_ADDRESS + APIC_ID,
558 offset: APIC_ID,
559 },
560 &mut data,
561 );
562 assert_eq!(data, [0, 0, 0, 0]);
563 chip.read(
564 BusAccessInfo {
565 id: 1,
566 address: APIC_BASE_ADDRESS + APIC_ID,
567 offset: APIC_ID,
568 },
569 &mut data,
570 );
571 assert_eq!(data, [0, 0, 0, 1]);
572 }
573
574 #[test]
575 #[ignore = "TODO(b/237977699): remove reliance on sleep"]
runnable_vcpu_unhalts()576 fn runnable_vcpu_unhalts() {
577 let chip = get_chip(1);
578 let vcpu = get_vcpus(&chip).remove(0);
579 let chip_copy = chip.try_clone().unwrap();
580 // BSP starts runnable.
581 assert_eq!(chip.wait_until_runnable(&vcpu), Ok(VcpuRunState::Runnable));
582 let start = Instant::now();
583 let handle = thread::spawn(move || {
584 thread::sleep(TEST_SLEEP_DURATION);
585 chip_copy.send_irq_to_apic(
586 0,
587 &InterruptData {
588 vector: 123,
589 delivery: DeliveryMode::Fixed,
590 trigger: TriggerMode::Level,
591 level: Level::Assert,
592 },
593 );
594 });
595 chip.halted(0);
596 assert_eq!(chip.wait_until_runnable(&vcpu), Ok(VcpuRunState::Runnable));
597 assert!(Instant::now() - start > Duration::from_millis(5));
598 handle.join().unwrap();
599 }
600
601 #[test]
602 #[ignore = "TODO(b/237977699): remove reliance on sleep"]
kicked_vcpu_unhalts()603 fn kicked_vcpu_unhalts() {
604 let chip = get_chip(1);
605 let vcpu = get_vcpus(&chip).remove(0);
606 let chip_copy = chip.try_clone().unwrap();
607 // BSP starts runnable.
608 assert_eq!(chip.wait_until_runnable(&vcpu), Ok(VcpuRunState::Runnable));
609 let start = Instant::now();
610 let handle = thread::spawn(move || {
611 thread::sleep(TEST_SLEEP_DURATION);
612 chip_copy.kick_halted_vcpus();
613 });
614 chip.halted(0);
615 assert_eq!(
616 chip.wait_until_runnable(&vcpu),
617 Ok(VcpuRunState::Interrupted)
618 );
619 assert!(Instant::now() - start > Duration::from_millis(5));
620 handle.join().unwrap();
621 }
622
623 /// Mock vcpu for testing interrupt injection.
624 struct FakeVcpu {
625 id: usize,
626 requested: Arc<Mutex<bool>>,
627 ready: Arc<Mutex<bool>>,
628 injected: Arc<Mutex<Option<u8>>>,
629 }
630
631 impl FakeVcpu {
632 /// Returns and clears the last interrupt set by `interrupt`.
clear_injected(&self) -> Option<u8>633 fn clear_injected(&self) -> Option<u8> {
634 self.injected.lock().take()
635 }
636
637 /// Returns true if an interrupt window was requested with `set_interrupt_window_requested`.
window_requested(&self) -> bool638 fn window_requested(&self) -> bool {
639 *self.requested.lock()
640 }
641
642 /// Sets the value to be returned by `ready_for_interrupt`.
set_ready(&self, val: bool)643 fn set_ready(&self, val: bool) {
644 *self.ready.lock() = val;
645 }
646 }
647
648 impl Vcpu for FakeVcpu {
try_clone(&self) -> Result<Self>649 fn try_clone(&self) -> Result<Self> {
650 Ok(FakeVcpu {
651 id: self.id,
652 requested: self.requested.clone(),
653 ready: self.ready.clone(),
654 injected: self.injected.clone(),
655 })
656 }
657
id(&self) -> usize658 fn id(&self) -> usize {
659 self.id
660 }
661
as_vcpu(&self) -> &dyn Vcpu662 fn as_vcpu(&self) -> &dyn Vcpu {
663 self
664 }
665
run(&mut self) -> Result<VcpuExit>666 fn run(&mut self) -> Result<VcpuExit> {
667 unimplemented!()
668 }
669
set_immediate_exit(&self, _exit: bool)670 fn set_immediate_exit(&self, _exit: bool) {}
671
672 #[cfg(any(target_os = "android", target_os = "linux"))]
signal_handle(&self) -> hypervisor::VcpuSignalHandle673 fn signal_handle(&self) -> hypervisor::VcpuSignalHandle {
674 unimplemented!()
675 }
676
handle_mmio(&self, _handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()>677 fn handle_mmio(&self, _handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()> {
678 unimplemented!()
679 }
handle_io(&self, _handle_fn: &mut dyn FnMut(IoParams)) -> Result<()>680 fn handle_io(&self, _handle_fn: &mut dyn FnMut(IoParams)) -> Result<()> {
681 unimplemented!()
682 }
on_suspend(&self) -> Result<()>683 fn on_suspend(&self) -> Result<()> {
684 unimplemented!()
685 }
enable_raw_capability(&self, _cap: u32, _args: &[u64; 4]) -> Result<()>686 unsafe fn enable_raw_capability(&self, _cap: u32, _args: &[u64; 4]) -> Result<()> {
687 unimplemented!()
688 }
689 }
690
691 impl VcpuX86_64 for FakeVcpu {
set_interrupt_window_requested(&self, requested: bool)692 fn set_interrupt_window_requested(&self, requested: bool) {
693 *self.requested.lock() = requested;
694 }
695
ready_for_interrupt(&self) -> bool696 fn ready_for_interrupt(&self) -> bool {
697 *self.ready.lock()
698 }
699
interrupt(&self, irq: u8) -> Result<()>700 fn interrupt(&self, irq: u8) -> Result<()> {
701 *self.injected.lock() = Some(irq);
702 Ok(())
703 }
704
inject_nmi(&self) -> Result<()>705 fn inject_nmi(&self) -> Result<()> {
706 Ok(())
707 }
708
get_regs(&self) -> Result<Regs>709 fn get_regs(&self) -> Result<Regs> {
710 unimplemented!()
711 }
set_regs(&self, _regs: &Regs) -> Result<()>712 fn set_regs(&self, _regs: &Regs) -> Result<()> {
713 unimplemented!()
714 }
get_sregs(&self) -> Result<Sregs>715 fn get_sregs(&self) -> Result<Sregs> {
716 unimplemented!()
717 }
set_sregs(&self, _sregs: &Sregs) -> Result<()>718 fn set_sregs(&self, _sregs: &Sregs) -> Result<()> {
719 unimplemented!()
720 }
get_fpu(&self) -> Result<Fpu>721 fn get_fpu(&self) -> Result<Fpu> {
722 unimplemented!()
723 }
set_fpu(&self, _fpu: &Fpu) -> Result<()>724 fn set_fpu(&self, _fpu: &Fpu) -> Result<()> {
725 unimplemented!()
726 }
get_xsave(&self) -> Result<Xsave>727 fn get_xsave(&self) -> Result<Xsave> {
728 unimplemented!()
729 }
set_xsave(&self, _xsave: &Xsave) -> Result<()>730 fn set_xsave(&self, _xsave: &Xsave) -> Result<()> {
731 unimplemented!()
732 }
get_interrupt_state(&self) -> Result<serde_json::Value>733 fn get_interrupt_state(&self) -> Result<serde_json::Value> {
734 unimplemented!()
735 }
set_interrupt_state(&self, _data: serde_json::Value) -> Result<()>736 fn set_interrupt_state(&self, _data: serde_json::Value) -> Result<()> {
737 unimplemented!()
738 }
get_debugregs(&self) -> Result<DebugRegs>739 fn get_debugregs(&self) -> Result<DebugRegs> {
740 unimplemented!()
741 }
set_debugregs(&self, _debugregs: &DebugRegs) -> Result<()>742 fn set_debugregs(&self, _debugregs: &DebugRegs) -> Result<()> {
743 unimplemented!()
744 }
get_xcrs(&self) -> Result<BTreeMap<u32, u64>>745 fn get_xcrs(&self) -> Result<BTreeMap<u32, u64>> {
746 unimplemented!()
747 }
set_xcr(&self, _xcr_index: u32, _value: u64) -> Result<()>748 fn set_xcr(&self, _xcr_index: u32, _value: u64) -> Result<()> {
749 unimplemented!()
750 }
get_msr(&self, _msr_index: u32) -> Result<u64>751 fn get_msr(&self, _msr_index: u32) -> Result<u64> {
752 unimplemented!()
753 }
get_all_msrs(&self) -> Result<BTreeMap<u32, u64>>754 fn get_all_msrs(&self) -> Result<BTreeMap<u32, u64>> {
755 unimplemented!()
756 }
set_msr(&self, _msr_index: u32, _value: u64) -> Result<()>757 fn set_msr(&self, _msr_index: u32, _value: u64) -> Result<()> {
758 unimplemented!()
759 }
set_cpuid(&self, _cpuid: &CpuId) -> Result<()>760 fn set_cpuid(&self, _cpuid: &CpuId) -> Result<()> {
761 unimplemented!()
762 }
handle_cpuid(&mut self, _entry: &CpuIdEntry) -> Result<()>763 fn handle_cpuid(&mut self, _entry: &CpuIdEntry) -> Result<()> {
764 unimplemented!()
765 }
set_guest_debug(&self, _addrs: &[GuestAddress], _enable_singlestep: bool) -> Result<()>766 fn set_guest_debug(&self, _addrs: &[GuestAddress], _enable_singlestep: bool) -> Result<()> {
767 unimplemented!()
768 }
snapshot(&self) -> anyhow::Result<VcpuSnapshot>769 fn snapshot(&self) -> anyhow::Result<VcpuSnapshot> {
770 unimplemented!()
771 }
restore( &mut self, _snapshot: &VcpuSnapshot, _host_tsc_reference_moment: u64, ) -> anyhow::Result<()>772 fn restore(
773 &mut self,
774 _snapshot: &VcpuSnapshot,
775 _host_tsc_reference_moment: u64,
776 ) -> anyhow::Result<()> {
777 unimplemented!()
778 }
restore_timekeeping(&self, _host_tsc_reference_moment: u64, _tsc_offset: u64) -> Result<()>779 fn restore_timekeeping(&self, _host_tsc_reference_moment: u64, _tsc_offset: u64) -> Result<()> {
780 unimplemented!()
781 }
782 }
783