Skip to content

Commit

Permalink
Merge pull request syswonder#47 from syswonder/dev
Browse files Browse the repository at this point in the history
Merge Dev into Main
  • Loading branch information
coolyjg authored Jan 8, 2024
2 parents e5efd5f + 291e6d6 commit 9e5201f
Show file tree
Hide file tree
Showing 37 changed files with 319 additions and 1,667 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,13 @@ jobs:
- name: Build c/udpserver
run: make ARCH=${{ matrix.arch }} A=apps/c/udpserver
- name: Build c/iperf
run: make ARCH=${{ matrix.arch }} A=apps/c/iperf
run: |
git clone https://github.com/syswonder/rux-iperf ./apps/c/iperf/ \
&& make ARCH=${{ matrix.arch }} A=apps/c/iperf
- name: Build c/redis
run: make ARCH=${{ matrix.arch }} A=apps/c/redis SMP=4
run: |
git clone https://github.com/syswonder/rux-redis ./apps/c/redis/ \
&& make ARCH=${{ matrix.arch }} A=apps/c/redis SMP=4
build-apps-for-std:
runs-on: ${{ matrix.os }}
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ disk.img
actual.out
qemu.log
rusty-tags.vi
apps/c/redis/
apps/c/iperf/
apps/c/wamr/
apps/c/nginx/
17 changes: 4 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ An experimental modular operating system (or unikernel) written in Rust.

RuxOS was inspired by [Unikraft](https://github.com/unikraft/unikraft) and [ArceOS](https://github.com/rcore-os/arceos)

🚧 Working In Progress.
🚧 Working In Progress. See [RuxOS Book](https://ruxos.syswonder.org) for more information.

## Features & TODOs

Expand Down Expand Up @@ -39,17 +39,8 @@ The currently supported applications (Rust), as well as their dependent modules

| App | Extra modules | Enabled features | Description |
|-|-|-|-|
| [helloworld](apps/helloworld/) | | | A minimal app that just prints a string |
| [exception](apps/exception/) | | paging | Exception handling test |
| [memtest](apps/memtest/) | axalloc | alloc, paging | Dynamic memory allocation test |
| [display](apps/display/) | axalloc, ruxdisplay | alloc, paging, display | Graphic/GUI test |
| [yield](apps/task/yield/) | axalloc, ruxtask | alloc, paging, multitask, sched_fifo | Multi-threaded yielding test |
| [parallel](apps/task/parallel/) | axalloc, ruxtask | alloc, paging, multitask, sched_fifo | Parallel computing test (to test synchronization & mutex) |
| [sleep](apps/task/sleep/) | axalloc, ruxtask | alloc, paging, multitask, sched_fifo | Thread sleeping test |
| [shell](apps/fs/shell/) | axalloc, ruxdriver, ruxfs | alloc, paging, fs | A simple shell that responds to filesystem operations |
| [httpclient](apps/net/httpclient/) | axalloc, ruxdriver, axnet | alloc, paging, net | A simple client that sends an HTTP request and then prints the response |
| [echoserver](apps/net/echoserver/) | axalloc, ruxdriver, axnet, ruxtask | alloc, paging, net, multitask | A multi-threaded TCP server that reverses messages sent by the client |
| [httpserver](apps/net/httpserver/) | axalloc, ruxdriver, axnet, ruxtask | alloc, paging, net, multitask | A multi-threaded HTTP server that serves a static web page |

### C

Expand Down Expand Up @@ -119,13 +110,13 @@ Where `<arch>` should be one of `riscv64`, `aarch64`,`x86_64`.

More arguments and targets can be found in [Makefile](Makefile).

For example, to run the [httpserver](apps/net/httpserver/) on `qemu-system-aarch64` with 4 cores:
For example, to run the [shell](apps/fs/shell/) on `qemu-system-aarch64`:

```bash
make A=apps/net/httpserver ARCH=aarch64 LOG=info SMP=4 run NET=y
make A=apps/fs/shell ARCH=aarch64 LOG=info run BLK=y
```

Note that the `NET=y` argument is required to enable the network device in QEMU. These arguments (`BLK`, `GRAPHIC`, etc.) only take effect at runtime not build time.
Note that the `BLK=y` argument is required to enable the block device in QEMU. These arguments (`NET`, `GRAPHIC`, etc.) only take effect at runtime not build time.

### Your custom apps

Expand Down
4 changes: 4 additions & 0 deletions api/ruxos_posix_api/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ typedef struct {{
"sigset_t",
"sigaction",
"kstat",
"stack_t",
"ino_t",
"dirent",
];
let allow_vars = [
"O_.*",
Expand All @@ -122,6 +125,7 @@ typedef struct {{
"EINVAL",
"CLONE_.*",
"AT_.*",
"MAP_FAILED",
];

#[derive(Debug)]
Expand Down
2 changes: 2 additions & 0 deletions api/ruxos_posix_api/ctypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <stddef.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/select.h>
#include <sys/socket.h>
Expand All @@ -29,3 +30,4 @@
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <dirent.h>
25 changes: 25 additions & 0 deletions api/ruxos_posix_api/src/imp/fd_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,31 @@ pub fn sys_fcntl(fd: c_int, cmd: c_int, arg: usize) -> c_int {
get_file_like(fd)?.set_nonblocking(arg & (ctypes::O_NONBLOCK as usize) > 0)?;
Ok(0)
}
ctypes::F_GETFL => {
use ctypes::{O_RDONLY, O_RDWR, O_WRONLY};
let f_state = get_file_like(fd)?.poll()?;
let mut flags: core::ffi::c_uint = 0;
// Only support read/write flags(O_ACCMODE)
if f_state.writable && f_state.readable {
flags |= O_RDWR;
} else if f_state.writable {
flags |= O_WRONLY;
} else if f_state.readable {
flags |= O_RDONLY;
}
Ok(flags as c_int)
}
ctypes::F_SETFD => {
if arg == 0 || arg == 1 || arg == 2 {
return Ok(0);
}
FD_TABLE
.write()
.add_at(arg, get_file_like(fd)?)
.ok_or(LinuxError::EMFILE)?;
let _ = close_file_like(fd);
Ok(0)
}
_ => {
warn!("unsupported fcntl parameters: cmd {}", cmd);
Ok(0)
Expand Down
145 changes: 141 additions & 4 deletions api/ruxos_posix_api/src/imp/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@
*/

use alloc::sync::Arc;
use core::ffi::{c_char, c_int};
use core::ffi::{c_char, c_int, c_long, c_uint};

use axerrno::{LinuxError, LinuxResult};
use axio::{PollState, SeekFrom};
use axsync::Mutex;
use ruxfs::fops::OpenOptions;
use ruxfs::fops::{DirEntry, OpenOptions};

use super::fd_ops::{get_file_like, FileLike};
use crate::{ctypes, utils::char_ptr_to_str};
use alloc::vec::Vec;

pub struct File {
inner: Mutex<ruxfs::fops::File>,
Expand Down Expand Up @@ -84,6 +85,58 @@ impl FileLike for File {
}
}

pub struct Directory {
inner: Mutex<ruxfs::fops::Directory>,
}

impl Directory {
fn new(inner: ruxfs::fops::Directory) -> Self {
Self {
inner: Mutex::new(inner),
}
}

fn add_to_fd_table(self) -> LinuxResult<c_int> {
super::fd_ops::add_file_like(Arc::new(self))
}

fn from_fd(fd: c_int) -> LinuxResult<Arc<Self>> {
let f = super::fd_ops::get_file_like(fd)?;
f.into_any()
.downcast::<Self>()
.map_err(|_| LinuxError::EINVAL)
}
}

impl FileLike for Directory {
fn read(&self, _buf: &mut [u8]) -> LinuxResult<usize> {
Err(LinuxError::EACCES)
}

fn write(&self, _buf: &[u8]) -> LinuxResult<usize> {
Err(LinuxError::EACCES)
}

fn stat(&self) -> LinuxResult<ctypes::stat> {
Err(LinuxError::EACCES)
}

fn into_any(self: Arc<Self>) -> Arc<dyn core::any::Any + Send + Sync> {
self
}

fn poll(&self) -> LinuxResult<PollState> {
Ok(PollState {
readable: true,
writable: true,
})
}

fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult {
Ok(())
}
}

/// Convert open flags to [`OpenOptions`].
fn flags_to_options(flags: c_int, _mode: ctypes::mode_t) -> OpenOptions {
let flags = flags as u32;
Expand Down Expand Up @@ -133,8 +186,13 @@ pub fn sys_openat(_fd: usize, path: *const c_char, flags: c_int, mode: ctypes::m
debug!("sys_openat <= {:?}, {:#o} {:#o}", path, flags, mode);
syscall_body!(sys_openat, {
let options = flags_to_options(flags, mode);
let file = ruxfs::fops::File::open(path?, &options)?;
File::new(file).add_to_fd_table()
if (flags as u32) & ctypes::O_DIRECTORY != 0 {
let dir = ruxfs::fops::Directory::open_dir(path?, &options)?;
Directory::new(dir).add_to_fd_table()
} else {
let file = ruxfs::fops::File::open(path?, &options)?;
File::new(file).add_to_fd_table()
}
})
}

Expand Down Expand Up @@ -402,3 +460,82 @@ pub fn sys_fchownat(
);
syscall_body!(sys_fchownat, Ok(0))
}

/// read value of a symbolic link relative to directory file descriptor
pub fn sys_readlinkat(
fd: c_int,
pathname: *const c_char,
buf: *mut c_char,
bufsize: usize,
) -> usize {
let path = char_ptr_to_str(pathname);
debug!(
"sys_readlinkat <= path = {:?}, fd = {:}, bufsize = {:}",
path, fd, bufsize
);
syscall_body!(sys_readlinkat, {
let mut options = OpenOptions::new();
options.read(true);
let dst = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, bufsize as _) };
// if fd == AT_FDCWD then readat the relative path
if fd == ctypes::AT_FDCWD as c_int {
let file = ruxfs::fops::File::open(path?, &options)?;
let file = File::new(file);
Ok(file.read(dst)?)
} else {
let dir = Directory::from_fd(fd)?;
let mut file = dir.inner.lock().open_file_at(path?, &options)?;
Ok(file.read(dst)?)
}
})
}

type LinuxDirent64 = ctypes::dirent;

fn convert_name_to_array(name: &[u8]) -> [i8; 256] {
let mut array = [0i8; 256];
let len = name.len();
let name_ptr = name.as_ptr() as *const i8;
let array_ptr = array.as_mut_ptr();

unsafe {
core::ptr::copy_nonoverlapping(name_ptr, array_ptr, len);
}

array
}

/// Read directory entries from a directory file descriptor.
///
/// TODO: check errors, change 280 to a special value
pub unsafe fn sys_getdents64(fd: c_uint, dirent: *mut LinuxDirent64, count: c_uint) -> c_long {
debug!(
"sys_getdents64 <= fd: {}, dirent: {:p}, count: {}",
fd, dirent, count
);

syscall_body!(sys_getdents64, {
let expect_entries = count as usize / 280;
let dir = Directory::from_fd(fd as i32)?;
let mut my_dirent: Vec<DirEntry> =
(0..expect_entries).map(|_| DirEntry::default()).collect();

let n = dir.inner.lock().read_dir(&mut my_dirent)?;

for (i, entry) in my_dirent.iter().enumerate() {
let linux_dirent = LinuxDirent64 {
d_ino: 1,
d_off: 280,
d_reclen: 280,
d_type: entry.entry_type() as u8,
d_name: convert_name_to_array(entry.name_as_bytes()),
};

unsafe {
core::ptr::write(dirent.add(i), linux_dirent);
}
}

Ok(n * 280)
})
}
2 changes: 2 additions & 0 deletions api/ruxos_posix_api/src/imp/ioctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub const TIOCGPGRP: usize = 0x540F;
pub const TIOCSPGRP: usize = 0x5410;
pub const TIOCGWINSZ: usize = 0x5413;
pub const FIONBIO: usize = 0x5421;
pub const FIOCLEX: usize = 0x5451;

#[derive(Clone, Copy, Default)]
pub struct ConsoleWinSize {
Expand Down Expand Up @@ -56,6 +57,7 @@ pub fn sys_ioctl(fd: c_int, request: usize, data: usize) -> c_int {
}
Ok(0)
}
FIOCLEX => Ok(0),
_ => Err(LinuxError::EINVAL),
}
})
Expand Down
36 changes: 36 additions & 0 deletions api/ruxos_posix_api/src/imp/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,39 @@ pub fn sys_mprotect(addr: *mut c_void, len: ctypes::size_t, prot: c_int) -> c_in
);
syscall_body!(sys_mprotect, Ok(0))
}

/// Remap a virtual memory address
///
/// TODO: only support
pub fn sys_mremap(
old_addr: *mut c_void,
old_size: ctypes::size_t,
new_size: ctypes::size_t,
_flags: c_int,
_new_addr: *mut c_void,
) -> *mut c_void {
debug!(
"sys_mremap <= old_addr: {:p}, old_size: {}, new_size: {}, flags: {}, new_addr: {:p}",
old_addr, old_size, new_size, _flags, _new_addr
);
syscall_body!(sys_mremap, {
if old_addr.is_null() {
// TODO: It should be ctypes::MAP_FAILED,
// but it is not defined in ctypes for an unknown reason
return Ok(-1 as _);
}
Ok::<*mut c_void, LinuxError>(-1 as _)
})
}

/// give advice about use of memory
/// if success return 0, if error return -1
///
/// TODO: implement this
pub fn sys_madvice(addr: *mut c_void, len: ctypes::size_t, advice: c_int) -> c_int {
debug!(
"sys_madvice <= addr: {:p}, len: {}, advice: {}",
addr, len, advice
);
syscall_body!(sys_madvice, Ok(0))
}
Loading

0 comments on commit 9e5201f

Please sign in to comment.