diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index ca0229b..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,32 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "os" -version = "0.1.0" -dependencies = [ - "log", - "sbi-rt", -] - -[[package]] -name = "sbi-rt" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbaa69be1eedc61c426e6d489b2260482e928b465360576900d52d496a58bd0" -dependencies = [ - "sbi-spec", -] - -[[package]] -name = "sbi-spec" -version = "0.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e36312fb5ddc10d08ecdc65187402baba4ac34585cb9d1b78522ae2358d890" 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/.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/os/Cargo.lock b/os/Cargo.lock new file mode 100644 index 0000000..ba98085 --- /dev/null +++ b/os/Cargo.lock @@ -0,0 +1,132 @@ +# 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 = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "os" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbaa69be1eedc61c426e6d489b2260482e928b465360576900d52d496a58bd0" +dependencies = [ + "sbi-spec", +] + +[[package]] +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 new file mode 100644 index 0000000..d7dfdfb --- /dev/null +++ b/os/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "os" +version = "0.1.0" +edition = "2021" + +[dependencies] +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 new file mode 100644 index 0000000..cf243f3 --- /dev/null +++ b/os/src/batch.rs @@ -0,0 +1,135 @@ +use core::{arch::asm, mem, slice}; + +use lazy_static::*; +use log::info; + +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, + 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() { + print_app_info(); +} + +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); + + 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/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/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/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 89% rename from src/main.rs rename to os/src/main.rs index c41ee8c..0268870 100644 --- a/src/main.rs +++ b/os/src/main.rs @@ -8,10 +8,16 @@ mod logger; #[macro_use] 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() -> ! { @@ -21,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/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/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 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/.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/Cargo.toml b/user/Cargo.toml similarity index 58% rename from Cargo.toml rename to user/Cargo.toml index 534f0dd..534e542 100644 --- a/Cargo.toml +++ b/user/Cargo.toml @@ -1,8 +1,7 @@ [package] -name = "os" +name = "user_lib" version = "0.1.0" edition = "2021" [dependencies] -log = "0.4.22" -sbi-rt = "0.0.3" +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_power.rs b/user/src/bin/02_power.rs new file mode 100644 index 0000000..54fde24 --- /dev/null +++ b/user/src/bin/02_power.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