From a49478d670c93c444ca4cb214cc1a7d7b2621892 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Thu, 16 Jul 2026 15:06:07 -0700 Subject: [PATCH 1/6] feat: common doorbell --- common/src/pipe.rs | 1 + common/src/pipe/bi.rs | 54 ++++++++++++++++++++++++++++++------- common/src/pipe/doorbell.rs | 6 +++++ 3 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 common/src/pipe/doorbell.rs diff --git a/common/src/pipe.rs b/common/src/pipe.rs index ed1ef456..9af69029 100644 --- a/common/src/pipe.rs +++ b/common/src/pipe.rs @@ -1,6 +1,7 @@ mod bi; mod error; mod uni; +mod doorbell; pub use bi::{pipe, Pipe}; pub use error::{Error, Result}; diff --git a/common/src/pipe/bi.rs b/common/src/pipe/bi.rs index 712ec4c9..f5a2f6c0 100644 --- a/common/src/pipe/bi.rs +++ b/common/src/pipe/bi.rs @@ -1,21 +1,30 @@ use super::error::Result; use super::uni::{channel, Reader, Writer}; +use super::doorbell::DoorBell; #[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,7 +32,13 @@ 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 { @@ -37,16 +52,37 @@ impl Pipe { /// # 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 core::sync::atomic::{AtomicUsize, Ordering}; + use super::*; + + 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); +} From 9520b63443711bd79ad0c93a899f48f1641ae5e4 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Fri, 17 Jul 2026 17:38:59 -0700 Subject: [PATCH 2/6] feat: kernel + vmm doorbell --- common/src/pipe.rs | 3 +- common/src/pipe/bi.rs | 48 ++++++++++++--- common/src/protocol/control.rs | 8 +++ kernel/src/doorbell.rs | 39 +++++++++++++ kernel/src/host.rs | 6 +- kernel/src/interrupts.rs | 2 +- kernel/src/lapic.rs | 6 ++ kernel/src/lib.rs | 1 + kernel/src/pipe.rs | 5 +- kernel/src/rsstart.rs | 17 +++++- vmm/src/comm.rs | 69 ++++++++++++++++------ vmm/src/doorbell.rs | 104 +++++++++++++++++++++++++++++++++ vmm/src/lib.rs | 1 + vmm/src/pipe.rs | 17 +++++- vmm/src/runtime.rs | 30 ++++++---- 15 files changed, 309 insertions(+), 47 deletions(-) create mode 100644 kernel/src/doorbell.rs create mode 100644 vmm/src/doorbell.rs diff --git a/common/src/pipe.rs b/common/src/pipe.rs index 9af69029..78ed2957 100644 --- a/common/src/pipe.rs +++ b/common/src/pipe.rs @@ -1,8 +1,9 @@ mod bi; +mod doorbell; mod error; mod uni; -mod doorbell; 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 f5a2f6c0..b166292d 100644 --- a/common/src/pipe/bi.rs +++ b/common/src/pipe/bi.rs @@ -1,6 +1,6 @@ +use super::doorbell::DoorBell; use super::error::Result; use super::uni::{channel, Reader, Writer}; -use super::doorbell::DoorBell; #[derive(Debug)] pub struct Pipe { @@ -10,10 +10,29 @@ pub struct Pipe { tx_avail: D, } -pub fn pipe(len: usize, rx_avail0: D0, tx_avail0: D0, rx_avail1: D1, tx_avail1: D1) -> (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, rx_avail: rx_avail0, tx_avail: tx_avail0 }, Pipe { rx: r1, tx: w0, rx_avail: rx_avail1, tx_avail: tx_avail1 }) + ( + 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 { @@ -45,25 +64,30 @@ impl Pipe { !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, rx_avail: D, tx_avail: D) -> Self { - Pipe { rx, tx, rx_avail, tx_avail } + Pipe { + rx, + tx, + rx_avail, + tx_avail, + } } } #[cfg(test)] mod tests { - use core::sync::atomic::{AtomicUsize, Ordering}; use super::*; + use core::sync::atomic::{AtomicUsize, Ordering}; pub struct TestDoorBell { - count: AtomicUsize + count: AtomicUsize, } impl DoorBell for TestDoorBell { @@ -82,7 +106,13 @@ mod tests { #[test] pub fn test_ping_pong() { - let (mut p, mut q) = super::pipe(1024, TestDoorBell::new(), TestDoorBell::new(), TestDoorBell::new(), TestDoorBell::new()); + 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/protocol/control.rs b/common/src/protocol/control.rs index a6d315cf..aa14fac6 100644 --- a/common/src/protocol/control.rs +++ b/common/src/protocol/control.rs @@ -73,12 +73,20 @@ impl From for IoErrorKind { } } +#[derive(Debug, Serialize, Deserialize)] +pub struct VMToHostDoorBellData { + pub addr: u64, + 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..3a712919 --- /dev/null +++ b/kernel/src/doorbell.rs @@ -0,0 +1,39 @@ +#![allow(unused)] + +use crate::vm; +use common::{pipe::DoorBell, protocol::control::VMToHostDoorBellData, BuddyAllocator}; + +#[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(raw.addr.try_into().unwrap()); + 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..02e92359 100644 --- a/kernel/src/interrupts.rs +++ b/kernel/src/interrupts.rs @@ -185,7 +185,7 @@ unsafe extern "C" fn isr_entry(registers: &mut IsrRegisterFile) { if registers.isr < 32 { panic!("unhandled exception: {:x?}", registers); } - if registers.isr == 0x20 { + if registers.isr == 0x20 || registers.isr == 0x32 { INTERRUPTED.store(true, Ordering::Relaxed); crate::iprofile::tick(registers); crate::lapic::LAPIC.borrow_mut().clear_interrupt(); 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..c6958c26 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,11 +10,11 @@ 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 } } diff --git a/kernel/src/rsstart.rs b/kernel/src/rsstart.rs index 0a41c269..916b946d 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,9 @@ use crate::{ vm, }; -use common::{buddy::BuddyAllocatorRawData, BuddyAllocator}; +use common::{ + buddy::BuddyAllocatorRawData, protocol::control::VMToHostDoorBellData, BuddyAllocator, +}; extern "C" { fn kmain(); @@ -108,6 +111,8 @@ unsafe extern "C" fn _start( init_cpu_tls(); }; + let ioaddr = 0x1_0000_0000 + BuddyAllocator.len(); + // per-cpu init crate::tsc::init(); crate::kvmclock::init(); @@ -147,7 +152,15 @@ 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 { + addr: ioaddr as u64, + datamatch: 0, + }); + let tx_avail = VMToHostDoorBell::from_raw_parts(VMToHostDoorBellData { + addr: ioaddr as u64, + 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..3e14dcfd 100644 --- a/vmm/src/comm.rs +++ b/vmm/src/comm.rs @@ -1,13 +1,17 @@ -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::IoEventAddress; +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 +23,37 @@ 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, + addr: IoEventAddress, + 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, addr, pipe_idx as u64 * 2); + let (tx_avail_vm, tx_avail_waiter) = + new_vm_to_host_door_bell(vm, addr, 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, + addr: IoEventAddress, + next_pipe_idx: Arc, + argv: Vec, + mut pipe: ControlPipe, +) { use common::protocol::control::*; loop { let response = match pipe.recv() { @@ -38,10 +69,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, addr, 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 +84,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, addr, 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, addr, 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, addr, 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 +137,21 @@ 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, + addr: IoEventAddress, + 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, addr, 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..0acc9b5a --- /dev/null +++ b/vmm/src/doorbell.rs @@ -0,0 +1,104 @@ +#![allow(unused)] + +use std::os::fd::{AsRawFd, RawFd}; + +use common::{pipe::DoorBell, protocol::control::VMToHostDoorBellData, BuddyAllocator}; +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 { + fd: EventFd, +} + +impl From for EventFd { + fn from(val: VMToHostDoorBellWaiter) -> Self { + val.fd + } +} + +impl AsRawFd for VMToHostDoorBellWaiter { + fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd { + self.fd.as_raw_fd() + } +} + +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(EFD_NONBLOCK).unwrap(); + vm.register_ioevent(&evtfd, addr, datamatch) + .expect("Failed to register ioevent"); + Self { fd: evtfd } + } + + pub fn drain(&mut self) -> std::io::Result<()> { + loop { + self.fd.read()?; + } + } +} + +pub struct VMToHostDoorBell { + addr: IoEventAddress, + datamatch: u64, +} + +impl VMToHostDoorBell { + fn new(addr: IoEventAddress, datamatch: u64) -> Self { + Self { addr, datamatch } + } + + pub fn into_raw_parts(self) -> VMToHostDoorBellData { + let addr = match self.addr { + IoEventAddress::Pio(_) => todo!(), + IoEventAddress::Mmio(addr) => addr, + }; + + VMToHostDoorBellData { + addr, + 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, + addr: IoEventAddress, + datamatch: u64, +) -> (VMToHostDoorBell, VMToHostDoorBellWaiter) { + let doorbellwaiter = VMToHostDoorBellWaiter::new(vm, &addr, datamatch); + let doorbell = VMToHostDoorBell::new(addr, 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..1f43d001 100644 --- a/vmm/src/pipe.rs +++ b/vmm/src/pipe.rs @@ -1,15 +1,26 @@ +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: rx_avail, + _tx_avail: tx_avail, + } } pub fn read(&mut self, bytes: &mut [u8]) -> Result { diff --git a/vmm/src/runtime.rs b/vmm/src/runtime.rs index 511cf170..aace4720 100644 --- a/vmm/src/runtime.rs +++ b/vmm/src/runtime.rs @@ -3,7 +3,7 @@ use std::{ io::{self, Read}, process::ExitCode, sync::{ - atomic::{AtomicBool, Ordering}, + atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, }, thread::{Scope, ScopedJoinHandle}, @@ -19,6 +19,8 @@ pub use common::mmap::Mmap; use libc::EFD_NONBLOCK; use vmm_sys_util::eventfd::EventFd; +use crate::comm::new_pipe; + const MEM_BASE: u64 = 0x1_0000_0000; fn new_cpu<'scope>( @@ -330,9 +332,11 @@ 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, + addr: IoEventAddress, } impl Runtime { @@ -380,9 +384,11 @@ impl Runtime { let mut x = Self { kvm, - vm, + vm: Arc::new(vm), cores, elf: elf.clone(), + next_pipe_idx: Arc::new(AtomicUsize::new(0)), + addr: IoEventAddress::Mmio(MEM_BASE + BuddyAllocator.len() as u64), }; let elf_bytes = ElfBytes::::minimal_parse(&elf).expect("could not read kernel elf file"); @@ -458,19 +464,23 @@ 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, self.addr, 8192, &self.next_pipe_idx); + + let vm_cl = self.vm.clone(); + let next_pipe_cl = self.next_pipe_idx.clone(); + let addr = self.addr; + let comm = s.spawn(move || { crate::comm::control_thread( + vm_cl, + addr, + 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(); From fa41154e85d0a2e665accf65b8fe5c2ea35c04e0 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Tue, 21 Jul 2026 17:21:36 -0700 Subject: [PATCH 3/6] feat: replace yield_now with doorbell --- common/src/lib.rs | 3 --- kernel/src/doorbell.rs | 4 +--- kernel/src/interrupts.rs | 7 ++++++- kernel/src/pipe.rs | 12 +++--------- vmm/src/doorbell.rs | 28 +++------------------------- vmm/src/pipe.rs | 14 ++++++-------- vmm/src/runtime.rs | 8 -------- 7 files changed, 19 insertions(+), 57 deletions(-) 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/kernel/src/doorbell.rs b/kernel/src/doorbell.rs index 3a712919..0747addd 100644 --- a/kernel/src/doorbell.rs +++ b/kernel/src/doorbell.rs @@ -1,7 +1,5 @@ -#![allow(unused)] - use crate::vm; -use common::{pipe::DoorBell, protocol::control::VMToHostDoorBellData, BuddyAllocator}; +use common::{pipe::DoorBell, protocol::control::VMToHostDoorBellData}; #[derive(Debug)] struct SendPtr(*mut u64); diff --git a/kernel/src/interrupts.rs b/kernel/src/interrupts.rs index 02e92359..d5017dc4 100644 --- a/kernel/src/interrupts.rs +++ b/kernel/src/interrupts.rs @@ -185,7 +185,12 @@ unsafe extern "C" fn isr_entry(registers: &mut IsrRegisterFile) { if registers.isr < 32 { panic!("unhandled exception: {:x?}", registers); } - if registers.isr == 0x20 || registers.isr == 0x32 { + if registers.isr == 0x32 { + INTERRUPTED.store(true, Ordering::Release); + crate::lapic::LAPIC.borrow_mut().clear_interrupt(); + return; + } + if registers.isr == 0x20 { INTERRUPTED.store(true, Ordering::Relaxed); crate::iprofile::tick(registers); crate::lapic::LAPIC.borrow_mut().clear_interrupt(); diff --git a/kernel/src/pipe.rs b/kernel/src/pipe.rs index c6958c26..270102bb 100644 --- a/kernel/src/pipe.rs +++ b/kernel/src/pipe.rs @@ -20,8 +20,7 @@ impl HostPipe { 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) } @@ -42,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/vmm/src/doorbell.rs b/vmm/src/doorbell.rs index 0acc9b5a..1914bfd8 100644 --- a/vmm/src/doorbell.rs +++ b/vmm/src/doorbell.rs @@ -1,8 +1,4 @@ -#![allow(unused)] - -use std::os::fd::{AsRawFd, RawFd}; - -use common::{pipe::DoorBell, protocol::control::VMToHostDoorBellData, BuddyAllocator}; +use common::{pipe::DoorBell, protocol::control::VMToHostDoorBellData}; use kvm_ioctls::{IoEventAddress, VmFd}; use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK}; @@ -30,19 +26,7 @@ impl DoorBell for HostToVMDoorBell { #[derive(Debug)] pub struct VMToHostDoorBellWaiter { - fd: EventFd, -} - -impl From for EventFd { - fn from(val: VMToHostDoorBellWaiter) -> Self { - val.fd - } -} - -impl AsRawFd for VMToHostDoorBellWaiter { - fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd { - self.fd.as_raw_fd() - } + pub fd: EventFd, } impl VMToHostDoorBellWaiter { @@ -51,17 +35,11 @@ impl VMToHostDoorBellWaiter { /// 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(EFD_NONBLOCK).unwrap(); + let evtfd = EventFd::new(0).unwrap(); vm.register_ioevent(&evtfd, addr, datamatch) .expect("Failed to register ioevent"); Self { fd: evtfd } } - - pub fn drain(&mut self) -> std::io::Result<()> { - loop { - self.fd.read()?; - } - } } pub struct VMToHostDoorBell { diff --git a/vmm/src/pipe.rs b/vmm/src/pipe.rs index 1f43d001..00317426 100644 --- a/vmm/src/pipe.rs +++ b/vmm/src/pipe.rs @@ -6,8 +6,8 @@ use std::marker::PhantomData; #[derive(Debug)] pub struct GuestPipe { inner: RawPipe, - _rx_avail: VMToHostDoorBellWaiter, - _tx_avail: VMToHostDoorBellWaiter, + rx_avail: VMToHostDoorBellWaiter, + tx_avail: VMToHostDoorBellWaiter, } impl GuestPipe { @@ -18,15 +18,14 @@ impl GuestPipe { ) -> Self { Self { inner: pipe, - _rx_avail: rx_avail, - _tx_avail: tx_avail, + 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) } @@ -47,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 aace4720..3bcab2d5 100644 --- a/vmm/src/runtime.rs +++ b/vmm/src/runtime.rs @@ -292,14 +292,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(); From e3b83217ef8c5629a4c1aa99986923856b5f4548 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Tue, 21 Jul 2026 17:39:36 -0700 Subject: [PATCH 4/6] fix: cleanup MEM_BASE and ioaddr --- common/src/buddy.rs | 12 +++++++----- common/src/protocol/control.rs | 1 - kernel/src/doorbell.rs | 4 ++-- kernel/src/rsstart.rs | 18 ++++++------------ vmm/src/comm.rs | 19 +++++++------------ vmm/src/doorbell.rs | 19 ++++++------------- vmm/src/runtime.rs | 10 ++-------- 7 files changed, 30 insertions(+), 53 deletions(-) diff --git a/common/src/buddy.rs b/common/src/buddy.rs index d86f02d5..f3893309 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)) @@ -93,11 +95,7 @@ impl<'a> BitRef<'a> { } pub fn write(&mut self, value: bool) -> bool { - if value { - self.set() - } else { - self.clear() - } + if value { self.set() } else { self.clear() } } } @@ -936,6 +934,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/protocol/control.rs b/common/src/protocol/control.rs index aa14fac6..ab619925 100644 --- a/common/src/protocol/control.rs +++ b/common/src/protocol/control.rs @@ -75,7 +75,6 @@ impl From for IoErrorKind { #[derive(Debug, Serialize, Deserialize)] pub struct VMToHostDoorBellData { - pub addr: u64, pub datamatch: u64, } diff --git a/kernel/src/doorbell.rs b/kernel/src/doorbell.rs index 0747addd..c111903f 100644 --- a/kernel/src/doorbell.rs +++ b/kernel/src/doorbell.rs @@ -1,5 +1,5 @@ use crate::vm; -use common::{pipe::DoorBell, protocol::control::VMToHostDoorBellData}; +use common::{buddy::ioaddr, pipe::DoorBell, protocol::control::VMToHostDoorBellData}; #[derive(Debug)] struct SendPtr(*mut u64); @@ -20,7 +20,7 @@ impl VMToHostDoorBell { /// /// 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(raw.addr.try_into().unwrap()); + let addr: *mut u64 = vm::pa2ka(ioaddr() as usize); Self { addr: SendPtr(addr), datamatch: raw.datamatch, diff --git a/kernel/src/rsstart.rs b/kernel/src/rsstart.rs index 916b946d..8325cd71 100644 --- a/kernel/src/rsstart.rs +++ b/kernel/src/rsstart.rs @@ -20,7 +20,9 @@ use crate::{ }; use common::{ - buddy::BuddyAllocatorRawData, protocol::control::VMToHostDoorBellData, BuddyAllocator, + buddy::{BuddyAllocatorRawData, MEM_BASE}, + protocol::control::VMToHostDoorBellData, + BuddyAllocator, }; extern "C" { @@ -101,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); @@ -111,8 +113,6 @@ unsafe extern "C" fn _start( init_cpu_tls(); }; - let ioaddr = 0x1_0000_0000 + BuddyAllocator.len(); - // per-cpu init crate::tsc::init(); crate::kvmclock::init(); @@ -152,14 +152,8 @@ 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 rx_avail = VMToHostDoorBell::from_raw_parts(VMToHostDoorBellData { - addr: ioaddr as u64, - datamatch: 0, - }); - let tx_avail = VMToHostDoorBell::from_raw_parts(VMToHostDoorBellData { - addr: ioaddr as u64, - datamatch: 1, - }); + 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(); diff --git a/vmm/src/comm.rs b/vmm/src/comm.rs index 3e14dcfd..8264509f 100644 --- a/vmm/src/comm.rs +++ b/vmm/src/comm.rs @@ -2,7 +2,6 @@ use crate::doorbell::{new_vm_to_host_door_bell, HostToVMDoorBell, VMToHostDoorBe use crate::pipe::{ControlPipe, FilePipe, GuestPipe, ListenerPipe, StreamPipe}; use common::protocol::control::PipeData; use common::BuddyAllocator; -use kvm_ioctls::IoEventAddress; use kvm_ioctls::VmFd; use std::fs::{File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; @@ -30,14 +29,12 @@ fn decompose_pipe(pipe: common::pipe::Pipe) -> PipeData { pub fn new_pipe( vm: &VmFd, - addr: IoEventAddress, 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, addr, pipe_idx as u64 * 2); - let (tx_avail_vm, tx_avail_waiter) = - new_vm_to_host_door_bell(vm, addr, pipe_idx as u64 * 2 + 1); + 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); @@ -49,7 +46,6 @@ pub fn new_pipe( pub fn control_thread( vm: Arc, - addr: IoEventAddress, next_pipe_idx: Arc, argv: Vec, mut pipe: ControlPipe, @@ -69,7 +65,7 @@ pub fn control_thread( .open(path); match f { Ok(f) => { - let (p, q) = new_pipe(&vm, addr, 1024, &next_pipe_idx); + let (p, q) = new_pipe(&vm, 1024, &next_pipe_idx); std::thread::spawn(move || { file_thread(f, FilePipe::new(q)); }); @@ -84,17 +80,17 @@ pub fn control_thread( }, Request::Listen { ip, port } => { let listener = TcpListener::bind(SocketAddr::from((ip, port))).unwrap(); - let (p, q) = new_pipe(&vm, addr, 1024, &next_pipe_idx); + 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 || { - listener_thread(vm_cl, addr, next_pipe_cl, listener, ListenerPipe::new(q)); + 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) = new_pipe(&vm, addr, 1024, &next_pipe_idx); + let (p, q) = new_pipe(&vm, 1024, &next_pipe_idx); std::thread::spawn(move || { stream_thread(stream, StreamPipe::new(q)); }); @@ -139,7 +135,6 @@ pub fn file_thread(mut file: File, mut pipe: FilePipe) { pub fn listener_thread( vm: Arc, - addr: IoEventAddress, next_pipe_idx: Arc, listener: TcpListener, mut pipe: ListenerPipe, @@ -149,7 +144,7 @@ pub fn listener_thread( let response = match pipe.recv() { Request::Accept => { let (stream, _) = listener.accept().unwrap(); - let (p, q) = new_pipe(&vm, addr, 1024, &next_pipe_idx); + let (p, q) = new_pipe(&vm, 1024, &next_pipe_idx); std::thread::spawn(move || { stream_thread(stream, StreamPipe::new(q)); }); diff --git a/vmm/src/doorbell.rs b/vmm/src/doorbell.rs index 1914bfd8..dfcb0587 100644 --- a/vmm/src/doorbell.rs +++ b/vmm/src/doorbell.rs @@ -1,4 +1,4 @@ -use common::{pipe::DoorBell, protocol::control::VMToHostDoorBellData}; +use common::{buddy::ioaddr, pipe::DoorBell, protocol::control::VMToHostDoorBellData}; use kvm_ioctls::{IoEventAddress, VmFd}; use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK}; @@ -43,23 +43,16 @@ impl VMToHostDoorBellWaiter { } pub struct VMToHostDoorBell { - addr: IoEventAddress, datamatch: u64, } impl VMToHostDoorBell { - fn new(addr: IoEventAddress, datamatch: u64) -> Self { - Self { addr, datamatch } + fn new(datamatch: u64) -> Self { + Self { datamatch } } pub fn into_raw_parts(self) -> VMToHostDoorBellData { - let addr = match self.addr { - IoEventAddress::Pio(_) => todo!(), - IoEventAddress::Mmio(addr) => addr, - }; - VMToHostDoorBellData { - addr, datamatch: self.datamatch, } } @@ -73,10 +66,10 @@ impl DoorBell for VMToHostDoorBell { pub fn new_vm_to_host_door_bell( vm: &VmFd, - addr: IoEventAddress, datamatch: u64, ) -> (VMToHostDoorBell, VMToHostDoorBellWaiter) { - let doorbellwaiter = VMToHostDoorBellWaiter::new(vm, &addr, datamatch); - let doorbell = VMToHostDoorBell::new(addr, datamatch); + let doorbellwaiter = + VMToHostDoorBellWaiter::new(vm, &IoEventAddress::Mmio(ioaddr()), datamatch); + let doorbell = VMToHostDoorBell::new(datamatch); (doorbell, doorbellwaiter) } diff --git a/vmm/src/runtime.rs b/vmm/src/runtime.rs index 3bcab2d5..5ca52b2e 100644 --- a/vmm/src/runtime.rs +++ b/vmm/src/runtime.rs @@ -10,7 +10,7 @@ use std::{ 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}; @@ -21,8 +21,6 @@ use vmm_sys_util::eventfd::EventFd; use crate::comm::new_pipe; -const MEM_BASE: u64 = 0x1_0000_0000; - fn new_cpu<'scope>( i: usize, scope: &'scope Scope<'scope, '_>, @@ -328,7 +326,6 @@ pub struct Runtime { cores: usize, elf: Arc<[u8]>, next_pipe_idx: Arc, - addr: IoEventAddress, } impl Runtime { @@ -380,7 +377,6 @@ impl Runtime { cores, elf: elf.clone(), next_pipe_idx: Arc::new(AtomicUsize::new(0)), - addr: IoEventAddress::Mmio(MEM_BASE + BuddyAllocator.len() as u64), }; let elf_bytes = ElfBytes::::minimal_parse(&elf).expect("could not read kernel elf file"); @@ -456,16 +452,14 @@ impl Runtime { std::thread::scope(|s| { let mut cpus = vec![]; - let (p, q) = new_pipe(&self.vm, self.addr, 8192, &self.next_pipe_idx); + 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 addr = self.addr; let comm = s.spawn(move || { crate::comm::control_thread( vm_cl, - addr, next_pipe_cl, argv, crate::pipe::ControlPipe::new(q), From 539068c6093e530a408cc9fea42df56ab987dbf0 Mon Sep 17 00:00:00 2001 From: Yuhan Deng Date: Wed, 29 Jul 2026 17:13:57 -0700 Subject: [PATCH 5/6] fix: interrupt ordering --- kernel/src/interrupts.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/src/interrupts.rs b/kernel/src/interrupts.rs index d5017dc4..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); @@ -185,11 +190,6 @@ unsafe extern "C" fn isr_entry(registers: &mut IsrRegisterFile) { if registers.isr < 32 { panic!("unhandled exception: {:x?}", registers); } - if registers.isr == 0x32 { - INTERRUPTED.store(true, Ordering::Release); - crate::lapic::LAPIC.borrow_mut().clear_interrupt(); - return; - } if registers.isr == 0x20 { INTERRUPTED.store(true, Ordering::Relaxed); crate::iprofile::tick(registers); From c29e3499b796f146117a30134b03825848bf9c79 Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Wed, 26 Aug 2026 00:36:44 -0700 Subject: [PATCH 6/6] format --- common/src/buddy.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/src/buddy.rs b/common/src/buddy.rs index f3893309..8b386a92 100644 --- a/common/src/buddy.rs +++ b/common/src/buddy.rs @@ -95,7 +95,11 @@ impl<'a> BitRef<'a> { } pub fn write(&mut self, value: bool) -> bool { - if value { self.set() } else { self.clear() } + if value { + self.set() + } else { + self.clear() + } } }