mod async_utils;
#[cfg(feature = "balloon")]
mod balloon;
mod descriptor_chain;
mod descriptor_utils;
pub mod device_constants;
pub mod input;
mod interrupt;
mod iommu;
#[cfg(feature = "net")]
pub mod net;
#[cfg(feature = "pvclock")]
pub mod pvclock;
mod queue;
mod rng;
#[cfg(feature = "vtpm")]
mod tpm;
#[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
mod video;
mod virtio_device;
mod virtio_mmio_device;
mod virtio_pci_common_config;
mod virtio_pci_device;
pub mod block;
pub mod console;
#[cfg(feature = "gpu")]
pub mod gpu;
#[cfg(all(unix, feature = "media"))]
pub mod media;
pub mod resource_bridge;
pub mod scsi;
#[cfg(feature = "audio")]
pub mod snd;
pub mod vhost;
pub mod vhost_user_backend;
pub mod vhost_user_frontend;
pub mod vsock;
#[cfg(feature = "balloon")]
pub use self::balloon::Balloon;
#[cfg(feature = "balloon")]
pub use self::balloon::BalloonFeatures;
pub use self::block::BlockAsync;
pub use self::console::Console;
pub use self::descriptor_chain::DescriptorChain;
pub use self::descriptor_chain::DescriptorChainIter;
pub use self::descriptor_utils::create_descriptor_chain;
pub use self::descriptor_utils::DescriptorType;
pub use self::descriptor_utils::Reader;
pub use self::descriptor_utils::Writer;
#[cfg(feature = "gpu")]
pub use self::gpu::DisplayBackend;
#[cfg(feature = "gpu")]
pub use self::gpu::Gpu;
#[cfg(feature = "gpu")]
pub use self::gpu::GpuDisplayMode;
#[cfg(feature = "gpu")]
pub use self::gpu::GpuDisplayParameters;
#[cfg(feature = "gpu")]
pub use self::gpu::GpuMode;
#[cfg(feature = "gpu")]
pub use self::gpu::GpuMouseMode;
#[cfg(feature = "gpu")]
pub use self::gpu::GpuParameters;
#[cfg(feature = "gpu")]
pub use self::gpu::GpuWsi;
pub use self::interrupt::Interrupt;
pub use self::interrupt::InterruptSnapshot;
pub use self::iommu::ipc_memory_mapper;
pub use self::iommu::memory_mapper;
pub use self::iommu::Iommu;
pub use self::iommu::IommuError;
#[cfg(feature = "net")]
pub use self::net::Net;
#[cfg(feature = "net")]
pub use self::net::NetError;
#[cfg(feature = "net")]
pub use self::net::NetParameters;
#[cfg(feature = "net")]
pub use self::net::NetParametersMode;
pub use self::queue::split_descriptor_chain::Desc;
pub use self::queue::split_descriptor_chain::SplitDescriptorChain;
pub use self::queue::PeekedDescriptorChain;
pub use self::queue::Queue;
pub use self::queue::QueueConfig;
pub use self::rng::Rng;
pub use self::scsi::Controller as ScsiController;
pub use self::scsi::DiskConfig as ScsiDiskConfig;
#[cfg(feature = "vtpm")]
pub use self::tpm::Tpm;
#[cfg(feature = "vtpm")]
pub use self::tpm::TpmBackend;
pub use self::vhost_user_frontend::VhostUserFrontend;
#[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
pub use self::video::VideoDevice;
pub use self::virtio_device::SharedMemoryMapper;
pub use self::virtio_device::SharedMemoryPrepareType;
pub use self::virtio_device::SharedMemoryRegion;
pub use self::virtio_device::VirtioDevice;
pub use self::virtio_mmio_device::VirtioMmioDevice;
pub use self::virtio_pci_device::PciCapabilityType;
pub use self::virtio_pci_device::VirtioPciCap;
pub use self::virtio_pci_device::VirtioPciDevice;
pub use self::virtio_pci_device::VirtioPciShmCap;
#[cfg(feature = "pvclock")]
pub use self::DeviceType::Pvclock;
cfg_if::cfg_if! {
    if #[cfg(any(target_os = "android", target_os = "linux"))] {
        mod p9;
        mod pmem;
        pub mod wl;
        pub mod fs;
        pub use self::iommu::sys::linux::vfio_wrapper;
        #[cfg(feature = "net")]
        pub use self::net::VhostNetParameters;
        #[cfg(feature = "net")]
        pub use self::net::VHOST_NET_DEFAULT_PATH;
        pub use self::p9::P9;
        pub use self::pmem::Pmem;
        pub use self::pmem::PmemConfig;
        pub use self::pmem::MemSlotConfig;
        #[cfg(feature = "audio")]
        pub use self::snd::new_sound;
        pub use self::wl::Wl;
    } else if #[cfg(windows)] {
        pub use self::vsock::Vsock;
    } else {
        compile_error!("Unsupported platform");
    }
}
use std::cmp;
use std::convert::TryFrom;
use futures::channel::oneshot;
use hypervisor::ProtectionType;
use serde::Deserialize;
use serde::Serialize;
use virtio_sys::virtio_config::VIRTIO_F_ACCESS_PLATFORM;
use virtio_sys::virtio_config::VIRTIO_F_SUSPEND;
use virtio_sys::virtio_config::VIRTIO_F_VERSION_1;
use virtio_sys::virtio_ids;
use virtio_sys::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
const DEVICE_RESET: u32 = 0x0;
const INTERRUPT_STATUS_USED_RING: u32 = 0x1;
const INTERRUPT_STATUS_CONFIG_CHANGED: u32 = 0x2;
const VIRTIO_MSI_NO_VECTOR: u16 = 0xffff;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
#[repr(u32)]
pub enum DeviceType {
    Net = virtio_ids::VIRTIO_ID_NET,
    Block = virtio_ids::VIRTIO_ID_BLOCK,
    Console = virtio_ids::VIRTIO_ID_CONSOLE,
    Rng = virtio_ids::VIRTIO_ID_RNG,
    Balloon = virtio_ids::VIRTIO_ID_BALLOON,
    Scsi = virtio_ids::VIRTIO_ID_SCSI,
    #[serde(rename = "9p")]
    P9 = virtio_ids::VIRTIO_ID_9P,
    Gpu = virtio_ids::VIRTIO_ID_GPU,
    Input = virtio_ids::VIRTIO_ID_INPUT,
    Vsock = virtio_ids::VIRTIO_ID_VSOCK,
    Iommu = virtio_ids::VIRTIO_ID_IOMMU,
    Sound = virtio_ids::VIRTIO_ID_SOUND,
    Fs = virtio_ids::VIRTIO_ID_FS,
    Pmem = virtio_ids::VIRTIO_ID_PMEM,
    #[serde(rename = "mac80211-hwsim")]
    Mac80211HwSim = virtio_ids::VIRTIO_ID_MAC80211_HWSIM,
    VideoEncoder = virtio_ids::VIRTIO_ID_VIDEO_ENCODER,
    VideoDecoder = virtio_ids::VIRTIO_ID_VIDEO_DECODER,
    Scmi = virtio_ids::VIRTIO_ID_SCMI,
    Wl = virtio_ids::VIRTIO_ID_WL,
    Tpm = virtio_ids::VIRTIO_ID_TPM,
    Pvclock = virtio_ids::VIRTIO_ID_PVCLOCK,
    Media = virtio_ids::VIRTIO_ID_MEDIA,
}
impl DeviceType {
    pub fn min_queues(&self) -> usize {
        match self {
            DeviceType::Net => 3,           DeviceType::Block => 1,         DeviceType::Console => 2,       DeviceType::Rng => 1,           DeviceType::Balloon => 2,       DeviceType::Scsi => 3,          DeviceType::P9 => 1,            DeviceType::Gpu => 2,           DeviceType::Input => 2,         DeviceType::Vsock => 3,         DeviceType::Iommu => 2,         DeviceType::Sound => 4,         DeviceType::Fs => 2,            DeviceType::Pmem => 1,          DeviceType::Mac80211HwSim => 2, DeviceType::VideoEncoder => 2,  DeviceType::VideoDecoder => 2,  DeviceType::Scmi => 2,          DeviceType::Wl => 2,            DeviceType::Tpm => 1,           DeviceType::Pvclock => 1,       DeviceType::Media => 2,         }
    }
}
impl std::fmt::Display for DeviceType {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match &self {
            DeviceType::Net => write!(f, "net"),
            DeviceType::Block => write!(f, "block"),
            DeviceType::Console => write!(f, "console"),
            DeviceType::Rng => write!(f, "rng"),
            DeviceType::Balloon => write!(f, "balloon"),
            DeviceType::Scsi => write!(f, "scsi"),
            DeviceType::P9 => write!(f, "9p"),
            DeviceType::Input => write!(f, "input"),
            DeviceType::Gpu => write!(f, "gpu"),
            DeviceType::Vsock => write!(f, "vsock"),
            DeviceType::Iommu => write!(f, "iommu"),
            DeviceType::Sound => write!(f, "sound"),
            DeviceType::Fs => write!(f, "fs"),
            DeviceType::Pmem => write!(f, "pmem"),
            DeviceType::Wl => write!(f, "wl"),
            DeviceType::Tpm => write!(f, "tpm"),
            DeviceType::Pvclock => write!(f, "pvclock"),
            DeviceType::VideoDecoder => write!(f, "video-decoder"),
            DeviceType::VideoEncoder => write!(f, "video-encoder"),
            DeviceType::Mac80211HwSim => write!(f, "mac80211-hwsim"),
            DeviceType::Scmi => write!(f, "scmi"),
            DeviceType::Media => write!(f, "media"),
        }
    }
}
pub fn copy_config(dst: &mut [u8], dst_offset: u64, src: &[u8], src_offset: u64) {
    if let Ok(dst_offset) = usize::try_from(dst_offset) {
        if let Ok(src_offset) = usize::try_from(src_offset) {
            if let Some(dst_slice) = dst.get_mut(dst_offset..) {
                if let Some(src_slice) = src.get(src_offset..) {
                    let len = cmp::min(dst_slice.len(), src_slice.len());
                    let dst_subslice = &mut dst_slice[0..len];
                    let src_subslice = &src_slice[0..len];
                    dst_subslice.copy_from_slice(src_subslice);
                }
            }
        }
    }
}
pub fn base_features(protection_type: ProtectionType) -> u64 {
    let mut features: u64 =
        1 << VIRTIO_F_VERSION_1 | 1 << VIRTIO_RING_F_EVENT_IDX | 1 << VIRTIO_F_SUSPEND;
    if protection_type != ProtectionType::Unprotected {
        features |= 1 << VIRTIO_F_ACCESS_PLATFORM;
    }
    features
}
pub enum VirtioDeviceType {
    Regular,
    VhostUser,
}
impl VirtioDeviceType {
    pub fn seccomp_policy_file(&self, base: &str) -> String {
        match self {
            VirtioDeviceType::Regular => format!("{base}_device"),
            VirtioDeviceType::VhostUser => format!("{base}_device_vhost_user"),
        }
    }
}
pub(crate) fn create_stop_oneshot(tx_vec: &mut Vec<oneshot::Sender<()>>) -> oneshot::Receiver<()> {
    let (stop_tx, stop_rx) = futures::channel::oneshot::channel();
    tx_vec.push(stop_tx);
    stop_rx
}
pub(crate) enum StoppedWorker<Q> {
    WithQueues(Box<Q>),
    AlreadyStopped,
    MissingQueues,
}