From 93d85e1d32d27b4b4bc8cfcc3438a4f475a9513d Mon Sep 17 00:00:00 2001 From: Tateisi Date: Sun, 3 Aug 2025 05:00:14 +0800 Subject: [PATCH 1/3] ch2: Applications user_lib user apps --- {.cargo => os/.cargo}/config.toml | 0 .gitignore => os/.gitignore | 0 Cargo.lock => os/Cargo.lock | 0 Cargo.toml => os/Cargo.toml | 0 {src => os/src}/console.rs | 0 {src => os/src}/entry.asm | 0 {src => os/src}/lang_items.rs | 5 +- {src => os/src}/linker.ld | 0 {src => os/src}/logger.rs | 0 {src => os/src}/main.rs | 0 {src => os/src}/sbi.rs | 0 user/.cargo/config.toml | 7 +++ user/.gitignore | 1 + user/Cargo.lock | 93 +++++++++++++++++++++++++++++++ user/Cargo.toml | 7 +++ user/src/bin/00_hello_world.rs | 11 ++++ user/src/bin/01_store_fault.rs | 15 +++++ user/src/bin/02_powers.rs | 27 +++++++++ user/src/bin/03_priv_inst.rs | 17 ++++++ user/src/bin/04_priv_csr.rs | 17 ++++++ user/src/console.rs | 32 +++++++++++ user/src/lang_items.rs | 17 ++++++ user/src/lib.rs | 38 +++++++++++++ user/src/linker.ld | 46 +++++++++++++++ user/src/syscall.rs | 26 +++++++++ 25 files changed, 357 insertions(+), 2 deletions(-) rename {.cargo => os/.cargo}/config.toml (100%) rename .gitignore => os/.gitignore (100%) rename Cargo.lock => os/Cargo.lock (100%) rename Cargo.toml => os/Cargo.toml (100%) rename {src => os/src}/console.rs (100%) rename {src => os/src}/entry.asm (100%) rename {src => os/src}/lang_items.rs (73%) rename {src => os/src}/linker.ld (100%) rename {src => os/src}/logger.rs (100%) rename {src => os/src}/main.rs (100%) rename {src => os/src}/sbi.rs (100%) create mode 100644 user/.cargo/config.toml create mode 100644 user/.gitignore create mode 100644 user/Cargo.lock create mode 100644 user/Cargo.toml create mode 100644 user/src/bin/00_hello_world.rs create mode 100644 user/src/bin/01_store_fault.rs create mode 100644 user/src/bin/02_powers.rs create mode 100644 user/src/bin/03_priv_inst.rs create mode 100644 user/src/bin/04_priv_csr.rs create mode 100644 user/src/console.rs create mode 100644 user/src/lang_items.rs create mode 100644 user/src/lib.rs create mode 100644 user/src/linker.ld create mode 100644 user/src/syscall.rs diff --git a/.cargo/config.toml b/os/.cargo/config.toml similarity index 100% rename from .cargo/config.toml rename to os/.cargo/config.toml diff --git a/.gitignore b/os/.gitignore similarity index 100% rename from .gitignore rename to os/.gitignore diff --git a/Cargo.lock b/os/Cargo.lock similarity index 100% rename from Cargo.lock rename to os/Cargo.lock diff --git a/Cargo.toml b/os/Cargo.toml similarity index 100% rename from Cargo.toml rename to os/Cargo.toml diff --git a/src/console.rs b/os/src/console.rs similarity index 100% rename from src/console.rs rename to os/src/console.rs diff --git a/src/entry.asm b/os/src/entry.asm similarity index 100% rename from src/entry.asm rename to os/src/entry.asm diff --git a/src/lang_items.rs b/os/src/lang_items.rs similarity index 73% rename from src/lang_items.rs rename to os/src/lang_items.rs index 749fc53..482328e 100644 --- a/src/lang_items.rs +++ b/os/src/lang_items.rs @@ -3,15 +3,16 @@ use crate::{sbi, println}; #[panic_handler] fn panic(info: &PanicInfo) -> ! { + let err = info.message().as_str().unwrap(); if let Some(location) = info.location() { println!( "Panicked at {}:{} {}", location.file(), location.line(), - info.message().as_str().unwrap() + err ); } else { - println!("Panicked: {}", info.message().as_str().unwrap()); + println!("Panicked: {}", err); } sbi::shutdown(true) } \ No newline at end of file diff --git a/src/linker.ld b/os/src/linker.ld similarity index 100% rename from src/linker.ld rename to os/src/linker.ld diff --git a/src/logger.rs b/os/src/logger.rs similarity index 100% rename from src/logger.rs rename to os/src/logger.rs diff --git a/src/main.rs b/os/src/main.rs similarity index 100% rename from src/main.rs rename to os/src/main.rs diff --git a/src/sbi.rs b/os/src/sbi.rs similarity index 100% rename from src/sbi.rs rename to os/src/sbi.rs diff --git a/user/.cargo/config.toml b/user/.cargo/config.toml new file mode 100644 index 0000000..6ddcd53 --- /dev/null +++ b/user/.cargo/config.toml @@ -0,0 +1,7 @@ +[build] +target = "riscv64gc-unknown-none-elf" + +[target.riscv64gc-unknown-none-elf] +rustflags = [ + "-Clink-arg=-Tsrc/linker.ld", "-Cforce-frame-pointers=yes" +] \ No newline at end of file diff --git a/user/.gitignore b/user/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/user/.gitignore @@ -0,0 +1 @@ +/target diff --git a/user/Cargo.lock b/user/Cargo.lock new file mode 100644 index 0000000..287fb7a --- /dev/null +++ b/user/Cargo.lock @@ -0,0 +1,93 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "riscv" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7" +dependencies = [ + "critical-section", + "embedded-hal", + "paste", + "riscv-macros", + "riscv-pac", +] + +[[package]] +name = "riscv-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "riscv-pac" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "user_lib" +version = "0.1.0" +dependencies = [ + "riscv", +] diff --git a/user/Cargo.toml b/user/Cargo.toml new file mode 100644 index 0000000..534e542 --- /dev/null +++ b/user/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "user_lib" +version = "0.1.0" +edition = "2021" + +[dependencies] +riscv = "0.12.1" diff --git a/user/src/bin/00_hello_world.rs b/user/src/bin/00_hello_world.rs new file mode 100644 index 0000000..684396a --- /dev/null +++ b/user/src/bin/00_hello_world.rs @@ -0,0 +1,11 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +#[no_mangle] +fn main() -> i32 { + println!("Hello, world!"); + 0 +} \ No newline at end of file diff --git a/user/src/bin/01_store_fault.rs b/user/src/bin/01_store_fault.rs new file mode 100644 index 0000000..855f285 --- /dev/null +++ b/user/src/bin/01_store_fault.rs @@ -0,0 +1,15 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +#[no_mangle] +fn main() -> i32 { + println!("Into Test store_fault, we will insert an invalid store operation..."); + println!("kerne; should kill this application"); + unsafe { + core::ptr::null_mut::().write_volatile(0); + } + 0 +} \ No newline at end of file diff --git a/user/src/bin/02_powers.rs b/user/src/bin/02_powers.rs new file mode 100644 index 0000000..54fde24 --- /dev/null +++ b/user/src/bin/02_powers.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +const SIZE: usize = 10; +const P: u32 = 3; +const STEP: usize = 100000; +const MOD: u32 = 10007; + +#[no_mangle] +fn main() -> i32 { + let mut pow = [0u32; SIZE]; + let mut index: usize = 0; + pow[index] = 1; + for i in 1..=STEP { + let last = pow[index]; + index = (index + 1) % SIZE; + pow[index] = last * P % MOD; + if i % 10000 == 0 { + println!("{}^{}={}(MOD {})", P, i, pow[index], MOD); + } + } + println!("Test power OK!"); + 0 +} \ No newline at end of file diff --git a/user/src/bin/03_priv_inst.rs b/user/src/bin/03_priv_inst.rs new file mode 100644 index 0000000..04dac37 --- /dev/null +++ b/user/src/bin/03_priv_inst.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use core::arch::asm; + +#[no_mangle] +fn main() -> i32 { + println!("Try to execute privileged instruction in U Mode"); + println!("Kernel should kill this application!"); + unsafe { + asm!("sret"); + } + 0 +} diff --git a/user/src/bin/04_priv_csr.rs b/user/src/bin/04_priv_csr.rs new file mode 100644 index 0000000..fbd678f --- /dev/null +++ b/user/src/bin/04_priv_csr.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use riscv::register::sstatus::{self, SPP}; + +#[no_mangle] +fn main() -> i32 { + println!("Try to access privileged CSR in U Mode"); + println!("Kernel should kill this application!"); + unsafe { + sstatus::set_spp(SPP::User); + } + 0 +} diff --git a/user/src/console.rs b/user/src/console.rs new file mode 100644 index 0000000..93e7255 --- /dev/null +++ b/user/src/console.rs @@ -0,0 +1,32 @@ +use super::write; +use core::fmt::{self, Write}; + + +struct Stdout; + +const STDOUT: usize = 1; + +impl Write for Stdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + write(STDOUT, s.as_bytes()); + Ok(()) + } +} + +pub fn print(args: fmt::Arguments) { + Stdout.write_fmt(args).unwrap(); +} + +#[macro_export] +macro_rules! print { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::console::print(format_args!($fmt $(, $($arg)+)?)); + } +} + +#[macro_export] +macro_rules! println { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); + } +} \ No newline at end of file diff --git a/user/src/lang_items.rs b/user/src/lang_items.rs new file mode 100644 index 0000000..afa93e2 --- /dev/null +++ b/user/src/lang_items.rs @@ -0,0 +1,17 @@ +use core::panic::PanicInfo; + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + let err = info.message().as_str().unwrap(); + if let Some(location) = info.location() { + println!( + "Panicked at {}:{}, {}", + location.file(), + location.line(), + err + ); + } else { + println!("Panicked: {}", err); + } + loop {} +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs new file mode 100644 index 0000000..63bf15a --- /dev/null +++ b/user/src/lib.rs @@ -0,0 +1,38 @@ +#![no_std] + +#[macro_use] +pub mod console; +mod syscall; +mod lang_items; + +#[no_mangle] +#[link_section = ".text.entry"] +pub extern "C" fn _start() -> ! { + // linkage is not stable + // but main function in user function required + extern "C" { + fn main() -> i32; + } + clear_bss(); + unsafe { + exit(main()); + } + panic!("unreachable after sys_exit") +} + +fn clear_bss() { + extern "C" { + fn sbss(); + fn ebss(); + } + (sbss as usize..ebss as usize).for_each(|addr| unsafe { + (addr as *mut u8).write_volatile(0); + }); +} + +pub fn write(fd: usize, buf: &[u8]) -> isize { + syscall::sys_write(fd, buf) +} +pub fn exit(exit_code: i32) -> isize { + syscall::sys_exit(exit_code) +} \ No newline at end of file diff --git a/user/src/linker.ld b/user/src/linker.ld new file mode 100644 index 0000000..01d13f2 --- /dev/null +++ b/user/src/linker.ld @@ -0,0 +1,46 @@ +OUTPUT_ARCH(riscv) +ENTRY(_start) +BASE_ADDRESS = 0x80400000; + +SECTIONS +{ + . = BASE_ADDRESS; + + stext = .; + .text : { + *(.text.entry) + *(.text .text.*) + } + + . = ALIGN(4K); + etext = .; + srodata = .; + .rodata : { + *(.data .rodata.*) + *(.srodata .srodata.*) + } + + . = ALIGN(4K); + erodata = .; + sdata = .; + .data : { + *(.data .data.*) + *(.sdata .sdata.*) + } + + . = ALIGN(4K); + edata = .; + .bss : { + *(.bss.stack) + sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + } + + . = ALIGN(4K); + ebss = .; + + /DISCARD/ : { + *(.eh_frame) + } +} \ No newline at end of file diff --git a/user/src/syscall.rs b/user/src/syscall.rs new file mode 100644 index 0000000..118cf83 --- /dev/null +++ b/user/src/syscall.rs @@ -0,0 +1,26 @@ +use core::arch::asm; + +const SYSCALL_WRITE: usize = 64; +const SYSCALL_EXIT: usize = 93; + +fn syscall(id: usize, args: [usize; 3]) -> isize { + let mut ret: isize; + unsafe { + asm!( + "ecall", + inlateout("x10") args[0] => ret, + in("x11") args[1], + in("x12") args[2], + in("x17") id + ); + } + ret +} + +pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { + syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()]) +} + +pub fn sys_exit(exit_code: i32) -> isize { + syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0]) +} \ No newline at end of file From 13e91ed7354864497951aa113e11e7b637375e71 Mon Sep 17 00:00:00 2001 From: Tateisi Date: Sun, 3 Aug 2025 06:54:14 +0800 Subject: [PATCH 2/3] ch2: Batch system AppManager --- os/Cargo.lock | 7 ++++ os/Cargo.toml | 1 + os/src/batch.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++++ os/src/main.rs | 3 ++ os/src/sync/mod.rs | 3 ++ os/src/sync/up.rs | 18 ++++++++++ 6 files changed, 119 insertions(+) create mode 100644 os/src/batch.rs create mode 100644 os/src/sync/mod.rs create mode 100644 os/src/sync/up.rs diff --git a/os/Cargo.lock b/os/Cargo.lock index ca0229b..58d7cf0 100644 --- a/os/Cargo.lock +++ b/os/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "log" version = "0.4.22" @@ -12,6 +18,7 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" name = "os" version = "0.1.0" dependencies = [ + "lazy_static", "log", "sbi-rt", ] diff --git a/os/Cargo.toml b/os/Cargo.toml index 534f0dd..c9551ee 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +lazy_static = "1.5.0" log = "0.4.22" sbi-rt = "0.0.3" diff --git a/os/src/batch.rs b/os/src/batch.rs new file mode 100644 index 0000000..7c80ae9 --- /dev/null +++ b/os/src/batch.rs @@ -0,0 +1,87 @@ +use core::{arch::asm, slice}; + +use lazy_static::*; +use log::info; + +use crate::{sbi::shutdown, sync::UPSafeCell}; + +const MAX_APP_NUM: usize = 16; +const APP_BASE_ADDRESS: usize = 0x80400000; +const APP_SIZE_LIMIT: usize = 0x20000; + +struct AppManager { + num_app: usize, + current_app: usize, + app_start: [usize; MAX_APP_NUM + 1], +} + +impl AppManager { + pub fn print_app_info(&self) { + info!(target: "kernel", "num_app = {}", self.num_app); + for i in 0..self.num_app { + info!(target: "kernel", "app_{} [{:#x}, {:#x}]", i, self.app_start[i], self.app_start[i + 1]); + } + } + + pub fn get_current_app(&self) -> usize { + self.current_app + } + + pub fn move_to_next_app(&mut self) { + self.current_app += 1; + } + + unsafe fn load_app(&self, app_id: usize) { + if app_id >= self.num_app { + info!(target: "kernel", "All applications completed"); + shutdown(false); + } + info!(target: "kernel", "Loading app_{}", app_id); + + slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, APP_SIZE_LIMIT).fill(0); + let app_src = slice::from_raw_parts(self.app_start[app_id] as *const u8, self.app_start[app_id + 1] - self.app_start[app_id]); + let app_dst = slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, app_src.len()); + app_dst.copy_from_slice(app_src); + asm!("fence.i"); + } +} + +lazy_static! { + static ref APP_MANAGER: UPSafeCell = unsafe { + UPSafeCell::new({ + extern "C" { + fn _num_app(); + } + + let num_app_ptr = _num_app as usize as *const usize; + let num_app = num_app_ptr.read_volatile(); + let mut app_start: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1]; + let app_start_raw: &[usize] = slice::from_raw_parts(num_app_ptr.add(1), num_app + 1); + app_start[..=num_app].copy_from_slice(app_start_raw); + AppManager { + num_app, + current_app: 0, + app_start, + } + }) + }; +} + +pub fn init() { +} + +pub fn print_app_info() { + APP_MANAGER.exclusive_access().print_app_info(); +} + +pub fn run_next_app() -> ! { + let mut app_manager = APP_MANAGER.exclusive_access(); + let current_app = app_manager.get_current_app(); + unsafe { + app_manager.load_app(current_app); + } + app_manager.move_to_next_app(); + drop(app_manager); + + // todo +} \ No newline at end of file diff --git a/os/src/main.rs b/os/src/main.rs index c41ee8c..abc0fe9 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -8,6 +8,9 @@ mod logger; #[macro_use] mod console; +mod batch; +mod sync; + use core::arch::global_asm; use log::{debug, error, info, trace, warn}; diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs new file mode 100644 index 0000000..7729524 --- /dev/null +++ b/os/src/sync/mod.rs @@ -0,0 +1,3 @@ +mod up; + +pub use up::UPSafeCell; \ No newline at end of file diff --git a/os/src/sync/up.rs b/os/src/sync/up.rs new file mode 100644 index 0000000..8ace25a --- /dev/null +++ b/os/src/sync/up.rs @@ -0,0 +1,18 @@ +use core::cell::{RefCell, RefMut}; + +pub struct UPSafeCell { + inner: RefCell +} + +unsafe impl Sync for UPSafeCell {} + +impl UPSafeCell { + pub unsafe fn new(value: T) -> Self { + Self { + inner: RefCell::new(value) + } + } + pub fn exclusive_access(&self) -> RefMut<'_, T> { + self.inner.borrow_mut() + } +} \ No newline at end of file From b4c3326d858712595e68549224f14a5c316edb0e Mon Sep 17 00:00:00 2001 From: Tateisi Date: Sun, 3 Aug 2025 08:48:14 +0800 Subject: [PATCH 3/3] ch2: Trap handling --- README.md | 12 +++ os/Cargo.lock | 93 ++++++++++++++++++++++ os/Cargo.toml | 3 +- os/src/batch.rs | 54 ++++++++++++- os/src/link_app.S | 47 +++++++++++ os/src/main.rs | 7 +- os/src/syscall/fs.rs | 17 ++++ os/src/syscall/mod.rs | 16 ++++ os/src/syscall/process.rs | 8 ++ os/src/trap/context.rs | 28 +++++++ os/src/trap/mod.rs | 44 ++++++++++ os/src/trap/trap.S | 64 +++++++++++++++ user/src/bin/{02_powers.rs => 02_power.rs} | 0 13 files changed, 388 insertions(+), 5 deletions(-) create mode 100644 os/src/link_app.S create mode 100644 os/src/syscall/fs.rs create mode 100644 os/src/syscall/mod.rs create mode 100644 os/src/syscall/process.rs create mode 100644 os/src/trap/context.rs create mode 100644 os/src/trap/mod.rs create mode 100644 os/src/trap/trap.S rename user/src/bin/{02_powers.rs => 02_power.rs} (100%) diff --git a/README.md b/README.md index 9251dac..8592b91 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,24 @@ ## Build +### in dir `user` + +``` bash +cargo build --release +rust-objcopy --strip-all target/riscv64gc-unknown-none-elf/release/00_hello_world -O binary target/riscv64gc-unknown-none-elf/release/00_hello_world.bin +... +``` + +### in dir `os` + ``` bash LOG=TRACE cargo build --release ``` ## Run +rustsbi-qemu should be downloaded manually. + ``` bash qemu-system-riscv64 -machine virt -nographic -bios target/riscv64gc-unknown-none-elf/release/rustsbi-qemu.bin -device loader,file=target/riscv64gc-unknown-none-elf/release/os ``` \ No newline at end of file diff --git a/os/Cargo.lock b/os/Cargo.lock index 58d7cf0..ba98085 100644 --- a/os/Cargo.lock +++ b/os/Cargo.lock @@ -2,11 +2,26 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "log" @@ -20,9 +35,64 @@ version = "0.1.0" dependencies = [ "lazy_static", "log", + "riscv", "sbi-rt", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "riscv" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7" +dependencies = [ + "critical-section", + "embedded-hal", + "paste", + "riscv-macros", + "riscv-pac", +] + +[[package]] +name = "riscv-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "riscv-pac" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" + [[package]] name = "sbi-rt" version = "0.0.3" @@ -37,3 +107,26 @@ name = "sbi-spec" version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e36312fb5ddc10d08ecdc65187402baba4ac34585cb9d1b78522ae2358d890" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" diff --git a/os/Cargo.toml b/os/Cargo.toml index c9551ee..d7dfdfb 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -lazy_static = "1.5.0" +lazy_static = { version = "1.5.0", features = ["spin_no_std"] } log = "0.4.22" +riscv = "0.12.1" sbi-rt = "0.0.3" diff --git a/os/src/batch.rs b/os/src/batch.rs index 7c80ae9..cf243f3 100644 --- a/os/src/batch.rs +++ b/os/src/batch.rs @@ -1,14 +1,52 @@ -use core::{arch::asm, slice}; +use core::{arch::asm, mem, slice}; use lazy_static::*; use log::info; -use crate::{sbi::shutdown, sync::UPSafeCell}; +use crate::{sbi::shutdown, sync::UPSafeCell, trap::TrapContext}; +const KERNEL_STACK_SIZE: usize = 4096 * 2; +const USER_STACK_SIZE: usize = 4096 * 2; const MAX_APP_NUM: usize = 16; const APP_BASE_ADDRESS: usize = 0x80400000; const APP_SIZE_LIMIT: usize = 0x20000; +#[repr(align(4096))] +struct KernelStack { + data: [u8; KERNEL_STACK_SIZE], +} +#[repr(align(4096))] +struct UserStack { + data: [u8; USER_STACK_SIZE], +} + +static KERNEL_STACK: KernelStack = KernelStack { + data: [0; KERNEL_STACK_SIZE], +}; +static USER_STACK: UserStack = UserStack { + data: [0; USER_STACK_SIZE], +}; + +impl KernelStack { + fn get_sp(&self) -> usize { + self.data.as_ptr() as usize + KERNEL_STACK_SIZE + } + + pub fn push_context(&self, cx: TrapContext) -> &'static mut TrapContext { + let cx_ptr = (self.get_sp() - mem::size_of::()) as *mut TrapContext; + unsafe { + *cx_ptr = cx; + } + unsafe { cx_ptr.as_mut().unwrap() } + } +} + +impl UserStack { + fn get_sp(&self) -> usize { + self.data.as_ptr() as usize + USER_STACK_SIZE + } +} + struct AppManager { num_app: usize, current_app: usize, @@ -68,6 +106,7 @@ lazy_static! { } pub fn init() { + print_app_info(); } pub fn print_app_info() { @@ -83,5 +122,14 @@ pub fn run_next_app() -> ! { app_manager.move_to_next_app(); drop(app_manager); - // todo + extern "C" { + fn __restore(cx_addr: usize); + } + unsafe { + __restore(KERNEL_STACK.push_context(TrapContext::app_init_context( + APP_BASE_ADDRESS, + USER_STACK.get_sp(), + )) as *const _ as usize); + } + panic!("Unreachable in batch::run_current_app"); } \ No newline at end of file diff --git a/os/src/link_app.S b/os/src/link_app.S new file mode 100644 index 0000000..c55d8e3 --- /dev/null +++ b/os/src/link_app.S @@ -0,0 +1,47 @@ + + .align 3 + .section .data + .global _num_app +_num_app: + .quad 5 + .quad app_0_start + .quad app_1_start + .quad app_2_start + .quad app_3_start + .quad app_4_start + .quad app_4_end + + .section .data + .global app_0_start + .global app_0_end +app_0_start: + .incbin "../user/target/riscv64gc-unknown-none-elf/release/00_hello_world.bin" +app_0_end: + + .section .data + .global app_1_start + .global app_1_end +app_1_start: + .incbin "../user/target/riscv64gc-unknown-none-elf/release/01_store_fault.bin" +app_1_end: + + .section .data + .global app_2_start + .global app_2_end +app_2_start: + .incbin "../user/target/riscv64gc-unknown-none-elf/release/02_power.bin" +app_2_end: + + .section .data + .global app_3_start + .global app_3_end +app_3_start: + .incbin "../user/target/riscv64gc-unknown-none-elf/release/03_priv_inst.bin" +app_3_end: + + .section .data + .global app_4_start + .global app_4_end +app_4_start: + .incbin "../user/target/riscv64gc-unknown-none-elf/release/04_priv_csr.bin" +app_4_end: diff --git a/os/src/main.rs b/os/src/main.rs index abc0fe9..0268870 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -10,11 +10,14 @@ mod console; mod batch; mod sync; +mod trap; +mod syscall; use core::arch::global_asm; use log::{debug, error, info, trace, warn}; global_asm!(include_str!("entry.asm")); +global_asm!(include_str!("link_app.S")); #[no_mangle] pub fn rust_main() -> ! { @@ -24,7 +27,9 @@ pub fn rust_main() -> ! { print_system_info(); print_to_console(); - panic!("Shutdown machine!"); + trap::init(); + batch::init(); + batch::run_next_app(); } fn clear_bss() { diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs new file mode 100644 index 0000000..453febd --- /dev/null +++ b/os/src/syscall/fs.rs @@ -0,0 +1,17 @@ +use core::{slice, str}; + +const FD_STDOUT: usize = 1; + +pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { + match fd { + FD_STDOUT => { + let slice = unsafe { slice::from_raw_parts(buf, len) }; + let str = str::from_utf8(slice).unwrap(); + print!("{}", str); + len as isize + } + _ => { + panic!("Unsupported fd in sys_write!"); + } + } +} \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs new file mode 100644 index 0000000..5be165c --- /dev/null +++ b/os/src/syscall/mod.rs @@ -0,0 +1,16 @@ +use fs::sys_write; +use process::sys_exit; + +const SYSCALL_WRITE: usize = 64; +const SYSCALL_EXIT: usize = 93; + +mod fs; +mod process; + +pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { + match syscall_id { + SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), + SYSCALL_EXIT => sys_exit(args[0] as i32), + _ => panic!("Unsupported syscall_id: {}", syscall_id) + } +} \ No newline at end of file diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs new file mode 100644 index 0000000..b93fa4d --- /dev/null +++ b/os/src/syscall/process.rs @@ -0,0 +1,8 @@ +use log::info; + +use crate::batch::run_next_app; + +pub fn sys_exit(exit_code: i32) -> ! { + info!(target: "kernel", "Application exited with code {}", exit_code); + run_next_app() +} \ No newline at end of file diff --git a/os/src/trap/context.rs b/os/src/trap/context.rs new file mode 100644 index 0000000..6abbfd6 --- /dev/null +++ b/os/src/trap/context.rs @@ -0,0 +1,28 @@ +use riscv::register::sstatus::{self, Sstatus, SPP}; + +#[repr(C)] +pub struct TrapContext { + pub x: [usize; 32], + pub sstatus: Sstatus, + pub sepc: usize, +} + +impl TrapContext { + pub fn set_sp(&mut self, sp: usize) { + self.x[2] = sp; + } + + pub fn app_init_context(entry: usize, sp: usize) -> Self { + let cur_sstatus = sstatus::read(); + unsafe { + sstatus::set_spp(SPP::User); + } + let mut cx = Self { + x: [0; 32], + sstatus: cur_sstatus, + sepc: entry, + }; + cx.set_sp(sp); + cx + } +} \ No newline at end of file diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs new file mode 100644 index 0000000..06b25b4 --- /dev/null +++ b/os/src/trap/mod.rs @@ -0,0 +1,44 @@ +mod context; +pub use context::TrapContext; +use log::error; + +use core::arch::global_asm; + +use riscv::{interrupt::{Exception, Trap}, register::{scause, stval, stvec::{self, TrapMode}}}; + +use crate::{batch::run_next_app, syscall}; + +global_asm!(include_str!("trap.S")); + +pub fn init() { + extern "C" { + fn __alltraps(); + } + unsafe { + stvec::write(__alltraps as usize, TrapMode::Direct); + } +} + +#[no_mangle] +pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext { + let scause = scause::read(); + let stval = stval::read(); + match scause.cause() { + Trap::Exception(e) if e == Exception::UserEnvCall as usize => { + cx.sepc += 4; + cx.x[10] = syscall::syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize; + } + Trap::Exception(e) if e == Exception::StoreFault as usize || e == Exception::StorePageFault as usize => { + error!(target: "kernel", "PageFault in application, kernel killed it."); + run_next_app(); + } + Trap::Exception(e) if e == Exception::IllegalInstruction as usize => { + error!(target: "kernel", "IllegalInstruction in application, kernel killed it."); + run_next_app(); + } + _ => { + panic!("un supported strp {:?}, stval = {:#x}!", scause.cause(), stval); + } + } + cx +} \ No newline at end of file diff --git a/os/src/trap/trap.S b/os/src/trap/trap.S new file mode 100644 index 0000000..9d6967c --- /dev/null +++ b/os/src/trap/trap.S @@ -0,0 +1,64 @@ +.altmacro +.macro SAVE_GP n + sd x\n, \n*8(sp) +.endm +.macro LOAD_GP n + ld x\n, \n*8(sp) +.endm + .section .text + .globl __alltraps + .globl __restore + .align 2 +__alltraps: + csrrw sp, sscratch, sp + # now sp->kernel stack, sscratch->user stack + # allocate a TrapContext on kernel stack + addi sp, sp, -34*8 + # save general-purpose registers + sd x1, 1*8(sp) + # skip sp(x2), we will save it later + sd x3, 3*8(sp) + # skip tp(x4), application does not use it + # save x5~x31 + .set n, 5 + .rept 27 + SAVE_GP %n + .set n, n+1 + .endr + # we can use t0/t1/t2 freely, because they were saved on kernel stack + csrr t0, sstatus + csrr t1, sepc + sd t0, 32*8(sp) + sd t1, 33*8(sp) + # read user stack from sscratch and save it on the kernel stack + csrr t2, sscratch + sd t2, 2*8(sp) + # set input argument of trap_handler(cx: &mut TrapContext) + mv a0, sp + call trap_handler + +__restore: + # case1: start running app by __restore + # case2: back to U after handling trap + mv sp, a0 + # now sp->kernel stack(after allocated), sscratch->user stack + # restore sstatus/sepc + ld t0, 32*8(sp) + ld t1, 33*8(sp) + ld t2, 2*8(sp) + csrw sstatus, t0 + csrw sepc, t1 + csrw sscratch, t2 + # restore general-purpuse registers except sp/tp + ld x1, 1*8(sp) + ld x3, 3*8(sp) + .set n, 5 + .rept 27 + LOAD_GP %n + .set n, n+1 + .endr + # release TrapContext on kernel stack + addi sp, sp, 34*8 + # now sp->kernel stack, sscratch->user stack + csrrw sp, sscratch, sp + sret diff --git a/user/src/bin/02_powers.rs b/user/src/bin/02_power.rs similarity index 100% rename from user/src/bin/02_powers.rs rename to user/src/bin/02_power.rs