Implement many process syscalls.

This commit is contained in:
Yifan Wu 2020-12-10 11:57:26 +08:00
parent 81bef97f09
commit 3642f9c56d
20 changed files with 383 additions and 88 deletions

View File

@ -7,12 +7,6 @@ pub const PAGE_SIZE_BITS: usize = 0xc;
pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE;
/// Return (bottom, top) of a kernel stack in kernel space.
pub fn kernel_stack_position(app_id: usize) -> (usize, usize) {
let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
let bottom = top - KERNEL_STACK_SIZE;
(bottom, top)
}
#[cfg(feature = "board_k210")]
pub const CPU_FREQ: usize = 10000000;

View File

@ -45,7 +45,8 @@ fn app_names() -> Vec<&'static str> {
let slice = core::slice::from_raw_parts(start, end as usize - start as usize);
let str = core::str::from_utf8(slice).unwrap();
v.push(str);
start = end.add(1);
// Mention that there is a extra char between names
start = end.add(2);
}
}
v

View File

@ -41,20 +41,11 @@ pub fn rust_main() -> ! {
clear_bss();
println!("[kernel] Hello, world!");
mm::init();
println!("[kernel] back to world!");
mm::remap_test();
// add apps
let num_app = loader::get_num_app();
println!("num_app={}", num_app);
for i in 0..num_app {
println!("i={}", i);
task::add_application(loader::get_app_data(i), i);
}
task::add_initproc();
trap::init();
trap::enable_timer_interrupt();
timer::set_next_trigger();
println!("before task::run_tasks!");
task::run_tasks();
panic!("Unreachable in rust_main!");
}

View File

@ -110,6 +110,13 @@ impl VirtPageNum {
}
}
impl PhysAddr {
pub fn get_mut<T>(&self) -> &'static mut T {
unsafe {
(self.0 as *mut T).as_mut().unwrap()
}
}
}
impl PhysPageNum {
pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] {
let pa: PhysAddr = self.clone().into();
@ -125,9 +132,7 @@ impl PhysPageNum {
}
pub fn get_mut<T>(&self) -> &'static mut T {
let pa: PhysAddr = self.clone().into();
unsafe {
(pa.0 as *mut T).as_mut().unwrap()
}
pa.get_mut()
}
}

View File

