diff --git a/common/src/buddy.rs b/common/src/buddy.rs index d86f02d5..8b386a92 100644 --- a/common/src/buddy.rs +++ b/common/src/buddy.rs @@ -30,6 +30,8 @@ static BUDDY: LazyLock = LazyLock::new(|| { } }); +pub const MEM_BASE: u64 = 0x1_0000_0000; + #[cfg(feature = "std")] pub fn init(size: usize) { LazyLock::set(&BUDDY, BuddyAllocatorImpl::new(size)) @@ -936,6 +938,10 @@ pub struct BuddyAllocator; // Rust requires explicit guarantee that clones of custom memory allocator for Arc can free memory allocated by each other unsafe impl AllocatorClone for BuddyAllocator {} +pub fn ioaddr() -> u64 { + MEM_BASE + BuddyAllocator.len() as u64 +} + impl BuddyAllocator { pub const MIN_ALLOCATION: usize = BuddyAllocatorImpl::MIN_ALLOCATION; } diff --git a/common/src/lib.rs b/common/src/lib.rs index 66425c37..63ca1c98 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -58,9 +58,6 @@ pub mod hypercall { pub const MEMSET: u64 = 3; pub const MEMCLR: u64 = 4; - pub const NOTIFY_READ: u64 = 16; - pub const NOTIFY_WRITE: u64 = 17; - #[derive(Debug, Default)] pub struct TcpInfo { pub ip: u32, diff --git a/common/src/pipe.rs b/common/src/pipe.rs index ed1ef456..78ed2957 100644 --- a/common/src/pipe.rs +++ b/common/src/pipe.rs @@ -1,7 +1,9 @@ mod bi; +mod doorbell; mod error; mod uni; pub use bi::{pipe, Pipe}; +pub use doorbell::DoorBell; pub use error::{Error, Result}; pub use uni::{channel, Reader, Writer}; diff --git a/common/src/pipe/bi.rs b/common/src/pipe/bi.rs index 712ec4c9..b166292d 100644 --- a/common/src/pipe/bi.rs +++ b/common/src/pipe/bi.rs @@ -1,21 +1,49 @@ +use super::doorbell::DoorBell; use super::error::Result; use super::uni::{channel, Reader, Writer}; #[derive(Debug)] -pub struct Pipe { +pub struct Pipe { rx: Reader, tx: Writer, + rx_avail: D, + tx_avail: D, } -pub fn pipe(len: usize) -> (Pipe, Pipe) { +pub fn pipe( + len: usize, + rx_avail0: D0, + tx_avail0: D0, + rx_avail1: D1, + tx_avail1: D1, +) -> (Pipe, Pipe) { let (r0, w0) = channel(len); let (r1, w1) = channel(len); - (Pipe { rx: r0, tx: w1 }, Pipe { rx: r1, tx: w0 }) + ( + Pipe { + rx: r0, + tx: w1, + rx_avail: rx_avail0, + tx_avail: tx_avail0, + }, + Pipe { + rx: r1, + tx: w0, + rx_avail: rx_avail1, + tx_avail: tx_avail1, + }, + ) } -impl Pipe { +impl Pipe { pub fn read(&mut self, data: &mut [u8]) -> Result { - self.rx.read(data) + let res = self.rx.read(data); + if let Ok(s) = res { + if s > 0 { + self.tx_avail.ring(); + } + } + res } pub fn can_read(&self) -> bool { @@ -23,30 +51,68 @@ impl Pipe { } pub fn write(&mut self, data: &[u8]) -> Result { - self.tx.write(data) + let res = self.tx.write(data); + if let Ok(s) = res { + if s > 0 { + self.rx_avail.ring(); + } + } + res } pub fn can_write(&self) -> bool { !self.tx.is_empty() } - pub fn into_inner(self) -> (Reader, Writer) { - (self.rx, self.tx) + pub fn into_inner(self) -> (Reader, Writer, D, D) { + (self.rx, self.tx, self.rx_avail, self.tx_avail) } /// # Safety /// The reader and writer must correspond to the two halves of a pipe, as previously returned /// from into_inner. - pub unsafe fn from_inner(rx: Reader, tx: Writer) -> Self { - Pipe { rx, tx } + pub unsafe fn from_inner(rx: Reader, tx: Writer, rx_avail: D, tx_avail: D) -> Self { + Pipe { + rx, + tx, + rx_avail, + tx_avail, + } } } #[cfg(test)] mod tests { + use super::*; + use core::sync::atomic::{AtomicUsize, Ordering}; + + pub struct TestDoorBell { + count: AtomicUsize, + } + + impl DoorBell for TestDoorBell { + fn ring(&self) { + self.count.fetch_add(1, Ordering::Release); + } + } + + impl TestDoorBell { + pub fn new() -> Self { + Self { + count: AtomicUsize::new(0), + } + } + } + #[test] pub fn test_ping_pong() { - let (mut p, mut q) = super::pipe(1024); + let (mut p, mut q) = super::pipe( + 1024, + TestDoorBell::new(), + TestDoorBell::new(), + TestDoorBell::new(), + TestDoorBell::new(), + ); std::thread::spawn(move || loop { let mut buf = [0; 8]; loop { diff --git a/common/src/pipe/doorbell.rs b/common/src/pipe/doorbell.rs new file mode 100644 index 00000000..50e4ca20 --- /dev/null +++ b/common/src/pipe/doorbell.rs @@ -0,0 +1,6 @@ +/// Notify the waiter on newly available event (readable/writable) +/// +/// ring blocks until it's possible to ring +pub trait DoorBell { + fn ring(&self); +} diff --git a/common/src/protocol/control.rs b/common/src/protocol/control.rs index a6d315cf..ab619925 100644 --- a/common/src/protocol/control.rs +++ b/common/src/protocol/control.rs @@ -73,12 +73,19 @@ impl From for IoErrorKind { } } +#[derive(Debug, Serialize, Deserialize)] +pub struct VMToHostDoorBellData { + pub datamatch: u64, +} + #[derive(Debug, Serialize, Deserialize)] pub struct PipeData { pub rx_ptr: usize, pub rx_len: usize, pub tx_ptr: usize, pub tx_len: usize, + pub rx_avail: VMToHostDoorBellData, + pub tx_avail: VMToHostDoorBellData, } #[derive(Debug, Default, Serialize, Deserialize)] diff --git a/kernel/src/doorbell.rs b/kernel/src/doorbell.rs new file mode 100644 index 00000000..c111903f --- /dev/null +++ b/kernel/src/doorbell.rs @@ -0,0 +1,37 @@ +use crate::vm; +use common::{buddy::ioaddr, pipe::DoorBell, protocol::control::VMToHostDoorBellData}; + +#[derive(Debug)] +struct SendPtr(*mut u64); + +/// #Safety +/// +/// The ptr remains valid during the lifetime of SendPtr +unsafe impl Send for SendPtr {} + +#[derive(Debug)] +pub struct VMToHostDoorBell { + addr: SendPtr, + datamatch: u64, +} + +impl VMToHostDoorBell { + /// #Safety + /// + /// raw must corresponds to a into_inner call on the vmm side on a VMToHostDoorBell + pub unsafe fn from_raw_parts(raw: VMToHostDoorBellData) -> Self { + let addr: *mut u64 = vm::pa2ka(ioaddr() as usize); + Self { + addr: SendPtr(addr), + datamatch: raw.datamatch, + } + } +} + +impl DoorBell for VMToHostDoorBell { + fn ring(&self) { + unsafe { + core::ptr::write_volatile(self.addr.0, self.datamatch); + } + } +} diff --git a/kernel/src/host.rs b/kernel/src/host.rs index e43a7fb9..d2241130 100644 --- a/kernel/src/host.rs +++ b/kernel/src/host.rs @@ -1,4 +1,4 @@ -use crate::prelude::*; +use crate::{doorbell::VMToHostDoorBell, prelude::*}; use alloc::format; use common::hypercall; @@ -115,7 +115,9 @@ unsafe fn get_pipe(data: common::protocol::control::PipeData) -> HostPipe { let rx = Reader::from_inner(rx); let tx = Arc::from_raw_in(core::ptr::from_raw_parts(txp, data.tx_len), BuddyAllocator); let tx = Writer::from_inner(tx); - let pipe = Pipe::from_inner(rx, tx); + let rx_avail = VMToHostDoorBell::from_raw_parts(data.rx_avail); + let tx_avail = VMToHostDoorBell::from_raw_parts(data.tx_avail); + let pipe = Pipe::from_inner(rx, tx, rx_avail, tx_avail); HostPipe::new(pipe) } diff --git a/kernel/src/interrupts.rs b/kernel/src/interrupts.rs index db9e65fa..86b904b5 100644 --- a/kernel/src/interrupts.rs +++ b/kernel/src/interrupts.rs @@ -119,6 +119,11 @@ unsafe extern "C" fn isr_entry(registers: &mut IsrRegisterFile) { crate::lapic::LAPIC.borrow_mut().clear_interrupt(); return; } + if registers.isr == 0x32 { + INTERRUPTED.store(true, Ordering::Release); + crate::lapic::LAPIC.borrow_mut().clear_interrupt(); + return; + } if registers.cs & 0b11 == 0b11 { if registers.isr == 0x20 { INTERRUPTED.store(true, Ordering::Relaxed); diff --git a/kernel/src/lapic.rs b/kernel/src/lapic.rs index a0ce9fff..7d2350b5 100644 --- a/kernel/src/lapic.rs +++ b/kernel/src/lapic.rs @@ -179,4 +179,10 @@ pub unsafe fn init() { win.write_volatile(0x31); regsel.write_volatile(0x13); // redirection entry 0-hi win.write_volatile(0x00); + + // GSI 2 -> INT 0x32 + regsel.write_volatile(0x14); // redirection entry 0-lo + win.write_volatile(0x32); + regsel.write_volatile(0x15); // redirection entry 0-hi + win.write_volatile(0x00); } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index a6836e30..8b67e22d 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -37,6 +37,7 @@ pub mod tsc; pub mod types; pub mod vm; +mod doorbell; mod gdt; mod idt; mod interrupts; diff --git a/kernel/src/pipe.rs b/kernel/src/pipe.rs index 6528e693..270102bb 100644 --- a/kernel/src/pipe.rs +++ b/kernel/src/pipe.rs @@ -1,3 +1,4 @@ +use crate::doorbell::VMToHostDoorBell; use crate::kthread; use crate::prelude::*; use common::pipe::Pipe as RawPipe; @@ -9,18 +10,17 @@ pub static HOST: KMutex> = KMutex::new(OnceCell::new()); #[derive(Debug)] pub struct HostPipe { - inner: RawPipe, + inner: RawPipe, } impl HostPipe { - pub fn new(pipe: RawPipe) -> Self { + pub fn new(pipe: RawPipe) -> Self { Self { inner: pipe } } pub fn read(&mut self, bytes: &mut [u8]) -> PipeResult { while !self.inner.can_read() { - // kthread::wfi(); - kthread::yield_now(); + kthread::wfi(); } self.inner.read(bytes) } @@ -41,14 +41,9 @@ impl HostPipe { pub fn write(&mut self, bytes: &[u8]) -> PipeResult { while !self.inner.can_write() { - // kthread::wfi(); - kthread::yield_now(); + kthread::wfi(); } - let n = self.inner.write(bytes); - // unsafe { - // crate::io::hypercall0(crate::hypercall::NOTIFY_READ); - // } - n + self.inner.write(bytes) } pub fn write_exact(&mut self, mut bytes: &[u8]) -> PipeResult<()> { diff --git a/kernel/src/rsstart.rs b/kernel/src/rsstart.rs index 0a41c269..8325cd71 100644 --- a/kernel/src/rsstart.rs +++ b/kernel/src/rsstart.rs @@ -9,6 +9,7 @@ use log::LevelFilter; use crate::{ debugcon::DEBUG, + doorbell::VMToHostDoorBell, gdt::{GdtDescriptor, PrivilegeLevel}, host::HOST, idt::{GateType, Idt, IdtDescriptor, IdtEntry}, @@ -18,7 +19,11 @@ use crate::{ vm, }; -use common::{buddy::BuddyAllocatorRawData, BuddyAllocator}; +use common::{ + buddy::{BuddyAllocatorRawData, MEM_BASE}, + protocol::control::VMToHostDoorBellData, + BuddyAllocator, +}; extern "C" { fn kmain(); @@ -98,7 +103,7 @@ unsafe extern "C" fn _start( } let ptr: *mut BuddyAllocatorRawData = vm::pa2ka(allocator_data_ptr + 0x1_0000_0000); let mut raw = *ptr; - raw.base = vm::pa2ka(0x1_0000_0000); + raw.base = vm::pa2ka(MEM_BASE as usize); common::buddy::import(raw); BuddyAllocator.set_caching(false); @@ -147,7 +152,9 @@ unsafe extern "C" fn _start( let rx = Reader::from_inner(rx); let tx = Arc::from_raw_in(core::ptr::from_raw_parts(txp, txn), BuddyAllocator); let tx = Writer::from_inner(tx); - let pipe = RawPipe::from_inner(rx, tx); + let rx_avail = VMToHostDoorBell::from_raw_parts(VMToHostDoorBellData { datamatch: 0 }); + let tx_avail = VMToHostDoorBell::from_raw_parts(VMToHostDoorBellData { datamatch: 1 }); + let pipe = RawPipe::from_inner(rx, tx, rx_avail, tx_avail); let pipe = HostPipe::new(pipe); let host = crate::pipe::HOST.lock(); host.set(ControlPipe::new(pipe)).unwrap(); diff --git a/vmm/src/comm.rs b/vmm/src/comm.rs index 61172a54..8264509f 100644 --- a/vmm/src/comm.rs +++ b/vmm/src/comm.rs @@ -1,13 +1,16 @@ -use crate::pipe::{ControlPipe, FilePipe, ListenerPipe, StreamPipe}; +use crate::doorbell::{new_vm_to_host_door_bell, HostToVMDoorBell, VMToHostDoorBell}; +use crate::pipe::{ControlPipe, FilePipe, GuestPipe, ListenerPipe, StreamPipe}; use common::protocol::control::PipeData; use common::BuddyAllocator; +use kvm_ioctls::VmFd; use std::fs::{File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::sync::atomic::AtomicUsize; use std::sync::Arc; -fn decompose_pipe(pipe: common::pipe::Pipe) -> PipeData { - let (rx, tx) = pipe.into_inner(); +fn decompose_pipe(pipe: common::pipe::Pipe) -> PipeData { + let (rx, tx, rx_avail, tx_avail) = pipe.into_inner(); let rx = rx.into_inner(); let tx = tx.into_inner(); let (rx_ptr, rx_len) = Arc::into_raw_with_allocator(rx).0.to_raw_parts(); @@ -19,10 +22,34 @@ fn decompose_pipe(pipe: common::pipe::Pipe) -> PipeData { rx_len, tx_ptr, tx_len, + rx_avail: rx_avail.into_raw_parts(), + tx_avail: tx_avail.into_raw_parts(), } } -pub fn control_thread(argv: Vec, mut pipe: ControlPipe) { +pub fn new_pipe( + vm: &VmFd, + len: usize, + next_pipe_idx: &Arc, +) -> (common::pipe::Pipe, GuestPipe) { + let pipe_idx = next_pipe_idx.fetch_add(1, std::sync::atomic::Ordering::Release); + let (rx_avail_vm, rx_avail_waiter) = new_vm_to_host_door_bell(vm, pipe_idx as u64 * 2); + let (tx_avail_vm, tx_avail_waiter) = new_vm_to_host_door_bell(vm, pipe_idx as u64 * 2 + 1); + + let rx_avail_host = HostToVMDoorBell::new(vm); + let tx_avail_host = HostToVMDoorBell::new(vm); + + let (p0, p1) = common::pipe::pipe(len, rx_avail_vm, tx_avail_vm, rx_avail_host, tx_avail_host); + let p1 = GuestPipe::new(p1, rx_avail_waiter, tx_avail_waiter); + (p0, p1) +} + +pub fn control_thread( + vm: Arc, + next_pipe_idx: Arc, + argv: Vec, + mut pipe: ControlPipe, +) { use common::protocol::control::*; loop { let response = match pipe.recv() { @@ -38,10 +65,9 @@ pub fn control_thread(argv: Vec, mut pipe: ControlPipe) { .open(path); match f { Ok(f) => { - let (p, q) = common::pipe::pipe(1024); + let (p, q) = new_pipe(&vm, 1024, &next_pipe_idx); std::thread::spawn(move || { - let pipe = crate::pipe::GuestPipe::new(q); - file_thread(f, FilePipe::new(pipe)); + file_thread(f, FilePipe::new(q)); }); Response::Pipe(decompose_pipe(p)) } @@ -54,19 +80,19 @@ pub fn control_thread(argv: Vec, mut pipe: ControlPipe) { }, Request::Listen { ip, port } => { let listener = TcpListener::bind(SocketAddr::from((ip, port))).unwrap(); - let (p, q) = common::pipe::pipe(1024); + let (p, q) = new_pipe(&vm, 1024, &next_pipe_idx); + let vm_cl = vm.clone(); + let next_pipe_cl = next_pipe_idx.clone(); std::thread::spawn(move || { - let pipe = crate::pipe::GuestPipe::new(q); - listener_thread(listener, ListenerPipe::new(pipe)); + listener_thread(vm_cl, next_pipe_cl, listener, ListenerPipe::new(q)); }); Response::Pipe(decompose_pipe(p)) } Request::Connect { host, port } => { let stream = TcpStream::connect((host.as_str(), port)).unwrap(); - let (p, q) = common::pipe::pipe(1024); + let (p, q) = new_pipe(&vm, 1024, &next_pipe_idx); std::thread::spawn(move || { - let pipe = crate::pipe::GuestPipe::new(q); - stream_thread(stream, StreamPipe::new(pipe)); + stream_thread(stream, StreamPipe::new(q)); }); Response::Pipe(decompose_pipe(p)) } @@ -107,16 +133,20 @@ pub fn file_thread(mut file: File, mut pipe: FilePipe) { } } -pub fn listener_thread(listener: TcpListener, mut pipe: ListenerPipe) { +pub fn listener_thread( + vm: Arc, + next_pipe_idx: Arc, + listener: TcpListener, + mut pipe: ListenerPipe, +) { use common::protocol::listener::*; loop { let response = match pipe.recv() { Request::Accept => { let (stream, _) = listener.accept().unwrap(); - let (p, q) = common::pipe::pipe(1024); + let (p, q) = new_pipe(&vm, 1024, &next_pipe_idx); std::thread::spawn(move || { - let pipe = crate::pipe::GuestPipe::new(q); - stream_thread(stream, StreamPipe::new(pipe)); + stream_thread(stream, StreamPipe::new(q)); }); Response::Pipe(decompose_pipe(p)) } diff --git a/vmm/src/doorbell.rs b/vmm/src/doorbell.rs new file mode 100644 index 00000000..dfcb0587 --- /dev/null +++ b/vmm/src/doorbell.rs @@ -0,0 +1,75 @@ +use common::{buddy::ioaddr, pipe::DoorBell, protocol::control::VMToHostDoorBellData}; +use kvm_ioctls::{IoEventAddress, VmFd}; +use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK}; + +#[derive(Debug)] +pub struct HostToVMDoorBell { + fd: EventFd, +} + +const HOST_TO_VM_GSI: u32 = 2; + +impl HostToVMDoorBell { + pub fn new(vm: &VmFd) -> Self { + let evtfd = EventFd::new(EFD_NONBLOCK).unwrap(); + vm.register_irqfd(&evtfd, HOST_TO_VM_GSI) + .expect("Failed to register irqfd"); + Self { fd: evtfd } + } +} + +impl DoorBell for HostToVMDoorBell { + fn ring(&self) { + while self.fd.write(1).is_err() {} + } +} + +#[derive(Debug)] +pub struct VMToHostDoorBellWaiter { + pub fd: EventFd, +} + +impl VMToHostDoorBellWaiter { + /// Each eventfd needs to have a unique {addr, datamatch} pair, and it is + /// allowed to have multiple eventfds registered at the same address with + /// different datamatch. The caller needs to guarantee that {addr, datamatch} + /// hasn't been registered before + fn new(vm: &VmFd, addr: &IoEventAddress, datamatch: u64) -> Self { + let evtfd = EventFd::new(0).unwrap(); + vm.register_ioevent(&evtfd, addr, datamatch) + .expect("Failed to register ioevent"); + Self { fd: evtfd } + } +} + +pub struct VMToHostDoorBell { + datamatch: u64, +} + +impl VMToHostDoorBell { + fn new(datamatch: u64) -> Self { + Self { datamatch } + } + + pub fn into_raw_parts(self) -> VMToHostDoorBellData { + VMToHostDoorBellData { + datamatch: self.datamatch, + } + } +} + +impl DoorBell for VMToHostDoorBell { + fn ring(&self) { + panic!("Ringing at the wrong location") + } +} + +pub fn new_vm_to_host_door_bell( + vm: &VmFd, + datamatch: u64, +) -> (VMToHostDoorBell, VMToHostDoorBellWaiter) { + let doorbellwaiter = + VMToHostDoorBellWaiter::new(vm, &IoEventAddress::Mmio(ioaddr()), datamatch); + let doorbell = VMToHostDoorBell::new(datamatch); + (doorbell, doorbellwaiter) +} diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 98cdc436..d42407fb 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -6,5 +6,6 @@ #![feature(cstr_display)] pub mod comm; +mod doorbell; pub mod pipe; pub mod runtime; diff --git a/vmm/src/pipe.rs b/vmm/src/pipe.rs index b57c1f21..00317426 100644 --- a/vmm/src/pipe.rs +++ b/vmm/src/pipe.rs @@ -1,21 +1,31 @@ +use crate::doorbell::{HostToVMDoorBell, VMToHostDoorBellWaiter}; use common::pipe::Pipe as RawPipe; pub use common::pipe::{Error, Result}; use std::marker::PhantomData; #[derive(Debug)] pub struct GuestPipe { - inner: RawPipe, + inner: RawPipe, + rx_avail: VMToHostDoorBellWaiter, + tx_avail: VMToHostDoorBellWaiter, } impl GuestPipe { - pub fn new(pipe: RawPipe) -> Self { - Self { inner: pipe } + pub fn new( + pipe: RawPipe, + rx_avail: VMToHostDoorBellWaiter, + tx_avail: VMToHostDoorBellWaiter, + ) -> Self { + Self { + inner: pipe, + rx_avail, + tx_avail, + } } pub fn read(&mut self, bytes: &mut [u8]) -> Result { while !self.inner.can_read() { - // self.read_fd.read().unwrap(); - std::thread::yield_now(); + self.rx_avail.fd.read().unwrap(); } self.inner.read(bytes) } @@ -36,8 +46,7 @@ impl GuestPipe { pub fn write(&mut self, bytes: &[u8]) -> Result { while !self.inner.can_write() { - // self.write_fd.read().unwrap(); - std::thread::yield_now(); + self.tx_avail.fd.read().unwrap(); } self.inner.write(bytes) } diff --git a/vmm/src/runtime.rs b/vmm/src/runtime.rs index 511cf170..5ca52b2e 100644 --- a/vmm/src/runtime.rs +++ b/vmm/src/runtime.rs @@ -3,14 +3,14 @@ use std::{ io::{self, Read}, process::ExitCode, sync::{ - atomic::{AtomicBool, Ordering}, + atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, }, thread::{Scope, ScopedJoinHandle}, time::{Duration, Instant}, }; -use common::{hypercall, BuddyAllocator}; +use common::{buddy::MEM_BASE, hypercall, BuddyAllocator}; use elf::{endian::AnyEndian, segment::ProgramHeader, ElfBytes}; use kvm_bindings::{kvm_userspace_memory_region, CpuId, KVM_MAX_CPUID_ENTRIES}; use kvm_ioctls::{IoEventAddress, Kvm, NoDatamatch, VcpuExit, VcpuFd, VmFd}; @@ -19,7 +19,7 @@ pub use common::mmap::Mmap; use libc::EFD_NONBLOCK; use vmm_sys_util::eventfd::EventFd; -const MEM_BASE: u64 = 0x1_0000_0000; +use crate::comm::new_pipe; fn new_cpu<'scope>( i: usize, @@ -290,14 +290,6 @@ fn run_cpu(mut vcpu_fd: VcpuFd, elf: &ElfBytes, exit: Arc regs.rax = mem.as_ptr() as u64; } } - hypercall::NOTIFY_READ => { - todo!(); - // read_fd.write(1).unwrap(); - } - hypercall::NOTIFY_WRITE => { - todo!(); - // write_fd.write(1).unwrap(); - } x => unimplemented!("hypercall {x}"), }; vcpu_fd.set_regs(®s).unwrap(); @@ -330,9 +322,10 @@ fn run_cpu(mut vcpu_fd: VcpuFd, elf: &ElfBytes, exit: Arc pub struct Runtime { kvm: Kvm, - vm: VmFd, + vm: Arc, cores: usize, elf: Arc<[u8]>, + next_pipe_idx: Arc, } impl Runtime { @@ -380,9 +373,10 @@ impl Runtime { let mut x = Self { kvm, - vm, + vm: Arc::new(vm), cores, elf: elf.clone(), + next_pipe_idx: Arc::new(AtomicUsize::new(0)), }; let elf_bytes = ElfBytes::::minimal_parse(&elf).expect("could not read kernel elf file"); @@ -458,19 +452,21 @@ impl Runtime { std::thread::scope(|s| { let mut cpus = vec![]; - let (p, q) = common::pipe::pipe(8192); - // let read = EventFd::new(0).unwrap(); - // let write = EventFd::new(0).unwrap(); - // let read_fd = read.try_clone().unwrap(); - // let write_fd = write.try_clone().unwrap(); + let (p, q) = new_pipe(&self.vm, 8192, &self.next_pipe_idx); + + let vm_cl = self.vm.clone(); + let next_pipe_cl = self.next_pipe_idx.clone(); + let comm = s.spawn(move || { crate::comm::control_thread( + vm_cl, + next_pipe_cl, argv, - crate::pipe::ControlPipe::new(crate::pipe::GuestPipe::new(q)), + crate::pipe::ControlPipe::new(q), ); }); - let (rx, tx) = p.into_inner(); + let (rx, tx, _, _) = p.into_inner(); let rx = rx.into_inner(); let tx = tx.into_inner(); let (rxp, rxn) = Arc::into_raw_with_allocator(rx).0.to_raw_parts();