Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/tests/irqchip/userspace.rs
5394 views
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::DestinationShorthand;
22
use devices::Interrupt;
23
use devices::InterruptData;
24
use devices::InterruptDestination;
25
use devices::IrqChip;
26
use devices::IrqChipX86_64;
27
use devices::IrqEdgeEvent;
28
use devices::IrqEventSource;
29
use devices::IrqLevelEvent;
30
use devices::UserspaceIrqChip;
31
use devices::VcpuRunState;
32
use devices::APIC_BASE_ADDRESS;
33
use devices::IOAPIC_BASE_ADDRESS;
34
use hypervisor::CpuId;
35
use hypervisor::CpuIdEntry;
36
use hypervisor::DebugRegs;
37
use hypervisor::DeliveryMode;
38
use hypervisor::DestinationMode;
39
use hypervisor::Fpu;
40
use hypervisor::IoParams;
41
use hypervisor::IoapicRedirectionTableEntry;
42
use hypervisor::IrqRoute;
43
use hypervisor::IrqSource;
44
use hypervisor::Level;
45
use hypervisor::PicSelect;
46
use hypervisor::PitRWMode;
47
use hypervisor::Regs;
48
use hypervisor::Sregs;
49
use hypervisor::TriggerMode;
50
use hypervisor::Vcpu;
51
use hypervisor::VcpuExit;
52
use hypervisor::VcpuSnapshot;
53
use hypervisor::VcpuX86_64;
54
use hypervisor::Xsave;
55
use resources::AddressRange;
56
use resources::SystemAllocator;
57
use resources::SystemAllocatorConfig;
58
use snapshot::AnySnapshot;
59
use sync::Mutex;
60
use vm_control::DeviceId;
61
use vm_control::PlatformDeviceId;
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.
77
fn get_chip(num_vcpus: usize) -> UserspaceIrqChip<FakeVcpu> {
78
get_chip_with_clock(num_vcpus, Arc::new(Mutex::new(Clock::new())))
79
}
80
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.
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]
110
fn set_pic() {
111
test_set_pic(get_chip(1));
112
}
113
114
#[test]
115
fn get_ioapic() {
116
test_get_ioapic(get_chip(1));
117
}
118
119
#[test]
120
fn set_ioapic() {
121
test_set_ioapic(get_chip(1));
122
}
123
124
#[test]
125
fn get_pit() {
126
test_get_pit(get_chip(1));
127
}
128
129
#[test]
130
fn set_pit() {
131
test_set_pit(get_chip(1));
132
}
133
134
#[test]
135
fn route_irq() {
136
test_route_irq(get_chip(1));
137
}
138
139
#[test]
140
fn pit_uses_speaker_port() {
141
let chip = get_chip(1);
142
assert!(chip.pit_uses_speaker_port());
143
}
144
145
#[test]
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]
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: PlatformDeviceId::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(PlatformDeviceId::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]
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: PlatformDeviceId::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]
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]
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: PlatformDeviceId::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]
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]
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: PlatformDeviceId::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]
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"]
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"]
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`.
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`.
639
fn window_requested(&self) -> bool {
640
*self.requested.lock()
641
}
642
643
/// Sets the value to be returned by `ready_for_interrupt`.
644
fn set_ready(&self, val: bool) {
645
*self.ready.lock() = val;
646
}
647
}
648
649
impl Vcpu for FakeVcpu {
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
659
fn id(&self) -> usize {
660
self.id
661
}
662
663
fn as_vcpu(&self) -> &dyn Vcpu {
664
self
665
}
666
667
fn run(&mut self) -> Result<VcpuExit> {
668
unimplemented!()
669
}
670
671
fn set_immediate_exit(&self, _exit: bool) {}
672
673
#[cfg(any(target_os = "android", target_os = "linux"))]
674
fn signal_handle(&self) -> hypervisor::VcpuSignalHandle {
675
unimplemented!()
676
}
677
678
fn handle_mmio(&self, _handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()> {
679
unimplemented!()
680
}
681
fn handle_io(&self, _handle_fn: &mut dyn FnMut(IoParams)) -> Result<()> {
682
unimplemented!()
683
}
684
fn on_suspend(&self) -> Result<()> {
685
unimplemented!()
686
}
687
unsafe fn enable_raw_capability(&self, _cap: u32, _args: &[u64; 4]) -> Result<()> {
688
unimplemented!()
689
}
690
}
691
692
impl VcpuX86_64 for FakeVcpu {
693
fn set_interrupt_window_requested(&self, requested: bool) {
694
*self.requested.lock() = requested;
695
}
696
697
fn ready_for_interrupt(&self) -> bool {
698
*self.ready.lock()
699
}
700
701
fn interrupt(&self, irq: u8) -> Result<()> {
702
*self.injected.lock() = Some(irq);
703
Ok(())
704
}
705
706
fn inject_nmi(&self) -> Result<()> {
707
Ok(())
708
}
709
710
fn get_regs(&self) -> Result<Regs> {
711
unimplemented!()
712
}
713
fn set_regs(&self, _regs: &Regs) -> Result<()> {
714
unimplemented!()
715
}
716
fn get_sregs(&self) -> Result<Sregs> {
717
unimplemented!()
718
}
719
fn set_sregs(&self, _sregs: &Sregs) -> Result<()> {
720
unimplemented!()
721
}
722
fn get_fpu(&self) -> Result<Fpu> {
723
unimplemented!()
724
}
725
fn set_fpu(&self, _fpu: &Fpu) -> Result<()> {
726
unimplemented!()
727
}
728
fn get_xsave(&self) -> Result<Xsave> {
729
unimplemented!()
730
}
731
fn set_xsave(&self, _xsave: &Xsave) -> Result<()> {
732
unimplemented!()
733
}
734
fn get_hypervisor_specific_state(&self) -> Result<AnySnapshot> {
735
unimplemented!()
736
}
737
fn set_hypervisor_specific_state(&self, _data: AnySnapshot) -> Result<()> {
738
unimplemented!()
739
}
740
fn get_debugregs(&self) -> Result<DebugRegs> {
741
unimplemented!()
742
}
743
fn set_debugregs(&self, _debugregs: &DebugRegs) -> Result<()> {
744
unimplemented!()
745
}
746
fn get_xcrs(&self) -> Result<BTreeMap<u32, u64>> {
747
unimplemented!()
748
}
749
fn set_xcr(&self, _xcr_index: u32, _value: u64) -> Result<()> {
750
unimplemented!()
751
}
752
fn get_msr(&self, _msr_index: u32) -> Result<u64> {
753
unimplemented!()
754
}
755
fn get_all_msrs(&self) -> Result<BTreeMap<u32, u64>> {
756
unimplemented!()
757
}
758
fn set_msr(&self, _msr_index: u32, _value: u64) -> Result<()> {
759
unimplemented!()
760
}
761
fn set_cpuid(&self, _cpuid: &CpuId) -> Result<()> {
762
unimplemented!()
763
}
764
fn handle_cpuid(&mut self, _entry: &CpuIdEntry) -> Result<()> {
765
unimplemented!()
766
}
767
fn set_guest_debug(&self, _addrs: &[GuestAddress], _enable_singlestep: bool) -> Result<()> {
768
unimplemented!()
769
}
770
fn snapshot(&self) -> anyhow::Result<VcpuSnapshot> {
771
unimplemented!()
772
}
773
fn restore(
774
&mut self,
775
_snapshot: &VcpuSnapshot,
776
_host_tsc_reference_moment: u64,
777
) -> anyhow::Result<()> {
778
unimplemented!()
779
}
780
fn restore_timekeeping(&self, _host_tsc_reference_moment: u64, _tsc_offset: u64) -> Result<()> {
781
unimplemented!()
782
}
783
}
784
785