diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca5488cacd..7155797ba7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -235,9 +235,9 @@ jobs: if: matrix.arch == 'x86_64' - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package rusty_demo --no-default-features --smp 4 firecracker --sudo if: matrix.arch == 'x86_64' - - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package rusty_demo --features fs uhyve --sudo + - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package rusty_demo --features fs,hermit/uhyve uhyve --sudo if: matrix.arch == 'x86_64' - - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package rusty_demo --features fs --smp 4 uhyve --sudo + - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package rusty_demo --features fs,hermit/uhyve --smp 4 uhyve --sudo if: matrix.arch == 'x86_64' - run: cargo clean working-directory: . diff --git a/Cargo.toml b/Cargo.toml index a9904c8533..d6368348d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ default = [ "pci", "smp", "tcp", + "uhyve", "virtio-fs", "virtio-net", "virtio-vsock", @@ -78,10 +79,18 @@ mman = [] ## [hermit-c]: https://github.com/hermit-os/hermit-c newlib = [] +#! ### Platform Features + +## Enables [Uhyve] support. +## +## Uhyve is a Hermit-specific _virtual machine monitor_ (VMM). +## +## [Uhyve]: https://github.com/hermit-os/uhyve +uhyve = ["dep:uhyve-interface"] + #! ### Hardware Features #! #! [microvm]: https://www.qemu.org/docs/master/system/i386/microvm.html -#! [Uhyve]: https://github.com/hermit-os/uhyve ## Enables _Advanced Configuration and Power Interface_ ([ACPI]) support. ## @@ -329,7 +338,7 @@ talc = { version = "5" } thiserror = { version = "2", default-features = false } time = { version = "0.3", default-features = false } volatile = "0.6" -uhyve-interface = "0.1.4" +uhyve-interface = { version = "0.1.4", optional = true } [dependencies.smoltcp] version = "0.13" diff --git a/src/arch/aarch64/kernel/processor.rs b/src/arch/aarch64/kernel/processor.rs index bba8af0992..dfef1771de 100644 --- a/src/arch/aarch64/kernel/processor.rs +++ b/src/arch/aarch64/kernel/processor.rs @@ -200,6 +200,7 @@ pub fn seed_entropy() -> Option<[u8; 32]> { } /// The halt function stops the processor until the next interrupt arrives +#[allow(dead_code)] pub fn halt() { aarch64_cpu::asm::wfi(); } diff --git a/src/arch/riscv64/kernel/processor.rs b/src/arch/riscv64/kernel/processor.rs index a236e03ad1..66c4e6efef 100644 --- a/src/arch/riscv64/kernel/processor.rs +++ b/src/arch/riscv64/kernel/processor.rs @@ -220,6 +220,7 @@ pub fn lsb(value: u64) -> Option { } /// The halt function stops the processor until the next interrupt arrives +#[allow(dead_code)] pub fn halt() { riscv::asm::wfi(); } diff --git a/src/console.rs b/src/console/mod.rs similarity index 75% rename from src/console.rs rename to src/console/mod.rs index e5d597fced..b927d0d283 100644 --- a/src/console.rs +++ b/src/console/mod.rs @@ -1,4 +1,5 @@ -#![allow(dead_code)] +#[cfg(feature = "uhyve")] +mod uhyve; use core::{fmt, mem}; @@ -11,14 +12,12 @@ use crate::arch::SerialDevice; use crate::drivers::console::VirtioUART; use crate::errno::Errno; use crate::executor::WakerRegistration; -#[cfg(not(target_arch = "riscv64"))] -use crate::uhyve::serial_buf_hypercall; const SERIAL_BUFFER_SIZE: usize = 256; pub(crate) enum IoDevice { - #[cfg(not(target_arch = "riscv64"))] - Uhyve(UhyveSerial), + #[cfg(feature = "uhyve")] + Uhyve(uhyve::UhyveSerial), Uart(SerialDevice), #[cfg(feature = "virtio-console")] Virtio(VirtioUART), @@ -31,7 +30,7 @@ impl ErrorType for IoDevice { impl Read for IoDevice { fn read(&mut self, buf: &mut [u8]) -> Result { match self { - #[cfg(not(target_arch = "riscv64"))] + #[cfg(feature = "uhyve")] IoDevice::Uhyve(s) => s.read(buf), IoDevice::Uart(s) => s.read(buf), #[cfg(feature = "virtio-console")] @@ -43,7 +42,7 @@ impl Read for IoDevice { impl ReadReady for IoDevice { fn read_ready(&mut self) -> Result { match self { - #[cfg(not(target_arch = "riscv64"))] + #[cfg(feature = "uhyve")] IoDevice::Uhyve(s) => s.read_ready(), IoDevice::Uart(s) => s.read_ready(), #[cfg(feature = "virtio-console")] @@ -55,7 +54,7 @@ impl ReadReady for IoDevice { impl Write for IoDevice { fn write(&mut self, buf: &[u8]) -> Result { match self { - #[cfg(not(target_arch = "riscv64"))] + #[cfg(feature = "uhyve")] IoDevice::Uhyve(s) => s.write_all(buf)?, IoDevice::Uart(s) => s.write_all(buf)?, #[cfg(feature = "virtio-console")] @@ -77,48 +76,6 @@ impl Write for IoDevice { } } -#[cfg(not(target_arch = "riscv64"))] -pub(crate) struct UhyveSerial; - -#[cfg(not(target_arch = "riscv64"))] -impl UhyveSerial { - pub const fn new() -> Self { - Self {} - } -} - -#[cfg(not(target_arch = "riscv64"))] -impl ErrorType for UhyveSerial { - type Error = Errno; -} - -#[cfg(not(target_arch = "riscv64"))] -impl Read for UhyveSerial { - fn read(&mut self, buf: &mut [u8]) -> Result { - let _ = buf; - Ok(0) - } -} - -#[cfg(not(target_arch = "riscv64"))] -impl ReadReady for UhyveSerial { - fn read_ready(&mut self) -> Result { - Ok(false) - } -} - -#[cfg(not(target_arch = "riscv64"))] -impl Write for UhyveSerial { - fn write(&mut self, buf: &[u8]) -> Result { - serial_buf_hypercall(buf); - Ok(buf.len()) - } - - fn flush(&mut self) -> Result<(), Self::Error> { - Ok(()) - } -} - pub(crate) struct Console { device: IoDevice, buffer: Vec, @@ -197,13 +154,11 @@ pub(crate) static CONSOLE_WAKER: InterruptTicketMutex = pub(crate) static CONSOLE: Lazy> = Lazy::new(|| { crate::CoreLocal::install(); - #[cfg(not(target_arch = "riscv64"))] + #[cfg(feature = "uhyve")] if crate::env::is_uhyve() { - InterruptTicketMutex::new(Console::new(IoDevice::Uhyve(UhyveSerial::new()))) - } else { - InterruptTicketMutex::new(Console::new(IoDevice::Uart(SerialDevice::new()))) + return InterruptTicketMutex::new(Console::new(IoDevice::Uhyve(uhyve::UhyveSerial::new()))); } - #[cfg(target_arch = "riscv64")] + InterruptTicketMutex::new(Console::new(IoDevice::Uart(SerialDevice::new()))) }); diff --git a/src/console/uhyve.rs b/src/console/uhyve.rs new file mode 100644 index 0000000000..1af887d9bd --- /dev/null +++ b/src/console/uhyve.rs @@ -0,0 +1,40 @@ +use embedded_io::{ErrorType, Read, ReadReady, Write}; + +use crate::errno::Errno; +use crate::uhyve::serial_buf_hypercall; + +pub(crate) struct UhyveSerial; + +impl UhyveSerial { + pub const fn new() -> Self { + Self {} + } +} + +impl ErrorType for UhyveSerial { + type Error = Errno; +} + +impl Read for UhyveSerial { + fn read(&mut self, buf: &mut [u8]) -> Result { + let _ = buf; + Ok(0) + } +} + +impl ReadReady for UhyveSerial { + fn read_ready(&mut self) -> Result { + Ok(false) + } +} + +impl Write for UhyveSerial { + fn write(&mut self, buf: &[u8]) -> Result { + serial_buf_hypercall(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} diff --git a/src/fd/delegate.rs b/src/fd/delegate.rs index 049342beff..dafaff99f1 100644 --- a/src/fd/delegate.rs +++ b/src/fd/delegate.rs @@ -11,13 +11,14 @@ use crate::fd::socket::tcp; use crate::fd::socket::udp; #[cfg(feature = "virtio-vsock")] use crate::fd::socket::vsock; -use crate::fd::stdio::{ - GenericStderr, GenericStdin, GenericStdout, UhyveStderr, UhyveStdin, UhyveStdout, -}; +use crate::fd::stdio::{ConsoleStderr, ConsoleStdin, ConsoleStdout}; +#[cfg(feature = "uhyve")] +use crate::fd::stdio::{UhyveStderr, UhyveStdin, UhyveStdout}; use crate::fd::{AccessPermission, ObjectInterface, PollEvent, StatusFlags}; #[cfg(any(feature = "net", feature = "virtio-vsock"))] use crate::fd::{Endpoint, ListenEndpoint, SocketOption}; use crate::fs::mem::{MemDirectoryInterface, RamFileInterface, RomFileInterface}; +#[cfg(feature = "uhyve")] use crate::fs::uhyve::UhyveFileHandle; #[cfg(feature = "virtio-fs")] use crate::fs::virtio_fs::{VirtioFsDirectoryHandle, VirtioFsFileHandle}; @@ -25,11 +26,14 @@ use crate::fs::{DirectoryReader, FileAttr, SeekWhence}; use crate::io; pub(crate) enum Fd { - GenericStdin(GenericStdin), - GenericStdout(GenericStdout), - GenericStderr(GenericStderr), + ConsoleStdin(ConsoleStdin), + ConsoleStdout(ConsoleStdout), + ConsoleStderr(ConsoleStderr), + #[cfg(feature = "uhyve")] UhyveStdin(UhyveStdin), + #[cfg(feature = "uhyve")] UhyveStdout(UhyveStdout), + #[cfg(feature = "uhyve")] UhyveStderr(UhyveStderr), EventFd(EventFd), #[cfg(feature = "tcp")] @@ -48,6 +52,7 @@ pub(crate) enum Fd { RamFileInterface(RamFileInterface), MemDirectoryInterface(MemDirectoryInterface), DirectoryReader(DirectoryReader), + #[cfg(feature = "uhyve")] UhyveFileHandle(UhyveFileHandle), } @@ -70,11 +75,14 @@ macro_rules! fd_from { } fd_from! { - GenericStdin(GenericStdin), - GenericStdout(GenericStdout), - GenericStderr(GenericStderr), + ConsoleStdin(ConsoleStdin), + ConsoleStdout(ConsoleStdout), + ConsoleStderr(ConsoleStderr), + #[cfg(feature = "uhyve")] UhyveStdin(UhyveStdin), + #[cfg(feature = "uhyve")] UhyveStdout(UhyveStdout), + #[cfg(feature = "uhyve")] UhyveStderr(UhyveStderr), EventFd(EventFd), #[cfg(feature = "tcp")] @@ -93,17 +101,21 @@ fd_from! { RamFileInterface(RamFileInterface), MemDirectoryInterface(MemDirectoryInterface), DirectoryReader(DirectoryReader), + #[cfg(feature = "uhyve")] UhyveFileHandle(UhyveFileHandle), } impl ObjectInterface for Fd { delegate! { to match self { - Self::GenericStdin(fd) => fd, - Self::GenericStdout(fd) => fd, - Self::GenericStderr(fd) => fd, + Self::ConsoleStdin(fd) => fd, + Self::ConsoleStdout(fd) => fd, + Self::ConsoleStderr(fd) => fd, + #[cfg(feature = "uhyve")] Self::UhyveStdin(fd) => fd, + #[cfg(feature = "uhyve")] Self::UhyveStdout(fd) => fd, + #[cfg(feature = "uhyve")] Self::UhyveStderr(fd) => fd, Self::EventFd(fd) => fd, #[cfg(feature = "tcp")] @@ -122,6 +134,7 @@ impl ObjectInterface for Fd { Self::RamFileInterface(fd) => fd, Self::MemDirectoryInterface(fd) => fd, Self::DirectoryReader(fd) => fd, + #[cfg(feature = "uhyve")] Self::UhyveFileHandle(fd) => fd, } { async fn poll(&self, event: PollEvent) -> io::Result; diff --git a/src/fd/stdio.rs b/src/fd/stdio.rs deleted file mode 100644 index 1205fce0b9..0000000000 --- a/src/fd/stdio.rs +++ /dev/null @@ -1,220 +0,0 @@ -use core::future; -use core::task::Poll; - -use embedded_io::{Read, ReadReady, Write}; -use uhyve_interface::parameters::WriteParams; -use uhyve_interface::{GuestVirtAddr, Hypercall}; - -use crate::console::{CONSOLE, CONSOLE_WAKER}; -use crate::fd::{ - AccessPermission, FileAttr, ObjectInterface, PollEvent, STDERR_FILENO, STDOUT_FILENO, -}; -use crate::io; -use crate::uhyve::uhyve_hypercall; - -pub struct GenericStdin; - -impl ObjectInterface for GenericStdin { - async fn poll(&self, event: PollEvent) -> io::Result { - let available = if CONSOLE.lock().read_ready()? { - PollEvent::POLLIN | PollEvent::POLLRDNORM | PollEvent::POLLRDBAND - } else { - PollEvent::empty() - }; - - Ok(event & available) - } - - async fn read(&self, buf: &mut [u8]) -> io::Result { - future::poll_fn(|cx| { - let read_bytes = CONSOLE.lock().read(buf)?; - if read_bytes > 0 { - CONSOLE.lock().write_all(&buf[..read_bytes])?; - CONSOLE.lock().flush()?; - Poll::Ready(Ok(read_bytes)) - } else { - CONSOLE_WAKER.lock().register(cx.waker()); - Poll::Pending - } - }) - .await - } - - async fn isatty(&self) -> io::Result { - Ok(true) - } - - async fn fstat(&self) -> io::Result { - let attr = FileAttr { - st_mode: AccessPermission::S_IFCHR, - ..Default::default() - }; - Ok(attr) - } -} - -impl GenericStdin { - pub const fn new() -> Self { - Self {} - } -} - -pub struct GenericStdout; - -impl ObjectInterface for GenericStdout { - async fn poll(&self, event: PollEvent) -> io::Result { - let available = PollEvent::POLLOUT | PollEvent::POLLWRNORM | PollEvent::POLLWRBAND; - Ok(event & available) - } - - async fn write(&self, buf: &[u8]) -> io::Result { - CONSOLE.lock().write(buf) - } - - async fn isatty(&self) -> io::Result { - Ok(true) - } - - async fn fstat(&self) -> io::Result { - let attr = FileAttr { - st_mode: AccessPermission::S_IFCHR, - ..Default::default() - }; - Ok(attr) - } -} - -impl GenericStdout { - pub const fn new() -> Self { - Self {} - } -} - -pub struct GenericStderr; - -impl ObjectInterface for GenericStderr { - async fn poll(&self, event: PollEvent) -> io::Result { - let available = PollEvent::POLLOUT | PollEvent::POLLWRNORM | PollEvent::POLLWRBAND; - Ok(event & available) - } - - async fn write(&self, buf: &[u8]) -> io::Result { - CONSOLE.lock().write(buf) - } - - async fn isatty(&self) -> io::Result { - Ok(true) - } - - async fn fstat(&self) -> io::Result { - let attr = FileAttr { - st_mode: AccessPermission::S_IFCHR, - ..Default::default() - }; - Ok(attr) - } -} - -impl GenericStderr { - pub const fn new() -> Self { - Self {} - } -} - -pub struct UhyveStdin; - -impl ObjectInterface for UhyveStdin { - async fn isatty(&self) -> io::Result { - Ok(true) - } - - async fn fstat(&self) -> io::Result { - let attr = FileAttr { - st_mode: AccessPermission::S_IFCHR, - ..Default::default() - }; - Ok(attr) - } -} - -impl UhyveStdin { - pub const fn new() -> Self { - Self {} - } -} - -pub struct UhyveStdout; - -impl ObjectInterface for UhyveStdout { - async fn poll(&self, event: PollEvent) -> io::Result { - let available = PollEvent::POLLOUT | PollEvent::POLLWRNORM | PollEvent::POLLWRBAND; - Ok(event & available) - } - - async fn write(&self, buf: &[u8]) -> io::Result { - let write_params = WriteParams { - fd: STDOUT_FILENO, - buf: GuestVirtAddr::from_ptr(buf.as_ptr()), - len: buf.len(), - }; - uhyve_hypercall(Hypercall::FileWrite(&write_params)); - - Ok(write_params.len) - } - - async fn isatty(&self) -> io::Result { - Ok(true) - } - - async fn fstat(&self) -> io::Result { - let attr = FileAttr { - st_mode: AccessPermission::S_IFCHR, - ..Default::default() - }; - Ok(attr) - } -} - -impl UhyveStdout { - pub const fn new() -> Self { - Self {} - } -} - -pub struct UhyveStderr; - -impl ObjectInterface for UhyveStderr { - async fn poll(&self, event: PollEvent) -> io::Result { - let available = PollEvent::POLLOUT | PollEvent::POLLWRNORM | PollEvent::POLLWRBAND; - Ok(event & available) - } - - async fn write(&self, buf: &[u8]) -> io::Result { - let write_params = WriteParams { - fd: STDERR_FILENO, - buf: GuestVirtAddr::from_ptr(buf.as_ptr()), - len: buf.len(), - }; - uhyve_hypercall(Hypercall::FileWrite(&write_params)); - - Ok(write_params.len) - } - - async fn isatty(&self) -> io::Result { - Ok(true) - } - - async fn fstat(&self) -> io::Result { - let attr = FileAttr { - st_mode: AccessPermission::S_IFCHR, - ..Default::default() - }; - Ok(attr) - } -} - -impl UhyveStderr { - pub const fn new() -> Self { - Self {} - } -} diff --git a/src/fd/stdio/console.rs b/src/fd/stdio/console.rs new file mode 100644 index 0000000000..93f688f305 --- /dev/null +++ b/src/fd/stdio/console.rs @@ -0,0 +1,117 @@ +use core::future; +use core::task::Poll; + +use embedded_io::{Read, ReadReady, Write}; + +use crate::console::{CONSOLE, CONSOLE_WAKER}; +use crate::fd::{AccessPermission, FileAttr, ObjectInterface, PollEvent}; +use crate::io; + +pub struct ConsoleStdin; + +impl ObjectInterface for ConsoleStdin { + async fn poll(&self, event: PollEvent) -> io::Result { + let available = if CONSOLE.lock().read_ready()? { + PollEvent::POLLIN | PollEvent::POLLRDNORM | PollEvent::POLLRDBAND + } else { + PollEvent::empty() + }; + + Ok(event & available) + } + + async fn read(&self, buf: &mut [u8]) -> io::Result { + future::poll_fn(|cx| { + let read_bytes = CONSOLE.lock().read(buf)?; + if read_bytes > 0 { + CONSOLE.lock().write_all(&buf[..read_bytes])?; + CONSOLE.lock().flush()?; + Poll::Ready(Ok(read_bytes)) + } else { + CONSOLE_WAKER.lock().register(cx.waker()); + Poll::Pending + } + }) + .await + } + + async fn isatty(&self) -> io::Result { + Ok(true) + } + + async fn fstat(&self) -> io::Result { + let attr = FileAttr { + st_mode: AccessPermission::S_IFCHR, + ..Default::default() + }; + Ok(attr) + } +} + +impl ConsoleStdin { + pub const fn new() -> Self { + Self {} + } +} + +pub struct ConsoleStdout; + +impl ObjectInterface for ConsoleStdout { + async fn poll(&self, event: PollEvent) -> io::Result { + let available = PollEvent::POLLOUT | PollEvent::POLLWRNORM | PollEvent::POLLWRBAND; + Ok(event & available) + } + + async fn write(&self, buf: &[u8]) -> io::Result { + CONSOLE.lock().write(buf) + } + + async fn isatty(&self) -> io::Result { + Ok(true) + } + + async fn fstat(&self) -> io::Result { + let attr = FileAttr { + st_mode: AccessPermission::S_IFCHR, + ..Default::default() + }; + Ok(attr) + } +} + +impl ConsoleStdout { + pub const fn new() -> Self { + Self {} + } +} + +pub struct ConsoleStderr; + +impl ObjectInterface for ConsoleStderr { + async fn poll(&self, event: PollEvent) -> io::Result { + let available = PollEvent::POLLOUT | PollEvent::POLLWRNORM | PollEvent::POLLWRBAND; + Ok(event & available) + } + + async fn write(&self, buf: &[u8]) -> io::Result { + CONSOLE.lock().write(buf) + } + + async fn isatty(&self) -> io::Result { + Ok(true) + } + + async fn fstat(&self) -> io::Result { + let attr = FileAttr { + st_mode: AccessPermission::S_IFCHR, + ..Default::default() + }; + Ok(attr) + } +} + +impl ConsoleStderr { + pub const fn new() -> Self { + Self {} + } +} diff --git a/src/fd/stdio/mod.rs b/src/fd/stdio/mod.rs new file mode 100644 index 0000000000..f37b847b97 --- /dev/null +++ b/src/fd/stdio/mod.rs @@ -0,0 +1,37 @@ +mod console; + +cfg_select! { + feature = "uhyve" => { + mod uhyve; + pub use self::uhyve::{UhyveStderr, UhyveStdin, UhyveStdout}; + } + _ => {} +} + +use alloc::sync::Arc; + +use ahash::RandomState; +use hashbrown::HashMap; + +pub use self::console::{ConsoleStderr, ConsoleStdin, ConsoleStdout}; +use crate::fd::{Fd, RawFd, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; + +pub(crate) fn setup(fds: &mut HashMap>, RandomState>) { + #[cfg(feature = "uhyve")] + if crate::env::is_uhyve() { + let stdin = Arc::new(async_lock::RwLock::new(UhyveStdin::new().into())); + let stdout = Arc::new(async_lock::RwLock::new(UhyveStdout::new().into())); + let stderr = Arc::new(async_lock::RwLock::new(UhyveStderr::new().into())); + fds.insert(STDIN_FILENO, stdin); + fds.insert(STDOUT_FILENO, stdout); + fds.insert(STDERR_FILENO, stderr); + return; + } + + let stdin = Arc::new(async_lock::RwLock::new(ConsoleStdin::new().into())); + let stdout = Arc::new(async_lock::RwLock::new(ConsoleStdout::new().into())); + let stderr = Arc::new(async_lock::RwLock::new(ConsoleStderr::new().into())); + fds.insert(STDIN_FILENO, stdin); + fds.insert(STDOUT_FILENO, stdout); + fds.insert(STDERR_FILENO, stderr); +} diff --git a/src/fd/stdio/uhyve.rs b/src/fd/stdio/uhyve.rs new file mode 100644 index 0000000000..21b1be45aa --- /dev/null +++ b/src/fd/stdio/uhyve.rs @@ -0,0 +1,106 @@ +use uhyve_interface::parameters::WriteParams; +use uhyve_interface::{GuestVirtAddr, Hypercall}; + +use crate::fd::{ + AccessPermission, FileAttr, ObjectInterface, PollEvent, STDERR_FILENO, STDOUT_FILENO, +}; +use crate::io; +use crate::uhyve::uhyve_hypercall; + +pub struct UhyveStdin; + +impl ObjectInterface for UhyveStdin { + async fn isatty(&self) -> io::Result { + Ok(true) + } + + async fn fstat(&self) -> io::Result { + let attr = FileAttr { + st_mode: AccessPermission::S_IFCHR, + ..Default::default() + }; + Ok(attr) + } +} + +impl UhyveStdin { + pub const fn new() -> Self { + Self {} + } +} + +pub struct UhyveStdout; + +impl ObjectInterface for UhyveStdout { + async fn poll(&self, event: PollEvent) -> io::Result { + let available = PollEvent::POLLOUT | PollEvent::POLLWRNORM | PollEvent::POLLWRBAND; + Ok(event & available) + } + + async fn write(&self, buf: &[u8]) -> io::Result { + let write_params = WriteParams { + fd: STDOUT_FILENO, + buf: GuestVirtAddr::from_ptr(buf.as_ptr()), + len: buf.len(), + }; + uhyve_hypercall(Hypercall::FileWrite(&write_params)); + + Ok(write_params.len) + } + + async fn isatty(&self) -> io::Result { + Ok(true) + } + + async fn fstat(&self) -> io::Result { + let attr = FileAttr { + st_mode: AccessPermission::S_IFCHR, + ..Default::default() + }; + Ok(attr) + } +} + +impl UhyveStdout { + pub const fn new() -> Self { + Self {} + } +} + +pub struct UhyveStderr; + +impl ObjectInterface for UhyveStderr { + async fn poll(&self, event: PollEvent) -> io::Result { + let available = PollEvent::POLLOUT | PollEvent::POLLWRNORM | PollEvent::POLLWRBAND; + Ok(event & available) + } + + async fn write(&self, buf: &[u8]) -> io::Result { + let write_params = WriteParams { + fd: STDERR_FILENO, + buf: GuestVirtAddr::from_ptr(buf.as_ptr()), + len: buf.len(), + }; + uhyve_hypercall(Hypercall::FileWrite(&write_params)); + + Ok(write_params.len) + } + + async fn isatty(&self) -> io::Result { + Ok(true) + } + + async fn fstat(&self) -> io::Result { + let attr = FileAttr { + st_mode: AccessPermission::S_IFCHR, + ..Default::default() + }; + Ok(attr) + } +} + +impl UhyveStderr { + pub const fn new() -> Self { + Self {} + } +} diff --git a/src/fs/mem.rs b/src/fs/mem.rs index 61002da066..d09208ff3a 100644 --- a/src/fs/mem.rs +++ b/src/fs/mem.rs @@ -648,6 +648,7 @@ impl VfsNode for MemDirectory { ) } + #[cfg(any(feature = "uhyve", feature = "virtio-fs"))] fn traverse_mount(&self, path: &str, obj: Box) -> io::Result<()> { block_on( async { diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 95600d1166..a7118b9256 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -1,9 +1,11 @@ pub(crate) mod mem; +#[cfg(feature = "uhyve")] pub(crate) mod uhyve; #[cfg(feature = "virtio-fs")] pub(crate) mod virtio_fs; use alloc::borrow::ToOwned; +#[cfg(any(feature = "uhyve", feature = "virtio-fs"))] use alloc::boxed::Box; use alloc::string::String; use alloc::sync::Arc; @@ -96,6 +98,7 @@ pub(crate) trait VfsNode: Send + Sync + fmt::Debug { } /// Mounts a file system + #[cfg(any(feature = "uhyve", feature = "virtio-fs"))] fn traverse_mount(&self, _path: &str, _obj: Box) -> io::Result<()> { Err(Errno::Nosys) } @@ -225,6 +228,7 @@ impl Filesystem { } /// Create new backing-fs at mountpoint mntpath + #[cfg(any(feature = "uhyve", feature = "virtio-fs"))] pub fn mount(&self, path: &str, obj: Box) -> io::Result<()> { debug!("Mounting {path}"); @@ -328,6 +332,7 @@ pub(crate) fn init() { #[cfg(feature = "virtio-fs")] virtio_fs::init(); + #[cfg(feature = "uhyve")] if crate::env::is_uhyve() { uhyve::init(); } @@ -367,19 +372,6 @@ pub fn create_dir(path: &str, mode: AccessPermission) -> io::Result<()> { }) } -/// Creates a directory and creates all missing parent directories as well. -fn create_dir_recursive(path: &str, mode: AccessPermission) -> io::Result<()> { - trace!("create_dir_recursive: {path}"); - create_dir(path, mode).or_else(|errno| { - if errno != Errno::Badf { - return Err(errno); - } - let (parent_path, _file_name) = path.rsplit_once('/').unwrap(); - create_dir_recursive(parent_path, mode)?; - create_dir(path, mode) - }) -} - /// Returns an vector with all the entries within a directory. pub fn readdir(name: &str) -> io::Result> { debug!("Read directory {name}"); diff --git a/src/fs/uhyve.rs b/src/fs/uhyve.rs index cae4748513..c37b924c76 100644 --- a/src/fs/uhyve.rs +++ b/src/fs/uhyve.rs @@ -18,7 +18,6 @@ use crate::errno::Errno; use crate::fd::Fd; use crate::fs::{ self, AccessPermission, FileAttr, NodeKind, ObjectInterface, OpenOption, SeekWhence, VfsNode, - create_dir_recursive, }; use crate::io; use crate::uhyve::uhyve_hypercall; @@ -265,3 +264,16 @@ pub(crate) fn init() { .unwrap(); } } + +/// Creates a directory and creates all missing parent directories as well. +fn create_dir_recursive(path: &str, mode: AccessPermission) -> io::Result<()> { + trace!("create_dir_recursive: {path}"); + fs::create_dir(path, mode).or_else(|errno| { + if errno != Errno::Badf { + return Err(errno); + } + let (parent_path, _file_name) = path.rsplit_once('/').unwrap(); + create_dir_recursive(parent_path, mode)?; + fs::create_dir(path, mode) + }) +} diff --git a/src/lib.rs b/src/lib.rs index cb7e06ee06..3006febe90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -127,6 +127,7 @@ mod shell; mod synch; pub mod syscalls; pub mod time; +#[cfg(feature = "uhyve")] mod uhyve; mod built_info { @@ -138,9 +139,6 @@ hermit_entry::define_abi_tag!(); #[cfg(target_os = "none")] hermit_entry::define_entry_version!(); -#[cfg(target_os = "none")] -hermit_entry::define_uhyve_interface_version!(uhyve_interface::UHYVE_INTERFACE_VERSION); - #[cfg(test)] #[cfg(target_os = "none")] #[unsafe(no_mangle)] diff --git a/src/scheduler/task/mod.rs b/src/scheduler/task/mod.rs index 37560a541b..2c0519a0b1 100644 --- a/src/scheduler/task/mod.rs +++ b/src/scheduler/task/mod.rs @@ -19,12 +19,11 @@ use memory_addresses::VirtAddr; #[cfg(not(feature = "common-os"))] use self::tls::Tls; use super::timer_interrupts::{Source, create_timer_abs}; +use crate::arch; use crate::arch::core_local::*; use crate::arch::scheduler::TaskStacks; -use crate::fd::stdio::*; -use crate::fd::{Fd, RawFd, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; +use crate::fd::{Fd, RawFd, stdio}; use crate::scheduler::CoreId; -use crate::{arch, env}; /// Returns the most significant bit. /// @@ -443,22 +442,7 @@ impl Task { // Thus, this is the only place where we set OBJECT_MAP. .unwrap_or_else(|_| unreachable!()); let objmap = OBJECT_MAP.get().unwrap().clone(); - let mut guard = objmap.write(); - if env::is_uhyve() { - let stdin = Arc::new(async_lock::RwLock::new(UhyveStdin::new().into())); - let stdout = Arc::new(async_lock::RwLock::new(UhyveStdout::new().into())); - let stderr = Arc::new(async_lock::RwLock::new(UhyveStderr::new().into())); - guard.insert(STDIN_FILENO, stdin); - guard.insert(STDOUT_FILENO, stdout); - guard.insert(STDERR_FILENO, stderr); - } else { - let stdin = Arc::new(async_lock::RwLock::new(GenericStdin::new().into())); - let stdout = Arc::new(async_lock::RwLock::new(GenericStdout::new().into())); - let stderr = Arc::new(async_lock::RwLock::new(GenericStderr::new().into())); - guard.insert(STDIN_FILENO, stdin); - guard.insert(STDOUT_FILENO, stdout); - guard.insert(STDERR_FILENO, stderr); - } + stdio::setup(&mut objmap.write()); } #[cfg(not(feature = "common-os"))] diff --git a/src/syscalls/mod.rs b/src/syscalls/mod.rs index f29f49ebdc..53c0490422 100644 --- a/src/syscalls/mod.rs +++ b/src/syscalls/mod.rs @@ -20,6 +20,7 @@ pub use self::spinlock::*; pub use self::system::*; pub use self::tasks::*; pub use self::timer::*; +use crate::env; use crate::errno::{Errno, ToErrno}; use crate::executor::block_on; use crate::fd::{ @@ -29,7 +30,6 @@ use crate::fd::{ use crate::fs::{self, FileAttr, SeekWhence}; #[cfg(all(target_os = "none", not(feature = "common-os")))] use crate::mm::ALLOCATOR; -use crate::{env, uhyve}; mod condvar; mod entropy; @@ -264,8 +264,9 @@ pub(crate) fn shutdown(arg: i32) -> ! { // print some performance statistics crate::arch::kernel::print_statistics(); + #[cfg(feature = "uhyve")] if env::is_uhyve() { - uhyve::shutdown(arg); + crate::uhyve::shutdown(arg); } // This is a stable message used for detecting exit codes for different hypervisors. diff --git a/src/uhyve.rs b/src/uhyve.rs index 1dd517509d..76b82d8f3d 100644 --- a/src/uhyve.rs +++ b/src/uhyve.rs @@ -7,9 +7,11 @@ use uhyve_interface::{Hypercall, HypercallAddress}; use crate::arch; use crate::arch::mm::paging::virtual_to_physical; +#[cfg(target_os = "none")] +hermit_entry::define_uhyve_interface_version!(uhyve_interface::UHYVE_INTERFACE_VERSION); + /// Perform a SerialWriteBuffer hypercall with `buf` as payload. #[inline] -#[cfg_attr(target_arch = "riscv64", expect(dead_code))] pub(crate) fn serial_buf_hypercall(buf: &[u8]) { let len = buf.len(); let buf = virtual_to_physical(VirtAddr::from_ptr(ptr::from_ref::<[u8]>(buf)))