1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-27 02:03:29 +04:00
rCore/src/process/process.rs

194 lines
6.3 KiB
Rust
Raw Normal View History

use super::*;
use memory::{self, Stack, InactivePageTable, MemoryAttr};
use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}, header::HeaderPt2};
use core::slice;
use alloc::{rc::Rc, String};
2018-05-22 19:48:39 +04:00
use arch::interrupt::*;
#[derive(Debug)]
pub struct Process {
pub(in process) pid: Pid,
2018-05-19 12:32:18 +04:00
pub(in process) parent: Pid,
pub(in process) name: String,
pub(in process) memory_set: MemorySet,
pub(in process) status: Status,
2018-06-02 16:49:09 +04:00
pub(in process) context: Context,
pub(in process) is_user: bool,
}
pub type Pid = usize;
2018-05-19 12:32:18 +04:00
pub type ErrorCode = usize;
2018-05-23 07:20:36 +04:00
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Status {
2018-05-19 12:32:18 +04:00
Ready,
Running,
Waiting(Pid),
Sleeping,
2018-05-19 12:32:18 +04:00
Exited(ErrorCode),
}
impl Process {
/// Make a new kernel thread
pub fn new(name: &str, entry: extern fn(usize) -> !, arg: usize) -> Self {
let ms = MemorySet::new(7);
let data = InitStack::new_kernel_thread(entry, arg, ms.kstack_top());
let context = unsafe { data.push_at(ms.kstack_top()) };
Process {
pid: 0,
2018-05-19 12:32:18 +04:00
parent: 0,
name: String::from(name),
memory_set: ms,
status: Status::Ready,
2018-06-02 16:49:09 +04:00
context,
is_user: false,
}
}
2018-05-13 11:06:44 +04:00
/// Make the first kernel thread `initproc`
/// Should be called only once
pub fn new_init(ms: MemorySet) -> Self {
assert_has_not_been_called!();
Process {
pid: 0,
2018-05-19 12:32:18 +04:00
parent: 0,
name: String::from("init"),
memory_set: ms,
status: Status::Running,
2018-06-02 16:49:09 +04:00
context: unsafe { Context::null() }, // will be set at first schedule
is_user: false,
}
}
2018-05-13 11:06:44 +04:00
/// Make a new user thread
/// The program elf data is placed at [begin, end)
2018-05-17 17:06:13 +04:00
/// uCore x86 32bit program is planned to be supported.
pub fn new_user(data: &[u8]) -> Self {
// Parse elf
let begin = data.as_ptr() as usize;
let elf = ElfFile::new(data).expect("failed to read elf");
2018-05-17 17:06:13 +04:00
let is32 = match elf.header.pt2 {
HeaderPt2::Header32(_) => true,
HeaderPt2::Header64(_) => false,
};
// User stack
use consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER_TCB_OFFSET};
2018-05-19 12:32:18 +04:00
let (user_stack_buttom, user_stack_top) = match is32 {
2018-05-17 17:06:13 +04:00
true => (USER_TCB_OFFSET, USER_TCB_OFFSET + USER_STACK_SIZE),
false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE),
};
// Make page table
let mut memory_set = MemorySet::from(&elf);
memory_set.push(MemoryArea::new(user_stack_buttom, user_stack_top, MemoryAttr::default().user(), "user_stack"));
trace!("{:#x?}", memory_set);
2018-05-17 17:06:13 +04:00
let entry_addr = match elf.header.pt2 {
HeaderPt2::Header32(header) => header.entry_point as usize,
HeaderPt2::Header64(header) => header.entry_point as usize,
};
// Temporary switch to it, in order to copy data
memory_set.with(|| {
for ph in elf.program_iter() {
2018-05-17 17:06:13 +04:00
let (virt_addr, offset, file_size) = match ph {
ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.offset as usize, ph.file_size as usize),
ProgramHeader::Ph64(ph) => (ph.virtual_addr as usize, ph.offset as usize, ph.file_size as usize),
};
let target = unsafe { slice::from_raw_parts_mut(virt_addr as *mut u8, file_size) };
target.copy_from_slice(&data[offset..offset + file_size]);
2018-05-17 17:06:13 +04:00
}
if is32 {
unsafe {
// TODO: full argc & argv
*(user_stack_top as *mut u32).offset(-1) = 0; // argv
*(user_stack_top as *mut u32).offset(-2) = 0; // argc
}
}
});
// Allocate kernel stack and push trap frame
2018-06-02 16:49:09 +04:00
let data = InitStack::new_user_thread(entry_addr, user_stack_top - 8, is32);
let context = unsafe { data.push_at(memory_set.kstack_top()) };
Process {
pid: 0,
2018-05-19 12:32:18 +04:00
parent: 0,
name: String::new(),
memory_set,
status: Status::Ready,
2018-06-02 16:49:09 +04:00
context,
is_user: true,
}
}
2018-05-13 11:06:44 +04:00
/// Fork
pub fn fork(&self, tf: &TrapFrame) -> Self {
2018-05-13 11:06:44 +04:00
assert!(self.is_user);
// Clone memory set, make a new page table
let memory_set = self.memory_set.clone(7);
// Copy data to temp space
use alloc::Vec;
let datas: Vec<Vec<u8>> = memory_set.iter().map(|area| {
Vec::from(unsafe { area.as_slice() })
}).collect();
// Temporary switch to it, in order to copy data
memory_set.with(|| {
for (area, data) in memory_set.iter().zip(datas.iter()) {
unsafe { area.as_slice_mut() }.copy_from_slice(data.as_slice())
}
});
// Allocate kernel stack and push trap frame
2018-05-22 19:48:39 +04:00
let data = InitStack::new_fork(tf);
let context = unsafe { data.push_at(memory_set.kstack_top()) };
Process {
pid: 0,
2018-05-19 12:32:18 +04:00
parent: self.pid,
name: self.name.clone() + "_fork",
memory_set,
status: Status::Ready,
2018-06-02 16:49:09 +04:00
context,
is_user: true,
}
2018-05-13 11:06:44 +04:00
}
2018-05-19 12:32:18 +04:00
pub fn exit_code(&self) -> Option<ErrorCode> {
match self.status {
Status::Exited(code) => Some(code),
_ => None,
}
}
}
use memory::{MemorySet, MemoryArea, PhysAddr, FromToVirtualAddress, EntryFlags};
impl<'a> From<&'a ElfFile<'a>> for MemorySet {
fn from(elf: &'a ElfFile<'a>) -> Self {
let mut set = MemorySet::new(7);
for ph in elf.program_iter() {
2018-05-17 17:06:13 +04:00
let (virt_addr, mem_size, flags) = match ph {
ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),
ProgramHeader::Ph64(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),
};
set.push(MemoryArea::new(virt_addr, virt_addr + mem_size, MemoryAttr::from(flags), ""));
}
set
}
}
impl From<Flags> for MemoryAttr {
fn from(elf_flags: Flags) -> Self {
let mut flags = MemoryAttr::default().user();
2018-05-17 17:06:13 +04:00
// TODO: handle readonly
if elf_flags.is_execute() { flags = flags.execute(); }
flags
}
}