mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 01:16:26 +04:00
Implement many process syscalls.
This commit is contained in:
parent
81bef97f09
commit
3642f9c56d
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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!");
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
@ -150,4 +170,28 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&
|
||||
start = end_va.into();
|
||||
}
|
||||
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()
|
||||
}
|
@ -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;
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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!");
|
||||
}
|
||||
@ -17,4 +36,60 @@ 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
|
||||
}
|
@ -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()
|
||||
}
|
@ -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)));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
task_cx_ptr: task_cx_ptr as usize,
|
||||
task_status,
|
||||
memory_set,
|
||||
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,
|
||||
}
|
@ -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],
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
println!("Shell: Process {} exited with code {}", pid, 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();
|
||||
}
|
||||
|
@ -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() }
|
||||
|
@ -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!");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user