Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions alioth-cli/src/vu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use alioth::virtio::dev::fs::shared_dir::SharedDirSpec;
use alioth::virtio::dev::net::tap::TapNetSpec;
use alioth::virtio::dev::vsock::UdsVsockSpec;
use alioth::virtio::dev::{DevSpec, Virtio, VirtioDevice};
use alioth::virtio::vu::backend::{VuBackend, VuEventfd, VuIrqSender};
use alioth::virtio::vu::backend::{VuBackend, VuIrqSender};
use clap::{Args, Subcommand};
use serde::Deserialize;
use serde_aco::{Help, help_text};
Expand Down Expand Up @@ -108,7 +108,7 @@ fn create_dev<D, P>(
name: String,
args: &DevArgs<P>,
memory: Arc<RamBus>,
) -> Result<VirtioDevice<VuIrqSender, VuEventfd>, Error>
) -> Result<VirtioDevice<VuIrqSender>, Error>
where
D: Virtio,
P: DevSpec<Device = D> + Help + for<'a> Deserialize<'a> + Send + Sync + 'static,
Expand Down
19 changes: 8 additions & 11 deletions alioth/src/hv/hv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ use crate::arch::sev::{SevPolicy, SevStatus, SnpPageType, SnpPolicy};
#[cfg(target_arch = "x86_64")]
use crate::arch::tdx::TdAttr;
use crate::errors::{DebugTrace, trace_error};
use crate::sync::notifier::Notifier;

#[cfg(target_os = "macos")]
pub use self::hvf::Hvf;
Expand Down Expand Up @@ -90,8 +91,8 @@ pub enum Error {
MemEncrypt { error: std::io::Error },
#[snafu(display("Failed to configure an IrqFd"))]
IrqFd { error: std::io::Error },
#[snafu(display("Failed to configure an IoeventFd"))]
IoeventFd { error: std::io::Error },
#[snafu(display("Failed to configure a Notifier"))]
Notifier { error: std::io::Error },
#[snafu(display("Failed to create an IrqSender for pin {pin}"))]
CreateIrq { pin: u8, error: std::io::Error },
#[snafu(display("Failed to send an interrupt"))]
Expand Down Expand Up @@ -243,13 +244,9 @@ pub trait MsiSender: Debug + Send + Sync + 'static {
fn create_irqfd(&self) -> Result<Self::IrqFd>;
}

pub trait IoeventFd: Debug + Send + Sync + AsFd + 'static {}

pub trait IoeventFdRegistry: Debug + Send + Sync + 'static {
type IoeventFd: IoeventFd;
fn create(&self) -> Result<Self::IoeventFd>;
fn register(&self, fd: &Self::IoeventFd, gpa: u64, len: u8, data: Option<u64>) -> Result<()>;
fn deregister(&self, fd: &Self::IoeventFd) -> Result<()>;
pub trait NotifierRegistry: Debug + Send + Sync + 'static {
fn register(&self, notifier: &Notifier, gpa: u64, len: u8, data: Option<u64>) -> Result<()>;
fn deregister(&self, notifier: &Notifier) -> Result<()>;
}

pub trait IrqFd: Debug + Send + Sync + AsFd + 'static {
Expand Down Expand Up @@ -326,14 +323,14 @@ pub trait Vm: Debug + Send + Sync + 'static {
type Vcpu: Vcpu;
type IrqSender: IrqSender + Send + Sync;
type MsiSender: MsiSender;
type IoeventFdRegistry: IoeventFdRegistry;
type NotifierRegistry: NotifierRegistry;
fn create_vcpu(&self, index: u16, identity: u64) -> Result<Self::Vcpu, Error>;
fn create_irq_sender(&self, pin: u8) -> Result<Self::IrqSender, Error>;
fn create_msi_sender(
&self,
#[cfg(target_arch = "aarch64")] devid: u32,
) -> Result<Self::MsiSender>;
fn create_ioeventfd_registry(&self) -> Result<Self::IoeventFdRegistry>;
fn create_notifier_registry(&self) -> Result<Self::NotifierRegistry>;
fn stop_vcpu<T>(&self, identity: u64, handle: &JoinHandle<T>) -> Result<(), Error>;

