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