diff --git a/.gitignore b/.gitignore index 3327607d..c44aa4fa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ os/target/* os/.idea/* os/src/link_app.S +os/last-* os/Cargo.lock user/target/* user/.idea/* diff --git a/os/Makefile b/os/Makefile index 2a4b3870..5330215f 100644 --- a/os/Makefile +++ b/os/Makefile @@ -29,7 +29,14 @@ OBJCOPY := rust-objcopy --binary-architecture=riscv64 # Disassembly DISASM ?= -x -build: env $(KERNEL_BIN) +build: env switch-check $(KERNEL_BIN) + +switch-check: +ifeq ($(BOARD), qemu) + (which last-qemu) || (rm last-k210 -f && touch last-qemu && make clean) +else ifeq ($(BOARD), k210) + (which last-k210) || (rm last-qemu -f && touch last-k210 && make clean) +endif env: (rustup target list | grep "riscv64gc-unknown-none-elf (installed)") || rustup target add $(TARGET) @@ -85,4 +92,4 @@ debug: build tmux split-window -h "riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'" && \ tmux -2 attach-session -d -.PHONY: build env kernel clean disasm disasm-vim run-inner +.PHONY: build env kernel clean disasm disasm-vim run-inner switch-check diff --git a/os/src/main.rs b/os/src/main.rs index 145f50a1..7879fc4e 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -3,7 +3,6 @@ #![feature(global_asm)] #![feature(llvm_asm)] #![feature(panic_info_message)] -#![feature(const_in_array_repeat_expressions)] #![feature(alloc_error_handler)] extern crate alloc; @@ -21,6 +20,7 @@ mod loader; mod config; mod task; mod timer; +mod sync; mod mm; global_asm!(include_str!("entry.asm")); @@ -31,9 +31,12 @@ fn clear_bss() { fn sbss(); fn ebss(); } - (sbss as usize..ebss as usize).for_each(|a| { - unsafe { (a as *mut u8).write_volatile(0) } - }); + unsafe { + core::slice::from_raw_parts_mut( + sbss as usize as *mut u8, + ebss as usize - sbss as usize, + ).fill(0); + } } #[no_mangle] diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs new file mode 100644 index 00000000..77295248 --- /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 00000000..849ac4bc --- /dev/null +++ b/os/src/sync/up.rs @@ -0,0 +1,27 @@ +/// Wrap a static data structure inside it so that we are +/// able to access it without any `unsafe`. +/// +/// We should only use it in uniprocessor. +/// +/// In order to get mutable reference of inner data, call +/// `upsafe_access`. +pub struct UPSafeCell { + /// inner data + data: T, +} + +unsafe impl Sync for UPSafeCell {} + +impl UPSafeCell { + /// User is responsible to guarantee that inner struct is only used in + /// uniprocessor. + pub unsafe fn new(value: T) -> Self { + Self { data: value, } + } + /// Mention that user should hold exactly one &mut T at a time. + pub fn upsafe_access(&self) -> &mut T { + unsafe { + &mut *(&self.data as *const _ as usize as *mut T) + } + } +} \ No newline at end of file diff --git a/os/src/task/context.rs b/os/src/task/context.rs index 340bc098..d25cc2c8 100644 --- a/os/src/task/context.rs +++ b/os/src/task/context.rs @@ -3,13 +3,22 @@ use crate::trap::trap_return; #[repr(C)] pub struct TaskContext { ra: usize, + sp: usize, s: [usize; 12], } impl TaskContext { - pub fn goto_trap_return() -> Self { + pub fn zero_init() -> Self { + Self { + ra: 0, + sp: 0, + s: [0; 12], + } + } + pub fn goto_trap_return(kstack_ptr: usize) -> Self { Self { ra: trap_return as usize, + sp: kstack_ptr, s: [0; 12], } } diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 4a98094a..56eb239d 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -4,7 +4,7 @@ mod task; use crate::loader::{get_num_app, get_app_data}; use crate::trap::TrapContext; -use core::cell::RefCell; +use crate::sync::UPSafeCell; use lazy_static::*; use switch::__switch; use task::{TaskControlBlock, TaskStatus}; @@ -14,7 +14,7 @@ pub use context::TaskContext; pub struct TaskManager { num_app: usize, - inner: RefCell, + inner: UPSafeCell, } struct TaskManagerInner { @@ -22,8 +22,6 @@ struct TaskManagerInner { current_task: usize, } -unsafe impl Sync for TaskManager {} - lazy_static! { pub static ref TASK_MANAGER: TaskManager = { println!("init TASK_MANAGER"); @@ -38,41 +36,41 @@ lazy_static! { } TaskManager { num_app, - inner: RefCell::new(TaskManagerInner { + inner: unsafe { UPSafeCell::new(TaskManagerInner { tasks, current_task: 0, - }), + })}, } }; } impl TaskManager { fn run_first_task(&self) { - self.inner.borrow_mut().tasks[0].task_status = TaskStatus::Running; - let next_task_cx_ptr2 = self.inner.borrow().tasks[0].get_task_cx_ptr2(); - let _unused: usize = 0; + let next_task = &mut self.inner.upsafe_access().tasks[0]; + next_task.task_status = TaskStatus::Running; + let next_task_cx_ptr = &next_task.task_cx as *const TaskContext; + drop(next_task); + let mut _unused = TaskContext::zero_init(); unsafe { __switch( - &_unused as *const _, - next_task_cx_ptr2, + &mut _unused as *mut _, + next_task_cx_ptr, ); } } fn mark_current_suspended(&self) { - let mut inner = self.inner.borrow_mut(); - let current = inner.current_task; - inner.tasks[current].task_status = TaskStatus::Ready; + let inner = self.inner.upsafe_access(); + inner.tasks[inner.current_task].task_status = TaskStatus::Ready; } fn mark_current_exited(&self) { - let mut inner = self.inner.borrow_mut(); - let current = inner.current_task; - inner.tasks[current].task_status = TaskStatus::Exited; + let inner = self.inner.upsafe_access(); + inner.tasks[inner.current_task].task_status = TaskStatus::Exited; } fn find_next_task(&self) -> Option { - let inner = self.inner.borrow(); + let inner = self.inner.upsafe_access(); let current = inner.current_task; (current + 1..current + self.num_app + 1) .map(|id| id % self.num_app) @@ -82,30 +80,28 @@ impl TaskManager { } fn get_current_token(&self) -> usize { - let inner = self.inner.borrow(); - let current = inner.current_task; - inner.tasks[current].get_user_token() + let inner = self.inner.upsafe_access(); + inner.tasks[inner.current_task].get_user_token() } fn get_current_trap_cx(&self) -> &mut TrapContext { - let inner = self.inner.borrow(); - let current = inner.current_task; - inner.tasks[current].get_trap_cx() + let inner = self.inner.upsafe_access(); + inner.tasks[inner.current_task].get_trap_cx() } fn run_next_task(&self) { if let Some(next) = self.find_next_task() { - let mut inner = self.inner.borrow_mut(); + let mut inner = self.inner.upsafe_access(); let current = inner.current_task; inner.tasks[next].task_status = TaskStatus::Running; inner.current_task = next; - let current_task_cx_ptr2 = inner.tasks[current].get_task_cx_ptr2(); - let next_task_cx_ptr2 = inner.tasks[next].get_task_cx_ptr2(); - core::mem::drop(inner); + let current_task_cx_ptr = &mut inner.tasks[current].task_cx as *mut TaskContext; + let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext; + drop(inner); unsafe { __switch( - current_task_cx_ptr2, - next_task_cx_ptr2, + current_task_cx_ptr, + next_task_cx_ptr, ); } } else { diff --git a/os/src/task/switch.S b/os/src/task/switch.S index 262511fe..3f985d24 100644 --- a/os/src/task/switch.S +++ b/os/src/task/switch.S @@ -1,37 +1,34 @@ .altmacro .macro SAVE_SN n - sd s\n, (\n+1)*8(sp) + sd s\n, (\n+2)*8(a0) .endm .macro LOAD_SN n - ld s\n, (\n+1)*8(sp) + ld s\n, (\n+2)*8(a1) .endm .section .text .globl __switch __switch: # __switch( - # current_task_cx_ptr2: &*const TaskContext, - # next_task_cx_ptr2: &*const TaskContext + # current_task_cx_ptr: *mut TaskContext, + # next_task_cx_ptr: *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) + # save kernel stack of current task + sd sp, 8(a0) + # save ra & s0~s11 of current execution + sd ra, 0(a0) .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) + # restore ra & s0~s11 of next execution + ld ra, 0(a1) .set n, 0 .rept 12 LOAD_SN %n .set n, n + 1 .endr - # pop TaskContext - addi sp, sp, 13*8 + # restore kernel stack of next task + ld sp, 8(a1) ret diff --git a/os/src/task/switch.rs b/os/src/task/switch.rs index 867fcb1e..fa75be1a 100644 --- a/os/src/task/switch.rs +++ b/os/src/task/switch.rs @@ -1,8 +1,10 @@ global_asm!(include_str!("switch.S")); +use super::TaskContext; + extern "C" { pub fn __switch( - current_task_cx_ptr2: *const usize, - next_task_cx_ptr2: *const usize + current_task_cx_ptr: *mut TaskContext, + next_task_cx_ptr: *const TaskContext ); } diff --git a/os/src/task/task.rs b/os/src/task/task.rs index 8e38635b..b08d82a9 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -4,17 +4,14 @@ use crate::config::{TRAP_CONTEXT, kernel_stack_position}; use super::TaskContext; pub struct TaskControlBlock { - pub task_cx_ptr: usize, pub task_status: TaskStatus, + pub task_cx: TaskContext, pub memory_set: MemorySet, pub trap_cx_ppn: PhysPageNum, pub base_size: usize, } impl TaskControlBlock { - pub fn get_task_cx_ptr2(&self) -> *const usize { - &self.task_cx_ptr as *const usize - } pub fn get_trap_cx(&self) -> &'static mut TrapContext { self.trap_cx_ppn.get_mut() } @@ -38,11 +35,9 @@ impl TaskControlBlock { kernel_stack_top.into(), MapPermission::R | MapPermission::W, ); - let task_cx_ptr = (kernel_stack_top - core::mem::size_of::()) as *mut TaskContext; - unsafe { *task_cx_ptr = TaskContext::goto_trap_return(); } let task_control_block = Self { - task_cx_ptr: task_cx_ptr as usize, task_status, + task_cx: TaskContext::goto_trap_return(kernel_stack_top), memory_set, trap_cx_ppn, base_size: user_sp, diff --git a/rust-toolchain b/rust-toolchain index a08f00d1..a14eedce 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2021-01-30 +nightly-2021-07-01 diff --git a/user/src/bin/00power_3.rs b/user/src/bin/00power_3.rs index 532829da..e14f1e2b 100644 --- a/user/src/bin/00power_3.rs +++ b/user/src/bin/00power_3.rs @@ -23,7 +23,7 @@ unsafe fn main() -> i32 { println!("power_3 [{}/{}]", i, iter); } } - println!("{}^{} = {}(mod {})", p, iter, S[cur], m); + println!("{}^{} = {}(MOD {})", p, iter, S[cur], m); println!("Test power_3 OK!"); 0 } \ No newline at end of file diff --git a/user/src/bin/01power_5.rs b/user/src/bin/01power_5.rs index f23e3b84..1bbe734f 100644 --- a/user/src/bin/01power_5.rs +++ b/user/src/bin/01power_5.rs @@ -23,7 +23,7 @@ unsafe fn main() -> i32 { println!("power_5 [{}/{}]", i, iter); } } - println!("{}^{} = {}(mod {})", p, iter, S[cur], m); + println!("{}^{} = {}(MOD {})", p, iter, S[cur], m); println!("Test power_5 OK!"); 0 } diff --git a/user/src/bin/02power_7.rs b/user/src/bin/02power_7.rs index 35bada18..8c50344e 100644 --- a/user/src/bin/02power_7.rs +++ b/user/src/bin/02power_7.rs @@ -23,7 +23,7 @@ unsafe fn main() -> i32 { println!("power_7 [{}/{}]", i, iter); } } - println!("{}^{} = {}(mod {})", p, iter, S[cur], m); + println!("{}^{} = {}(MOD {})", p, iter, S[cur], m); println!("Test power_7 OK!"); 0 }