@ -47,6 +47,7 @@ impl MemorySet {
areas: Vec::new(),
}
}
#[allow(unused)]
pub fn dealloc_all_frames(&mut self) {
*self = Self::new_bare();
}
@ -68,7 +69,6 @@ impl MemorySet {
area.unmap(&mut self.page_table);
self.areas.remove(idx);
}
panic!("Area not found!");
}
fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
map_area.map(&mut self.page_table);
@ -189,6 +189,23 @@ impl MemorySet {
), None);
(memory_set, user_stack_top, elf.header.pt2.entry_point() as usize)
}
pub fn from_existed_user(user_space: &MemorySet) -> MemorySet {
let mut memory_set = Self::new_bare();
// map trampoline
memory_set.map_trampoline();
// copy data sections/trap_context/user_stack
for area in user_space.areas.iter() {
let new_area = MapArea::from_another(area);
memory_set.push(new_area, None);
// copy data from another space
for vpn in area.vpn_range {
let src_ppn = user_space.translate(vpn).unwrap().ppn();
let dst_ppn = memory_set.translate(vpn).unwrap().ppn();
dst_ppn.get_bytes_array().copy_from_slice(src_ppn.get_bytes_array());
}
}
memory_set
}
pub fn activate(&self) {
let satp = self.page_table.token();
unsafe {
@ -199,6 +216,9 @@ impl MemorySet {
pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
self.page_table.translate(vpn)
}
pub fn clear(&mut self) {
*self = Self::new_bare();
}
}
pub struct MapArea {
@ -224,6 +244,14 @@ impl MapArea {
map_perm,
}
}
pub fn from_another(another: &MapArea) -> Self {
Self {
vpn_range: VPNRange::new(another.vpn_range.get_start(), another.vpn_range.get_end()),
data_frames: BTreeMap::new(),
map_type: another.map_type,
map_perm: another.map_perm,
}
}
pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
let ppn: PhysPageNum;
match self.map_type {

View File

@ -8,7 +8,12 @@ use page_table::{PageTable, PTEFlags};
use address::{VPNRange, StepByOne};
pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum};
pub use frame_allocator::{FrameTracker, frame_alloc};
pub use page_table::{PageTableEntry, translated_byte_buffer};
pub use page_table::{
PageTableEntry,
translated_byte_buffer,
translated_str,
translated_refmut,
};
pub use memory_set::{MemorySet, KERNEL_SPACE, MapPermission};
pub use memory_set::remap_test;

View File

@ -1,6 +1,15 @@
use super::{frame_alloc, PhysPageNum, FrameTracker, VirtPageNum, VirtAddr, StepByOne};
use super::{
frame_alloc,
PhysPageNum,
FrameTracker,
VirtPageNum,
VirtAddr,
PhysAddr,
StepByOne
};
use alloc::vec::Vec;
use alloc::vec;
use alloc::string::String;
use bitflags::*;
bitflags! {
@ -126,6 +135,17 @@ impl PageTable {
self.find_pte(vpn)
.map(|pte| {pte.clone()})
}
pub fn translate_va(&self, va: VirtAddr) -> Option<PhysAddr> {
self.find_pte(va.clone().floor())
.map(|pte| {
//println!("translate_va:va = {:?}", va);
let aligned_pa: PhysAddr = pte.ppn().into();
//println!("translate_va:pa_align = {:?}", aligned_pa);
let offset = va.page_offset();
let aligned_pa_usize: usize = aligned_pa.into();
(aligned_pa_usize + offset).into()
})
}
pub fn token(&self) -> usize {
8usize << 60 | self.root_ppn.0
}
@ -151,3 +171,27 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&
}
v
}
pub fn translated_str(token: usize, ptr: *const u8) -> String {
let page_table = PageTable::from_token(token);
let mut string = String::new();
let mut va = ptr as usize;
loop {
let ch: u8 = *(page_table.translate_va(VirtAddr::from(va)).unwrap().get_mut());
if ch == 0 {
break;
} else {
string.push(ch as char);
va += 1;
}
}
string
}
pub fn translated_refmut<T>(token: usize, ptr: *mut T) -> &'static mut T {
//println!("into translated_refmut!");
let page_table = PageTable::from_token(token);
let va = ptr as usize;
//println!("translated_refmut: before translate_va");
page_table.translate_va(VirtAddr::from(va)).unwrap().get_mut()
}

View File

