mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 01:43:22 +00:00
Rename aster-frame to ostd
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
fb59fa7a55
commit
59350a8578
87
docs/src/ostd/README.md
Normal file
87
docs/src/ostd/README.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Asterinas OSTD
|
||||
|
||||
> Confucious remarked,
|
||||
> "I could follow whatever my heart desired
|
||||
> without transgressing the law."
|
||||
>
|
||||
> 子曰:
|
||||
> "从心所欲,不逾矩。"
|
||||
|
||||
With Asterinas OSTD,
|
||||
you don't have to learn the dark art of unsafe Rust programming
|
||||
and risk shooting yourself in the foot.
|
||||
You will be doing whatever your heart desired
|
||||
and be confident that your kernel will never crash
|
||||
or be hacked due to undefined behaviors,
|
||||
even if today marks your Day 1 as a Rust programmer.
|
||||
|
||||
## APIs
|
||||
|
||||
Asterinas OSTD stands
|
||||
as a powerful and solid foundation for safe kernel development,
|
||||
providing high-level safe Rust APIs that are
|
||||
|
||||
1. Essential for OS development, and
|
||||
2. Dependent on the use of unsafe Rust.
|
||||
|
||||
Most of these APIs fall into the following categories:
|
||||
|
||||
* Memory management (e.g., allocating and accessing physical memory pages)
|
||||
* Task management (e.g., context switching between kernel tasks)
|
||||
* User space (e.g., manipulating and entering the user space)
|
||||
* Interrupt handling (e.g., registering interrupt handlers)
|
||||
* Timer management (e.g., registering timer handlers)
|
||||
* Driver support (e.g., performing DMA and MMIO)
|
||||
* Boot support (e.g., retrieving information from the bootloader)
|
||||
* Synchronization (e.g., locking and sleeping)
|
||||
|
||||
To explore how these APIs come into play,
|
||||
see [the example of a 100-line kernel in safe Rust](a-100-line-kernel.md).
|
||||
|
||||
The OSTD APIs have been extensively documented.
|
||||
You can access the comprehensive API documentation for each release by visiting the [API docs](https://asterinas.github.io/api-docs).
|
||||
Additionally, you can refer to the latest nightly version API documentation at [API docs nightly](https://asterinas.github.io/api-docs-nightly),
|
||||
which remains in sync with the latest changes in the main branch.
|
||||
|
||||
## Four Requirements Satisfied
|
||||
|
||||
In designing and implementing OSTD,
|
||||
we have risen to meet the challenge of
|
||||
fulfilling [the aforementioned four criteria as demanded by the framekernel architecture](../kernel/the-framekernel-architecture.md).
|
||||
|
||||
Expressiveness is evident through Asterinas Kernel itself,
|
||||
where all system calls,
|
||||
file systems,
|
||||
network protocols,
|
||||
and device drivers (e.g., Virtio drivers)
|
||||
have been implemented in safe Rust
|
||||
by leveraging OSTD.
|
||||
|
||||
Adopting a minimalist philosophy,
|
||||
OSTD has a small codebase.
|
||||
At its core lies the `ostd` crate,
|
||||
currently encompassing about 10K lines of code
|
||||
---a figure that is even smaller than those of many microkernels.
|
||||
As OSTD evolves,
|
||||
its codebase will expand,
|
||||
albeit at a relatively slow rate
|
||||
in comparison to the OS services layered atop it.
|
||||
|
||||
OSTD's efficiency is measurable
|
||||
through the performance metrics of its APIs
|
||||
and the system calls of Asterinas Kernel.
|
||||
No intrinsic limitations have been identified within Rust
|
||||
or the framekernel architecture
|
||||
that could hinder kernel performance.
|
||||
|
||||
Soundness,
|
||||
unlike the other three requirements,
|
||||
is not as easily quantified or proved.
|
||||
While formal verification stands as the gold standard,
|
||||
it requires considerable resources and time
|
||||
and is not an immediate priority.
|
||||
As a more pragmatic approach,
|
||||
we will explain why the high-level design is sound
|
||||
in the [soundness analysis]()
|
||||
and rely on the many eyes of the community
|
||||
to catch any potential flaws in the implementation.
|
172
docs/src/ostd/a-100-line-kernel.md
Normal file
172
docs/src/ostd/a-100-line-kernel.md
Normal file
@ -0,0 +1,172 @@
|
||||
# Example: Writing a Kernel in About 100 Lines of Safe Rust
|
||||
|
||||
To give you a sense of
|
||||
how Asterinas OSTD enables writing kernels in safe Rust,
|
||||
we will show a new kernel in about 100 lines of safe Rust.
|
||||
|
||||
Our new kernel will be able to run the following Hello World program.
|
||||
|
||||
```s
|
||||
.global _start # entry point
|
||||
.section .text # code section
|
||||
_start:
|
||||
mov $1, %rax # syscall number of write
|
||||
mov $1, %rdi # stdout
|
||||
mov $message, %rsi # address of message
|
||||
mov $message_end, %rdx
|
||||
sub %rsi, %rdx # calculate message len
|
||||
syscall
|
||||
mov $60, %rax # syscall number of exit, move it to rax
|
||||
mov $0, %rdi # exit code, move it to rdi
|
||||
syscall
|
||||
|
||||
.section .rodata # read only data section
|
||||
message:
|
||||
.ascii "Hello, world\n"
|
||||
message_end:
|
||||
```
|
||||
|
||||
The assembly program above can be compiled with the following command.
|
||||
|
||||
```bash
|
||||
gcc -static -nostdlib hello.S -o hello
|
||||
```
|
||||
|
||||
The user program above requires our kernel to support three main features:
|
||||
1. Loading a program as a process image in user space;
|
||||
3. Handling the write system call;
|
||||
4. Handling the exit system call.
|
||||
|
||||
A sample implementation of the kernel in safe Rust is given below.
|
||||
Comments are added
|
||||
to highlight how the APIs of Asterinas OSTD enable safe kernel development.
|
||||
|
||||
```rust
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use core::str;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec;
|
||||
|
||||
use ostd::cpu::UserContext;
|
||||
use ostd::prelude::*;
|
||||
use ostd::task::{Task, TaskOptions};
|
||||
use ostd::user::{ReturnReason, UserMode, UserSpace};
|
||||
use ostd::mm::{PageFlags, PAGE_SIZE, Vaddr, FrameAllocOptions, VmIo, VmMapOptions, VmSpace};
|
||||
|
||||
/// The kernel's boot and initialization process is managed by Asterinas OSTD.
|
||||
/// After the process is done, the kernel's execution environment
|
||||
/// (e.g., stack, heap, tasks) will be ready for use and the entry function
|
||||
/// labeled as `#[aster_main]` will be called.
|
||||
#[aster_main]
|
||||
pub fn main() {
|
||||
let program_binary = include_bytes!("../hello_world");
|
||||
let user_space = create_user_space(program_binary);
|
||||
let user_task = create_user_task(Arc::new(user_space));
|
||||
user_task.run();
|
||||
}
|
||||
|
||||
fn create_user_space(program: &[u8]) -> UserSpace {
|
||||
let user_pages = {
|
||||
let nframes = program.len().align_up(PAGE_SIZE) / PAGE_SIZE;
|
||||
let vm_frames = FrameAllocOptions::new(nframes).alloc().unwrap();
|
||||
// Phyiscal memory pages can be only accessed
|
||||
// via the Frame abstraction.
|
||||
vm_frames.write_bytes(0, program).unwrap();
|
||||
vm_frames
|
||||
};
|
||||
let user_address_space = {
|
||||
const MAP_ADDR: Vaddr = 0x0040_0000; // The map addr for statically-linked executable
|
||||
|
||||
// The page table of the user space can be
|
||||
// created and manipulated safely through
|
||||
// the VmSpace abstraction.
|
||||
let vm_space = VmSpace::new();
|
||||
let mut options = VmMapOptions::new();
|
||||
options.addr(Some(MAP_ADDR)).flags(PageFlags::RWX);
|
||||
vm_space.map(user_pages, &options).unwrap();
|
||||
vm_space
|
||||
};
|
||||
let user_cpu_state = {
|
||||
const ENTRY_POINT: Vaddr = 0x0040_1000; // The entry point for statically-linked executable
|
||||
|
||||
// The user-space CPU states can be initialized
|
||||
// to arbitrary values via the UserContext
|
||||
// abstraction.
|
||||
let mut user_cpu_state = UserContext::default();
|
||||
user_cpu_state.set_rip(ENTRY_POINT);
|
||||
user_cpu_state
|
||||
};
|
||||
UserSpace::new(user_address_space, user_cpu_state)
|
||||
}
|
||||
|
||||
fn create_user_task(user_space: Arc<UserSpace>) -> Arc<Task> {
|
||||
fn user_task() {
|
||||
let current = Task::current();
|
||||
// Switching between user-kernel space is
|
||||
// performed via the UserMode abstraction.
|
||||
let mut user_mode = {
|
||||
let user_space = current.user_space().unwrap();
|
||||
UserMode::new(user_space)
|
||||
};
|
||||
|
||||
loop {
|
||||
// The execute method returns when system
|
||||
// calls or CPU exceptions occur or some
|
||||
// events specified by the kernel occur.
|
||||
let return_reason = user_mode.execute(|| false);
|
||||
|
||||
// The CPU registers of the user space
|
||||
// can be accessed and manipulated via
|
||||
// the `UserContext` abstraction.
|
||||
let user_context = user_mode.context_mut();
|
||||
if ReturnReason::UserSyscall == return_reason {
|
||||
handle_syscall(user_context, current.user_space().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kernel tasks are managed by OSTD,
|
||||
// while scheduling algorithms for them can be
|
||||
// determined by the users of OSTD.
|
||||
TaskOptions::new(user_task)
|
||||
.user_space(Some(user_space))
|
||||
.data(0)
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn handle_syscall(user_context: &mut UserContext, user_space: &UserSpace) {
|
||||
const SYS_WRITE: usize = 1;
|
||||
const SYS_EXIT: usize = 60;
|
||||
|
||||
match user_context.rax() {
|
||||
SYS_WRITE => {
|
||||
// Access the user-space CPU registers safely.
|
||||
let (_, buf_addr, buf_len) =
|
||||
(user_context.rdi(), user_context.rsi(), user_context.rdx());
|
||||
let buf = {
|
||||
let mut buf = vec![0u8; buf_len];
|
||||
// Copy data from the user space without
|
||||
// unsafe pointer dereferencing.
|
||||
user_space
|
||||
.vm_space()
|
||||
.read_bytes(buf_addr, &mut buf)
|
||||
.unwrap();
|
||||
buf
|
||||
};
|
||||
// Use the console for output safely.
|
||||
println!("{}", str::from_utf8(&buf).unwrap());
|
||||
// Manipulate the user-space CPU registers safely.
|
||||
user_context.set_rax(buf_len);
|
||||
}
|
||||
SYS_EXIT => Task::current().exit(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
Reference in New Issue
Block a user