o8vm
octox
Rust

Unix-like OS in Rust inspired by xv6-riscv

Last updated Jul 6, 2026
1.6k
Stars
64
Forks
3
Issues
+1
Stars/day
Attention Score
59
Language breakdown
No language data available.
β–Έ Files click to expand
README

#+title: octox #+author: Hayato Ohhashi #+email: o8@vmm.dev

octox is a Unix-like operating system inspired by xv6-riscv. octox loosely follows the structure and style of xv6, but is implemented in pure Rust.

[[https://vhs.charm.sh/vhs-6MQBIyAo3DpBrARBxHxL35.gif]]

  • Everything from kernel, userland, mkfs, to build system is written in safe
Rust as much as possible.
  • There are no dependencies on external crates.
  • The userland has a library similar to Rust’s std with K&R malloc.
  • Multi-core support, buddy allocator as kernel-side memory allocator, file
system with logging support, etc.
  • Getting Started
** Requirements
  • Install the rust toolchain to have cargo installed by following
[[https://www.rust-lang.org/tools/install][this]] guide.
  • Install ~qemu-system-riscv~
  • (option) Install ~gdb-multiarch~
** Build and Run
  • Clone this project & enter: ~git clone ... && cd octox~
  • Build: ~cargo build --target riscv64gc-unknown-none-elf~.
  • Run: ~cargo run --target riscv64gc-unknown-none-elf~, then qemu will boot
octox. To exit, press ~Ctrl+a~ and ~x~.

** Play with the Shell

A very simple shell is implemented. In addition to executing commands, you can only do the following things.

  • Pipe: ~cat file | head | grep test~
  • Dump processes: ~Ctrl + P~
  • End of line: ~Ctrl + D~
  • Redirect output: ~>~, ~>>~
  • Development
** Userland Application

The userland comes with a user library called ulib (located at src/user/lib) that is similar to Rust’s std, so you can use it to develop your favorite commands. If you create a bin crate named ~_command~ in src/user/bin, the build.rs and mkfs.rs will place a file named ~command~ in the file system and make it available for use.

  • In src/user/Cargo.toml, define a bin crate with the name of the command you
want to create with a ~_~ prefix #+begin_src toml [[bin]] name = "_rm" path = "bin/rm.rs" #+end_src
  • userland is also nostd, so don’t forget to add ~#[nostd]~. Use ulib to
develop any command you like. Here is an example of the rm command. #+begin_src rust #![no_std] use ulib::{env, fs};

fn main() { let mut args = env::args().skip(1).peekable();

if args.peek().is_none() { panic!("Usage: rm files...") } for arg in args { fs::remove_file(arg).unwrap() } } #+end_src

  • Then, ~cargo run --target riscv64gc-unknown-none-elf~ in the root of octox.
  • To use ~Vec~ and ~String~, etc, do the following:
#+begin_src rust extern crate alloc; use alloc::{string::String, vec::Vec}; #+end_src

** Kernel

Developing in src/kernel. Here is an example of adding a system call. If you want to add a new system call, you only need to add a definition to the system call table in libkernel, and the userland library will be automatically generated by build.rs.

  • Add a variant and Syscall Number to ~enum SysCalls~ in src/kernel/syscall.rs.
Here is ~Dup2~ as an example: #+begin_src rust pub enum SysCalls { Fork = 1, ..., Dup2 = 23, Invalid = 0, } #+end_src
  • Define the function signature of the system call in the ~TABLE~ of
~SysCalls~. Use the enum type ~Fn~ to describe the return type(~U~ (Unit), ~I~ (Integer), ~N~ (never)) and use ~&str~ to represent arguments. then, define kernel-side implementation as a method on ~SysCalls~. ~cfg~ flag is used to control the compilation target for kernel and the rest. Here is an example of ~dup2~: #+begin_src rust impl SysCalls { pub const TABLE: [(fn, &'static str); variant_count::()] = [ (Fn::N(Self::Invalid), ""), (Fn::I(Self::fork), "()"), (Fn::N(Self::exit), "(xstatus: i32)"), ..., (Fn::I(Self::dup2), "(src: usize, dst: usize)"), ]; pub fn dup2() -> Result { #[cfg(not(all(target_os = "none", feature = "kernel")))] return Ok(0); #[cfg(all(target_os = "none", feature = "kernel"))] { let p = Cpus::myproc().unwrap().data_mut(); let srcfd = argraw(0); let dstfd = argraw(1); if srcfd != dstfd { let mut src = p.ofile.getmut(srcfd).unwrap() .take().unwrap(); src.clear_cloexec(); p.ofile.getmut(dstfd) .ok_or(FileDescriptorTooLarge)?.replace(src); } Ok(dst_fd) } } #+end_src
  • With just these steps, the dup2 system call is implemented in both kernel and
userland.
  • License
Licensed under either of
  • [[http://www.apache.org/licenses/LICENSE-2.0][Apache License, Version 2.0]]
  • [[http://opensource.org/licenses/MIT][MIT license]]
at your option.
  • Acknowledgments
octox is inspired by [[https://github.com/mit-pdos/xv6-riscv][xv6-riscv]].

I'm also grateful for the bug reports and discussion about the implementation contributed by Takahiro Itazuri and Kuniyuki Iwashima.

  • Contribution
This is a hobby learning project, but contributions are welcome! However, please note that reviews may take considerable time. Discussions and advice are always appreciated.
πŸ”— More in this category

Β© 2026 GitRepoTrend Β· o8vm/octox Β· Updated daily from GitHub