Skip to content

Commit

Permalink
revise IO interface
Browse files Browse the repository at this point in the history
- using more suitable data types
- create file /proc/version to show the kernel version
- create abstraction layout for file access, which is derived from
  Rust's std
  • Loading branch information
stlankes committed Jan 5, 2024
1 parent 58abdbb commit bf8ce18
Show file tree
Hide file tree
Showing 13 changed files with 482 additions and 421 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ take-static = "0.1"
talc = { version = "4" }
time = { version = "0.3", default-features = false }
zerocopy = { version = "0.7", features = ["derive"] }
build-time = "0.1.3"

[dependencies.smoltcp]
version = "0.10"
Expand Down
72 changes: 24 additions & 48 deletions src/fd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ use hashbrown::HashMap;
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};

use crate::env;
use crate::errno::*;
use crate::fd::stdio::*;
use crate::fs::{self, FileAttr, SeekWhence};
use crate::fs::{self, DirectoryEntry, FileAttr, SeekWhence};

#[cfg(all(any(feature = "tcp", feature = "udp"), not(feature = "newlib")))]
pub(crate) mod socket;
Expand All @@ -23,7 +22,7 @@ const STDERR_FILENO: FileDescriptor = 2;
// TODO: Integrate with src/errno.rs ?
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
pub(crate) enum IoError {
pub enum IoError {
ENOENT = crate::errno::ENOENT as isize,
ENOSYS = crate::errno::ENOSYS as isize,
EIO = crate::errno::EIO as isize,
Expand Down Expand Up @@ -104,33 +103,16 @@ impl Default for AccessPermission {
}
}

#[repr(C)]
#[derive(Debug, Copy, Clone, Default)]
pub struct Dirent {
pub d_ino: u64,
pub d_off: u64,
pub d_namelen: u32,
pub d_type: u32,
pub d_name: [u8; 0],
}

#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum DirectoryEntry {
Invalid(i32),
Valid(*const Dirent),
}

