mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-25 17:33:28 +04:00
fix last commit. improve process code.
This commit is contained in:
parent
e3fb47a03e
commit
6923efd250
@ -1,3 +1,10 @@
|
||||
# Commands:
|
||||
# make build Build
|
||||
# make run Build and run in QEMU
|
||||
# make justrun Run the last build
|
||||
# make doc Generate docs
|
||||
# make asm Open the deassemble file of the last build
|
||||
# make header Open 'objdump -h' of the last build
|
||||
# make addr2line Use addr2line to recover line info in backtrace
|
||||
# make clean Clean
|
||||
#
|
||||
|
@ -3,7 +3,7 @@ use core::fmt;
|
||||
|
||||
use log::*;
|
||||
use spin::{Mutex, RwLock};
|
||||
use xmas_elf::{ElfFile, header, program::{Flags, Type}};
|
||||
use xmas_elf::{ElfFile, header, program::{Flags, Type, SegmentData}};
|
||||
use rcore_memory::PAGE_SIZE;
|
||||
use rcore_thread::Tid;
|
||||
use core::str;
|
||||
@ -183,51 +183,41 @@ impl Thread {
|
||||
pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<Thread>
|
||||
where Iter: Iterator<Item=&'a str>
|
||||
{
|
||||
// Parse elf
|
||||
// Parse ELF
|
||||
let elf = ElfFile::new(data).expect("failed to read elf");
|
||||
let is32 = match elf.header.pt2 {
|
||||
header::HeaderPt2::Header32(_) => true,
|
||||
header::HeaderPt2::Header64(_) => false,
|
||||
};
|
||||
|
||||
// Check ELF type
|
||||
match elf.header.pt2.type_().as_type() {
|
||||
header::Type::Executable => {
|
||||
// panic!("ELF is not shared object");
|
||||
},
|
||||
header::Type::Executable => {},
|
||||
header::Type::SharedObject => {},
|
||||
_ => panic!("ELF is not executable or shared object"),
|
||||
}
|
||||
|
||||
if let Some(interp) = elf.program_iter().filter(|ph| ph.get_type() == Ok(Type::Interp)).next() {
|
||||
let offset = interp.offset() as usize;
|
||||
let size = interp.file_size() as usize - 1; // skip last '\0'
|
||||
if offset + size < data.len() {
|
||||
if let Ok(loader_path) = str::from_utf8(&data[offset..(offset+size)]) {
|
||||
// assuming absolute path
|
||||
if let Ok(inode) = crate::fs::ROOT_INODE.lookup_follow(&loader_path[1..], FOLLOW_MAX_DEPTH) {
|
||||
if let Ok(buf) = inode.read_as_vec() {
|
||||
debug!("using loader {}", &loader_path);
|
||||
// Elf loader should not have INTERP
|
||||
// No infinite loop
|
||||
let mut new_args: Vec<&str> = args.collect();
|
||||
new_args.insert(0, loader_path);
|
||||
return Thread::new_user(buf.as_slice(), new_args.into_iter());
|
||||
} else {
|
||||
warn!("loader specified as {} but failed to read", &loader_path);
|
||||
}
|
||||
} else {
|
||||
warn!("loader specified as {} but not found", &loader_path);
|
||||
}
|
||||
// Check interpreter
|
||||
if let Ok(loader_path) = elf.get_interpreter() {
|
||||
// assuming absolute path
|
||||
if let Ok(inode) = crate::fs::ROOT_INODE.lookup_follow(&loader_path[1..], FOLLOW_MAX_DEPTH) {
|
||||
if let Ok(buf) = inode.read_as_vec() {
|
||||
debug!("using loader {}", &loader_path);
|
||||
// Elf loader should not have INTERP
|
||||
// No infinite loop
|
||||
let mut new_args: Vec<&str> = args.collect();
|
||||
new_args.insert(0, loader_path);
|
||||
return Thread::new_user(buf.as_slice(), new_args.into_iter());
|
||||
} else {
|
||||
warn!("loader specified but not found");
|
||||
warn!("loader specified as {} but failed to read", &loader_path);
|
||||
}
|
||||
} else {
|
||||
warn!("loader specified but invalid");
|
||||
warn!("loader specified as {} but not found", &loader_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Make page table
|
||||
let (mut vm, entry_addr) = memory_set_from(&elf);
|
||||
let mut vm = elf.make_memory_set();
|
||||
|
||||
// User stack
|
||||
use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET};
|
||||
@ -240,20 +230,14 @@ impl Thread {
|
||||
ustack_top
|
||||
};
|
||||
|
||||
// Make init info
|
||||
let init_info = ProcInitInfo {
|
||||
args: args.map(|s| String::from(s)).collect(),
|
||||
envs: BTreeMap::new(),
|
||||
auxv: {
|
||||
let mut map = BTreeMap::new();
|
||||
if let Some(phdr) = elf.program_iter()
|
||||
.find(|ph| ph.get_type() == Ok(Type::Phdr)) {
|
||||
// if phdr exists in program header, use it
|
||||
map.insert(abi::AT_PHDR, phdr.virtual_addr() as usize);
|
||||
} else if let Some(elf_addr) = elf.program_iter().find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) {
|
||||
// otherwise, check if elf is loaded from the beginning, then phdr can be inferred.
|
||||
map.insert(abi::AT_PHDR, elf_addr.virtual_addr() as usize + elf.header.pt2.ph_offset() as usize);
|
||||
} else {
|
||||
warn!("new_user: no phdr found, tls might not work");
|
||||
if let Some(phdr_vaddr) = elf.get_phdr_vaddr() {
|
||||
map.insert(abi::AT_PHDR, phdr_vaddr as usize);
|
||||
}
|
||||
map.insert(abi::AT_PHENT, elf.header.pt2.ph_entry_size() as usize);
|
||||
map.insert(abi::AT_PHNUM, elf.header.pt2.ph_count() as usize);
|
||||
@ -274,6 +258,8 @@ impl Thread {
|
||||
files.insert(1, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })));
|
||||
files.insert(2, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })));
|
||||
|
||||
let entry_addr = elf.header.pt2.entry_point() as usize;
|
||||
|
||||
Box::new(Thread {
|
||||
context: unsafe {
|
||||
Context::new_user_thread(
|
||||
@ -299,9 +285,11 @@ impl Thread {
|
||||
/// Fork a new process from current one
|
||||
pub fn fork(&self, tf: &TrapFrame) -> Box<Thread> {
|
||||
// Clone memory set, make a new page table
|
||||
let vm = self.proc.lock().vm.clone();
|
||||
let files = self.proc.lock().files.clone();
|
||||
let cwd = self.proc.lock().cwd.clone();
|
||||
let proc = self.proc.lock();
|
||||
let vm = proc.vm.clone();
|
||||
let files = proc.files.clone();
|
||||
let cwd = proc.cwd.clone();
|
||||
drop(proc);
|
||||
let parent = Some(self.proc.clone());
|
||||
debug!("fork: finish clone MemorySet");
|
||||
|
||||
@ -324,7 +312,6 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Box::new(Thread {
|
||||
context: unsafe { Context::new_fork(tf, kstack.top(), vm.token()) },
|
||||
kstack,
|
||||
@ -376,50 +363,6 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Generate a MemorySet according to the ELF file.
|
||||
/// Also return the real entry point address.
|
||||
fn memory_set_from(elf: &ElfFile<'_>) -> (MemorySet, usize) {
|
||||
debug!("creating MemorySet from ELF");
|
||||
let mut ms = MemorySet::new();
|
||||
let entry = elf.header.pt2.entry_point() as usize;
|
||||
|
||||
// [NoMMU] Get total memory size and alloc space
|
||||
let va_begin = elf.program_iter()
|
||||
.filter(|ph| ph.get_type() == Ok(Type::Load))
|
||||
.map(|ph| ph.virtual_addr()).min().unwrap() as usize;
|
||||
let va_end = elf.program_iter()
|
||||
.filter(|ph| ph.get_type() == Ok(Type::Load))
|
||||
.map(|ph| ph.virtual_addr() + ph.mem_size()).max().unwrap() as usize;
|
||||
let va_size = va_end - va_begin;
|
||||
|
||||
for ph in elf.program_iter() {
|
||||
if ph.get_type() != Ok(Type::Load) {
|
||||
continue;
|
||||
}
|
||||
let virt_addr = ph.virtual_addr() as usize;
|
||||
let offset = ph.offset() as usize;
|
||||
let file_size = ph.file_size() as usize;
|
||||
let mem_size = ph.mem_size() as usize;
|
||||
|
||||
// Get target slice
|
||||
let target = {
|
||||
ms.push(virt_addr, virt_addr + mem_size, ph.flags().to_attr(), ByFrame::new(GlobalFrameAlloc), "");
|
||||
unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }
|
||||
};
|
||||
// Copy data
|
||||
unsafe {
|
||||
ms.with(|| {
|
||||
if file_size != 0 {
|
||||
target[..file_size].copy_from_slice(&elf.input[offset..offset + file_size]);
|
||||
}
|
||||
target[file_size..].iter_mut().for_each(|x| *x = 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
(ms, entry)
|
||||
}
|
||||
|
||||
trait ToMemoryAttr {
|
||||
fn to_attr(&self) -> MemoryAttr;
|
||||
}
|
||||
@ -432,3 +375,78 @@ impl ToMemoryAttr for Flags {
|
||||
flags
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper functions to process ELF file
|
||||
trait ElfExt {
|
||||
/// Generate a MemorySet according to the ELF file.
|
||||
fn make_memory_set(&self) -> MemorySet;
|
||||
|
||||
/// Get interpreter string if it has.
|
||||
fn get_interpreter(&self) -> Result<&str, &str>;
|
||||
|
||||
/// Get virtual address of PHDR section if it has.
|
||||
fn get_phdr_vaddr(&self) -> Option<u64>;
|
||||
}
|
||||
|
||||
impl ElfExt for ElfFile<'_> {
|
||||
fn make_memory_set(&self) -> MemorySet {
|
||||
debug!("creating MemorySet from ELF");
|
||||
let mut ms = MemorySet::new();
|
||||
|
||||
for ph in self.program_iter() {
|
||||
if ph.get_type() != Ok(Type::Load) {
|
||||
continue;
|
||||
}
|
||||
let virt_addr = ph.virtual_addr() as usize;
|
||||
let mem_size = ph.mem_size() as usize;
|
||||
let data = match ph.get_data(self).unwrap() {
|
||||
SegmentData::Undefined(data) => data,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// Get target slice
|
||||
let target = {
|
||||
ms.push(virt_addr, virt_addr + mem_size, ph.flags().to_attr(), ByFrame::new(GlobalFrameAlloc), "");
|
||||
unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }
|
||||
};
|
||||
// Copy data
|
||||
unsafe {
|
||||
ms.with(|| {
|
||||
if data.len() != 0 {
|
||||
target[..data.len()].copy_from_slice(data);
|
||||
}
|
||||
target[data.len()..].iter_mut().for_each(|x| *x = 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
ms
|
||||
}
|
||||
|
||||
fn get_interpreter(&self) -> Result<&str, &str> {
|
||||
let header = self.program_iter()
|
||||
.filter(|ph| ph.get_type() == Ok(Type::Interp))
|
||||
.next().ok_or("no interp header")?;
|
||||
let data = match header.get_data(self)? {
|
||||
SegmentData::Undefined(data) => data,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let path = str::from_utf8(data)
|
||||
.map_err(|_| "failed to convert to utf8")?;
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn get_phdr_vaddr(&self) -> Option<u64> {
|
||||
if let Some(phdr) = self.program_iter()
|
||||
.find(|ph| ph.get_type() == Ok(Type::Phdr)) {
|
||||
// if phdr exists in program header, use it
|
||||
Some(phdr.virtual_addr())
|
||||
} else if let Some(elf_addr) = self.program_iter()
|
||||
.find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) {
|
||||
// otherwise, check if elf is loaded from the beginning, then phdr can be inferred.
|
||||
Some(elf_addr.virtual_addr() + self.header.pt2.ph_offset())
|
||||
} else {
|
||||
warn!("elf: no phdr found, tls might not work");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user