@ -1,5 +1,5 @@
use crate::mm::translated_byte_buffer;
use crate::task::{current_user_token, suspend_current_and_run_next};
use crate::task::{current_user_token};
use crate::sbi::console_getchar;
const FD_STDIN: usize = 0;
@ -28,7 +28,7 @@ pub fn sys_read(fd: usize, buf: *const u8, len: usize) -> isize {
loop {
c = console_getchar();
if c == 0 {
suspend_current_and_run_next();
//suspend_current_and_run_next();
continue;
} else {
break;

View File

@ -3,6 +3,10 @@ const SYSCALL_WRITE: usize = 64;
const SYSCALL_EXIT: usize = 93;
const SYSCALL_YIELD: usize = 124;
const SYSCALL_GET_TIME: usize = 169;
const SYSCALL_GETPID: usize = 172;
const SYSCALL_FORK: usize = 220;
const SYSCALL_EXEC: usize = 221;
const SYSCALL_WAITPID: usize = 260;
mod fs;
mod process;
@ -17,6 +21,10 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
SYSCALL_EXIT => sys_exit(args[0] as i32),
SYSCALL_YIELD => sys_yield(),
SYSCALL_GET_TIME => sys_get_time(),
SYSCALL_GETPID => sys_getpid(),
SYSCALL_FORK => sys_fork(),
SYSCALL_EXEC => sys_exec(args[0] as *const u8),
SYSCALL_WAITPID => sys_waitpid(args[0] as isize, args[1] as *mut i32),
_ => panic!("Unsupported syscall_id: {}", syscall_id),
}
}

View File

@ -1,11 +1,30 @@
use crate::task::{
suspend_current_and_run_next,
exit_current_and_run_next,
current_task,
current_user_token,
add_task,
};
use crate::timer::get_time;
use crate::mm::{
translated_str,
translated_refmut,
};
use crate::loader::get_app_data_by_name;
use alloc::sync::Arc;
pub fn sys_exit(exit_code: i32) -> ! {
// save exit code
let task = current_task().unwrap();
// ---- hold current PCB lock
task.acquire_inner_lock().exit_code = exit_code;
// ---- release current PCB lock
// this function will not return
// drop task manually to maintain rc correctly
drop(task);
pub fn sys_exit(xstate: i32) -> ! {
println!("[kernel] Application exited with code {}", xstate);
exit_current_and_run_next();
panic!("Unreachable in sys_exit!");
}
@ -18,3 +37,59 @@ pub fn sys_yield() -> isize {
pub fn sys_get_time() -> isize {
get_time() as isize
}
pub fn sys_getpid() -> isize {
current_task().unwrap().pid.0 as isize
}
pub fn sys_fork() -> isize {
let current_task = current_task().unwrap();
let new_task = current_task.fork();
let new_pid = new_task.pid.0;
// modify trap context of new_task, because it returns immediately after switching
let trap_cx = new_task.acquire_inner_lock().get_trap_cx();
// we do not have to move to next instruction since we have done it before
// for child process, fork returns 0
trap_cx.x[10] = 0;
// add new task to scheduler
add_task(new_task);
new_pid as isize
}
pub fn sys_exec(path: *const u8) -> isize {
let token = current_user_token();
let path = translated_str(token, path);
let data = get_app_data_by_name(path.as_str()).unwrap();
let task = current_task().unwrap();
task.exec(data);
0
}
pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize {
let task = current_task().unwrap();
// find a child process
// ---- hold current PCB lock
let mut inner = task.acquire_inner_lock();
let pair = inner.children
.iter()
.enumerate()
.find(|(_, p)| {
// ++++ temporarily hold child PCB lock
p.acquire_inner_lock().is_zombie() && (pid == -1 || pid as usize == p.getpid())
// ++++ release child PCB lock
});
if let Some((idx, _)) = pair {
let child = inner.children.remove(idx);
// confirm that child will be deallocated after removing from children list
assert_eq!(Arc::strong_count(&child), 1);
let found_pid = child.getpid();
// ++++ temporarily hold child lock
let exit_code = child.acquire_inner_lock().exit_code;
// ++++ release child PCB lock
*translated_refmut(inner.memory_set.token(), exit_code_ptr) = exit_code;
found_pid as isize
} else {
-1
}
// ---- release current PCB lock automatically
}

View File

@ -5,7 +5,7 @@ use spin::Mutex;
use lazy_static::*;
pub struct TaskManager {
ready_queue: VecDeque<Arc<Mutex<TaskControlBlock>>>,
ready_queue: VecDeque<Arc<TaskControlBlock>>,
}
/// A simple FIFO scheduler.
@ -13,10 +13,10 @@ impl TaskManager {
pub fn new() -> Self {
Self { ready_queue: VecDeque::new(), }
}
pub fn add(&mut self, task: Arc<Mutex<TaskControlBlock>>) {
pub fn add(&mut self, task: Arc<TaskControlBlock>) {
self.ready_queue.push_back(task);
}
pub fn fetch(&mut self) -> Option<Arc<Mutex<TaskControlBlock>>> {
pub fn fetch(&mut self) -> Option<Arc<TaskControlBlock>> {
self.ready_queue.pop_front()
}
}
@ -25,10 +25,10 @@ lazy_static! {
pub static ref TASK_MANAGER: Mutex<TaskManager> = Mutex::new(TaskManager::new());
}
pub fn add_task(task: Arc<Mutex<TaskControlBlock>>) {
pub fn add_task(task: Arc<TaskControlBlock>) {
TASK_MANAGER.lock().add(task);
}
pub fn fetch_task() -> Option<Arc<Mutex<TaskControlBlock>>> {
pub fn fetch_task() -> Option<Arc<TaskControlBlock>> {
TASK_MANAGER.lock().fetch()
}

View File

@ -5,17 +5,11 @@ mod manager;
mod processor;
mod pid;
use crate::loader::{get_num_app, get_app_data};
use crate::trap::TrapContext;
use core::cell::RefCell;
use lazy_static::*;
use crate::loader::{get_app_data_by_name};
use switch::__switch;
use task::{TaskControlBlock, TaskStatus};
use alloc::vec::Vec;
use alloc::sync::Arc;
use spin::Mutex;
use manager::fetch_task;
use pid::{PidHandle, pid_alloc, KernelStack};
pub use context::TaskContext;
pub use processor::{
@ -27,13 +21,21 @@ pub use processor::{
schedule,
};
pub use manager::add_task;
pub use pid::{PidHandle, pid_alloc, KernelStack};
pub fn suspend_current_and_run_next() {
// There must be an application running.
let task = current_task().unwrap();
let task_cx_ptr = task.lock().get_task_cx_ptr2();
// Change status to Ready.
task.lock().task_status = TaskStatus::Ready;
let task = take_current_task().unwrap();
// ---- temporarily hold current PCB lock
let task_cx_ptr = task.acquire_inner_lock().get_task_cx_ptr2();
// ---- release current PCB lock
// ++++ temporarily hold current PCB lock
// Change status to Ready
task.acquire_inner_lock().task_status = TaskStatus::Ready;
// ++++ release current PCB lock
// push back to ready queue.
add_task(task);
// jump to scheduling cycle
@ -41,10 +43,37 @@ pub fn suspend_current_and_run_next() {
}
pub fn exit_current_and_run_next() {
// The resource recycle mechanism needs child processes. Now we just panic!
panic!("An application exited!");
// take from Processor
let task = take_current_task().unwrap();
// **** hold current PCB lock
let mut inner = task.acquire_inner_lock();
// Change status to Zombie
inner.task_status = TaskStatus::Zombie;
// move any child to its parent
// ++++++ hold parent PCB lock here
{
let parent = inner.parent.as_ref().unwrap().upgrade().unwrap();
let mut parent_inner = parent.acquire_inner_lock();
for child in inner.children.iter() {
parent_inner.children.push(child.clone());
}
}
// ++++++ release parent PCB lock here
inner.children.clear();
// deallocate user space
inner.memory_set.clear();
drop(inner);
// **** release current PCB lock
// drop task manually to maintain rc correctly
drop(task);
// we do not have to save task context
let _unused: usize = 0;
schedule(&_unused as *const _);
}
pub fn add_application(elf_data: &[u8], app_id: usize) {
add_task(Arc::new(Mutex::new(TaskControlBlock::new(elf_data, app_id))));
pub fn add_initproc() {
let data = get_app_data_by_name("initproc").unwrap();
add_task(Arc::new(TaskControlBlock::new(data)));
}

View File

@ -46,6 +46,7 @@ pub struct PidHandle(pub usize);
impl Drop for PidHandle {
fn drop(&mut self) {
//println!("drop pid {}", self.0);
PID_ALLOCATOR.lock().dealloc(self.0);
}
}
@ -82,7 +83,7 @@ impl KernelStack {
}
pub fn push_on_top<T>(&self, value: T) -> *mut T where
T: Sized, {
let (_, kernel_stack_top) = kernel_stack_position(self.pid);
let kernel_stack_top = self.get_top();
let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T;
unsafe { *ptr_mut = value; }
ptr_mut

View File

@ -2,7 +2,7 @@ use super::TaskControlBlock;
use alloc::sync::Arc;
use spin::Mutex;
use lazy_static::*;
use super::{add_task, fetch_task};
use super::{fetch_task, TaskStatus};
use super::__switch;
use crate::trap::TrapContext;
@ -13,7 +13,7 @@ pub struct Processor {
unsafe impl Sync for Processor {}
struct ProcessorInner {
current: Option<Arc<Mutex<TaskControlBlock>>>,
current: Option<Arc<TaskControlBlock>>,
idle_task_cx_ptr: usize,
}
@ -31,13 +31,13 @@ impl Processor {
&inner.idle_task_cx_ptr as *const usize
}
pub fn run(&self) {
//println!("into Processor::run");
loop {
if let Some(task) = fetch_task() {
//println!("found task!");
let idle_task_cx_ptr = self.get_idle_task_cx_ptr2();
let next_task_cx_ptr = task.lock().get_task_cx_ptr2();
//println!("next_task_cx_ptr={:p}", next_task_cx_ptr);
// acquire
let next_task_cx_ptr = task.acquire_inner_lock().get_task_cx_ptr2();
task.acquire_inner_lock().task_status = TaskStatus::Running;
// release
self.inner.lock().current = Some(task);
unsafe {
__switch(
@ -48,10 +48,10 @@ impl Processor {
}
}
}
pub fn take_current(&self) -> Option<Arc<Mutex<TaskControlBlock>>> {
pub fn take_current(&self) -> Option<Arc<TaskControlBlock>> {
self.inner.lock().current.take()
}
pub fn current(&self) -> Option<Arc<Mutex<TaskControlBlock>>> {
pub fn current(&self) -> Option<Arc<TaskControlBlock>> {
self.inner.lock().current.as_ref().map(|task| task.clone())
}
}
@ -64,25 +64,22 @@ pub fn run_tasks() {
PROCESSOR.run();
}
pub fn take_current_task() -> Option<Arc<Mutex<TaskControlBlock>>> {
pub fn take_current_task() -> Option<Arc<TaskControlBlock>> {
PROCESSOR.take_current()
}
pub fn current_task() -> Option<Arc<Mutex<TaskControlBlock>>> {
//println!("into current_task!");
pub fn current_task() -> Option<Arc<TaskControlBlock>> {
PROCESSOR.current()
}
pub fn current_user_token() -> usize {
//println!("into current_user_token!");
let task = current_task().unwrap();
//println!("Got task in current_user_token!");
let token = task.lock().get_user_token();
let token = task.acquire_inner_lock().get_user_token();
token
}
pub fn current_trap_cx() -> &'static mut TrapContext {
current_task().unwrap().as_ref().lock().get_trap_cx()
current_task().unwrap().acquire_inner_lock().get_trap_cx()
}
pub fn schedule(switched_task_cx_ptr2: *const usize) {

View File

@ -1,22 +1,32 @@
use crate::mm::{MemorySet, MapPermission, PhysPageNum, KERNEL_SPACE, VirtAddr};
use crate::mm::{MemorySet, PhysPageNum, KERNEL_SPACE, VirtAddr};
use crate::trap::{TrapContext, trap_handler};
use crate::config::{TRAP_CONTEXT, kernel_stack_position};
use crate::config::{TRAP_CONTEXT};
use super::TaskContext;
use super::{PidHandle, pid_alloc, KernelStack};
use alloc::sync::{Weak, Arc};
use alloc::vec::Vec;
use spin::{Mutex, MutexGuard};
pub struct TaskControlBlock {
// immutable
pub trap_cx_ppn: PhysPageNum,
pub base_size: usize,
pub pid: PidHandle,
pub kernel_stack: KernelStack,
// mutable
inner: Mutex<TaskControlBlockInner>,
}
pub struct TaskControlBlockInner {
pub trap_cx_ppn: PhysPageNum,
pub base_size: usize,
pub task_cx_ptr: usize,
pub task_status: TaskStatus,
pub memory_set: MemorySet,
pub parent: Option<Weak<TaskControlBlock>>,
pub children: Vec<Arc<TaskControlBlock>>,
pub exit_code: i32,
}
impl TaskControlBlock {
impl TaskControlBlockInner {
pub fn get_task_cx_ptr2(&self) -> *const usize {
&self.task_cx_ptr as *const usize
}
@ -26,7 +36,19 @@ impl TaskControlBlock {
pub fn get_user_token(&self) -> usize {
self.memory_set.token()
}
pub fn new(elf_data: &[u8], app_id: usize) -> Self {
fn get_status(&self) -> TaskStatus {
self.task_status
}
pub fn is_zombie(&self) -> bool {
self.get_status() == TaskStatus::Zombie
}
}
impl TaskControlBlock {
pub fn acquire_inner_lock(&self) -> MutexGuard<TaskControlBlockInner> {
self.inner.lock()
}
pub fn new(elf_data: &[u8]) -> Self {
// memory_set with elf program headers/trampoline/trap context/user stack
let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
let trap_cx_ppn = memory_set
@ -41,16 +63,23 @@ impl TaskControlBlock {
// push a task context which goes to trap_return to the top of kernel stack
let task_cx_ptr = kernel_stack.push_on_top(TaskContext::goto_trap_return());
let task_control_block = Self {
trap_cx_ppn,
base_size: user_sp,
pid: pid_handle,
kernel_stack,
inner: Mutex::new(TaskControlBlockInner {
trap_cx_ppn,
base_size: user_sp,
task_cx_ptr: task_cx_ptr as usize,
task_status,
memory_set,
parent: None,
children: Vec::new(),
exit_code: 0,
}),
};
// prepare TrapContext in user space
let trap_cx = task_control_block.get_trap_cx();
// ---- acquire child PCB lock
let trap_cx = task_control_block.acquire_inner_lock().get_trap_cx();
// ---- release child PCB lock
*trap_cx = TrapContext::app_init_context(
entry_point,
user_sp,
@ -60,12 +89,86 @@ impl TaskControlBlock {
);
task_control_block
}
pub fn exec(&self, elf_data: &[u8]) {
// memory_set with elf program headers/trampoline/trap context/user stack
let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
let trap_cx_ppn = memory_set
.translate(VirtAddr::from(TRAP_CONTEXT).into())
.unwrap()
.ppn();
// **** hold current PCB lock
let mut inner = self.inner.lock();
// substitute memory_set
inner.memory_set = memory_set;
// update trap_cx ppn
inner.trap_cx_ppn = trap_cx_ppn;
drop(inner);
// **** release current PCB lock manually
// initialize trap_cx
// **** acquire current PCB lock
let trap_cx = self.acquire_inner_lock().get_trap_cx();
// **** release current PCB lock
*trap_cx = TrapContext::app_init_context(
entry_point,
user_sp,
KERNEL_SPACE.lock().token(),
self.kernel_stack.get_top(),
trap_handler as usize,
);
}
pub fn fork(self: &Arc<TaskControlBlock>) -> Arc<TaskControlBlock> {
// ---- hold parent PCB lock
let mut parent_inner = self.inner.lock();
// copy user space(include trap context)
let memory_set = MemorySet::from_existed_user(
&parent_inner.memory_set
);
let trap_cx_ppn = memory_set
.translate(VirtAddr::from(TRAP_CONTEXT).into())
.unwrap()
.ppn();
let task_status = TaskStatus::Ready;
// alloc a pid and a kernel stack in kernel space
let pid_handle = pid_alloc();
let kernel_stack = KernelStack::new(&pid_handle);
let kernel_stack_top = kernel_stack.get_top();
// push a goto_trap_return task_cx on the top of kernel stack
let task_cx_ptr = kernel_stack.push_on_top(TaskContext::goto_trap_return());
let task_control_block = Arc::new(TaskControlBlock {
pid: pid_handle,
kernel_stack,
inner: Mutex::new(TaskControlBlockInner {
trap_cx_ppn,
base_size: parent_inner.base_size,
task_cx_ptr: task_cx_ptr as usize,
task_status,
memory_set,
parent: Some(Arc::downgrade(self)),
children: Vec::new(),
exit_code: 0,
}),
});
// add child
parent_inner.children.push(task_control_block.clone());
// modify kernel_sp in trap_cx
// **** acquire child PCB lock
let trap_cx = task_control_block.acquire_inner_lock().get_trap_cx();
// **** release child PCB lock
trap_cx.kernel_sp = kernel_stack_top;
// return
task_control_block
// ---- release parent PCB lock
}
pub fn getpid(&self) -> usize {
self.pid.0
}
}
#[derive(Copy, Clone, PartialEq)]
pub enum TaskStatus {
Ready,
Running,
Exited,
Zombie,
}

View File

@ -20,7 +20,9 @@ impl TrapContext {
trap_handler: usize,
) -> Self {
let mut sstatus = sstatus::read();
// set CPU privilege to User after trapping back
sstatus.set_spp(SPP::User);
// enable Supervisor mode interrupt after trapping back
sstatus.set_spie(true);
let mut cx = Self {
x: [0; 32],

View File

@ -53,17 +53,22 @@ pub fn enable_timer_interrupt() {
#[no_mangle]
pub fn trap_handler() -> ! {
set_kernel_trap_entry();
let cx = current_trap_cx();
let scause = scause::read();
let stval = stval::read();
match scause.cause() {
Trap::Exception(Exception::UserEnvCall) => {
// jump to next instruction anyway
let mut cx = current_trap_cx();
cx.sepc += 4;
cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize;
// get system call return value
let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]);
// cx is changed during sys_exec, so we have to call it again
cx = current_trap_cx();
cx.x[10] = result as usize;
}
Trap::Exception(Exception::StoreFault) |
Trap::Exception(Exception::StorePageFault) => {
println!("[kernel] PageFault in application, bad addr = {:#x}, bad instruction = {:#x}, core dumped.", stval, cx.sepc);
println!("[kernel] PageFault in application, bad addr = {:#x}, bad instruction = {:#x}, core dumped.", stval, current_trap_cx().sepc);
exit_current_and_run_next();
}
Trap::Exception(Exception::IllegalInstruction) => {
@ -83,7 +88,6 @@ pub fn trap_handler() -> ! {
#[no_mangle]
pub fn trap_return() -> ! {
//println!("into trap_return!");
set_user_trap_entry();
let trap_cx_ptr = TRAP_CONTEXT;
let user_satp = current_user_token();
@ -92,7 +96,6 @@ pub fn trap_return() -> ! {
fn __restore();
}
let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE;
//println!("before jr!");
unsafe {
llvm_asm!("jr $0" :: "r"(restore_va), "{a0}"(trap_cx_ptr), "{a1}"(user_satp) :: "volatile");
}
@ -101,7 +104,7 @@ pub fn trap_return() -> ! {
#[no_mangle]
pub fn trap_from_kernel() -> ! {
panic!("a trap from kernel!");
panic!("a trap {:?} from kernel!", scause::read().cause());
}
pub use context::{TrapContext};

View File

@ -12,7 +12,7 @@ const DL: u8 = 0x7fu8;
const BS: u8 = 0x08u8;
use alloc::string::String;
use user_lib::{fork, exec, wait};
use user_lib::{fork, exec, waitpid, yield_};
use user_lib::console::getchar;
#[no_mangle]
@ -37,8 +37,17 @@ pub fn main() -> i32 {
unreachable!();
} else {
let mut xstate: i32 = 0;
wait(&mut xstate);
let mut exit_pid: isize = 0;
loop {
exit_pid = waitpid(pid as usize, &mut xstate);
if exit_pid == -1 {
yield_();
} else {
assert_eq!(pid, exit_pid);
println!("Shell: Process {} exited with code {}", pid, xstate);
break;
}
}
}
line.clear();
}

View File

@ -42,7 +42,7 @@ fn main() -> i32 {
pub fn read(fd: usize, buf: &mut [u8]) -> isize { sys_read(fd, buf) }
pub fn write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) }
pub fn exit(xstate: i32) -> ! { sys_exit(xstate); }
pub fn exit(exit_code: i32) -> ! { sys_exit(exit_code); }
pub fn yield_() -> isize { sys_yield() }
pub fn get_time() -> isize { sys_get_time() }
pub fn getpid() -> isize { sys_getpid() }

View File

@ -29,8 +29,8 @@ pub fn sys_write(fd: usize, buffer: &[u8]) -> isize {
syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()])
}
pub fn sys_exit(xstate: i32) -> ! {
syscall(SYSCALL_EXIT, [xstate as usize, 0, 0]);
pub fn sys_exit(exit_code: i32) -> ! {
syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0]);
panic!("sys_exit never returns!");
}