pub(crate) trait ObjectInterface: Sync + Send + core::fmt::Debug + DynClone {
/// `read` attempts to read `len` bytes from the object references
/// by the descriptor
fn read(&self, _buf: &mut [u8]) -> Result<isize, IoError> {
fn read(&self, _buf: &mut [u8]) -> Result<usize, IoError> {
Err(IoError::ENOSYS)
}

/// `write` attempts to write `len` bytes to the object references
/// by the descriptor
fn write(&self, _buf: &[u8]) -> Result<isize, IoError> {
fn write(&self, _buf: &[u8]) -> Result<usize, IoError> {
Err(IoError::ENOSYS)
}

Expand All @@ -157,8 +139,8 @@ pub(crate) trait ObjectInterface: Sync + Send + core::fmt::Debug + DynClone {
/// 'readdir' returns a pointer to a dirent structure
/// representing the next directory entry in the directory stream
/// pointed to by the file descriptor
fn readdir(&self) -> DirectoryEntry {
DirectoryEntry::Invalid(-ENOSYS)
fn readdir(&self) -> Result<Option<DirectoryEntry>, IoError> {
Err(IoError::EINVAL)
}

/// `mkdir` creates a directory entry
Expand Down Expand Up @@ -216,7 +198,7 @@ pub(crate) trait ObjectInterface: Sync + Send + core::fmt::Debug + DynClone {

/// receive a message from a socket
#[cfg(all(any(feature = "tcp", feature = "udp"), not(feature = "newlib")))]
fn recvfrom(&self, _buffer: &mut [u8]) -> Result<(isize, IpEndpoint), IoError> {
fn recvfrom(&self, _buffer: &mut [u8]) -> Result<(usize, IpEndpoint), IoError> {
Err(IoError::ENOSYS)
}

Expand All @@ -228,7 +210,7 @@ pub(crate) trait ObjectInterface: Sync + Send + core::fmt::Debug + DynClone {
/// be sent to the address specified by dest_addr (overriding the pre-specified peer
/// address).
#[cfg(all(any(feature = "tcp", feature = "udp"), not(feature = "newlib")))]
fn sendto(&self, _buffer: &[u8], _endpoint: IpEndpoint) -> Result<isize, IoError> {
fn sendto(&self, _buffer: &[u8], _endpoint: IpEndpoint) -> Result<usize, IoError> {
Err(IoError::ENOSYS)
}

Expand All @@ -248,19 +230,19 @@ pub(crate) trait ObjectInterface: Sync + Send + core::fmt::Debug + DynClone {
fn close(&self) {}
}

pub(crate) fn open(name: &str, flags: i32, mode: u32) -> Result<FileDescriptor, IoError> {
pub(crate) fn open(
name: &str,
flags: OpenOption,
mode: AccessPermission,
) -> Result<FileDescriptor, IoError> {
// mode is 0x777 (0b0111_0111_0111), when flags | O_CREAT, else 0
// flags is bitmask of O_DEC_* defined above.
// (taken from rust stdlib/sys hermit target )

debug!("Open {}, {}, {}", name, flags, mode);
debug!("Open {}, {:?}, {:?}", name, flags, mode);

let fs = fs::FILESYSTEM.get().unwrap();
if let Ok(file) = fs.open(
name,
OpenOption::from_bits(flags).ok_or(IoError::EINVAL)?,
AccessPermission::from_bits(mode).ok_or(IoError::EINVAL)?,
) {
if let Ok(file) = fs.open(name, flags, mode) {
let fd = FD_COUNTER.fetch_add(1, Ordering::SeqCst);
if OBJECT_MAP.write().try_insert(fd, file).is_err() {
Err(IoError::EINVAL)
Expand All @@ -272,28 +254,22 @@ pub(crate) fn open(name: &str, flags: i32, mode: u32) -> Result<FileDescriptor,
}
}

pub(crate) fn opendir(name: &str) -> Result<FileDescriptor, IoError> {
debug!("Open directory {}", name);
pub(crate) fn close(fd: FileDescriptor) {
let _ = remove_object(fd).map(|v| v.close());
}

let fs = fs::FILESYSTEM.get().unwrap();
if let Ok(obj) = fs.opendir(name) {
let fd = FD_COUNTER.fetch_add(1, Ordering::SeqCst);
// Would a GenericDir make sense?
if OBJECT_MAP.write().try_insert(fd, obj).is_err() {
Err(IoError::EINVAL)
} else {
Ok(fd as FileDescriptor)
}
} else {
Err(IoError::EINVAL)
}
pub(crate) fn read(fd: FileDescriptor, buf: &mut [u8]) -> Result<usize, IoError> {
get_object(fd)?.read(buf)
}

pub(crate) fn write(fd: FileDescriptor, buf: &[u8]) -> Result<usize, IoError> {
get_object(fd)?.write(buf)
}

pub(crate) fn get_object(fd: FileDescriptor) -> Result<Arc<dyn ObjectInterface>, IoError> {
Ok((*(OBJECT_MAP.read().get(&fd).ok_or(IoError::EINVAL)?)).clone())
}

#[cfg(all(any(feature = "tcp", feature = "udp"), not(feature = "newlib")))]
pub(crate) fn insert_object(
fd: FileDescriptor,
obj: Arc<dyn ObjectInterface>,
Expand Down
12 changes: 6 additions & 6 deletions src/fd/socket/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl Socket {
// TODO: Remove allow once fixed:
// https://github.com/rust-lang/rust-clippy/issues/11380
#[allow(clippy::needless_pass_by_ref_mut)]
async fn async_read(&self, buffer: &mut [u8]) -> Result<isize, IoError> {
async fn async_read(&self, buffer: &mut [u8]) -> Result<usize, IoError> {
future::poll_fn(|cx| {
self.with(|socket| match socket.state() {
tcp::State::Closed | tcp::State::Closing | tcp::State::CloseWait => {
Expand All @@ -80,7 +80,7 @@ impl Socket {
.recv(|data| {
let len = core::cmp::min(buffer.len(), data.len());
buffer[..len].copy_from_slice(&data[..len]);
(len, isize::try_from(len).unwrap())
(len, len)
})
.map_err(|_| IoError::EIO),
)
Expand All @@ -94,7 +94,7 @@ impl Socket {
.await
}

async fn async_write(&self, buffer: &[u8]) -> Result<isize, IoError> {
async fn async_write(&self, buffer: &[u8]) -> Result<usize, IoError> {
let mut pos: usize = 0;

while pos < buffer.len() {
Expand Down Expand Up @@ -134,7 +134,7 @@ impl Socket {
pos += n;
}

Ok(pos.try_into().unwrap())
Ok(pos)
}

async fn async_connect(&self, endpoint: IpEndpoint) -> Result<(), IoError> {
Expand Down Expand Up @@ -269,7 +269,7 @@ impl ObjectInterface for Socket {
self.with(|socket| socket.local_endpoint())
}

fn read(&self, buf: &mut [u8]) -> Result<isize, IoError> {
fn read(&self, buf: &mut [u8]) -> Result<usize, IoError> {
if buf.is_empty() {
return Ok(0);
}
Expand All @@ -291,7 +291,7 @@ impl ObjectInterface for Socket {
}
}

fn write(&self, buf: &[u8]) -> Result<isize, IoError> {
fn write(&self, buf: &[u8]) -> Result<usize, IoError> {
if buf.is_empty() {
return Ok(0);
}
Expand Down
24 changes: 12 additions & 12 deletions src/fd/socket/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl Socket {
.await
}

async fn async_read(&self, buffer: &mut [u8]) -> Result<isize, IoError> {
async fn async_read(&self, buffer: &mut [u8]) -> Result<usize, IoError> {
future::poll_fn(|cx| {
self.with(|socket| {
if socket.is_open() {
Expand All @@ -62,14 +62,14 @@ impl Socket {
Ok((len, meta)) => match self.endpoint.load() {
Some(ep) => {
if meta.endpoint == ep {
Poll::Ready(Ok(len.try_into().unwrap()))
Poll::Ready(Ok(len))
} else {
buffer[..len].iter_mut().for_each(|x| *x = 0);
socket.register_recv_waker(cx.waker());
Poll::Pending
}
}
None => Poll::Ready(Ok(len.try_into().unwrap())),
None => Poll::Ready(Ok(len)),
},
_ => Poll::Ready(Err(IoError::EIO)),
}
Expand All @@ -85,7 +85,7 @@ impl Socket {
.await
}

async fn async_recvfrom(&self, buffer: &mut [u8]) -> Result<(isize, IpEndpoint), IoError> {
async fn async_recvfrom(&self, buffer: &mut [u8]) -> Result<(usize, IpEndpoint), IoError> {
future::poll_fn(|cx| {
self.with(|socket| {
if socket.is_open() {
Expand All @@ -94,14 +94,14 @@ impl Socket {
Ok((len, meta)) => match self.endpoint.load() {
Some(ep) => {
if meta.endpoint == ep {
Poll::Ready(Ok((len.try_into().unwrap(), meta.endpoint)))
Poll::Ready(Ok((len, meta.endpoint)))
} else {
buffer[..len].iter_mut().for_each(|x| *x = 0);
socket.register_recv_waker(cx.waker());
Poll::Pending
}
}
None => Poll::Ready(Ok((len.try_into().unwrap(), meta.endpoint))),
None => Poll::Ready(Ok((len, meta.endpoint))),
},
_ => Poll::Ready(Err(IoError::EIO)),
}
Expand All @@ -117,15 +117,15 @@ impl Socket {
.await
}

async fn async_write(&self, buffer: &[u8], meta: &UdpMetadata) -> Result<isize, IoError> {
async fn async_write(&self, buffer: &[u8], meta: &UdpMetadata) -> Result<usize, IoError> {
future::poll_fn(|cx| {
self.with(|socket| {
if socket.is_open() {
if socket.can_send() {
Poll::Ready(
socket
.send_slice(buffer, *meta)
.map(|_| buffer.len() as isize)
.map(|_| buffer.len())
.map_err(|_| IoError::EIO),
)
} else {
Expand All @@ -151,7 +151,7 @@ impl ObjectInterface for Socket {
Ok(())
}

fn sendto(&self, buf: &[u8], endpoint: IpEndpoint) -> Result<isize, IoError> {
fn sendto(&self, buf: &[u8], endpoint: IpEndpoint) -> Result<usize, IoError> {
let meta = UdpMetadata::from(endpoint);

if self.nonblocking.load(Ordering::Acquire) {
Expand All @@ -161,7 +161,7 @@ impl ObjectInterface for Socket {
}
}

fn recvfrom(&self, buf: &mut [u8]) -> Result<(isize, IpEndpoint), IoError> {
fn recvfrom(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), IoError> {
if self.nonblocking.load(Ordering::Acquire) {
poll_on(self.async_recvfrom(buf), Some(Duration::ZERO)).map_err(|x| {
if x == IoError::ETIME {
Expand All @@ -179,7 +179,7 @@ impl ObjectInterface for Socket {
}
}

fn read(&self, buf: &mut [u8]) -> Result<isize, IoError> {
fn read(&self, buf: &mut [u8]) -> Result<usize, IoError> {
if buf.len() == 0 {
return Ok(0);
}
Expand All @@ -201,7 +201,7 @@ impl ObjectInterface for Socket {
}
}

fn write(&self, buf: &[u8]) -> Result<isize, IoError> {
fn write(&self, buf: &[u8]) -> Result<usize, IoError> {
if buf.len() == 0 {
return Ok(0);
}
Expand Down
17 changes: 8 additions & 9 deletions src/fd/stdio.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use core::isize;
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use core::ptr;

Expand Down Expand Up @@ -78,11 +77,11 @@ impl GenericStdin {
pub struct GenericStdout;

impl ObjectInterface for GenericStdout {
fn write(&self, buf: &[u8]) -> Result<isize, IoError> {
fn write(&self, buf: &[u8]) -> Result<usize, IoError> {
// stdin/err/out all go to console
CONSOLE.lock().write_all(buf);

Ok(buf.len().try_into().unwrap())
Ok(buf.len())
}
}

Expand All @@ -96,11 +95,11 @@ impl GenericStdout {
pub struct GenericStderr;

impl ObjectInterface for GenericStderr {
fn write(&self, buf: &[u8]) -> Result<isize, IoError> {
fn write(&self, buf: &[u8]) -> Result<usize, IoError> {
// stdin/err/out all go to console
CONSOLE.lock().write_all(buf);

Ok(buf.len().try_into().unwrap())
Ok(buf.len())
}
}

Expand All @@ -125,11 +124,11 @@ impl UhyveStdin {
pub struct UhyveStdout;

impl ObjectInterface for UhyveStdout {
fn write(&self, buf: &[u8]) -> Result<isize, IoError> {
fn write(&self, buf: &[u8]) -> Result<usize, IoError> {
let mut syswrite = SysWrite::new(STDOUT_FILENO, buf.as_ptr(), buf.len());
uhyve_send(UHYVE_PORT_WRITE, &mut syswrite);

Ok(syswrite.len as isize)
Ok(syswrite.len)
}
}

Expand All @@ -143,11 +142,11 @@ impl UhyveStdout {
pub struct UhyveStderr;

impl ObjectInterface for UhyveStderr {
fn write(&self, buf: &[u8]) -> Result<isize, IoError> {
fn write(&self, buf: &[u8]) -> Result<usize, IoError> {
let mut syswrite = SysWrite::new(STDERR_FILENO, buf.as_ptr(), buf.len());
uhyve_send(UHYVE_PORT_WRITE, &mut syswrite);

Ok(syswrite.len as isize)
Ok(syswrite.len)
}
}

Expand Down
Loading

0 comments on commit bf8ce18

Please sign in to comment.