mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 08:26:30 +00:00
Update a-100-line-kernel.md
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
c3c6b0c19d
commit
726632ad70
@ -7,23 +7,29 @@ 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.
|
Our new kernel will be able to run the following Hello World program.
|
||||||
|
|
||||||
```s
|
```s
|
||||||
global _start
|
.global _start # entry point
|
||||||
|
.section .text # code section
|
||||||
section .text
|
|
||||||
|
|
||||||
_start:
|
_start:
|
||||||
mov rax, 1 ; syswrite
|
mov $1, %rax # syscall number of write
|
||||||
mov rdi, 1 ; fd
|
mov $1, %rdi # stdout
|
||||||
mov rsi, msg ; "Hello, world!\n",
|
mov $message, %rsi # address of message
|
||||||
mov rdx, msglen ; sizeof("Hello, world!\n")
|
mov $message_end, %rdx
|
||||||
|
sub %rsi, %rdx # calculate message len
|
||||||
syscall
|
syscall
|
||||||
|
mov $60, %rax # syscall number of exit, move it to rax
|
||||||
|
mov $0, %rdi # exit code, move it to rdi
|
||||||
|
syscall
|
||||||
|
|
||||||
mov rax, 60 ; sys_exit
|
.section .rodata # read only data section
|
||||||
mov rdi, 0 ; exit_code
|
message:
|
||||||
syscall
|
.ascii "Hello, world\n"
|
||||||
|
message_end:
|
||||||
|
```
|
||||||
|
|
||||||
section .rodata
|
The assembly program above can be compiled with the following command.
|
||||||
msg: db "Hello, world!", 10
|
|
||||||
|
```bash
|
||||||
|
gcc -static -nostdlib hello.S -o hello
|
||||||
```
|
```
|
||||||
|
|
||||||
The user program above requires our kernel to support three main features:
|
The user program above requires our kernel to support three main features:
|
||||||
@ -40,8 +46,9 @@ to highlight how the APIs of Asterinas Framework enable safe kernel development.
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
use align_ext::AlignExt;
|
||||||
use alloc::collections::VecDeque;
|
use core::str;
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
|
|
||||||
@ -49,7 +56,7 @@ use aster_frame::cpu::UserContext;
|
|||||||
use aster_frame::prelude::*;
|
use aster_frame::prelude::*;
|
||||||
use aster_frame::task::{Task, TaskOptions};
|
use aster_frame::task::{Task, TaskOptions};
|
||||||
use aster_frame::user::{UserEvent, UserMode, UserSpace};
|
use aster_frame::user::{UserEvent, UserMode, UserSpace};
|
||||||
use aster_frame::vm::{Vaddr, VmAllocOptions, VmIo, VmMapOptions, VmPerm, VmSpace};
|
use aster_frame::vm::{Vaddr, VmAllocOptions, VmIo, VmMapOptions, VmPerm, VmSpace, PAGE_SIZE};
|
||||||
|
|
||||||
/// The kernel's boot and initialization process is managed by Asterinas Framework.
|
/// The kernel's boot and initialization process is managed by Asterinas Framework.
|
||||||
/// After the process is done, the kernel's execution environment
|
/// After the process is done, the kernel's execution environment
|
||||||
@ -59,17 +66,18 @@ use aster_frame::vm::{Vaddr, VmAllocOptions, VmIo, VmMapOptions, VmPerm, VmSpace
|
|||||||
pub fn main() {
|
pub fn main() {
|
||||||
let program_binary = include_bytes!("../hello_world");
|
let program_binary = include_bytes!("../hello_world");
|
||||||
let user_space = create_user_space(program_binary);
|
let user_space = create_user_space(program_binary);
|
||||||
let user_task = create_user_task(user_space);
|
let user_task = create_user_task(Arc::new(user_space));
|
||||||
user_task.run();
|
user_task.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_user_space(program: &[u8]) -> UserSpace {
|
fn create_user_space(program: &[u8]) -> UserSpace {
|
||||||
let user_pages = {
|
let user_pages = {
|
||||||
let nframes = content.len().align_up(PAGE_SIZE) / PAGE_SIZE;
|
let nframes = program.len().align_up(PAGE_SIZE) / PAGE_SIZE;
|
||||||
let vm_frames = VmAllocOptions::new(nframes).alloc().unwrap();
|
let vm_frames = VmAllocOptions::new(nframes).alloc().unwrap();
|
||||||
// Phyiscal memory pages can be only accessed
|
// Phyiscal memory pages can be only accessed
|
||||||
// via the VmFrame abstraction.
|
// via the VmFrame abstraction.
|
||||||
frames.write_bytes(0, program).unwrap()
|
vm_frames.write_bytes(0, program).unwrap();
|
||||||
|
vm_frames
|
||||||
};
|
};
|
||||||
let user_address_space = {
|
let user_address_space = {
|
||||||
const MAP_ADDR: Vaddr = 0x0040_0000; // The map addr for statically-linked executable
|
const MAP_ADDR: Vaddr = 0x0040_0000; // The map addr for statically-linked executable
|
||||||
@ -91,6 +99,7 @@ fn create_user_space(program: &[u8]) -> UserSpace {
|
|||||||
// abstraction.
|
// abstraction.
|
||||||
let mut user_cpu_state = UserContext::default();
|
let mut user_cpu_state = UserContext::default();
|
||||||
user_cpu_state.set_rip(ENTRY_POINT);
|
user_cpu_state.set_rip(ENTRY_POINT);
|
||||||
|
user_cpu_state
|
||||||
};
|
};
|
||||||
UserSpace::new(user_address_space, user_cpu_state)
|
UserSpace::new(user_address_space, user_cpu_state)
|
||||||
}
|
}
|
||||||
@ -114,7 +123,7 @@ fn create_user_task(user_space: Arc<UserSpace>) -> Arc<Task> {
|
|||||||
// the `UserContext` abstraction.
|
// the `UserContext` abstraction.
|
||||||
let user_context = user_mode.context_mut();
|
let user_context = user_mode.context_mut();
|
||||||
if UserEvent::Syscall == user_event {
|
if UserEvent::Syscall == user_event {
|
||||||
handle_syscall(user_context, user_space);
|
handle_syscall(user_context, current.user_space().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,7 +145,7 @@ fn handle_syscall(user_context: &mut UserContext, user_space: &UserSpace) {
|
|||||||
match user_context.rax() {
|
match user_context.rax() {
|
||||||
SYS_WRITE => {
|
SYS_WRITE => {
|
||||||
// Access the user-space CPU registers safely.
|
// Access the user-space CPU registers safely.
|
||||||
let (fd, buf_addr, buf_len) =
|
let (_, buf_addr, buf_len) =
|
||||||
(user_context.rdi(), user_context.rsi(), user_context.rdx());
|
(user_context.rdi(), user_context.rsi(), user_context.rdx());
|
||||||
let buf = {
|
let buf = {
|
||||||
let mut buf = vec![0u8; buf_len];
|
let mut buf = vec![0u8; buf_len];
|
||||||
@ -146,6 +155,7 @@ fn handle_syscall(user_context: &mut UserContext, user_space: &UserSpace) {
|
|||||||
.vm_space()
|
.vm_space()
|
||||||
.read_bytes(buf_addr, &mut buf)
|
.read_bytes(buf_addr, &mut buf)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
buf
|
||||||
};
|
};
|
||||||
// Use the console for output safely.
|
// Use the console for output safely.
|
||||||
println!("{}", str::from_utf8(&buf).unwrap());
|
println!("{}", str::from_utf8(&buf).unwrap());
|
||||||
|
Reference in New Issue
Block a user