fn map(&self, gpa: u64, size: u64, hva: usize, option: MemMapOption) -> Result<(), Error>;
Expand Down
32 changes: 6 additions & 26 deletions alioth/src/hv/hv_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ use std::sync::Arc;
use parking_lot::{Condvar, Mutex, RwLock};
use snafu::ResultExt;

use crate::hv::{IoeventFd, IrqFd, IrqSender, MsiSender, Result, error};
use crate::hv::{IrqFd, IrqSender, MsiSender, Result, error};
use crate::sync::notifier::Notifier;

#[derive(Debug)]
struct TestIrqFdInner {
Expand Down Expand Up @@ -141,17 +142,6 @@ impl MsiSender for TestMsiSender {
}
}

#[derive(Debug, Default)]
pub struct TestIoeventFd;

impl AsFd for TestIoeventFd {
fn as_fd(&self) -> BorrowedFd<'_> {
unsafe { BorrowedFd::borrow_raw(0) }
}
}

impl IoeventFd for TestIoeventFd {}

#[derive(Debug, Default, PartialEq, Eq)]
pub struct RegisteredAddr {
pub gpa: u64,
Expand All @@ -160,30 +150,20 @@ pub struct RegisteredAddr {
}

#[derive(Debug, Default)]
pub struct TestIoeventFdRegistry {
pub struct TestNotifierRegistry {
pub registered: Arc<Mutex<Vec<RegisteredAddr>>>,
pub deregistered: Arc<Mutex<usize>>,
pub fail_mode: Option<ErrorKind>,
}

impl super::IoeventFdRegistry for TestIoeventFdRegistry {
type IoeventFd = TestIoeventFd;

fn create(&self) -> Result<Self::IoeventFd> {
if let Some(kind) = self.fail_mode {
return Err(io::Error::from(kind)).context(error::IoeventFd);
}
Ok(TestIoeventFd)
}

fn register(&self, _fd: &Self::IoeventFd, gpa: u64, len: u8, data: Option<u64>) -> Result<()> {
impl super::NotifierRegistry for TestNotifierRegistry {
fn register(&self, _notifier: &Notifier, gpa: u64, len: u8, data: Option<u64>) -> Result<()> {
self.registered
.lock()
.push(RegisteredAddr { gpa, len, data });
Ok(())
}

fn deregister(&self, _fd: &Self::IoeventFd) -> Result<()> {
fn deregister(&self, _notifier: &Notifier) -> Result<()> {
*self.deregistered.lock() += 1;
Ok(())
}
Expand Down
44 changes: 16 additions & 28 deletions alioth/src/hv/hvf/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ use crate::arch::reg::MpidrEl1;
use crate::hv::hvf::vcpu::{HvfVcpu, VcpuHandle};
use crate::hv::hvf::{OsObject, check_ret};
use crate::hv::{
GicV2, GicV2m, GicV3, IoeventFd, IoeventFdRegistry, IrqFd, IrqSender, Its, MemMapOption,
MsiSender, Result, Vm, error,
GicV2, GicV2m, GicV3, IrqFd, IrqSender, Its, MemMapOption, MsiSender, NotifierRegistry, Result,
Vm, error,
};
use crate::sync::notifier::Notifier;
use crate::sys::hvf::{
HvMemoryFlag, hv_gic_config_create, hv_gic_config_set_distributor_base,
hv_gic_config_set_msi_interrupt_range, hv_gic_config_set_msi_region_base,
Expand Down Expand Up @@ -107,39 +108,25 @@ impl MsiSender for HvfMsiSender {
}
}

/// Hypervisor.framework has no `KVM_IOEVENTFD` equivalent, so this registry is
/// deliberately uninhabited: [`HvfVm::create_notifier_registry()`] always fails
/// and no value of this type can ever be constructed.
#[derive(Debug)]
pub struct HvfIoeventFd {}
pub enum HvfNotifierRegistry {}

impl IoeventFd for HvfIoeventFd {}

impl AsFd for HvfIoeventFd {
fn as_fd(&self) -> BorrowedFd<'_> {
unreachable!()
}
}

#[derive(Debug)]
pub struct HvfIoeventFdRegistry;

impl IoeventFdRegistry for HvfIoeventFdRegistry {
type IoeventFd = HvfIoeventFd;

fn create(&self) -> Result<Self::IoeventFd> {
Err(ErrorKind::Unsupported.into()).context(error::IoeventFd)
}

fn deregister(&self, _fd: &Self::IoeventFd) -> Result<()> {
unreachable!()
impl NotifierRegistry for HvfNotifierRegistry {
fn deregister(&self, _notifier: &Notifier) -> Result<()> {
match *self {}
}

fn register(
&self,
_fd: &Self::IoeventFd,
_notifier: &Notifier,
_gpa: u64,
_len: u8,
_data: Option<u64>,
) -> Result<()> {
unreachable!()
match *self {}
}
}

Expand Down Expand Up @@ -239,14 +226,15 @@ impl Vm for HvfVm {
type GicV2 = HvfGicV2;
type GicV2m = HvfGicV2m;
type GicV3 = HvfGicV3;
type IoeventFdRegistry = HvfIoeventFdRegistry;
type IrqSender = HvfIrqSender;
type Its = HvfIts;
type MsiSender = HvfMsiSender;
type NotifierRegistry = HvfNotifierRegistry;
type Vcpu = HvfVcpu;

fn create_ioeventfd_registry(&self) -> Result<Self::IoeventFdRegistry> {
Ok(HvfIoeventFdRegistry)
fn create_notifier_registry(&self) -> Result<Self::NotifierRegistry> {
// Hypervisor.framework has no KVM_IOEVENTFD equivalent.
Err(ErrorKind::Unsupported.into()).context(error::Notifier)
}

fn create_msi_sender(&self, _devid: u32) -> Result<Self::MsiSender> {
Expand Down
46 changes: 12 additions & 34 deletions alioth/src/hv/kvm/vm/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ use crate::ffi;
use crate::hv::kvm::vcpu::KvmVcpu;
use crate::hv::kvm::{KvmError, check_extension, kvm_error};
use crate::hv::{
Error, IoeventFd, IoeventFdRegistry, IrqFd, IrqSender, Kvm, MemMapOption, MsiSender, Result,
Vm, VmSpec, error,
Error, IrqFd, IrqSender, Kvm, MemMapOption, MsiSender, NotifierRegistry, Result, Vm, VmSpec,
error,
};
use crate::sync::notifier::Notifier;
#[cfg(target_arch = "x86_64")]
use crate::sys::kvm::KVM_IRQCHIP_IOAPIC;
#[cfg(target_arch = "aarch64")]
Expand Down Expand Up @@ -405,57 +406,34 @@ impl MsiSender for KvmMsiSender {
}
}

#[derive(Debug)]
pub struct KvmIoeventFd {
fd: OwnedFd,
}

impl AsFd for KvmIoeventFd {
fn as_fd(&self) -> BorrowedFd<'_> {
self.fd.as_fd()
}
}

impl IoeventFd for KvmIoeventFd {}

#[derive(Debug)]
pub struct KvmIoeventFdRegistry {
vm: Arc<VmInner>,
}

impl IoeventFdRegistry for KvmIoeventFdRegistry {
type IoeventFd = KvmIoeventFd;

fn create(&self) -> Result<Self::IoeventFd> {
let fd =
ffi!(unsafe { eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK) }).context(error::IoeventFd)?;
Ok(KvmIoeventFd {
fd: unsafe { OwnedFd::from_raw_fd(fd) },
})
}

fn register(&self, fd: &Self::IoeventFd, gpa: u64, len: u8, data: Option<u64>) -> Result<()> {
impl NotifierRegistry for KvmIoeventFdRegistry {
fn register(&self, notifier: &Notifier, gpa: u64, len: u8, data: Option<u64>) -> Result<()> {
let mut request = KvmIoEventFd {
addr: gpa,
len: len as u32,
fd: fd.as_fd().as_raw_fd(),
fd: notifier.as_fd().as_raw_fd(),
..Default::default()
};
if let Some(data) = data {
request.datamatch = data;
request.flags |= KvmIoEventFdFlag::DATA_MATCH;
}
unsafe { kvm_ioeventfd(&self.vm.fd, &request) }.context(error::IoeventFd)?;
unsafe { kvm_ioeventfd(&self.vm.fd, &request) }.context(error::Notifier)?;
let mut fds = self.vm.ioeventfds.lock();
fds.insert(request.fd, request);
Ok(())
}

fn deregister(&self, fd: &Self::IoeventFd) -> Result<()> {
fn deregister(&self, notifier: &Notifier) -> Result<()> {
let mut fds = self.vm.ioeventfds.lock();
if let Some(mut request) = fds.remove(&fd.as_fd().as_raw_fd()) {
if let Some(mut request) = fds.remove(&notifier.as_fd().as_raw_fd()) {
request.flags |= KvmIoEventFdFlag::DEASSIGN;
unsafe { kvm_ioeventfd(&self.vm.fd, &request) }.context(error::IoeventFd)?;
unsafe { kvm_ioeventfd(&self.vm.fd, &request) }.context(error::Notifier)?;
}
Ok(())
}
Expand Down Expand Up @@ -507,11 +485,11 @@ impl Vm for KvmVm {
type GicV2m = aarch64::KvmGicV2m;
#[cfg(target_arch = "aarch64")]
type GicV3 = aarch64::KvmGicV3;
type IoeventFdRegistry = KvmIoeventFdRegistry;
type IrqSender = KvmIrqSender;
#[cfg(target_arch = "aarch64")]
type Its = aarch64::KvmIts;
type MsiSender = KvmMsiSender;
type NotifierRegistry = KvmIoeventFdRegistry;
type Vcpu = KvmVcpu;

fn create_vcpu(&self, index: u16, identity: u64) -> Result<Self::Vcpu, Error> {
Expand Down Expand Up @@ -558,7 +536,7 @@ impl Vm for KvmVm {
})
}

fn create_ioeventfd_registry(&self) -> Result<Self::IoeventFdRegistry> {
fn create_notifier_registry(&self) -> Result<Self::NotifierRegistry> {
Ok(KvmIoeventFdRegistry {
vm: self.vm.clone(),
})
Expand Down
18 changes: 17 additions & 1 deletion alioth/src/sync/notifier/notifier_linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use std::fs::File;
use std::io::{ErrorKind, Read, Result, Write};
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd};
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd};

use libc::{EFD_CLOEXEC, EFD_NONBLOCK, eventfd};
use mio::event::Source;
Expand Down Expand Up @@ -51,6 +51,22 @@ impl Notifier {
}
}

/// Wraps an eventfd created elsewhere, e.g. a vhost-user kick fd sent by a
/// frontend.
///
/// The fd is forced into non-blocking mode, since [`Notifier::notify()`]
/// relies on `EAGAIN` to detect a saturated eventfd counter. An external
/// sender is under no obligation to have set `EFD_NONBLOCK` itself.
impl TryFrom<OwnedFd> for Notifier {
type Error = std::io::Error;

fn try_from(fd: OwnedFd) -> Result<Self> {
let flags = ffi!(unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_GETFL) })?;
ffi!(unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_SETFL, flags | libc::O_NONBLOCK) })?;
Ok(Notifier { fd: File::from(fd) })
}
}

impl Source for Notifier {
fn register(&mut self, registry: &Registry, token: Token, interests: Interest) -> Result<()> {
registry.register(&mut SourceFd(&self.fd.as_raw_fd()), token, interests)
Expand Down
Loading