Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/hypervisor/src/lib.rs
5394 views
1
// Copyright 2020 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
//! A crate for abstracting the underlying kernel hypervisor used in crosvm.
6
7
#[cfg(target_arch = "aarch64")]
8
pub mod aarch64;
9
pub mod caps;
10
#[cfg(all(unix, target_arch = "aarch64", feature = "geniezone"))]
11
pub mod geniezone;
12
#[cfg(all(unix, target_arch = "aarch64", feature = "gunyah"))]
13
pub mod gunyah;
14
#[cfg(target_arch = "aarch64")]
15
#[cfg(all(unix, target_arch = "aarch64", feature = "halla"))]
16
pub mod halla;
17
#[cfg(all(windows, feature = "haxm"))]
18
pub mod haxm;
19
#[cfg(any(target_os = "android", target_os = "linux"))]
20
pub mod kvm;
21
#[cfg(target_arch = "riscv64")]
22
pub mod riscv64;
23
#[cfg(all(windows, feature = "whpx"))]
24
pub mod whpx;
25
#[cfg(target_arch = "x86_64")]
26
pub mod x86_64;
27
28
use base::AsRawDescriptor;
29
use base::Event;
30
use base::MappedRegion;
31
use base::Protection;
32
use base::Result;
33
use base::SafeDescriptor;
34
use serde::Deserialize;
35
use serde::Serialize;
36
use vm_memory::GuestAddress;
37
use vm_memory::GuestMemory;
38
39
#[cfg(target_arch = "aarch64")]
40
pub use crate::aarch64::*;
41
pub use crate::caps::*;
42
#[cfg(target_arch = "riscv64")]
43
pub use crate::riscv64::*;
44
#[cfg(target_arch = "x86_64")]
45
pub use crate::x86_64::*;
46
47
/// An index in the list of guest-mapped memory regions.
48
pub type MemSlot = u32;
49
50
/// Range of GPA space. Starting from `guest_address` up to `size`.
51
pub struct MemRegion {
52
pub guest_address: GuestAddress,
53
pub size: u64,
54
}
55
56
/// Signal to the hypervisor on kernels that support the KVM_CAP_USER_CONFIGURE_NONCOHERENT_DMA (or
57
/// equivalent) that during user memory region (memslot) configuration, a guest page's memtype
58
/// should be considered in SLAT effective memtype determination rather than implicitly respecting
59
/// only the host page's memtype.
60
///
61
/// This explicit control is needed for Virtio devices (e.g. gpu) that configure memslots for host
62
/// WB page mappings with guest WC page mappings. See b/316337317, b/360295883 for more detail.
63
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
64
pub enum MemCacheType {
65
/// Don't provide any explicit instruction to the hypervisor on how it should determine a
66
/// memslot's effective memtype.
67
///
68
/// On KVM-VMX (Intel), this means that the memslot is flagged with VMX_EPT_IPAT_BIT such that
69
/// only the host memtype is respected.
70
CacheCoherent,
71
/// explicitly instruct the hypervisor to respect the guest page's memtype when determining the
72
/// memslot's effective memtype.
73
///
74
/// On KVM-VMX (Intel), this means the memslot is NOT flagged with VMX_EPT_IPAT_BIT, and the
75
/// effective memtype will generally decay to the weaker amongst the host/guest memtypes and
76
/// the MTRR for the physical address.
77
CacheNonCoherent,
78
}
79
80
/// This is intended for use with virtio-balloon, where a guest driver determines unused ranges and
81
/// requests they be freed. Use without the guest's knowledge is sure to break something.
82
pub enum BalloonEvent {
83
/// Balloon event when the region is acquired from the guest. The guest cannot access this
84
/// region any more. The guest memory can be reclaimed by the host OS. As per virtio-balloon
85
/// spec, the given address and size are intended to be page-aligned.
86
Inflate(MemRegion),
87
/// Balloon event when the region is returned to the guest. VMM should reallocate memory and
88
/// register it with the hypervisor for accesses by the guest.
89
Deflate(MemRegion),
90
/// Balloon event when the requested memory size is achieved. This can be achieved through
91
/// either inflation or deflation. The `u64` will be the current size of the balloon in bytes.
92
BalloonTargetReached(u64),
93
}
94
95
/// Supported hypervisors.
96
///
97
/// When adding a new one, also update the HypervisorFfi in crosvm_control/src/lib.rs
98
#[derive(Serialize, Deserialize, Debug, Clone)]
99
pub enum HypervisorKind {
100
Geniezone,
101
Gunyah,
102
Halla,
103
Kvm,
104
Haxm,
105
Whpx,
106
}
107
108
/// A trait for checking hypervisor capabilities.
109
pub trait Hypervisor: Send {
110
/// Makes a shallow clone of this `Hypervisor`.
111
fn try_clone(&self) -> Result<Self>
112
where
113
Self: Sized;
114
115
/// Checks if a particular `HypervisorCap` is available.
116
fn check_capability(&self, cap: HypervisorCap) -> bool;
117
}
118
119
/// A wrapper for using a VM and getting/setting its state.
120
pub trait Vm: Send {
121
/// Makes a shallow clone of this `Vm`.
122
fn try_clone(&self) -> Result<Self>
123
where
124
Self: Sized;
125
126
/// Makes a shallow clone of the fd of this `Vm`.
127
fn try_clone_descriptor(&self) -> Result<SafeDescriptor>;
128
129
/// Returns hypervisor managing this `Vm`.
130
fn hypervisor_kind(&self) -> HypervisorKind;
131
132
/// Checks if a particular `VmCap` is available.
133
///
134
/// This is distinct from the `Hypervisor` version of this method because some extensions depend
135
/// on the particular `Vm` instance. This method is encouraged because it more accurately
136
/// reflects the usable capabilities.
137
fn check_capability(&self, c: VmCap) -> bool;
138
139
/// Enable the VM capabilities.
140
fn enable_capability(&self, _capability: VmCap, _flags: u32) -> Result<bool> {
141
Err(std::io::Error::from(std::io::ErrorKind::Unsupported).into())
142
}
143
144
/// Get the guest physical address size in bits.
145
fn get_guest_phys_addr_bits(&self) -> u8;
146
147
/// Gets the guest-mapped memory for the Vm.
148
fn get_memory(&self) -> &GuestMemory;
149
150
/// Inserts the given `MappedRegion` into the VM's address space at `guest_addr`.
151
///
152
/// The slot that was assigned the memory mapping is returned on success. The slot can be given
153
/// to `Vm::remove_memory_region` to remove the memory from the VM's address space and take back
154
/// ownership of `mem_region`.
155
///
156
/// Note that memory inserted into the VM's address space must not overlap with any other memory
157
/// slot's region.
158
///
159
/// If `read_only` is true, the guest will be able to read the memory as normal, but attempts to
160
/// write will trigger a mmio VM exit, leaving the memory untouched.
161
///
162
/// If `log_dirty_pages` is true, the slot number can be used to retrieve the pages written to
163
/// by the guest with `get_dirty_log`.
164
///
165
/// `cache` can be used to set guest mem cache attribute if supported. Default is cache coherent
166
/// memory. Noncoherent memory means this memory might not be coherent from all access points,
167
/// e.g this could be the case when host GPU doesn't set the memory to be coherent with CPU
168
/// access. Setting this attribute would allow hypervisor to adjust guest mem control to ensure
169
/// synchronized guest access in noncoherent DMA case.
170
fn add_memory_region(
171
&mut self,
172
guest_addr: GuestAddress,
173
mem_region: Box<dyn MappedRegion>,
174
read_only: bool,
175
log_dirty_pages: bool,
176
cache: MemCacheType,
177
) -> Result<MemSlot>;
178
179
/// Does a synchronous msync of the memory mapped at `slot`, syncing `size` bytes starting at
180
/// `offset` from the start of the region. `offset` must be page aligned.
181
fn msync_memory_region(&mut self, slot: MemSlot, offset: usize, size: usize) -> Result<()>;
182
183
/// Gives a MADV_PAGEOUT advice to the memory region mapped at `slot`, with the address range
184
/// starting at `offset` from the start of the region, and with size `size`. `offset`
185
/// must be page aligned.
186
#[cfg(any(target_os = "android", target_os = "linux"))]
187
fn madvise_pageout_memory_region(
188
&mut self,
189
slot: MemSlot,
190
offset: usize,
191
size: usize,
192
) -> Result<()>;
193
194
/// Gives a MADV_REMOVE advice to the memory region mapped at `slot`, with the address range
195
/// starting at `offset` from the start of the region, and with size `size`. `offset`
196
/// must be page aligned.
197
#[cfg(any(target_os = "android", target_os = "linux"))]
198
fn madvise_remove_memory_region(
199
&mut self,
200
slot: MemSlot,
201
offset: usize,
202
size: usize,
203
) -> Result<()>;
204
205
/// Removes and drops the `UserMemoryRegion` that was previously added at the given slot.
206
fn remove_memory_region(&mut self, slot: MemSlot) -> Result<Box<dyn MappedRegion>>;
207
208
/// Creates an emulated device.
209
fn create_device(&self, kind: DeviceKind) -> Result<SafeDescriptor>;
210
211
/// Gets the bitmap of dirty pages since the last call to `get_dirty_log` for the memory at
212
/// `slot`. Only works on VMs that support `VmCap::DirtyLog`.
213
///
214
/// The size of `dirty_log` must be at least as many bits as there are pages in the memory
215
/// region `slot` represents. For example, if the size of `slot` is 16 pages, `dirty_log` must
216
/// be 2 bytes or greater.
217
fn get_dirty_log(&self, slot: MemSlot, dirty_log: &mut [u8]) -> Result<()>;
218
219
/// Registers an event to be signaled whenever a certain address is written to.
220
///
221
/// The `datamatch` parameter can be used to limit signaling `evt` to only the cases where the
222
/// value being written is equal to `datamatch`. Note that the size of `datamatch` is important
223
/// and must match the expected size of the guest's write.
224
///
225
/// In all cases where `evt` is signaled, the ordinary vmexit to userspace that would be
226
/// triggered is prevented.
227
fn register_ioevent(
228
&mut self,
229
evt: &Event,
230
addr: IoEventAddress,
231
datamatch: Datamatch,
232
) -> Result<()>;
233
234
/// Unregisters an event previously registered with `register_ioevent`.
235
///
236
/// The `evt`, `addr`, and `datamatch` set must be the same as the ones passed into
237
/// `register_ioevent`.
238
fn unregister_ioevent(
239
&mut self,
240
evt: &Event,
241
addr: IoEventAddress,
242
datamatch: Datamatch,
243
) -> Result<()>;
244
245
/// Trigger any matching registered io events based on an MMIO or PIO write at `addr`. The
246
/// `data` slice represents the contents and length of the write, which is used to compare with
247
/// the registered io events' Datamatch values. If the hypervisor does in-kernel IO event
248
/// delivery, this is a no-op.
249
fn handle_io_events(&self, addr: IoEventAddress, data: &[u8]) -> Result<()>;
250
251
/// Retrieves the current timestamp of the paravirtual clock as seen by the current guest.
252
/// Only works on VMs that support `VmCap::PvClock`.
253
fn get_pvclock(&self) -> Result<ClockState>;
254
255
/// Sets the current timestamp of the paravirtual clock as seen by the current guest.
256
/// Only works on VMs that support `VmCap::PvClock`.
257
fn set_pvclock(&self, state: &ClockState) -> Result<()>;
258
259
/// Maps `size` bytes starting at `fs_offset` bytes from within the given `fd`
260
/// at `offset` bytes from the start of the arena with `prot` protections.
261
/// `offset` must be page aligned.
262
///
263
/// # Arguments
264
/// * `offset` - Page aligned offset into the arena in bytes.
265
/// * `size` - Size of memory region in bytes.
266
/// * `fd` - File descriptor to mmap from.
267
/// * `fd_offset` - Offset in bytes from the beginning of `fd` to start the mmap.
268
/// * `prot` - Protection (e.g. readable/writable) of the memory region.
269
fn add_fd_mapping(
270
&mut self,
271
slot: u32,
272
offset: usize,
273
size: usize,
274
fd: &dyn AsRawDescriptor,
275
fd_offset: u64,
276
prot: Protection,
277
) -> Result<()>;
278
279
/// Remove `size`-byte mapping starting at `offset`.
280
fn remove_mapping(&mut self, slot: u32, offset: usize, size: usize) -> Result<()>;
281
282
/// Events from virtio-balloon that affect the state for guest memory and host memory.
283
fn handle_balloon_event(&mut self, event: BalloonEvent) -> Result<()>;
284
285
/// Registers with the hypervisor for CrosVM to handle any guest hypercall in the range.
286
fn enable_hypercalls(&mut self, nr: u64, count: usize) -> Result<()>;
287
288
/// Registers with the hypervisor for CrosVM to handle the guest hypercall.
289
fn enable_hypercall(&mut self, nr: u64) -> Result<()> {
290
self.enable_hypercalls(nr, 1)
291
}
292
}
293
294
/// Operation for Io and Mmio
295
#[derive(Debug)]
296
pub enum IoOperation<'a> {
297
/// Data to be read from a device on the bus.
298
///
299
/// The `handle_fn` should fill the entire slice with the read data.
300
Read(&'a mut [u8]),
301
302
/// Data to be written to a device on the bus.
303
Write(&'a [u8]),
304
}
305
306
/// Parameters describing an MMIO or PIO from the guest.
307
#[derive(Debug)]
308
pub struct IoParams<'a> {
309
pub address: u64,
310
pub operation: IoOperation<'a>,
311
}
312
313
/// Architecture-agnostic wrapper for any hypercall ABI between CrosVM and the guest.
314
#[derive(Debug)]
315
pub struct HypercallAbi {
316
hypercall_id: usize,
317
args: Vec<usize>,
318
res: Vec<usize>,
319
}
320
321
impl HypercallAbi {
322
/// Creates a new `HypercallAbi` instance, with the default error result.
323
pub fn new(hypercall_id: usize, args: &[usize], default_res: &[usize]) -> Self {
324
Self {
325
hypercall_id,
326
args: args.to_owned(),
327
res: default_res.to_owned(),
328
}
329
}
330
331
/// Returns the hypercall unique identifier, for routing.
332
pub fn hypercall_id(&self) -> usize {
333
self.hypercall_id
334
}
335
336
/// Returns the n-th guest-provided architecture-specific arguments.
337
pub fn get_argument(&self, n: usize) -> Option<&usize> {
338
self.args.get(n)
339
}
340
341
/// Returns the architecture-specific results for the guest, if set.
342
pub fn get_results(&self) -> &[usize] {
343
self.res.as_slice()
344
}
345
346
/// Sets the architecture-specific results for the guest.
347
pub fn set_results(&mut self, res: &[usize]) {
348
self.res = res.to_owned()
349
}
350
}
351
352
/// Handle to a virtual CPU that may be used to request a VM exit from within a signal handler.
353
#[cfg(any(target_os = "android", target_os = "linux"))]
354
pub struct VcpuSignalHandle {
355
inner: Box<dyn VcpuSignalHandleInner>,
356
}
357
358
#[cfg(any(target_os = "android", target_os = "linux"))]
359
impl VcpuSignalHandle {
360
/// Request an immediate exit for this VCPU.
361
///
362
/// This function is safe to call from a signal handler.
363
pub fn signal_immediate_exit(&self) {
364
self.inner.signal_immediate_exit()
365
}
366
}
367
368
/// Signal-safe mechanism for requesting an immediate VCPU exit.
369
///
370
/// Each hypervisor backend must implement this for its VCPU type.
371
#[cfg(any(target_os = "android", target_os = "linux"))]
372
pub(crate) trait VcpuSignalHandleInner {
373
/// Signal the associated VCPU to exit if it is currently running.
374
///
375
/// # Safety
376
///
377
/// The implementation of this function must be async signal safe.
378
/// <https://man7.org/linux/man-pages/man7/signal-safety.7.html>
379
fn signal_immediate_exit(&self);
380
}
381
382
/// A virtual CPU holding a virtualized hardware thread's state, such as registers and interrupt
383
/// state, which may be used to execute virtual machines.
384
pub trait Vcpu: downcast_rs::DowncastSync {
385
/// Makes a shallow clone of this `Vcpu`.
386
fn try_clone(&self) -> Result<Self>
387
where
388
Self: Sized;
389
390
/// Casts this architecture specific trait object to the base trait object `Vcpu`.
391
fn as_vcpu(&self) -> &dyn Vcpu;
392
393
/// Runs the VCPU until it exits, returning the reason for the exit.
394
fn run(&mut self) -> Result<VcpuExit>;
395
396
/// Returns the vcpu id.
397
fn id(&self) -> usize;
398
399
/// Sets the bit that requests an immediate exit.
400
fn set_immediate_exit(&self, exit: bool);
401
402
/// Returns a handle that can be used to cause this VCPU to exit from `run()` from a signal
403
/// handler.
404
#[cfg(any(target_os = "android", target_os = "linux"))]
405
fn signal_handle(&self) -> VcpuSignalHandle;
406
407
/// Handles an incoming MMIO request from the guest.
408
///
409
/// This function should be called after `Vcpu::run` returns `VcpuExit::Mmio`, and in the same
410
/// thread as run().
411
///
412
/// Once called, it will determine whether a MMIO read or MMIO write was the reason for the MMIO
413
/// exit, call `handle_fn` with the respective IoParams to perform the MMIO read or write, and
414
/// set the return data in the vcpu so that the vcpu can resume running.
415
fn handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()>;
416
417
/// Handles an incoming PIO from the guest.
418
///
419
/// This function should be called after `Vcpu::run` returns `VcpuExit::Io`, and in the same
420
/// thread as run().
421
///
422
/// Once called, it will determine whether an input or output was the reason for the Io exit,
423
/// call `handle_fn` with the respective IoParams to perform the input/output operation, and set
424
/// the return data in the vcpu so that the vcpu can resume running.
425
fn handle_io(&self, handle_fn: &mut dyn FnMut(IoParams)) -> Result<()>;
426
427
/// Handles an incoming hypercall from the guest.
428
fn handle_hypercall(
429
&self,
430
_handle_fn: &mut dyn FnMut(&mut HypercallAbi) -> anyhow::Result<()>,
431
) -> anyhow::Result<()> {
432
anyhow::bail!(
433
"handle_hypercall not implemented for {}",
434
std::any::type_name::<Self>(),
435
)
436
}
437
438
/// Signals to the hypervisor that this Vcpu is being paused by userspace.
439
fn on_suspend(&self) -> Result<()>;
440
441
/// Enables a hypervisor-specific extension on this Vcpu. `cap` is a constant defined by the
442
/// hypervisor API (e.g., kvm.h). `args` are the arguments for enabling the feature, if any.
443
///
444
/// # Safety
445
/// This function is marked as unsafe because `args` may be interpreted as pointers for some
446
/// capabilities. The caller must ensure that any pointers passed in the `args` array are
447
/// allocated as the kernel expects, and that mutable pointers are owned.
448
unsafe fn enable_raw_capability(&self, cap: u32, args: &[u64; 4]) -> Result<()>;
449
}
450
451
downcast_rs::impl_downcast!(sync Vcpu);
452
453
/// An address either in programmable I/O space or in memory mapped I/O space.
454
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, std::hash::Hash)]
455
pub enum IoEventAddress {
456
Pio(u64),
457
Mmio(u64),
458
}
459
460
/// Used in `Vm::register_ioevent` to indicate a size and optionally value to match.
461
#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
462
pub enum Datamatch {
463
AnyLength,
464
U8(Option<u8>),
465
U16(Option<u16>),
466
U32(Option<u32>),
467
U64(Option<u64>),
468
}
469
470
#[derive(Copy, Clone, Debug)]
471
pub enum VcpuShutdownErrorKind {
472
DoubleFault,
473
TripleFault,
474
Other,
475
}
476
477
/// A Vcpu shutdown may signify an error, such as a double or triple fault,
478
/// or hypervisor specific reasons. This error covers all such cases.
479
#[derive(Copy, Clone, Debug)]
480
pub struct VcpuShutdownError {
481
kind: VcpuShutdownErrorKind,
482
raw_error_code: u64,
483
}
484
485
impl VcpuShutdownError {
486
pub fn new(kind: VcpuShutdownErrorKind, raw_error_code: u64) -> VcpuShutdownError {
487
Self {
488
kind,
489
raw_error_code,
490
}
491
}
492
pub fn kind(&self) -> VcpuShutdownErrorKind {
493
self.kind
494
}
495
pub fn get_raw_error_code(&self) -> u64 {
496
self.raw_error_code
497
}
498
}
499
500
// Note that when adding entries to the VcpuExit enum you may want to add corresponding entries in
501
// crosvm::stats::exit_to_index and crosvm::stats::exit_index_to_str if you don't want the new
502
// exit type to be categorized as "Unknown".
503
504
/// A reason why a VCPU exited. One of these returns every time `Vcpu::run` is called.
505
#[derive(Debug, Clone, Copy)]
506
pub enum VcpuExit {
507
/// An io instruction needs to be emulated.
508
/// vcpu handle_io should be called to handle the io operation
509
Io,
510
/// A mmio instruction needs to be emulated.
511
/// vcpu handle_mmio should be called to handle the mmio operation
512
Mmio,
513
IoapicEoi {
514
vector: u8,
515
},
516
Exception,
517
Hypercall,
518
Debug,
519
Hlt,
520
IrqWindowOpen,
521
Shutdown(std::result::Result<(), VcpuShutdownError>),
522
FailEntry {
523
hardware_entry_failure_reason: u64,
524
},
525
Intr,
526
SetTpr,
527
TprAccess,
528
InternalError,
529
SystemEventShutdown,
530
SystemEventReset,
531
SystemEventCrash,
532
/// An invalid vcpu register was set while running.
533
InvalidVpRegister,
534
/// incorrect setup for vcpu requiring an unsupported feature
535
UnsupportedFeature,
536
/// vcpu run was user cancelled
537
Canceled,
538
/// an unrecoverable exception was encountered (different from Exception)
539
UnrecoverableException,
540
/// vcpu stopped due to an msr access.
541
MsrAccess,
542
/// vcpu stopped due to a cpuid request.
543
#[cfg(target_arch = "x86_64")]
544
Cpuid {
545
entry: CpuIdEntry,
546
},
547
/// vcpu stopped due to calling rdtsc
548
RdTsc,
549
/// vcpu stopped for an apic smi trap
550
ApicSmiTrap,
551
/// vcpu stopped due to an apic trap
552
ApicInitSipiTrap,
553
/// vcpu stoppted due to bus lock
554
BusLock,
555
/// Riscv supervisor call.
556
Sbi {
557
extension_id: u64,
558
function_id: u64,
559
args: [u64; 6],
560
},
561
/// Emulate CSR access from guest.
562
RiscvCsr {
563
csr_num: u64,
564
new_value: u64,
565
write_mask: u64,
566
ret_value: u64,
567
},
568
}
569
570
/// A device type to create with `Vm.create_device`.
571
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
572
pub enum DeviceKind {
573
/// VFIO device for direct access to devices from userspace
574
Vfio,
575
/// ARM virtual general interrupt controller v2
576
#[cfg(target_arch = "aarch64")]
577
ArmVgicV2,
578
/// ARM virtual general interrupt controller v3
579
#[cfg(target_arch = "aarch64")]
580
ArmVgicV3,
581
/// ARM virtual interrupt translation service
582
#[cfg(target_arch = "aarch64")]
583
ArmVgicIts,
584
/// RiscV AIA in-kernel emulation
585
#[cfg(target_arch = "riscv64")]
586
RiscvAia,
587
}
588
589
/// The source chip of an `IrqSource`
590
#[repr(C)]
591
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
592
pub enum IrqSourceChip {
593
PicPrimary,
594
PicSecondary,
595
Ioapic,
596
Gic,
597
Aia,
598
}
599
600
/// A source of IRQs in an `IrqRoute`.
601
#[repr(C)]
602
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
603
pub enum IrqSource {
604
Irqchip {
605
chip: IrqSourceChip,
606
pin: u32,
607
},
608
Msi {
609
address: u64,
610
data: u32,
611
#[cfg(target_arch = "aarch64")]
612
pci_address: resources::PciAddress,
613
},
614
}
615
616
/// A single route for an IRQ.
617
#[repr(C)]
618
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
619
pub struct IrqRoute {
620
pub gsi: u32,
621
pub source: IrqSource,
622
}
623
624
/// The state of the paravirtual clock.
625
#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
626
pub struct ClockState {
627
/// Current pv clock timestamp, as seen by the guest
628
pub clock: u64,
629
}
630
631
/// The MPState represents the state of a processor.
632
#[repr(C)]
633
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
634
pub enum MPState {
635
/// the vcpu is currently running (x86/x86_64,arm/arm64)
636
Runnable,
637
/// the vcpu is an application processor (AP) which has not yet received an INIT signal
638
/// (x86/x86_64)
639
Uninitialized,
640
/// the vcpu has received an INIT signal, and is now ready for a SIPI (x86/x86_64)
641
InitReceived,
642
/// the vcpu has executed a HLT instruction and is waiting for an interrupt (x86/x86_64)
643
Halted,
644
/// the vcpu has just received a SIPI (vector accessible via KVM_GET_VCPU_EVENTS) (x86/x86_64)
645
SipiReceived,
646
/// the vcpu is stopped (arm/arm64)
647
Stopped,
648
}
649
650
/// Whether the VM should be run in protected mode or not.
651
#[derive(Copy, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
652
pub enum ProtectionType {
653
/// The VM should be run in the unprotected mode, where the host has access to its memory.
654
Unprotected,
655
/// The VM should be run in protected mode, so the host cannot access its memory directly. It
656
/// should be booted via the protected VM firmware, so that it can access its secrets.
657
Protected,
658
/// The VM should be run in protected mode, so the host cannot access its memory directly. It
659
/// should be booted via a custom VM firmware, useful for debugging and testing.
660
ProtectedWithCustomFirmware,
661
/// The VM should be run in protected mode, but booted directly without pVM firmware. The host
662
/// will still be unable to access the VM memory, but it won't be given any secrets.
663
ProtectedWithoutFirmware,
664
/// The VM should be run in unprotected mode, but with the same memory layout as protected
665
/// mode, protected VM firmware loaded, and simulating protected mode as much as possible.
666
/// This is useful for debugging the protected VM firmware and other protected mode issues.
667
UnprotectedWithFirmware,
668
}
669
670
impl ProtectionType {
671
/// Returns whether the hypervisor will prevent us from accessing the VM's memory.
672
pub fn isolates_memory(&self) -> bool {
673
matches!(
674
self,
675
Self::Protected | Self::ProtectedWithCustomFirmware | Self::ProtectedWithoutFirmware
676
)
677
}
678
679
/// Returns whether the VMM needs to load the pVM firmware.
680
pub fn needs_firmware_loaded(&self) -> bool {
681
matches!(
682
self,
683
Self::UnprotectedWithFirmware | Self::ProtectedWithCustomFirmware
684
)
685
}
686
687
/// Returns whether the VM runs a pVM firmware.
688
pub fn runs_firmware(&self) -> bool {
689
self.needs_firmware_loaded() || matches!(self, Self::Protected)
690
}
691
}
692
693
#[derive(Clone, Copy)]
694
pub struct Config {
695
#[cfg(target_arch = "aarch64")]
696
/// enable the Memory Tagging Extension in the guest
697
pub mte: bool,
698
pub protection_type: ProtectionType,
699
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
700
pub ffa: bool,
701
pub force_disable_readonly_mem: bool,
702
}
703
704
impl Default for Config {
705
fn default() -> Config {
706
Config {
707
#[cfg(target_arch = "aarch64")]
708
mte: false,
709
protection_type: ProtectionType::Unprotected,
710
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
711
ffa: false,
712
force_disable_readonly_mem: false,
713
}
714
}
715
}
716
717