// Copyright 2020 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34//! A crate for abstracting the underlying kernel hypervisor used in crosvm.56#[cfg(target_arch = "aarch64")]7pub mod aarch64;8pub mod caps;9#[cfg(all(unix, target_arch = "aarch64", feature = "geniezone"))]10pub mod geniezone;11#[cfg(all(unix, target_arch = "aarch64", feature = "gunyah"))]12pub mod gunyah;13#[cfg(target_arch = "aarch64")]14#[cfg(all(unix, target_arch = "aarch64", feature = "halla"))]15pub mod halla;16#[cfg(all(windows, feature = "haxm"))]17pub mod haxm;18#[cfg(any(target_os = "android", target_os = "linux"))]19pub mod kvm;20#[cfg(target_arch = "riscv64")]21pub mod riscv64;22#[cfg(all(windows, feature = "whpx"))]23pub mod whpx;24#[cfg(target_arch = "x86_64")]25pub mod x86_64;2627use base::AsRawDescriptor;28use base::Event;29use base::MappedRegion;30use base::Protection;31use base::Result;32use base::SafeDescriptor;33use serde::Deserialize;34use serde::Serialize;35use vm_memory::GuestAddress;36use vm_memory::GuestMemory;3738#[cfg(target_arch = "aarch64")]39pub use crate::aarch64::*;40pub use crate::caps::*;41#[cfg(target_arch = "riscv64")]42pub use crate::riscv64::*;43#[cfg(target_arch = "x86_64")]44pub use crate::x86_64::*;4546/// An index in the list of guest-mapped memory regions.47pub type MemSlot = u32;4849/// Range of GPA space. Starting from `guest_address` up to `size`.50pub struct MemRegion {51pub guest_address: GuestAddress,52pub size: u64,53}5455/// Signal to the hypervisor on kernels that support the KVM_CAP_USER_CONFIGURE_NONCOHERENT_DMA (or56/// equivalent) that during user memory region (memslot) configuration, a guest page's memtype57/// should be considered in SLAT effective memtype determination rather than implicitly respecting58/// only the host page's memtype.59///60/// This explicit control is needed for Virtio devices (e.g. gpu) that configure memslots for host61/// WB page mappings with guest WC page mappings. See b/316337317, b/360295883 for more detail.62#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]63pub enum MemCacheType {64/// Don't provide any explicit instruction to the hypervisor on how it should determine a65/// memslot's effective memtype.66///67/// On KVM-VMX (Intel), this means that the memslot is flagged with VMX_EPT_IPAT_BIT such that68/// only the host memtype is respected.69CacheCoherent,70/// explicitly instruct the hypervisor to respect the guest page's memtype when determining the71/// memslot's effective memtype.72///73/// On KVM-VMX (Intel), this means the memslot is NOT flagged with VMX_EPT_IPAT_BIT, and the74/// effective memtype will generally decay to the weaker amongst the host/guest memtypes and75/// the MTRR for the physical address.76CacheNonCoherent,77}7879/// This is intended for use with virtio-balloon, where a guest driver determines unused ranges and80/// requests they be freed. Use without the guest's knowledge is sure to break something.81pub enum BalloonEvent {82/// Balloon event when the region is acquired from the guest. The guest cannot access this83/// region any more. The guest memory can be reclaimed by the host OS. As per virtio-balloon84/// spec, the given address and size are intended to be page-aligned.85Inflate(MemRegion),86/// Balloon event when the region is returned to the guest. VMM should reallocate memory and87/// register it with the hypervisor for accesses by the guest.88Deflate(MemRegion),89/// Balloon event when the requested memory size is achieved. This can be achieved through90/// either inflation or deflation. The `u64` will be the current size of the balloon in bytes.91BalloonTargetReached(u64),92}9394/// Supported hypervisors.95///96/// When adding a new one, also update the HypervisorFfi in crosvm_control/src/lib.rs97#[derive(Serialize, Deserialize, Debug, Clone)]98pub enum HypervisorKind {99Geniezone,100Gunyah,101Halla,102Kvm,103Haxm,104Whpx,105}106107/// A trait for checking hypervisor capabilities.108pub trait Hypervisor: Send {109/// Makes a shallow clone of this `Hypervisor`.110fn try_clone(&self) -> Result<Self>111where112Self: Sized;113114/// Checks if a particular `HypervisorCap` is available.115fn check_capability(&self, cap: HypervisorCap) -> bool;116}117118/// A wrapper for using a VM and getting/setting its state.119pub trait Vm: Send {120/// Makes a shallow clone of this `Vm`.121fn try_clone(&self) -> Result<Self>122where123Self: Sized;124125/// Makes a shallow clone of the fd of this `Vm`.126fn try_clone_descriptor(&self) -> Result<SafeDescriptor>;127128/// Returns hypervisor managing this `Vm`.129fn hypervisor_kind(&self) -> HypervisorKind;130131/// Checks if a particular `VmCap` is available.132///133/// This is distinct from the `Hypervisor` version of this method because some extensions depend134/// on the particular `Vm` instance. This method is encouraged because it more accurately135/// reflects the usable capabilities.136fn check_capability(&self, c: VmCap) -> bool;137138/// Enable the VM capabilities.139fn enable_capability(&self, _capability: VmCap, _flags: u32) -> Result<bool> {140Err(std::io::Error::from(std::io::ErrorKind::Unsupported).into())141}142143/// Get the guest physical address size in bits.144fn get_guest_phys_addr_bits(&self) -> u8;145146/// Gets the guest-mapped memory for the Vm.147fn get_memory(&self) -> &GuestMemory;148149/// Inserts the given `MappedRegion` into the VM's address space at `guest_addr`.150///151/// The slot that was assigned the memory mapping is returned on success. The slot can be given152/// to `Vm::remove_memory_region` to remove the memory from the VM's address space and take back153/// ownership of `mem_region`.154///155/// Note that memory inserted into the VM's address space must not overlap with any other memory156/// slot's region.157///158/// If `read_only` is true, the guest will be able to read the memory as normal, but attempts to159/// write will trigger a mmio VM exit, leaving the memory untouched.160///161/// If `log_dirty_pages` is true, the slot number can be used to retrieve the pages written to162/// by the guest with `get_dirty_log`.163///164/// `cache` can be used to set guest mem cache attribute if supported. Default is cache coherent165/// memory. Noncoherent memory means this memory might not be coherent from all access points,166/// e.g this could be the case when host GPU doesn't set the memory to be coherent with CPU167/// access. Setting this attribute would allow hypervisor to adjust guest mem control to ensure168/// synchronized guest access in noncoherent DMA case.169fn add_memory_region(170&mut self,171guest_addr: GuestAddress,172mem_region: Box<dyn MappedRegion>,173read_only: bool,174log_dirty_pages: bool,175cache: MemCacheType,176) -> Result<MemSlot>;177178/// Does a synchronous msync of the memory mapped at `slot`, syncing `size` bytes starting at179/// `offset` from the start of the region. `offset` must be page aligned.180fn msync_memory_region(&mut self, slot: MemSlot, offset: usize, size: usize) -> Result<()>;181182/// Gives a MADV_PAGEOUT advice to the memory region mapped at `slot`, with the address range183/// starting at `offset` from the start of the region, and with size `size`. `offset`184/// must be page aligned.185#[cfg(any(target_os = "android", target_os = "linux"))]186fn madvise_pageout_memory_region(187&mut self,188slot: MemSlot,189offset: usize,190size: usize,191) -> Result<()>;192193/// Gives a MADV_REMOVE advice to the memory region mapped at `slot`, with the address range194/// starting at `offset` from the start of the region, and with size `size`. `offset`195/// must be page aligned.196#[cfg(any(target_os = "android", target_os = "linux"))]197fn madvise_remove_memory_region(198&mut self,199slot: MemSlot,200offset: usize,201size: usize,202) -> Result<()>;203204/// Removes and drops the `UserMemoryRegion` that was previously added at the given slot.205fn remove_memory_region(&mut self, slot: MemSlot) -> Result<Box<dyn MappedRegion>>;206207/// Creates an emulated device.208fn create_device(&self, kind: DeviceKind) -> Result<SafeDescriptor>;209210/// Gets the bitmap of dirty pages since the last call to `get_dirty_log` for the memory at211/// `slot`. Only works on VMs that support `VmCap::DirtyLog`.212///213/// The size of `dirty_log` must be at least as many bits as there are pages in the memory214/// region `slot` represents. For example, if the size of `slot` is 16 pages, `dirty_log` must215/// be 2 bytes or greater.216fn get_dirty_log(&self, slot: MemSlot, dirty_log: &mut [u8]) -> Result<()>;217218/// Registers an event to be signaled whenever a certain address is written to.219///220/// The `datamatch` parameter can be used to limit signaling `evt` to only the cases where the221/// value being written is equal to `datamatch`. Note that the size of `datamatch` is important222/// and must match the expected size of the guest's write.223///224/// In all cases where `evt` is signaled, the ordinary vmexit to userspace that would be225/// triggered is prevented.226fn register_ioevent(227&mut self,228evt: &Event,229addr: IoEventAddress,230datamatch: Datamatch,231) -> Result<()>;232233/// Unregisters an event previously registered with `register_ioevent`.234///235/// The `evt`, `addr`, and `datamatch` set must be the same as the ones passed into236/// `register_ioevent`.237fn unregister_ioevent(238&mut self,239evt: &Event,240addr: IoEventAddress,241datamatch: Datamatch,242) -> Result<()>;243244/// Trigger any matching registered io events based on an MMIO or PIO write at `addr`. The245/// `data` slice represents the contents and length of the write, which is used to compare with246/// the registered io events' Datamatch values. If the hypervisor does in-kernel IO event247/// delivery, this is a no-op.248fn handle_io_events(&self, addr: IoEventAddress, data: &[u8]) -> Result<()>;249250/// Retrieves the current timestamp of the paravirtual clock as seen by the current guest.251/// Only works on VMs that support `VmCap::PvClock`.252fn get_pvclock(&self) -> Result<ClockState>;253254/// Sets the current timestamp of the paravirtual clock as seen by the current guest.255/// Only works on VMs that support `VmCap::PvClock`.256fn set_pvclock(&self, state: &ClockState) -> Result<()>;257258/// Maps `size` bytes starting at `fs_offset` bytes from within the given `fd`259/// at `offset` bytes from the start of the arena with `prot` protections.260/// `offset` must be page aligned.261///262/// # Arguments263/// * `offset` - Page aligned offset into the arena in bytes.264/// * `size` - Size of memory region in bytes.265/// * `fd` - File descriptor to mmap from.266/// * `fd_offset` - Offset in bytes from the beginning of `fd` to start the mmap.267/// * `prot` - Protection (e.g. readable/writable) of the memory region.268fn add_fd_mapping(269&mut self,270slot: u32,271offset: usize,272size: usize,273fd: &dyn AsRawDescriptor,274fd_offset: u64,275prot: Protection,276) -> Result<()>;277278/// Remove `size`-byte mapping starting at `offset`.279fn remove_mapping(&mut self, slot: u32, offset: usize, size: usize) -> Result<()>;280281/// Events from virtio-balloon that affect the state for guest memory and host memory.282fn handle_balloon_event(&mut self, event: BalloonEvent) -> Result<()>;283284/// Registers with the hypervisor for CrosVM to handle any guest hypercall in the range.285fn enable_hypercalls(&mut self, nr: u64, count: usize) -> Result<()>;286287/// Registers with the hypervisor for CrosVM to handle the guest hypercall.288fn enable_hypercall(&mut self, nr: u64) -> Result<()> {289self.enable_hypercalls(nr, 1)290}291}292293/// Operation for Io and Mmio294#[derive(Debug)]295pub enum IoOperation<'a> {296/// Data to be read from a device on the bus.297///298/// The `handle_fn` should fill the entire slice with the read data.299Read(&'a mut [u8]),300301/// Data to be written to a device on the bus.302Write(&'a [u8]),303}304305/// Parameters describing an MMIO or PIO from the guest.306#[derive(Debug)]307pub struct IoParams<'a> {308pub address: u64,309pub operation: IoOperation<'a>,310}311312/// Architecture-agnostic wrapper for any hypercall ABI between CrosVM and the guest.313#[derive(Debug)]314pub struct HypercallAbi {315hypercall_id: usize,316args: Vec<usize>,317res: Vec<usize>,318}319320impl HypercallAbi {321/// Creates a new `HypercallAbi` instance, with the default error result.322pub fn new(hypercall_id: usize, args: &[usize], default_res: &[usize]) -> Self {323Self {324hypercall_id,325args: args.to_owned(),326res: default_res.to_owned(),327}328}329330/// Returns the hypercall unique identifier, for routing.331pub fn hypercall_id(&self) -> usize {332self.hypercall_id333}334335/// Returns the n-th guest-provided architecture-specific arguments.336pub fn get_argument(&self, n: usize) -> Option<&usize> {337self.args.get(n)338}339340/// Returns the architecture-specific results for the guest, if set.341pub fn get_results(&self) -> &[usize] {342self.res.as_slice()343}344345/// Sets the architecture-specific results for the guest.346pub fn set_results(&mut self, res: &[usize]) {347self.res = res.to_owned()348}349}350351/// Handle to a virtual CPU that may be used to request a VM exit from within a signal handler.352#[cfg(any(target_os = "android", target_os = "linux"))]353pub struct VcpuSignalHandle {354inner: Box<dyn VcpuSignalHandleInner>,355}356357#[cfg(any(target_os = "android", target_os = "linux"))]358impl VcpuSignalHandle {359/// Request an immediate exit for this VCPU.360///361/// This function is safe to call from a signal handler.362pub fn signal_immediate_exit(&self) {363self.inner.signal_immediate_exit()364}365}366367/// Signal-safe mechanism for requesting an immediate VCPU exit.368///369/// Each hypervisor backend must implement this for its VCPU type.370#[cfg(any(target_os = "android", target_os = "linux"))]371pub(crate) trait VcpuSignalHandleInner {372/// Signal the associated VCPU to exit if it is currently running.373///374/// # Safety375///376/// The implementation of this function must be async signal safe.377/// <https://man7.org/linux/man-pages/man7/signal-safety.7.html>378fn signal_immediate_exit(&self);379}380381/// A virtual CPU holding a virtualized hardware thread's state, such as registers and interrupt382/// state, which may be used to execute virtual machines.383pub trait Vcpu: downcast_rs::DowncastSync {384/// Makes a shallow clone of this `Vcpu`.385fn try_clone(&self) -> Result<Self>386where387Self: Sized;388389/// Casts this architecture specific trait object to the base trait object `Vcpu`.390fn as_vcpu(&self) -> &dyn Vcpu;391392/// Runs the VCPU until it exits, returning the reason for the exit.393fn run(&mut self) -> Result<VcpuExit>;394395/// Returns the vcpu id.396fn id(&self) -> usize;397398/// Sets the bit that requests an immediate exit.399fn set_immediate_exit(&self, exit: bool);400401/// Returns a handle that can be used to cause this VCPU to exit from `run()` from a signal402/// handler.403#[cfg(any(target_os = "android", target_os = "linux"))]404fn signal_handle(&self) -> VcpuSignalHandle;405406/// Handles an incoming MMIO request from the guest.407///408/// This function should be called after `Vcpu::run` returns `VcpuExit::Mmio`, and in the same409/// thread as run().410///411/// Once called, it will determine whether a MMIO read or MMIO write was the reason for the MMIO412/// exit, call `handle_fn` with the respective IoParams to perform the MMIO read or write, and413/// set the return data in the vcpu so that the vcpu can resume running.414fn handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Result<()>) -> Result<()>;415416/// Handles an incoming PIO from the guest.417///418/// This function should be called after `Vcpu::run` returns `VcpuExit::Io`, and in the same419/// thread as run().420///421/// Once called, it will determine whether an input or output was the reason for the Io exit,422/// call `handle_fn` with the respective IoParams to perform the input/output operation, and set423/// the return data in the vcpu so that the vcpu can resume running.424fn handle_io(&self, handle_fn: &mut dyn FnMut(IoParams)) -> Result<()>;425426/// Handles an incoming hypercall from the guest.427fn handle_hypercall(428&self,429_handle_fn: &mut dyn FnMut(&mut HypercallAbi) -> anyhow::Result<()>,430) -> anyhow::Result<()> {431anyhow::bail!(432"handle_hypercall not implemented for {}",433std::any::type_name::<Self>(),434)435}436437/// Signals to the hypervisor that this Vcpu is being paused by userspace.438fn on_suspend(&self) -> Result<()>;439440/// Enables a hypervisor-specific extension on this Vcpu. `cap` is a constant defined by the441/// hypervisor API (e.g., kvm.h). `args` are the arguments for enabling the feature, if any.442///443/// # Safety444/// This function is marked as unsafe because `args` may be interpreted as pointers for some445/// capabilities. The caller must ensure that any pointers passed in the `args` array are446/// allocated as the kernel expects, and that mutable pointers are owned.447unsafe fn enable_raw_capability(&self, cap: u32, args: &[u64; 4]) -> Result<()>;448}449450downcast_rs::impl_downcast!(sync Vcpu);451452/// An address either in programmable I/O space or in memory mapped I/O space.453#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, std::hash::Hash)]454pub enum IoEventAddress {455Pio(u64),456Mmio(u64),457}458459/// Used in `Vm::register_ioevent` to indicate a size and optionally value to match.460#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]461pub enum Datamatch {462AnyLength,463U8(Option<u8>),464U16(Option<u16>),465U32(Option<u32>),466U64(Option<u64>),467}468469#[derive(Copy, Clone, Debug)]470pub enum VcpuShutdownErrorKind {471DoubleFault,472TripleFault,473Other,474}475476/// A Vcpu shutdown may signify an error, such as a double or triple fault,477/// or hypervisor specific reasons. This error covers all such cases.478#[derive(Copy, Clone, Debug)]479pub struct VcpuShutdownError {480kind: VcpuShutdownErrorKind,481raw_error_code: u64,482}483484impl VcpuShutdownError {485pub fn new(kind: VcpuShutdownErrorKind, raw_error_code: u64) -> VcpuShutdownError {486Self {487kind,488raw_error_code,489}490}491pub fn kind(&self) -> VcpuShutdownErrorKind {492self.kind493}494pub fn get_raw_error_code(&self) -> u64 {495self.raw_error_code496}497}498499// Note that when adding entries to the VcpuExit enum you may want to add corresponding entries in500// crosvm::stats::exit_to_index and crosvm::stats::exit_index_to_str if you don't want the new501// exit type to be categorized as "Unknown".502503/// A reason why a VCPU exited. One of these returns every time `Vcpu::run` is called.504#[derive(Debug, Clone, Copy)]505pub enum VcpuExit {506/// An io instruction needs to be emulated.507/// vcpu handle_io should be called to handle the io operation508Io,509/// A mmio instruction needs to be emulated.510/// vcpu handle_mmio should be called to handle the mmio operation511Mmio,512IoapicEoi {513vector: u8,514},515Exception,516Hypercall,517Debug,518Hlt,519IrqWindowOpen,520Shutdown(std::result::Result<(), VcpuShutdownError>),521FailEntry {522hardware_entry_failure_reason: u64,523},524Intr,525SetTpr,526TprAccess,527InternalError,528SystemEventShutdown,529SystemEventReset,530SystemEventCrash,531/// An invalid vcpu register was set while running.532InvalidVpRegister,533/// incorrect setup for vcpu requiring an unsupported feature534UnsupportedFeature,535/// vcpu run was user cancelled536Canceled,537/// an unrecoverable exception was encountered (different from Exception)538UnrecoverableException,539/// vcpu stopped due to an msr access.540MsrAccess,541/// vcpu stopped due to a cpuid request.542#[cfg(target_arch = "x86_64")]543Cpuid {544entry: CpuIdEntry,545},546/// vcpu stopped due to calling rdtsc547RdTsc,548/// vcpu stopped for an apic smi trap549ApicSmiTrap,550/// vcpu stopped due to an apic trap551ApicInitSipiTrap,552/// vcpu stoppted due to bus lock553BusLock,554/// Riscv supervisor call.555Sbi {556extension_id: u64,557function_id: u64,558args: [u64; 6],559},560/// Emulate CSR access from guest.561RiscvCsr {562csr_num: u64,563new_value: u64,564write_mask: u64,565ret_value: u64,566},567}568569/// A device type to create with `Vm.create_device`.570#[derive(Clone, Copy, Debug, PartialEq, Eq)]571pub enum DeviceKind {572/// VFIO device for direct access to devices from userspace573Vfio,574/// ARM virtual general interrupt controller v2575#[cfg(target_arch = "aarch64")]576ArmVgicV2,577/// ARM virtual general interrupt controller v3578#[cfg(target_arch = "aarch64")]579ArmVgicV3,580/// ARM virtual interrupt translation service581#[cfg(target_arch = "aarch64")]582ArmVgicIts,583/// RiscV AIA in-kernel emulation584#[cfg(target_arch = "riscv64")]585RiscvAia,586}587588/// The source chip of an `IrqSource`589#[repr(C)]590#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]591pub enum IrqSourceChip {592PicPrimary,593PicSecondary,594Ioapic,595Gic,596Aia,597}598599/// A source of IRQs in an `IrqRoute`.600#[repr(C)]601#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]602pub enum IrqSource {603Irqchip {604chip: IrqSourceChip,605pin: u32,606},607Msi {608address: u64,609data: u32,610#[cfg(target_arch = "aarch64")]611pci_address: resources::PciAddress,612},613}614615/// A single route for an IRQ.616#[repr(C)]617#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]618pub struct IrqRoute {619pub gsi: u32,620pub source: IrqSource,621}622623/// The state of the paravirtual clock.624#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]625pub struct ClockState {626/// Current pv clock timestamp, as seen by the guest627pub clock: u64,628}629630/// The MPState represents the state of a processor.631#[repr(C)]632#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]633pub enum MPState {634/// the vcpu is currently running (x86/x86_64,arm/arm64)635Runnable,636/// the vcpu is an application processor (AP) which has not yet received an INIT signal637/// (x86/x86_64)638Uninitialized,639/// the vcpu has received an INIT signal, and is now ready for a SIPI (x86/x86_64)640InitReceived,641/// the vcpu has executed a HLT instruction and is waiting for an interrupt (x86/x86_64)642Halted,643/// the vcpu has just received a SIPI (vector accessible via KVM_GET_VCPU_EVENTS) (x86/x86_64)644SipiReceived,645/// the vcpu is stopped (arm/arm64)646Stopped,647}648649/// Whether the VM should be run in protected mode or not.650#[derive(Copy, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]651pub enum ProtectionType {652/// The VM should be run in the unprotected mode, where the host has access to its memory.653Unprotected,654/// The VM should be run in protected mode, so the host cannot access its memory directly. It655/// should be booted via the protected VM firmware, so that it can access its secrets.656Protected,657/// The VM should be run in protected mode, so the host cannot access its memory directly. It658/// should be booted via a custom VM firmware, useful for debugging and testing.659ProtectedWithCustomFirmware,660/// The VM should be run in protected mode, but booted directly without pVM firmware. The host661/// will still be unable to access the VM memory, but it won't be given any secrets.662ProtectedWithoutFirmware,663/// The VM should be run in unprotected mode, but with the same memory layout as protected664/// mode, protected VM firmware loaded, and simulating protected mode as much as possible.665/// This is useful for debugging the protected VM firmware and other protected mode issues.666UnprotectedWithFirmware,667}668669impl ProtectionType {670/// Returns whether the hypervisor will prevent us from accessing the VM's memory.671pub fn isolates_memory(&self) -> bool {672matches!(673self,674Self::Protected | Self::ProtectedWithCustomFirmware | Self::ProtectedWithoutFirmware675)676}677678/// Returns whether the VMM needs to load the pVM firmware.679pub fn needs_firmware_loaded(&self) -> bool {680matches!(681self,682Self::UnprotectedWithFirmware | Self::ProtectedWithCustomFirmware683)684}685686/// Returns whether the VM runs a pVM firmware.687pub fn runs_firmware(&self) -> bool {688self.needs_firmware_loaded() || matches!(self, Self::Protected)689}690}691692#[derive(Clone, Copy)]693pub struct Config {694#[cfg(target_arch = "aarch64")]695/// enable the Memory Tagging Extension in the guest696pub mte: bool,697pub protection_type: ProtectionType,698#[cfg(all(target_os = "android", target_arch = "aarch64"))]699pub ffa: bool,700pub force_disable_readonly_mem: bool,701}702703impl Default for Config {704fn default() -> Config {705Config {706#[cfg(target_arch = "aarch64")]707mte: false,708protection_type: ProtectionType::Unprotected,709#[cfg(all(target_os = "android", target_arch = "aarch64"))]710ffa: false,711force_disable_readonly_mem: false,712}713}714}715716717