|
|
|
@ -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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|