From 91043b08cd7db27f81e7fe88818efcc49197744f Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Sun, 29 Nov 2020 01:31:36 +0800 Subject: [PATCH] Switch ok with debug mode apps, implement sys_exit correctly later. --- os/build.rs | 2 +- os/src/batch.rs | 129 -------------------------------------- os/src/config.rs | 5 ++ os/src/loader.rs | 94 +++++++++++++++++++++++++++ os/src/main.rs | 10 ++- os/src/syscall/mod.rs | 3 +- os/src/syscall/process.rs | 10 ++- os/src/task/context.rs | 16 +++++ os/src/task/mod.rs | 61 ++++++++++++++++++ os/src/task/switch.S | 34 ++++++++++ os/src/task/switch.rs | 7 +++ os/src/trap/mod.rs | 7 ++- os/src/trap/trap.S | 3 - user/Makefile | 4 +- user/build.py | 4 +- user/src/linker.ld | 2 +- 16 files changed, 244 insertions(+), 147 deletions(-) delete mode 100644 os/src/batch.rs create mode 100644 os/src/config.rs create mode 100644 os/src/loader.rs create mode 100644 os/src/task/context.rs create mode 100644 os/src/task/mod.rs create mode 100644 os/src/task/switch.S create mode 100644 os/src/task/switch.rs diff --git a/os/build.rs b/os/build.rs index eb553e5b..4a996053 100644 --- a/os/build.rs +++ b/os/build.rs @@ -6,7 +6,7 @@ fn main() { insert_app_data().unwrap(); } -static TARGET_PATH: &str = "../user/target/riscv64gc-unknown-none-elf/release/"; +static TARGET_PATH: &str = "../user/target/riscv64gc-unknown-none-elf/debug/"; fn insert_app_data() -> Result<()> { let mut f = File::create("src/link_app.S").unwrap(); diff --git a/os/src/batch.rs b/os/src/batch.rs deleted file mode 100644 index 31903dee..00000000 --- a/os/src/batch.rs +++ /dev/null @@ -1,129 +0,0 @@ -use core::cell::RefCell; -use lazy_static::*; -use crate::trap::TrapContext; - -const USER_STACK_SIZE: usize = 4096 * 2; -const KERNEL_STACK_SIZE: usize = 4096 * 2; -const MAX_APP_NUM: usize = 16; -const APP_BASE_ADDRESS: usize = 0x80040000; -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() - core::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 { - inner: RefCell, -} -struct AppManagerInner { - num_app: usize, - current_app: usize, - app_start: [usize; MAX_APP_NUM + 1], -} -unsafe impl Sync for AppManager {} - -impl AppManagerInner { - pub fn print_app_info(&self) { - println!("[kernel] num_app = {}", self.num_app); - for i in 0..self.num_app { - println!("[kernel] app_{} [{:#x}, {:#x})", i, self.app_start[i], self.app_start[i + 1]); - } - } - - unsafe fn load_app(&self, app_id: usize) { - if app_id >= self.num_app { - panic!("All applications completed!"); - } - println!("[kernel] Loading app_{}", app_id); - // clear icache - llvm_asm!("fence.i" :::: "volatile"); - // clear app area - (APP_BASE_ADDRESS..APP_BASE_ADDRESS + APP_SIZE_LIMIT).for_each(|addr| { - (addr as *mut u8).write_volatile(0); - }); - let app_src = core::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 = core::slice::from_raw_parts_mut( - APP_BASE_ADDRESS as *mut u8, - app_src.len() - ); - app_dst.copy_from_slice(app_src); - } - - pub fn get_current_app(&self) -> usize { self.current_app } - - pub fn move_to_next_app(&mut self) { - self.current_app += 1; - } -} - -lazy_static! { - static ref APP_MANAGER: AppManager = AppManager { - inner: RefCell::new({ - extern "C" { fn _num_app(); } - let num_app_ptr = _num_app as usize as *const usize; - let num_app = unsafe { num_app_ptr.read_volatile() }; - let mut app_start: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1]; - let app_start_raw: &[usize] = unsafe { - core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1) - }; - app_start[..=num_app].copy_from_slice(app_start_raw); - AppManagerInner { - num_app, - current_app: 0, - app_start, - } - }), - }; -} - -pub fn init() { - print_app_info(); -} - -pub fn print_app_info() { - APP_MANAGER.inner.borrow().print_app_info(); -} - -pub fn run_next_app() -> ! { - let current_app = APP_MANAGER.inner.borrow().get_current_app(); - unsafe { - APP_MANAGER.inner.borrow().load_app(current_app); - } - APP_MANAGER.inner.borrow_mut().move_to_next_app(); - 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!"); -} diff --git a/os/src/config.rs b/os/src/config.rs new file mode 100644 index 00000000..9bc7a3d2 --- /dev/null +++ b/os/src/config.rs @@ -0,0 +1,5 @@ +pub const USER_STACK_SIZE: usize = 4096 * 2; +pub const KERNEL_STACK_SIZE: usize = 4096 * 2; +pub const MAX_APP_NUM: usize = 4; +pub const APP_BASE_ADDRESS: usize = 0x80100000; +pub const APP_SIZE_LIMIT: usize = 0x20000; \ No newline at end of file diff --git a/os/src/loader.rs b/os/src/loader.rs new file mode 100644 index 00000000..33c8dd5d --- /dev/null +++ b/os/src/loader.rs @@ -0,0 +1,94 @@ +use core::cell::RefCell; +use lazy_static::*; +use crate::trap::TrapContext; +use crate::task::TaskContext; +use crate::config::*; + +#[repr(align(4096))] +struct KernelStack { + data: [u8; KERNEL_STACK_SIZE], +} + +#[repr(align(4096))] +struct UserStack { + data: [u8; USER_STACK_SIZE], +} + +static KERNEL_STACK: [KernelStack; MAX_APP_NUM] = [ + KernelStack { data: [0; KERNEL_STACK_SIZE], }; + MAX_APP_NUM +]; + +static USER_STACK: [UserStack; MAX_APP_NUM] = [ + UserStack { data: [0; USER_STACK_SIZE], }; + MAX_APP_NUM +]; + +impl KernelStack { + fn get_sp(&self) -> usize { + self.data.as_ptr() as usize + KERNEL_STACK_SIZE + } + pub fn push_context(&self, trap_cx: TrapContext, task_cx: TaskContext) -> &'static mut TaskContext { + let trap_cx_ptr = (self.get_sp() - core::mem::size_of::()) as *mut TrapContext; + unsafe { *trap_cx_ptr = trap_cx; } + let task_cx_ptr = (trap_cx_ptr as usize - core::mem::size_of::()) as *mut TaskContext; + unsafe { *task_cx_ptr = task_cx; } + unsafe { task_cx_ptr.as_mut().unwrap() } + } +} + +impl UserStack { + fn get_sp(&self) -> usize { + self.data.as_ptr() as usize + USER_STACK_SIZE + } +} + +fn get_base_i(app_id: usize) -> usize { + APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT +} + +pub fn get_num_app() -> usize { + extern "C" { fn _num_app(); } + unsafe { (_num_app as usize as *const usize).read_volatile() } +} + +pub fn load_apps() { + extern "C" { fn _num_app(); } + let num_app_ptr = _num_app as usize as *const usize; + let num_app = get_num_app(); + let app_start = unsafe { + core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1) + }; + // clear i-cache first + unsafe { llvm_asm!("fence.i" :::: "volatile"); } + // load apps + for i in 0..num_app { + println!("i = {}", i); + println!("[{:#x}, {:#x})", app_start[i], app_start[i + 1]); + let base_i = get_base_i(i); + // clear region + (base_i..base_i + APP_SIZE_LIMIT).for_each(|addr| unsafe { + (addr as *mut u8).write_volatile(0) + }); + // load app from data section to memory + let src = unsafe { + core::slice::from_raw_parts(app_start[i] as *const u8, app_start[i + 1] - app_start[i]) + }; + let dst = unsafe { + core::slice::from_raw_parts_mut(base_i as *mut u8, src.len()) + }; + dst.copy_from_slice(src); + } +} + +pub fn init_app_cx(app_id: usize) -> &'static TaskContext { + println!("app_id = {}, kernel_sp = {:#x}, user_sp = {:#x}", + app_id, + KERNEL_STACK[app_id].get_sp(), + USER_STACK[app_id].get_sp() + ); + KERNEL_STACK[app_id].push_context( + TrapContext::app_init_context(get_base_i(app_id), USER_STACK[app_id].get_sp()), + TaskContext::goto_restore(), + ) +} diff --git a/os/src/main.rs b/os/src/main.rs index 8f8fdeb7..0b55c6f7 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -3,6 +3,7 @@ #![feature(global_asm)] #![feature(llvm_asm)] #![feature(panic_info_message)] +#![feature(const_in_array_repeat_expressions)] #[macro_use] mod console; @@ -10,7 +11,9 @@ mod lang_items; mod sbi; mod syscall; mod trap; -mod batch; +mod loader; +mod config; +mod task; global_asm!(include_str!("entry.asm")); global_asm!(include_str!("link_app.S")); @@ -30,6 +33,7 @@ pub fn rust_main() -> ! { clear_bss(); println!("[kernel] Hello, world!"); trap::init(); - batch::init(); - batch::run_next_app(); + loader::load_apps(); + task::run_first_task(); + panic!("Unreachable in rust_main!"); } \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 0a72b193..d64bc73c 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,7 +1,7 @@ const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; const SYSCALL_YIELD: usize = 124; -const SYSCALL_GET_TIME: usize = 169; +//const SYSCALL_GET_TIME: usize = 169; mod fs; mod process; @@ -13,6 +13,7 @@ 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), + SYSCALL_YIELD => sys_yield(), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index ef56607a..77a3a7c9 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -1,6 +1,12 @@ -use crate::batch::run_next_app; +use crate::task::switch_to_next_task; pub fn sys_exit(xstate: i32) -> ! { println!("[kernel] Application exited with code {}", xstate); - run_next_app() + //run_next_app() + panic!("[kernel] first exit!"); +} + +pub fn sys_yield() -> isize { + switch_to_next_task(); + 0 } \ No newline at end of file diff --git a/os/src/task/context.rs b/os/src/task/context.rs new file mode 100644 index 00000000..47a652d3 --- /dev/null +++ b/os/src/task/context.rs @@ -0,0 +1,16 @@ +#[repr(C)] +pub struct TaskContext { + ra: usize, + s: [usize; 12], +} + +impl TaskContext { + pub fn goto_restore() -> Self { + extern "C" { fn __restore(); } + Self { + ra: __restore as usize, + s: [0; 12], + } + } +} + diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs new file mode 100644 index 00000000..32efb4e8 --- /dev/null +++ b/os/src/task/mod.rs @@ -0,0 +1,61 @@ +mod context; +mod switch; + +use crate::config::MAX_APP_NUM; +use crate::loader::{get_num_app, init_app_cx}; +use core::cell::RefCell; +use lazy_static::*; +use switch::__switch; + +pub use context::TaskContext; + +struct TaskControlBlock { + task_cx_ptr: usize, +} + +pub struct TaskManager { + num_app: usize, + tasks: [TaskControlBlock; MAX_APP_NUM], + current_task: RefCell, +} + +unsafe impl Sync for TaskManager {} + +lazy_static! { + pub static ref TASK_MANAGER: TaskManager = { + let num_app = get_num_app(); + let mut tasks = [TaskControlBlock { task_cx_ptr: 0 }; MAX_APP_NUM]; + for i in 0..num_app { + tasks[i] = TaskControlBlock { task_cx_ptr: init_app_cx(i) as *const _ as usize, }; + } + TaskManager { + num_app, + tasks, + current_task: RefCell::new(0), + } + }; +} + +impl TaskManager { + pub fn run_first_task(&self) { + unsafe { + __switch(&0usize, &self.tasks[0].task_cx_ptr); + } + } + pub fn switch_to_next_task(&self) { + let current = *self.current_task.borrow(); + let next = if current == self.num_app - 1 { 0 } else { current + 1 }; + *self.current_task.borrow_mut() = next; + unsafe { + __switch(&self.tasks[current].task_cx_ptr, &self.tasks[next].task_cx_ptr); + } + } +} + +pub fn run_first_task() { + TASK_MANAGER.run_first_task(); +} + +pub fn switch_to_next_task() { + TASK_MANAGER.switch_to_next_task(); +} \ No newline at end of file diff --git a/os/src/task/switch.S b/os/src/task/switch.S new file mode 100644 index 00000000..df668f35 --- /dev/null +++ b/os/src/task/switch.S @@ -0,0 +1,34 @@ +.altmacro +.macro SAVE_SN n + sd s\n, (\n+1)*8(sp) +.endm +.macro LOAD_SN n + ld s\n, (\n+1)*8(sp) +.endm + .section .text + .globl __switch +__switch: + # __switch(current_task_cx: &*const TaskContext, next_task_cx: &*const TaskContext) + # push TaskContext to current sp and save its address to where a0 points to + addi sp, sp, -13*8 + sd sp, 0(a0) + # fill TaskContext with ra & s0-s11 + sd ra, 0(sp) + .set n, 0 + .rept 12 + SAVE_SN %n + .set n, n + 1 + .endr + # ready for loading TaskContext a1 points to + ld sp, 0(a1) + # load registers in the TaskContext + ld ra, 0(sp) + .set n, 0 + .rept 12 + LOAD_SN %n + .set n, n + 1 + .endr + # pop TaskContext + addi sp, sp, 13*8 + ret + diff --git a/os/src/task/switch.rs b/os/src/task/switch.rs new file mode 100644 index 00000000..0b0f6b76 --- /dev/null +++ b/os/src/task/switch.rs @@ -0,0 +1,7 @@ +use super::TaskContext; + +global_asm!(include_str!("switch.S")); + +extern "C" { + pub fn __switch(current_task_cx: &usize, next_task_cx: &usize); +} diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index e42b05fb..6948cbf1 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -11,7 +11,6 @@ use riscv::register::{ stval, }; use crate::syscall::syscall; -use crate::batch::run_next_app; global_asm!(include_str!("trap.S")); @@ -34,11 +33,13 @@ pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext { Trap::Exception(Exception::StoreFault) | Trap::Exception(Exception::StorePageFault) => { println!("[kernel] PageFault in application, core dumped."); - run_next_app(); + panic!("[kernel] Cannot continue!"); + //run_next_app(); } Trap::Exception(Exception::IllegalInstruction) => { println!("[kernel] IllegalInstruction in application, core dumped."); - run_next_app(); + panic!("[kernel] Cannot continue!"); + //run_next_app(); } _ => { panic!("Unsupported trap {:?}, stval = {:#x}!", scause.cause(), stval); diff --git a/os/src/trap/trap.S b/os/src/trap/trap.S index 9d6967cb..70a18a92 100644 --- a/os/src/trap/trap.S +++ b/os/src/trap/trap.S @@ -38,9 +38,6 @@ __alltraps: 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) diff --git a/user/Makefile b/user/Makefile index 5cce8cbf..1e548149 100644 --- a/user/Makefile +++ b/user/Makefile @@ -1,5 +1,5 @@ TARGET := riscv64gc-unknown-none-elf -MODE := release +MODE := debug APP_DIR := src/bin TARGET_DIR := target/$(TARGET)/$(MODE) APPS := $(wildcard $(APP_DIR)/*.rs) @@ -9,7 +9,7 @@ BINS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%.bin, $(APPS)) OBJDUMP := rust-objdump --arch-name=riscv64 OBJCOPY := rust-objcopy --binary-architecture=riscv64 -elf: +elf: $(APPS) @python3 build.py binary: elf diff --git a/user/build.py b/user/build.py index 1d1d8953..1a220881 100644 --- a/user/build.py +++ b/user/build.py @@ -1,6 +1,6 @@ import os -base_address = 0x80040000 +base_address = 0x80100000 step = 0x20000 linker = 'src/linker.ld' @@ -18,7 +18,7 @@ for app in apps: lines.append(line) with open(linker, 'w+') as f: f.writelines(lines) - os.system('cargo build --bin %s --release' % app) + os.system('cargo build --bin %s' % app) print('[build.py] application %s start with address %s' %(app, hex(base_address+step*app_id))) with open(linker, 'w+') as f: f.writelines(lines_before) diff --git a/user/src/linker.ld b/user/src/linker.ld index ed9f3017..1c64a19b 100644 --- a/user/src/linker.ld +++ b/user/src/linker.ld @@ -2,7 +2,7 @@ OUTPUT_ARCH(riscv) ENTRY(_start) -BASE_ADDRESS = 0x80040000; +BASE_ADDRESS = 0x80100000; SECTIONS {