From c19662b70ca1c74c2bf5c930c51ad9ad57455e76 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Mon, 1 Nov 2021 09:44:10 -0700 Subject: [PATCH] Merge recent patch on ch3. --- .gitignore | 1 + README.md | 12 +++++++++- os/Makefile | 13 +++++++--- os/src/loader.rs | 20 +++++++--------- os/src/main.rs | 15 +++++++----- os/src/sbi.rs | 11 +++++---- os/src/sync/mod.rs | 3 +++ os/src/sync/up.rs | 27 +++++++++++++++++++++ os/src/task/context.rs | 12 +++++++++- os/src/task/mod.rs | 54 ++++++++++++++++++++++++------------------ os/src/task/switch.S | 27 ++++++++++----------- os/src/task/switch.rs | 6 +++-- os/src/task/task.rs | 11 ++++----- rust-toolchain | 2 +- user/src/lib.rs | 2 +- user/src/syscall.rs | 11 +++++---- 16 files changed, 145 insertions(+), 82 deletions(-) create mode 100644 os/src/sync/mod.rs create mode 100644 os/src/sync/up.rs diff --git a/.gitignore b/.gitignore index 4b5497cf..614368ae 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ os/target/* os/.idea/* os/Cargo.lock os/src/link_app.S +os/last-* user/target/* user/.idea/* user/Cargo.lock diff --git a/README.md b/README.md index dd356b5f..e28e783e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,12 @@ # rCore-Tutorial-v3 -rCore-Tutorial version 3. \ No newline at end of file +rCore-Tutorial version 3.x + +## Dependency + +### Binaries + +* rustc 1.56.0-nightly (b03ccace5 2021-08-24) + +* qemu: 5.0.0 + +* rustsbi: qemu[7d71bfb7] k210[563144b0] diff --git a/os/Makefile b/os/Makefile index 77d89776..26c049c1 100644 --- a/os/Makefile +++ b/os/Makefile @@ -29,12 +29,19 @@ 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 component add rust-src rustup component add llvm-tools-preview - cargo install cargo-binutils --vers ~0.2 + cargo install cargo-binutils --vers =0.3.3 rustup target add riscv64gc-unknown-none-elf $(KERNEL_BIN): kernel @@ -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/loader.rs b/os/src/loader.rs index 893a0677..d4ae5731 100644 --- a/os/src/loader.rs +++ b/os/src/loader.rs @@ -1,13 +1,14 @@ use crate::trap::TrapContext; -use crate::task::TaskContext; use crate::config::*; #[repr(align(4096))] +#[derive(Copy, Clone)] struct KernelStack { data: [u8; KERNEL_STACK_SIZE], } #[repr(align(4096))] +#[derive(Copy, Clone)] struct UserStack { data: [u8; USER_STACK_SIZE], } @@ -26,14 +27,10 @@ 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 { - unsafe { - let trap_cx_ptr = (self.get_sp() - core::mem::size_of::()) as *mut TrapContext; - *trap_cx_ptr = trap_cx; - let task_cx_ptr = (trap_cx_ptr as usize - core::mem::size_of::()) as *mut TaskContext; - *task_cx_ptr = task_cx; - task_cx_ptr.as_mut().unwrap() - } + pub fn push_context(&self, trap_cx: TrapContext) -> usize { + let trap_cx_ptr = (self.get_sp() - core::mem::size_of::()) as *mut TrapContext; + unsafe { *trap_cx_ptr = trap_cx; } + trap_cx_ptr as usize } } @@ -60,7 +57,7 @@ pub fn load_apps() { core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1) }; // clear i-cache first - unsafe { llvm_asm!("fence.i" :::: "volatile"); } + unsafe { asm!("fence.i"); } // load apps for i in 0..num_app { let base_i = get_base_i(i); @@ -79,9 +76,8 @@ pub fn load_apps() { } } -pub fn init_app_cx(app_id: usize) -> &'static TaskContext { +pub fn init_app_cx(app_id: usize) -> usize { 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 0b55c6f7..608f1b09 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -1,9 +1,8 @@ #![no_std] #![no_main] #![feature(global_asm)] -#![feature(llvm_asm)] +#![feature(asm)] #![feature(panic_info_message)] -#![feature(const_in_array_repeat_expressions)] #[macro_use] mod console; @@ -14,6 +13,7 @@ mod trap; mod loader; mod config; mod task; +mod sync; global_asm!(include_str!("entry.asm")); global_asm!(include_str!("link_app.S")); @@ -23,9 +23,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] @@ -36,4 +39,4 @@ pub fn rust_main() -> ! { loader::load_apps(); task::run_first_task(); panic!("Unreachable in rust_main!"); -} \ No newline at end of file +} diff --git a/os/src/sbi.rs b/os/src/sbi.rs index 9fc74a97..935fe24e 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -14,11 +14,12 @@ const SBI_SHUTDOWN: usize = 8; fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize { let mut ret; unsafe { - llvm_asm!("ecall" - : "={x10}" (ret) - : "{x10}" (arg0), "{x11}" (arg1), "{x12}" (arg2), "{x17}" (which) - : "memory" - : "volatile" + asm!( + "ecall", + inlateout("x10") arg0 => ret, + in("x11") arg1, + in("x12") arg2, + in("x17") which, ); } ret 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..642668c1 --- /dev/null +++ b/os/src/sync/up.rs @@ -0,0 +1,27 @@ +use core::cell::{RefCell, RefMut}; + +/// 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 +/// `exclusive_access`. +pub struct UPSafeCell { + /// inner data + inner: RefCell, +} + +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 { inner: RefCell::new(value) } + } + /// Panic if the data has been borrowed. + pub fn exclusive_access(&self) -> RefMut<'_, T> { + self.inner.borrow_mut() + } +} \ No newline at end of file diff --git a/os/src/task/context.rs b/os/src/task/context.rs index 47a652d3..35055d0c 100644 --- a/os/src/task/context.rs +++ b/os/src/task/context.rs @@ -1,14 +1,24 @@ +#[derive(Copy, Clone)] #[repr(C)] pub struct TaskContext { ra: usize, + sp: usize, s: [usize; 12], } impl TaskContext { - pub fn goto_restore() -> Self { + pub fn zero_init() -> Self { + Self { + ra: 0, + sp: 0, + s: [0; 12], + } + } + pub fn goto_restore(kstack_ptr: usize) -> Self { extern "C" { fn __restore(); } Self { ra: __restore as usize, + sp: kstack_ptr, s: [0; 12], } } diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 24062bee..66c8a796 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -4,16 +4,16 @@ mod task; 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; use task::{TaskControlBlock, TaskStatus}; +use crate::sync::UPSafeCell; pub use context::TaskContext; pub struct TaskManager { num_app: usize, - inner: RefCell, + inner: UPSafeCell, } struct TaskManagerInner { @@ -21,56 +21,62 @@ struct TaskManagerInner { current_task: usize, } -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, task_status: TaskStatus::UnInit }; + TaskControlBlock { + task_cx: TaskContext::zero_init(), + task_status: TaskStatus::UnInit + }; MAX_APP_NUM ]; for i in 0..num_app { - tasks[i].task_cx_ptr = init_app_cx(i) as * const _ as usize; + tasks[i].task_cx = TaskContext::goto_restore(init_app_cx(i)); tasks[i].task_status = TaskStatus::Ready; } 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; + fn run_first_task(&self) -> ! { + let mut inner = self.inner.exclusive_access(); + let task0 = &mut inner.tasks[0]; + task0.task_status = TaskStatus::Running; + let next_task_cx_ptr = &task0.task_cx as *const TaskContext; + drop(inner); + let mut _unused = TaskContext::zero_init(); + // before this, we should drop local variables that must be dropped manually unsafe { __switch( - &_unused as *const _, - next_task_cx_ptr2, + &mut _unused as *mut TaskContext, + next_task_cx_ptr, ); } + panic!("unreachable in run_first_task!"); } fn mark_current_suspended(&self) { - let mut inner = self.inner.borrow_mut(); + let mut inner = self.inner.exclusive_access(); let current = inner.current_task; inner.tasks[current].task_status = TaskStatus::Ready; } fn mark_current_exited(&self) { - let mut inner = self.inner.borrow_mut(); + let mut inner = self.inner.exclusive_access(); let current = inner.current_task; inner.tasks[current].task_status = TaskStatus::Exited; } fn find_next_task(&self) -> Option { - let inner = self.inner.borrow(); + let inner = self.inner.exclusive_access(); let current = inner.current_task; (current + 1..current + self.num_app + 1) .map(|id| id % self.num_app) @@ -81,19 +87,21 @@ impl TaskManager { 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.exclusive_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); + // before this, we should drop local variables that must be dropped manually unsafe { __switch( - current_task_cx_ptr2, - next_task_cx_ptr2, + current_task_cx_ptr, + next_task_cx_ptr, ); } + // go back to user mode } else { panic!("All applications completed!"); } 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 54dc3600..fd5f5f9c 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -1,12 +1,9 @@ +use super::TaskContext; + +#[derive(Copy, Clone)] pub struct TaskControlBlock { - pub task_cx_ptr: usize, pub task_status: TaskStatus, -} - -impl TaskControlBlock { - pub fn get_task_cx_ptr2(&self) -> *const usize { - &self.task_cx_ptr as *const usize - } + pub task_cx: TaskContext, } #[derive(Copy, Clone, PartialEq)] diff --git a/rust-toolchain b/rust-toolchain index a08f00d1..fd472758 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2021-01-30 +nightly-2021-10-15 diff --git a/user/src/lib.rs b/user/src/lib.rs index d14e3d89..94cce773 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(llvm_asm)] +#![feature(asm)] #![feature(linkage)] #![feature(panic_info_message)] diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 6a09f46e..4a1f781b 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -5,11 +5,12 @@ const SYSCALL_YIELD: usize = 124; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; unsafe { - llvm_asm!("ecall" - : "={x10}" (ret) - : "{x10}" (args[0]), "{x11}" (args[1]), "{x12}" (args[2]), "{x17}" (id) - : "memory" - : "volatile" + asm!( + "ecall", + inlateout("x10") args[0] => ret, + in("x11") args[1], + in("x12") args[2], + in("x17") id ); } ret