Merge recent patch on ch3.

This commit is contained in:
Yifan Wu 2021-11-01 09:44:10 -07:00
parent 9fa4fd6daa
commit c19662b70c
16 changed files with 146 additions and 83 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@ os/target/*
os/.idea/* os/.idea/*
os/Cargo.lock os/Cargo.lock
os/src/link_app.S os/src/link_app.S
os/last-*
user/target/* user/target/*
user/.idea/* user/.idea/*
user/Cargo.lock user/Cargo.lock

View File

@ -1,2 +1,12 @@
# rCore-Tutorial-v3 # rCore-Tutorial-v3
rCore-Tutorial version 3. 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]

View File

@ -29,12 +29,19 @@ OBJCOPY := rust-objcopy --binary-architecture=riscv64
# Disassembly # Disassembly
DISASM ?= -x 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: env:
rustup component add rust-src rustup component add rust-src
rustup component add llvm-tools-preview 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 rustup target add riscv64gc-unknown-none-elf
$(KERNEL_BIN): kernel $(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 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 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

View File

@ -1,13 +1,14 @@
use crate::trap::TrapContext; use crate::trap::TrapContext;
use crate::task::TaskContext;
use crate::config::*; use crate::config::*;
#[repr(align(4096))] #[repr(align(4096))]
#[derive(Copy, Clone)]
struct KernelStack { struct KernelStack {
data: [u8; KERNEL_STACK_SIZE], data: [u8; KERNEL_STACK_SIZE],
} }
#[repr(align(4096))] #[repr(align(4096))]
#[derive(Copy, Clone)]
struct UserStack { struct UserStack {
data: [u8; USER_STACK_SIZE], data: [u8; USER_STACK_SIZE],
} }
@ -26,14 +27,10 @@ impl KernelStack {
fn get_sp(&self) -> usize { fn get_sp(&self) -> usize {
self.data.as_ptr() as usize + KERNEL_STACK_SIZE self.data.as_ptr() as usize + KERNEL_STACK_SIZE
} }
pub fn push_context(&self, trap_cx: TrapContext, task_cx: TaskContext) -> &'static mut TaskContext { pub fn push_context(&self, trap_cx: TrapContext) -> usize {
unsafe {
let trap_cx_ptr = (self.get_sp() - core::mem::size_of::<TrapContext>()) as *mut TrapContext; let trap_cx_ptr = (self.get_sp() - core::mem::size_of::<TrapContext>()) as *mut TrapContext;
*trap_cx_ptr = trap_cx; unsafe { *trap_cx_ptr = trap_cx; }
let task_cx_ptr = (trap_cx_ptr as usize - core::mem::size_of::<TaskContext>()) as *mut TaskContext; trap_cx_ptr as usize
*task_cx_ptr = task_cx;
task_cx_ptr.as_mut().unwrap()
}
} }
} }
@ -60,7 +57,7 @@ pub fn load_apps() {
core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1) core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1)
}; };
// clear i-cache first // clear i-cache first
unsafe { llvm_asm!("fence.i" :::: "volatile"); } unsafe { asm!("fence.i"); }
// load apps // load apps
for i in 0..num_app { for i in 0..num_app {
let base_i = get_base_i(i); 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( KERNEL_STACK[app_id].push_context(
TrapContext::app_init_context(get_base_i(app_id), USER_STACK[app_id].get_sp()), TrapContext::app_init_context(get_base_i(app_id), USER_STACK[app_id].get_sp()),
TaskContext::goto_restore(),
) )
} }

View File

@ -1,9 +1,8 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(global_asm)] #![feature(global_asm)]
#![feature(llvm_asm)] #![feature(asm)]
#![feature(panic_info_message)] #![feature(panic_info_message)]
#![feature(const_in_array_repeat_expressions)]
#[macro_use] #[macro_use]
mod console; mod console;
@ -14,6 +13,7 @@ mod trap;
mod loader; mod loader;
mod config; mod config;
mod task; mod task;
mod sync;
global_asm!(include_str!("entry.asm")); global_asm!(include_str!("entry.asm"));
global_asm!(include_str!("link_app.S")); global_asm!(include_str!("link_app.S"));
@ -23,9 +23,12 @@ fn clear_bss() {
fn sbss(); fn sbss();
fn ebss(); fn ebss();
} }
(sbss as usize..ebss as usize).for_each(|a| { unsafe {
unsafe { (a as *mut u8).write_volatile(0) } core::slice::from_raw_parts_mut(
}); sbss as usize as *mut u8,
ebss as usize - sbss as usize,
).fill(0);
}
} }
#[no_mangle] #[no_mangle]

View File

@ -14,11 +14,12 @@ const SBI_SHUTDOWN: usize = 8;
fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize { fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
let mut ret; let mut ret;
unsafe { unsafe {
llvm_asm!("ecall" asm!(
: "={x10}" (ret) "ecall",
: "{x10}" (arg0), "{x11}" (arg1), "{x12}" (arg2), "{x17}" (which) inlateout("x10") arg0 => ret,
: "memory" in("x11") arg1,
: "volatile" in("x12") arg2,
in("x17") which,
); );
} }
ret ret

3
os/src/sync/mod.rs Normal file
View File

@ -0,0 +1,3 @@
mod up;
pub use up::UPSafeCell;

27
os/src/sync/up.rs Normal file
View File

@ -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<T> {
/// inner data
inner: RefCell<T>,
}
unsafe impl<T> Sync for UPSafeCell<T> {}
impl<T> UPSafeCell<T> {
/// 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()
}
}

View File

@ -1,14 +1,24 @@
#[derive(Copy, Clone)]
#[repr(C)] #[repr(C)]
pub struct TaskContext { pub struct TaskContext {
ra: usize, ra: usize,
sp: usize,
s: [usize; 12], s: [usize; 12],
} }
impl TaskContext { 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(); } extern "C" { fn __restore(); }
Self { Self {
ra: __restore as usize, ra: __restore as usize,
sp: kstack_ptr,
s: [0; 12], s: [0; 12],
} }
} }

View File

@ -4,16 +4,16 @@ mod task;
use crate::config::MAX_APP_NUM; use crate::config::MAX_APP_NUM;
use crate::loader::{get_num_app, init_app_cx}; use crate::loader::{get_num_app, init_app_cx};
use core::cell::RefCell;
use lazy_static::*; use lazy_static::*;
use switch::__switch; use switch::__switch;
use task::{TaskControlBlock, TaskStatus}; use task::{TaskControlBlock, TaskStatus};
use crate::sync::UPSafeCell;
pub use context::TaskContext; pub use context::TaskContext;
pub struct TaskManager { pub struct TaskManager {
num_app: usize, num_app: usize,
inner: RefCell<TaskManagerInner>, inner: UPSafeCell<TaskManagerInner>,
} }
struct TaskManagerInner { struct TaskManagerInner {
@ -21,56 +21,62 @@ struct TaskManagerInner {
current_task: usize, current_task: usize,
} }
unsafe impl Sync for TaskManager {}
lazy_static! { lazy_static! {
pub static ref TASK_MANAGER: TaskManager = { pub static ref TASK_MANAGER: TaskManager = {
let num_app = get_num_app(); let num_app = get_num_app();
let mut tasks = [ 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 MAX_APP_NUM
]; ];
for i in 0..num_app { 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; tasks[i].task_status = TaskStatus::Ready;
} }
TaskManager { TaskManager {
num_app, num_app,
inner: RefCell::new(TaskManagerInner { inner: unsafe { UPSafeCell::new(TaskManagerInner {
tasks, tasks,
current_task: 0, current_task: 0,
}), })},
} }
}; };
} }
impl TaskManager { impl TaskManager {
fn run_first_task(&self) { fn run_first_task(&self) -> ! {
self.inner.borrow_mut().tasks[0].task_status = TaskStatus::Running; let mut inner = self.inner.exclusive_access();
let next_task_cx_ptr2 = self.inner.borrow().tasks[0].get_task_cx_ptr2(); let task0 = &mut inner.tasks[0];
let _unused: usize = 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 { unsafe {
__switch( __switch(
&_unused as *const _, &mut _unused as *mut TaskContext,
next_task_cx_ptr2, next_task_cx_ptr,
); );
} }
panic!("unreachable in run_first_task!");
} }
fn mark_current_suspended(&self) { fn mark_current_suspended(&self) {
let mut inner = self.inner.borrow_mut(); let mut inner = self.inner.exclusive_access();
let current = inner.current_task; let current = inner.current_task;
inner.tasks[current].task_status = TaskStatus::Ready; inner.tasks[current].task_status = TaskStatus::Ready;
} }
fn mark_current_exited(&self) { fn mark_current_exited(&self) {
let mut inner = self.inner.borrow_mut(); let mut inner = self.inner.exclusive_access();
let current = inner.current_task; let current = inner.current_task;
inner.tasks[current].task_status = TaskStatus::Exited; inner.tasks[current].task_status = TaskStatus::Exited;
} }
fn find_next_task(&self) -> Option<usize> { fn find_next_task(&self) -> Option<usize> {
let inner = self.inner.borrow(); let inner = self.inner.exclusive_access();
let current = inner.current_task; let current = inner.current_task;
(current + 1..current + self.num_app + 1) (current + 1..current + self.num_app + 1)
.map(|id| id % self.num_app) .map(|id| id % self.num_app)
@ -81,19 +87,21 @@ impl TaskManager {
fn run_next_task(&self) { fn run_next_task(&self) {
if let Some(next) = self.find_next_task() { 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; let current = inner.current_task;
inner.tasks[next].task_status = TaskStatus::Running; inner.tasks[next].task_status = TaskStatus::Running;
inner.current_task = next; inner.current_task = next;
let current_task_cx_ptr2 = inner.tasks[current].get_task_cx_ptr2(); let current_task_cx_ptr = &mut inner.tasks[current].task_cx as *mut TaskContext;
let next_task_cx_ptr2 = inner.tasks[next].get_task_cx_ptr2(); let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext;
core::mem::drop(inner); drop(inner);
// before this, we should drop local variables that must be dropped manually
unsafe { unsafe {
__switch( __switch(
current_task_cx_ptr2, current_task_cx_ptr,
next_task_cx_ptr2, next_task_cx_ptr,
); );
} }
// go back to user mode
} else { } else {
panic!("All applications completed!"); panic!("All applications completed!");
} }

View File

@ -1,37 +1,34 @@
.altmacro .altmacro
.macro SAVE_SN n .macro SAVE_SN n
sd s\n, (\n+1)*8(sp) sd s\n, (\n+2)*8(a0)
.endm .endm
.macro LOAD_SN n .macro LOAD_SN n
ld s\n, (\n+1)*8(sp) ld s\n, (\n+2)*8(a1)
.endm .endm
.section .text .section .text
.globl __switch .globl __switch
__switch: __switch:
# __switch( # __switch(
# current_task_cx_ptr2: &*const TaskContext, # current_task_cx_ptr: *mut TaskContext,
# next_task_cx_ptr2: &*const TaskContext # next_task_cx_ptr: *const TaskContext
# ) # )
# push TaskContext to current sp and save its address to where a0 points to # save kernel stack of current task
addi sp, sp, -13*8 sd sp, 8(a0)
sd sp, 0(a0) # save ra & s0~s11 of current execution
# fill TaskContext with ra & s0-s11 sd ra, 0(a0)
sd ra, 0(sp)
.set n, 0 .set n, 0
.rept 12 .rept 12
SAVE_SN %n SAVE_SN %n
.set n, n + 1 .set n, n + 1
.endr .endr
# ready for loading TaskContext a1 points to # restore ra & s0~s11 of next execution
ld sp, 0(a1) ld ra, 0(a1)
# load registers in the TaskContext
ld ra, 0(sp)
.set n, 0 .set n, 0
.rept 12 .rept 12
LOAD_SN %n LOAD_SN %n
.set n, n + 1 .set n, n + 1
.endr .endr
# pop TaskContext # restore kernel stack of next task
addi sp, sp, 13*8 ld sp, 8(a1)
ret ret

View File

@ -1,8 +1,10 @@
global_asm!(include_str!("switch.S")); global_asm!(include_str!("switch.S"));
use super::TaskContext;
extern "C" { extern "C" {
pub fn __switch( pub fn __switch(
current_task_cx_ptr2: *const usize, current_task_cx_ptr: *mut TaskContext,
next_task_cx_ptr2: *const usize next_task_cx_ptr: *const TaskContext
); );
} }

View File

@ -1,12 +1,9 @@
pub struct TaskControlBlock { use super::TaskContext;
pub task_cx_ptr: usize,
pub task_status: TaskStatus,
}
impl TaskControlBlock { #[derive(Copy, Clone)]
pub fn get_task_cx_ptr2(&self) -> *const usize { pub struct TaskControlBlock {
&self.task_cx_ptr as *const usize pub task_status: TaskStatus,
} pub task_cx: TaskContext,
} }
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]

View File

@ -1 +1 @@
nightly-2021-01-30 nightly-2021-10-15

View File

@ -1,5 +1,5 @@
#![no_std] #![no_std]
#![feature(llvm_asm)] #![feature(asm)]
#![feature(linkage)] #![feature(linkage)]
#![feature(panic_info_message)] #![feature(panic_info_message)]

View File

@ -5,11 +5,12 @@ const SYSCALL_YIELD: usize = 124;
fn syscall(id: usize, args: [usize; 3]) -> isize { fn syscall(id: usize, args: [usize; 3]) -> isize {
let mut ret: isize; let mut ret: isize;
unsafe { unsafe {
llvm_asm!("ecall" asm!(
: "={x10}" (ret) "ecall",
: "{x10}" (args[0]), "{x11}" (args[1]), "{x12}" (args[2]), "{x17}" (id) inlateout("x10") args[0] => ret,
: "memory" in("x11") args[1],
: "volatile" in("x12") args[2],
in("x17") id
); );
} }
ret ret