Top Related Projects
🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.
A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...
Empowering everyone to build reliable and efficient software.
:books: Learn to write an embedded OS in Rust :crab:
Writing an OS in Rust
The Rust package manager
Quick Overview
rCore-Tutorial-v3 is an educational project aimed at teaching operating system development using the Rust programming language. It provides a step-by-step guide to building a simple operating system from scratch, focusing on key concepts such as process management, memory allocation, and file systems.
Pros
- Offers hands-on experience in OS development using a modern, safe language (Rust)
- Provides detailed explanations and documentation for each step of the process
- Includes exercises and labs to reinforce learning
- Regularly updated to incorporate new Rust features and best practices
Cons
- Requires a solid understanding of Rust programming language
- May be challenging for beginners in systems programming
- Limited to x86_64 architecture, not covering other platforms
- Some advanced OS concepts are not covered in depth
Code Examples
Here are a few code examples from the rCore-Tutorial-v3 project:
- Initializing the kernel entry point:
#[no_mangle]
pub fn rust_main() -> ! {
clear_bss();
println!("Hello, world!");
panic!("Shutdown machine!");
}
- Implementing a simple memory allocator:
pub struct StackFrameAllocator {
current: usize,
end: usize,
recycled: Vec<usize>,
}
impl StackFrameAllocator {
pub fn alloc(&mut self) -> Option<PhysPageNum> {
if let Some(ppn) = self.recycled.pop() {
Some(ppn.into())
} else if self.current == self.end {
None
} else {
self.current += 1;
Some((self.current - 1).into())
}
}
}
- Implementing a basic process structure:
pub struct ProcessControlBlock {
pub pid: PidHandle,
pub kernel_stack: KernelStack,
pub inner: UPSafeCell<ProcessControlBlockInner>,
}
impl ProcessControlBlock {
pub fn new(elf_data: &[u8]) -> Self {
// ... implementation details ...
}
}
Getting Started
To get started with rCore-Tutorial-v3:
-
Clone the repository:
git clone https://github.com/rcore-os/rCore-Tutorial-v3.git cd rCore-Tutorial-v3
-
Install dependencies:
rustup target add riscv64gc-unknown-none-elf cargo install cargo-binutils
-
Build and run the OS:
cd os make run
Follow the tutorial chapters in the docs
directory for detailed instructions and explanations.
Competitor Comparisons
🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.
Pros of sqlx
- Focuses on database interaction, providing a robust SQL toolkit for Rust
- Offers compile-time checked queries, enhancing type safety
- Supports multiple database backends (PostgreSQL, MySQL, SQLite, MSSQL)
Cons of sqlx
- Limited to database operations, not a full operating system tutorial
- May have a steeper learning curve for those new to SQL or database concepts
- Less comprehensive in terms of system-level programming education
Code Comparison
sqlx:
let pool = SqlitePool::connect("sqlite::memory:").await?;
let row: (i64,) = sqlx::query_as("SELECT $1")
.bind(150_i64)
.fetch_one(&pool).await?;
rCore-Tutorial-v3:
#[no_mangle]
pub fn rust_main() -> ! {
clear_bss();
println!("Hello, world!");
panic!("Shutdown machine!");
}
The sqlx example demonstrates database interaction, while rCore-Tutorial-v3 focuses on low-level system operations. sqlx is more specialized for database tasks, whereas rCore-Tutorial-v3 provides a broader education in operating system development.
A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...
Pros of Tokio
- Mature and widely-used asynchronous runtime for Rust
- Extensive documentation and community support
- Optimized for high-performance networking applications
Cons of Tokio
- Steeper learning curve for beginners
- Focused on async I/O, not a full operating system tutorial
- May introduce complexity for simple applications
Code Comparison
rCore-Tutorial-v3 (OS kernel initialization):
#[no_mangle]
pub fn rust_main() -> ! {
clear_bss();
println!("Hello, world!");
panic!("Shutdown machine!");
}
Tokio (Asynchronous TCP server):
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (socket, _) = listener.accept().await?;
tokio::spawn(async move { handle_connection(socket).await });
}
}
rCore-Tutorial-v3 is an educational project focused on building an operating system kernel in Rust, while Tokio is a production-ready asynchronous runtime for building scalable network applications. rCore-Tutorial-v3 provides hands-on experience with low-level system programming, whereas Tokio abstracts away many of these details to provide a high-performance framework for concurrent programming.
Empowering everyone to build reliable and efficient software.
Pros of rust
- Larger community and more extensive documentation
- Broader scope, covering the entire Rust programming language
- More frequent updates and active development
Cons of rust
- Steeper learning curve for beginners
- Less focused on operating system concepts
- Larger codebase, potentially overwhelming for new contributors
Code comparison
rCore-Tutorial-v3:
#[no_mangle]
pub fn rust_main() -> ! {
clear_bss();
println!("Hello, world!");
panic!("Shutdown machine!");
}
rust:
#[lang = "start"]
fn start<T>(main: fn() -> T, argc: isize, argv: *const *const u8) -> isize {
unsafe {
::sys_common::backtrace::__rust_begin_short_backtrace(main);
}
0
}
The rCore-Tutorial-v3 code snippet shows a simple entry point for an operating system, while the rust code demonstrates a more complex language-level start function. rCore-Tutorial-v3 focuses on OS-specific concepts, whereas rust covers broader language functionality.
:books: Learn to write an embedded OS in Rust :crab:
Pros of rust-raspberrypi-OS-tutorials
- Focuses specifically on Raspberry Pi hardware, providing hands-on experience with a popular embedded platform
- Includes detailed explanations of hardware-specific concepts and peripherals
- Offers a gradual learning curve, starting from basic "blinky" examples to more complex OS features
Cons of rust-raspberrypi-OS-tutorials
- Limited to Raspberry Pi architecture, potentially less applicable to other platforms
- May not cover as many advanced OS concepts as rCore-Tutorial-v3
- Smaller community and fewer contributors compared to rCore-Tutorial-v3
Code Comparison
rust-raspberrypi-OS-tutorials:
#[no_mangle]
pub extern "C" fn kernel_main() -> ! {
let mut gpio = GPIO::new();
let mut timer = Timer::new();
loop {
gpio.set(16);
timer.wait_ms(500);
gpio.clear(16);
timer.wait_ms(500);
}
}
rCore-Tutorial-v3:
#[no_mangle]
pub fn rust_main() -> ! {
clear_bss();
println!("Hello, world!");
trap::init();
loader::load_apps();
task::run_first_task();
panic!("Unreachable in rust_main!");
}
The code snippets demonstrate the different focus areas of each tutorial. rust-raspberrypi-OS-tutorials emphasizes hardware interaction, while rCore-Tutorial-v3 covers more OS-specific concepts like trap handling and task management.
Writing an OS in Rust
Pros of blog_os
- Written in Rust, providing memory safety and modern language features
- Extensive documentation and step-by-step explanations for beginners
- Focuses on x86_64 architecture, which is widely used and well-documented
Cons of blog_os
- Limited to x86_64 architecture, less versatile than rCore-Tutorial-v3
- Slower development pace compared to rCore-Tutorial-v3
- Less emphasis on advanced operating system concepts
Code Comparison
blog_os:
#[no_mangle]
pub extern "C" fn _start() -> ! {
println!("Hello World{}", "!");
loop {}
}
rCore-Tutorial-v3:
#[no_mangle]
pub fn rust_main() -> ! {
clear_bss();
println!("Hello, world!");
panic!("Shutdown machine!");
}
Both projects use Rust for OS development, but rCore-Tutorial-v3 focuses on RISC-V architecture and includes more advanced concepts. blog_os provides a more beginner-friendly approach with detailed explanations, while rCore-Tutorial-v3 offers a broader range of topics and faster development. The code snippets show similar entry points, but rCore-Tutorial-v3 includes additional functionality like clearing BSS and explicitly panicking for shutdown.
The Rust package manager
Pros of Cargo
- Mature and widely-used package manager for Rust
- Extensive documentation and community support
- Integrated build system and dependency management
Cons of Cargo
- Larger codebase, potentially more complex to contribute to
- Focused solely on Rust package management, not OS development
- May have a steeper learning curve for beginners
Code Comparison
rCore-Tutorial-v3:
#[no_mangle]
pub fn rust_main() -> ! {
clear_bss();
println!("Hello, world!");
panic!("Shutdown machine!");
}
Cargo:
pub fn run(config: Config) -> CliResult {
let mut config = config;
config.configure()?;
let workspace = Workspace::new(config.workspace_path(), &config)?;
ops::compile(&workspace, &config.compile_options())?;
Ok(())
}
Summary
Cargo is a robust package manager and build tool for Rust, while rCore-Tutorial-v3 is an educational project for learning OS development in Rust. Cargo offers more comprehensive features for Rust development, but rCore-Tutorial-v3 provides a focused learning experience for OS concepts. The code examples highlight their different purposes: rCore-Tutorial-v3 demonstrates low-level OS operations, while Cargo showcases project configuration and compilation.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
rCore-Tutorial-v3
rCore-Tutorial version 3.6. See the Documentation in Chinese.
rCore-Tutorial API Docs. See the API Docs of Ten OSes
If you don't know Rust Language and try to learn it, please visit Rust Learning Resources
Official QQ group number: 735045051
news
- 23/06/2022: Version 3.6.0 is on the way! Now we directly update the code on chX branches, please periodically check if there are any updates.
Overview
This project aims to show how to write an Unix-like OS running on RISC-V platforms from scratch in Rust for beginners without any background knowledge about computer architectures, assembly languages or operating systems.
Features
- Platform supported:
qemu-system-riscv64
simulator or dev boards based on Kendryte K210 SoC such as Maix Dock - OS
- concurrency of multiple processes each of which contains mutiple native threads
- preemptive scheduling(Round-Robin algorithm)
- dynamic memory management in kernel
- virtual memory
- a simple file system with a block cache
- an interactive shell in the userspace
- only 4K+ LoC
- A detailed documentation in Chinese in spite of the lack of comments in the code(English version is not available at present)
Prerequisites
Install Rust
See official guide.
Install some tools:
$ rustup target add riscv64gc-unknown-none-elf
$ cargo install cargo-binutils --vers =0.3.3
$ rustup component add llvm-tools-preview
$ rustup component add rust-src
Install Qemu
Here we manually compile and install Qemu 7.0.0. For example, on Ubuntu 18.04:
# install dependency packages
$ sudo apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \
gawk build-essential bison flex texinfo gperf libtool patchutils bc \
zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev git tmux python3 python3-pip ninja-build
# download Qemu source code
$ wget https://download.qemu.org/qemu-7.0.0.tar.xz
# extract to qemu-7.0.0/
$ tar xvJf qemu-7.0.0.tar.xz
$ cd qemu-7.0.0
# build
$ ./configure --target-list=riscv64-softmmu,riscv64-linux-user
$ make -j$(nproc)
Then, add following contents to ~/.bashrc
(please adjust these paths according to your environment):
export PATH=$PATH:/path/to/qemu-7.0.0/build
Finally, update the current shell:
$ source ~/.bashrc
Now we can check the version of Qemu:
$ qemu-system-riscv64 --version
QEMU emulator version 7.0.0
Copyright (c) 2003-2020 Fabrice Bellard and the QEMU Project developers
Install RISC-V GNU Embedded Toolchain(including GDB)
Download the compressed file according to your platform From Sifive website(Ctrl+F 'toolchain').
Extract it and append the location of the 'bin' directory under its root directory to $PATH
.
For example, we can check the version of GDB:
$ riscv64-unknown-elf-gdb --version
GNU gdb (SiFive GDB-Metal 10.1.0-2020.12.7) 10.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Install serial tools(Optional, if you want to run on K210)
$ pip3 install pyserial
$ sudo apt install python3-serial
Run our project
Qemu
$ git clone https://github.com/rcore-os/rCore-Tutorial-v3.git
$ cd rCore-Tutorial-v3/os
$ make run
After outputing some debug messages, the kernel lists all the applications available and enter the user shell:
/**** APPS ****
mpsc_sem
usertests
pipetest
forktest2
cat
initproc
race_adder_loop
threads_arg
race_adder_mutex_spin
race_adder_mutex_blocking
forktree
user_shell
huge_write
race_adder
race_adder_atomic
threads
stack_overflow
filetest_simple
forktest_simple
cmdline_args
run_pipe_test
forktest
matrix
exit
fantastic_text
sleep_simple
yield
hello_world
pipe_large_test
sleep
phil_din_mutex
**************/
Rust user shell
>>
You can run any application except for initproc
and user_shell
itself. To run an application, just input its filename and hit enter. usertests
can run a bunch of applications, thus it is recommended.
Type Ctrl+a
then x
to exit Qemu.
K210
Before chapter 6, you do not need a SD card:
$ git clone https://github.com/rcore-os/rCore-Tutorial-v3.git
$ cd rCore-Tutorial-v3/os
$ make run BOARD=k210
From chapter 6, before running the kernel, we should insert a SD card into PC and manually write the filesystem image to it:
$ cd rCore-Tutorial-v3/os
$ make sdcard
By default it will overwrite the device /dev/sdb
which is the SD card, but you can provide another location. For example, make sdcard SDCARD=/dev/sdc
.
After that, remove the SD card from PC and insert it to the slot of K210. Connect the K210 to PC and then:
$ git clone https://github.com/rcore-os/rCore-Tutorial-v3.git
$ cd rCore-Tutorial-v3/os
$ make run BOARD=k210
Type Ctrl+]
to disconnect from K210.
Show runtime debug info of OS kernel version
The branch of ch9-log contains a lot of debug info. You could try to run rcore tutorial for understand the internal behavior of os kernel.
$ git clone https://github.com/rcore-os/rCore-Tutorial-v3.git
$ cd rCore-Tutorial-v3/os
$ git checkout ch9-log
$ make run
......
[rustsbi] RustSBI version 0.2.0-alpha.10, adapting to RISC-V SBI v0.3
.______ __ __ _______.___________. _______..______ __
| _ \ | | | | / | | / || _ \ | |
| |_) | | | | | | (----`---| |----`| (----`| |_) || |
| / | | | | \ \ | | \ \ | _ < | |
| |\ \----.| `--' |.----) | | | .----) | | |_) || |
| _| `._____| \______/ |_______/ |__| |_______/ |______/ |__|
[rustsbi] Implementation: RustSBI-QEMU Version 0.0.2
[rustsbi-dtb] Hart count: cluster0 with 1 cores
[rustsbi] misa: RV64ACDFIMSU
[rustsbi] mideleg: ssoft, stimer, sext (0x222)
[rustsbi] medeleg: ima, ia, bkpt, la, sa, uecall, ipage, lpage, spage (0xb1ab)
[rustsbi] pmp0: 0x10000000 ..= 0x10001fff (rw-)
[rustsbi] pmp1: 0x2000000 ..= 0x200ffff (rw-)
[rustsbi] pmp2: 0xc000000 ..= 0xc3fffff (rw-)
[rustsbi] pmp3: 0x80000000 ..= 0x8fffffff (rwx)
[rustsbi] enter supervisor 0x80200000
[KERN] rust_main() begin
[KERN] clear_bss() begin
[KERN] clear_bss() end
[KERN] mm::init() begin
[KERN] mm::init_heap() begin
[KERN] mm::init_heap() end
[KERN] mm::init_frame_allocator() begin
[KERN] mm::frame_allocator::lazy_static!FRAME_ALLOCATOR begin
......
Rustdoc
Currently it can only help you view the code since only a tiny part of the code has been documented.
You can open a doc html of os
using cargo doc --no-deps --open
under os
directory.
OS-API-DOCS
The API Docs for Ten OS
- Lib-OS API doc
- Batch-OS API doc
- MultiProg-OS API doc
- TimeSharing-OS API doc
- AddrSpace-OS API doc
- Process-OS API doc
- FileSystem-OS API doc
- IPC-OS API doc
- SyncMutex-OS API doc
- IODevice-OS API doc
Working in progress
Our first release 3.6.0 (chapter 1-9) has been published, and we are still working on it.
- chapter 9: need more descripts about different I/O devices
Here are the updates since 3.5.0:
Completed
- automatically clean up and rebuild before running our project on a different platform
- fix
power
series application in early chapters, now you can find modulus in the output - use
UPSafeCell
instead ofRefCell
orspin::Mutex
in order to access static data structures and adjust its API so that it cannot be borrowed twice at a time(mention& .exclusive_access().task[0]
inrun_first_task
) - move
TaskContext
intoTaskControlBlock
instead of restoring it in place on kernel stack(since ch3), eliminating annoyingtask_cx_ptr2
- replace
llvm_asm!
withasm!
- expand the fs image size generated by
rcore-fs-fuse
to 128MiB - add a new test named
huge_write
which evaluates the fs performance(qemu~500KiB/s k210~50KiB/s) - flush all block cache to disk after a fs transaction which involves write operation
- replace
spin::Mutex
withUPSafeCell
before SMP chapter - add codes for a new chapter about synchronization & mutual exclusion(uniprocessor only)
- bug fix: we should call
find_pte
rather thanfind_pte_create
inPageTable::unmap
- clarify: "check validity of level-3 pte in
find_pte
instead of checking it outside this function" should not be a bug - code of chapter 8: synchronization on a uniprocessor
- switch the code of chapter 6 and chapter 7
- support signal mechanism in chapter 7/8(only works for apps with a single thread)
- Add boards/ directory and support rustdoc, for example you can use
cargo doc --no-deps --open
to view the documentation of a crate - code of chapter 9: device drivers based on interrupts, including UART, block, keyboard, mouse, gpu devices
- add CI autotest and doc in github
Todo(High priority)
- review documentation, current progress: 8/9
- use old fs image optionally, do not always rebuild the image
- shell functionality improvement(to be continued...)
- give every non-zero process exit code an unique and clear error type
- effective error handling of mm module
- add more os functions for understanding os conecpts and principles
Todo(Low priority)
- rewrite practice doc and remove some inproper questions
- provide smooth debug experience at a Rust source code level
- format the code using official tools
Crates
We will add them later.
Top Related Projects
🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.
A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...
Empowering everyone to build reliable and efficient software.
:books: Learn to write an embedded OS in Rust :crab:
Writing an OS in Rust
The Rust package manager
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot