mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 02:43:24 +00:00
load elf from file
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
57297e0cd5
commit
896910b44a
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c04094e4c0da36e9f8cc5059f540dbc2123d5e4caa1d0b7427577ee734710b23
|
||||
oid sha256:c7cc90df87ade7ff2cb494e13678aceaf93542883558fda947bd2fc01e2d73a6
|
||||
size 871952
|
||||
|
@ -4,10 +4,11 @@
|
||||
int main() {
|
||||
char* argv[] = { "argv1", "argv2", NULL };
|
||||
char* envp[] = { "home=/", "version=1.1", NULL };
|
||||
printf("Execve a new file ./hello:\n");
|
||||
// The hello will be put at /execve/hello in InitRamfs
|
||||
printf("Execve a new file /execve/hello:\n");
|
||||
// flush the stdout content to ensure the content print to console
|
||||
fflush(stdout);
|
||||
execve("./hello", argv, envp);
|
||||
execve("/execve/hello", argv, envp);
|
||||
printf("Should not print\n");
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
|
@ -6,7 +6,6 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
}
|
||||
|
||||
fn limine_build_script() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
|
||||
// Have cargo rerun this script if the linker script or CARGO_PKG_ENV changes.
|
||||
println!("cargo:rerun-if-changed=boot/limine/conf/linker.ld");
|
||||
println!("cargo:rerun-if-env-changed=CARGO_PKG_NAME");
|
||||
|
@ -67,18 +67,31 @@ pub fn init_thread() {
|
||||
"[jinux-std/lib.rs] spawn kernel thread, tid = {}",
|
||||
thread.tid()
|
||||
);
|
||||
|
||||
|
||||
// FIXME: should be running this apps before we running shell?
|
||||
println!("");
|
||||
println!("[kernel] Running test programs");
|
||||
println!("");
|
||||
// Run test apps
|
||||
for app in get_all_apps().unwrap().into_iter() {
|
||||
let UserApp {
|
||||
executable_path: app_name,
|
||||
argv,
|
||||
envp,
|
||||
} = app;
|
||||
println!("[jinux-std/lib.rs] spwan {:?} process", app_name);
|
||||
Process::spawn_user_process(app_name.clone(), argv, Vec::new());
|
||||
}
|
||||
|
||||
// Run busybox ash
|
||||
let UserApp {
|
||||
elf_path: app_name,
|
||||
app_content,
|
||||
executable_path: app_name,
|
||||
argv,
|
||||
envp,
|
||||
} = get_busybox_app().unwrap();
|
||||
let app_content = app_content.into_boxed_slice();
|
||||
println!("");
|
||||
println!("BusyBox v1.35.0 built-in shell (ash)\n");
|
||||
Process::spawn_user_process(app_name.clone(), Box::leak(app_content), argv, Vec::new());
|
||||
Process::spawn_user_process(app_name.clone(), argv, Vec::new());
|
||||
|
||||
loop {
|
||||
// We don't have preemptive scheduler now.
|
||||
|
@ -6,6 +6,8 @@ pub(crate) use alloc::collections::BTreeSet;
|
||||
pub(crate) use alloc::collections::LinkedList;
|
||||
pub(crate) use alloc::collections::VecDeque;
|
||||
pub(crate) use alloc::ffi::CString;
|
||||
pub(crate) use alloc::string::String;
|
||||
pub(crate) use alloc::string::ToString;
|
||||
pub(crate) use alloc::sync::Arc;
|
||||
pub(crate) use alloc::sync::Weak;
|
||||
pub(crate) use alloc::vec;
|
||||
|
@ -218,8 +218,8 @@ fn clone_child_process(parent_context: CpuContext, clone_args: CloneArgs) -> Res
|
||||
// clone system V semaphore
|
||||
clone_sysvsem(clone_flags)?;
|
||||
|
||||
let child_elf_path = current.filename().unwrap().clone();
|
||||
let child_thread_name = ThreadName::new_from_elf_path(&child_elf_path)?;
|
||||
let child_elf_path = current.executable_path().unwrap().clone();
|
||||
let child_thread_name = ThreadName::new_from_executable_path(&child_elf_path)?;
|
||||
|
||||
// inherit parent's sig mask
|
||||
let current_thread = current_thread!();
|
||||
|
@ -45,6 +45,42 @@ impl Elf {
|
||||
program_headers,
|
||||
})
|
||||
}
|
||||
|
||||
// The following info is used to setup init stack
|
||||
/// the entry point of the elf
|
||||
pub fn entry_point(&self) -> Vaddr {
|
||||
self.elf_header.pt2.entry_point as Vaddr
|
||||
}
|
||||
/// page header table offset
|
||||
pub fn ph_off(&self) -> u64 {
|
||||
self.elf_header.pt2.ph_offset
|
||||
}
|
||||
/// number of program headers
|
||||
pub fn ph_count(&self) -> u16 {
|
||||
self.elf_header.pt2.ph_count
|
||||
}
|
||||
/// The size of a program header
|
||||
pub fn ph_ent(&self) -> u16 {
|
||||
self.elf_header.pt2.ph_entry_size
|
||||
}
|
||||
|
||||
/// The virtual addr of program headers table address
|
||||
pub fn ph_addr(&self) -> Result<Vaddr> {
|
||||
let ph_offset = self.ph_off();
|
||||
for program_header in &self.program_headers {
|
||||
if program_header.offset <= ph_offset
|
||||
&& ph_offset < program_header.offset + program_header.file_size
|
||||
{
|
||||
return Ok(
|
||||
(ph_offset - program_header.offset + program_header.virtual_addr) as Vaddr,
|
||||
);
|
||||
}
|
||||
}
|
||||
return_errno_with_message!(
|
||||
Errno::ENOEXEC,
|
||||
"can not find program header table address in elf"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ElfHeader {
|
||||
|
@ -1,36 +1,47 @@
|
||||
use core::ops::Range;
|
||||
|
||||
use crate::fs::file_handle::FileHandle;
|
||||
use crate::fs::utils::SeekFrom;
|
||||
use crate::prelude::*;
|
||||
use crate::vm::vmar::{get_intersected_range, is_intersected};
|
||||
use jinux_frame::vm::{VmAllocOptions, VmFrameVec, VmIo};
|
||||
use jinux_frame::AlignExt;
|
||||
use xmas_elf::program::ProgramHeader64;
|
||||
|
||||
use crate::vm::vmo::Pager;
|
||||
|
||||
use super::load_elf::ElfSegment;
|
||||
// use super::load_elf::ElfSegment;
|
||||
|
||||
/// The pager behind a elf segment
|
||||
pub struct ElfSegmentPager {
|
||||
/// The pager size
|
||||
pager_size: usize,
|
||||
/// data for current segment
|
||||
segment_data: &'static [u8],
|
||||
/// the back up file
|
||||
file: Arc<FileHandle>,
|
||||
/// The segment offset in backup file
|
||||
file_offset: usize,
|
||||
/// The segment size in backup file
|
||||
file_size: usize,
|
||||
/// The offset for the segment data.
|
||||
/// The pager always starts at page-align address, while the segment data may start at any address.
|
||||
/// So the offset will be the segment data start address % PAGE_SIZE
|
||||
offset: usize,
|
||||
page_offset: usize,
|
||||
}
|
||||
|
||||
impl ElfSegmentPager {
|
||||
pub fn new(elf_file_content: &'static [u8], elf_segment: &ElfSegment) -> Self {
|
||||
let start = elf_segment.start_address().align_down(PAGE_SIZE);
|
||||
let end = elf_segment.end_address().align_up(PAGE_SIZE);
|
||||
pub fn new(file: Arc<FileHandle>, program_header: &ProgramHeader64) -> Self {
|
||||
let ph_start = program_header.virtual_addr as Vaddr;
|
||||
let ph_end = ph_start + program_header.mem_size as Vaddr;
|
||||
let start = ph_start.align_down(PAGE_SIZE);
|
||||
let end = ph_end.align_up(PAGE_SIZE);
|
||||
let pager_size = end - start;
|
||||
let offset = elf_segment.start_address() % PAGE_SIZE;
|
||||
let elf_file_segment =
|
||||
&elf_file_content[elf_segment.offset..elf_segment.offset + elf_segment.file_size];
|
||||
let offset = ph_start % PAGE_SIZE;
|
||||
Self {
|
||||
pager_size,
|
||||
segment_data: elf_file_segment,
|
||||
offset,
|
||||
file,
|
||||
file_offset: program_header.offset as usize,
|
||||
file_size: program_header.file_size as usize,
|
||||
page_offset: offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -40,21 +51,28 @@ impl Pager for ElfSegmentPager {
|
||||
if offset >= self.pager_size {
|
||||
return_errno_with_message!(Errno::EINVAL, "offset exceeds pager size");
|
||||
}
|
||||
|
||||
let vm_alloc_option = VmAllocOptions::new(1);
|
||||
let mut vm_frames = VmFrameVec::allocate(&vm_alloc_option)?;
|
||||
vm_frames.zero();
|
||||
|
||||
let page_start = offset.align_down(PAGE_SIZE);
|
||||
let page_end = page_start + PAGE_SIZE;
|
||||
let page_range = page_start..page_end;
|
||||
let data_range = self.offset..self.offset + self.segment_data.len();
|
||||
if is_intersected(&page_range, &data_range) {
|
||||
let intersected_range = get_intersected_range(&page_range, &data_range);
|
||||
let data_write_range =
|
||||
(intersected_range.start - self.offset)..(intersected_range.end - self.offset);
|
||||
let write_content = &self.segment_data[data_write_range];
|
||||
let segment_range = self.page_offset..self.page_offset + self.file_size;
|
||||
if is_intersected(&page_range, &segment_range) {
|
||||
let intersected_range = get_intersected_range(&page_range, &segment_range);
|
||||
let segment_from_file_range = (intersected_range.start - self.page_offset)
|
||||
..(intersected_range.end - self.page_offset);
|
||||
let mut segment_data = vec![0u8; segment_from_file_range.len()];
|
||||
self.file.seek(SeekFrom::Start(
|
||||
self.file_offset + segment_from_file_range.start,
|
||||
))?;
|
||||
self.file.read(&mut segment_data)?;
|
||||
let write_offset = intersected_range.start % PAGE_SIZE;
|
||||
vm_frames.write_bytes(write_offset, write_content)?;
|
||||
vm_frames.write_bytes(write_offset, &segment_data)?;
|
||||
}
|
||||
|
||||
let vm_frame = vm_frames.pop().unwrap();
|
||||
Ok(vm_frame)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use jinux_frame::{
|
||||
};
|
||||
|
||||
use super::aux_vec::{AuxKey, AuxVec};
|
||||
use super::load_elf::ElfHeaderInfo;
|
||||
use super::elf_file::Elf;
|
||||
|
||||
pub const INIT_STACK_BASE: Vaddr = 0x0000_0000_2000_0000;
|
||||
pub const INIT_STACK_SIZE: usize = 0x1000 * 16; // 64KB
|
||||
@ -79,7 +79,6 @@ pub struct InitStack {
|
||||
impl InitStack {
|
||||
/// initialize user stack on base addr
|
||||
pub fn new(
|
||||
// filename: CString,
|
||||
init_stack_top: Vaddr,
|
||||
init_stack_size: usize,
|
||||
argv: Vec<CString>,
|
||||
@ -115,14 +114,9 @@ impl InitStack {
|
||||
self.init_stack_top - self.init_stack_size
|
||||
}
|
||||
|
||||
pub fn init(
|
||||
&mut self,
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf_header_info: &ElfHeaderInfo,
|
||||
ph_addr: Vaddr,
|
||||
) -> Result<()> {
|
||||
pub fn init(&mut self, root_vmar: &Vmar<Full>, elf: &Elf) -> Result<()> {
|
||||
self.map_and_zeroed(root_vmar)?;
|
||||
self.write_stack_content(root_vmar, elf_header_info, ph_addr)?;
|
||||
self.write_stack_content(root_vmar, elf)?;
|
||||
self.debug_print_stack_content(root_vmar);
|
||||
Ok(())
|
||||
}
|
||||
@ -161,12 +155,7 @@ impl InitStack {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_stack_content(
|
||||
&mut self,
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf_header_info: &ElfHeaderInfo,
|
||||
ph_addr: Vaddr,
|
||||
) -> Result<()> {
|
||||
fn write_stack_content(&mut self, root_vmar: &Vmar<Full>, elf: &Elf) -> Result<()> {
|
||||
// write envp string
|
||||
let envp_pointers = self.write_envp_strings(root_vmar)?;
|
||||
// write argv string
|
||||
@ -176,11 +165,9 @@ impl InitStack {
|
||||
let random_value_pointer = self.write_bytes(&random_value, root_vmar)?;
|
||||
self.aux_vec.set(AuxKey::AT_RANDOM, random_value_pointer)?;
|
||||
self.aux_vec.set(AuxKey::AT_PAGESZ, PAGE_SIZE as _)?;
|
||||
self.aux_vec.set(AuxKey::AT_PHDR, ph_addr as u64)?;
|
||||
self.aux_vec
|
||||
.set(AuxKey::AT_PHNUM, elf_header_info.ph_num as u64)?;
|
||||
self.aux_vec
|
||||
.set(AuxKey::AT_PHENT, elf_header_info.ph_ent as u64)?;
|
||||
self.aux_vec.set(AuxKey::AT_PHDR, elf.ph_addr()? as u64)?;
|
||||
self.aux_vec.set(AuxKey::AT_PHNUM, elf.ph_count() as u64)?;
|
||||
self.aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?;
|
||||
self.adjust_stack_alignment(root_vmar, &envp_pointers, &argv_pointers)?;
|
||||
self.write_aux_vec(root_vmar)?;
|
||||
self.write_envp_pointers(root_vmar, envp_pointers)?;
|
||||
|
@ -1,6 +1,8 @@
|
||||
//! This module is used to parse elf file content to get elf_load_info.
|
||||
//! When create a process from elf file, we will use the elf_load_info to construct the VmSpace
|
||||
|
||||
use crate::fs::file_handle::FileHandle;
|
||||
use crate::process::elf::init_stack::InitStack;
|
||||
use crate::vm::perms::VmPerms;
|
||||
use crate::vm::vmo::VmoRightsOp;
|
||||
use crate::{
|
||||
@ -17,234 +19,102 @@ use xmas_elf::program::{self, ProgramHeader64};
|
||||
|
||||
use super::elf_file::Elf;
|
||||
use super::elf_segment_pager::ElfSegmentPager;
|
||||
use super::init_stack::InitStack;
|
||||
|
||||
/// load elf to the root vmar. this function will
|
||||
/// 1. read the vaddr of each segment to get all elf pages.
|
||||
/// 2. create a vmo for each elf segment, create a backup pager for each segment. Then map the vmo to the root vmar.
|
||||
/// 3. write proper content to the init stack.
|
||||
pub fn load_elf_to_root_vmar(
|
||||
file_header: &[u8],
|
||||
elf_file: Arc<FileHandle>,
|
||||
root_vmar: &Vmar<Full>,
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
) -> Result<ElfLoadInfo> {
|
||||
let elf = Elf::parse_elf(file_header)?;
|
||||
map_segment_vmos(&elf, root_vmar, elf_file)?;
|
||||
let mut init_stack = InitStack::new_default_config(argv, envp);
|
||||
init_stack.init(root_vmar, &elf)?;
|
||||
let elf_load_info = ElfLoadInfo::new(elf.entry_point(), init_stack.user_stack_top());
|
||||
debug!("load elf succeeds.");
|
||||
Ok(elf_load_info)
|
||||
}
|
||||
|
||||
pub struct ElfLoadInfo {
|
||||
segments: Vec<ElfSegment>,
|
||||
init_stack: InitStack,
|
||||
elf_header_info: ElfHeaderInfo,
|
||||
}
|
||||
|
||||
pub struct ElfSegment {
|
||||
/// The virtual addr where to put the segment.
|
||||
pub virtual_addr: Vaddr,
|
||||
/// The segment's size in memory, in bytes.
|
||||
pub mem_size: usize,
|
||||
/// The segment's offset in origin elf file
|
||||
pub offset: usize,
|
||||
/// The size the segment has in origin elf file, in bytes
|
||||
pub file_size: usize,
|
||||
type_: program::Type,
|
||||
vm_perm: VmPerm,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
/// Info parsed from elf header. The entry point is used to set rip
|
||||
/// The other info is used to set auxv vectors.
|
||||
pub struct ElfHeaderInfo {
|
||||
/// the entry point of the elf
|
||||
pub entry_point: Vaddr,
|
||||
/// page header table offset
|
||||
pub ph_off: u64,
|
||||
/// number of program headers
|
||||
pub ph_num: u16,
|
||||
/// The size of a program header
|
||||
pub ph_ent: u16,
|
||||
}
|
||||
|
||||
impl ElfSegment {
|
||||
fn parse_elf_segment(program_header: ProgramHeader64) -> Result<Self> {
|
||||
let start = program_header.virtual_addr as Vaddr;
|
||||
let end = start + program_header.mem_size as Vaddr;
|
||||
let type_ = program_header
|
||||
.get_type()
|
||||
.map_err(|_| Error::new(Errno::ENOEXEC))?;
|
||||
let vm_perm = Self::parse_segment_perm(program_header.flags)?;
|
||||
Ok(Self {
|
||||
virtual_addr: program_header.virtual_addr as _,
|
||||
mem_size: program_header.mem_size as usize,
|
||||
offset: program_header.offset as usize,
|
||||
file_size: program_header.file_size as usize,
|
||||
type_,
|
||||
vm_perm,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_segment_perm(flags: xmas_elf::program::Flags) -> Result<VmPerm> {
|
||||
if !flags.is_read() {
|
||||
return_errno_with_message!(Errno::ENOEXEC, "unreadable segment");
|
||||
}
|
||||
let mut vm_perm = VmPerm::R;
|
||||
if flags.is_write() {
|
||||
vm_perm |= VmPerm::W;
|
||||
}
|
||||
if flags.is_execute() {
|
||||
vm_perm |= VmPerm::X;
|
||||
}
|
||||
Ok(vm_perm)
|
||||
}
|
||||
|
||||
fn contains_program_headers_table(&self, ph_offset: usize) -> bool {
|
||||
// program headers table is at ph_offset of elf file
|
||||
self.offset <= ph_offset && ph_offset < self.offset + self.file_size
|
||||
}
|
||||
|
||||
/// If this segment contains ph table, then returns the ph table addr
|
||||
/// Otherwise, returns None
|
||||
pub fn program_headers_table_addr(&self, ph_offset: usize) -> Option<Vaddr> {
|
||||
if self.contains_program_headers_table(ph_offset) {
|
||||
Some(ph_offset - self.offset + self.virtual_addr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_loadable(&self) -> bool {
|
||||
self.type_ == program::Type::Load
|
||||
}
|
||||
|
||||
pub fn start_address(&self) -> Vaddr {
|
||||
self.virtual_addr
|
||||
}
|
||||
|
||||
pub fn end_address(&self) -> Vaddr {
|
||||
self.virtual_addr + self.mem_size
|
||||
}
|
||||
|
||||
pub fn init_segment_vmo(&self, elf_file_content: &'static [u8]) -> Vmo<Full> {
|
||||
let vmo_start = self.start_address().align_down(PAGE_SIZE);
|
||||
let vmo_end = self.end_address().align_up(PAGE_SIZE);
|
||||
let segment_len = vmo_end - vmo_start;
|
||||
let pager = Arc::new(ElfSegmentPager::new(elf_file_content, self)) as Arc<dyn Pager>;
|
||||
let vmo_alloc_options: VmoOptions<Full> = VmoOptions::new(segment_len).pager(pager);
|
||||
vmo_alloc_options.alloc().unwrap()
|
||||
}
|
||||
|
||||
// create vmo for each segment and map the segment to root_vmar
|
||||
fn map_segment_vmo(
|
||||
&self,
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf_file_content: &'static [u8],
|
||||
) -> Result<()> {
|
||||
let vmo = self.init_segment_vmo(elf_file_content).to_dyn();
|
||||
let perms = VmPerms::from(self.vm_perm);
|
||||
// The segment may not be aligned to page
|
||||
let offset = self.start_address().align_down(PAGE_SIZE);
|
||||
let vm_map_options = root_vmar.new_map(vmo, perms)?.offset(offset);
|
||||
let map_addr = vm_map_options.build()?;
|
||||
Ok(())
|
||||
}
|
||||
entry_point: Vaddr,
|
||||
user_stack_top: Vaddr,
|
||||
}
|
||||
|
||||
impl ElfLoadInfo {
|
||||
fn with_capacity(
|
||||
capacity: usize,
|
||||
init_stack: InitStack,
|
||||
elf_header_info: ElfHeaderInfo,
|
||||
) -> Self {
|
||||
pub fn new(entry_point: Vaddr, user_stack_top: Vaddr) -> Self {
|
||||
Self {
|
||||
segments: Vec::with_capacity(capacity),
|
||||
init_stack,
|
||||
elf_header_info,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_segment(&mut self, elf_segment: ElfSegment) {
|
||||
self.segments.push(elf_segment);
|
||||
}
|
||||
|
||||
pub fn parse_elf_data(
|
||||
elf_file_content: &'static [u8],
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
) -> Result<Self> {
|
||||
let elf_file = Elf::parse_elf(elf_file_content)?;
|
||||
// parse elf header
|
||||
let elf_header_info = ElfHeaderInfo::parse_elf_header(&elf_file);
|
||||
// FIXME: only contains load segment?
|
||||
let ph_count = elf_file.program_headers.len();
|
||||
let init_stack = InitStack::new_default_config(argv, envp);
|
||||
let mut elf_load_info = ElfLoadInfo::with_capacity(ph_count, init_stack, elf_header_info);
|
||||
|
||||
// parse each segemnt
|
||||
for program_header in elf_file.program_headers {
|
||||
let elf_segment = ElfSegment::parse_elf_segment(program_header)?;
|
||||
if elf_segment.is_loadable() {
|
||||
elf_load_info.add_segment(elf_segment)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(elf_load_info)
|
||||
}
|
||||
|
||||
/// init vmo for each segment and then map segment to root vmar
|
||||
pub fn map_segment_vmos(
|
||||
&self,
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf_file_content: &'static [u8],
|
||||
) -> Result<()> {
|
||||
for segment in &self.segments {
|
||||
segment.map_segment_vmo(root_vmar, elf_file_content)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init_stack(&mut self, root_vmar: &Vmar<Full>, file_content: &[u8]) -> Result<()> {
|
||||
let ph_addr = self.program_headers_table_addr()?;
|
||||
self.init_stack
|
||||
.init(root_vmar, &self.elf_header_info, ph_addr)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn program_headers_table_addr(&self) -> Result<Vaddr> {
|
||||
let ph_offset = self.elf_header_info.ph_off as usize;
|
||||
for segment in &self.segments {
|
||||
if let Some(ph_addr) = segment.program_headers_table_addr(ph_offset) {
|
||||
return Ok(ph_addr);
|
||||
}
|
||||
}
|
||||
return_errno_with_message!(
|
||||
Errno::ENOEXEC,
|
||||
"can not find program header table address in elf"
|
||||
);
|
||||
}
|
||||
|
||||
pub fn entry_point(&self) -> u64 {
|
||||
self.elf_header_info.entry_point as u64
|
||||
}
|
||||
|
||||
pub fn user_stack_top(&self) -> u64 {
|
||||
self.init_stack.user_stack_top() as u64
|
||||
}
|
||||
|
||||
pub fn argc(&self) -> u64 {
|
||||
self.init_stack.argc()
|
||||
}
|
||||
|
||||
pub fn argv(&self) -> u64 {
|
||||
self.init_stack.argv()
|
||||
}
|
||||
|
||||
pub fn envc(&self) -> u64 {
|
||||
self.init_stack.envc()
|
||||
}
|
||||
|
||||
pub fn envp(&self) -> u64 {
|
||||
self.init_stack.envp()
|
||||
}
|
||||
}
|
||||
|
||||
impl ElfHeaderInfo {
|
||||
fn parse_elf_header(elf_file: &Elf) -> Self {
|
||||
let entry_point = elf_file.elf_header.pt2.entry_point as Vaddr;
|
||||
let ph_off = elf_file.elf_header.pt2.ph_offset;
|
||||
let ph_num = elf_file.elf_header.pt2.ph_count;
|
||||
let ph_ent = elf_file.elf_header.pt2.ph_entry_size;
|
||||
ElfHeaderInfo {
|
||||
entry_point,
|
||||
ph_off,
|
||||
ph_num,
|
||||
ph_ent,
|
||||
user_stack_top,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn entry_point(&self) -> Vaddr {
|
||||
self.entry_point
|
||||
}
|
||||
|
||||
pub fn user_stack_top(&self) -> Vaddr {
|
||||
self.user_stack_top
|
||||
}
|
||||
}
|
||||
|
||||
/// init vmo for each segment and then map segment to root vmar
|
||||
pub fn map_segment_vmos(
|
||||
elf: &Elf,
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf_file: Arc<FileHandle>,
|
||||
) -> Result<()> {
|
||||
for program_header in &elf.program_headers {
|
||||
let type_ = program_header
|
||||
.get_type()
|
||||
.map_err(|_| Error::new(Errno::ENOEXEC))?;
|
||||
if type_ == program::Type::Load {
|
||||
let vmo = init_segment_vmo(program_header, elf_file.clone())?;
|
||||
map_segment_vmo(program_header, vmo, root_vmar, elf_file.clone())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// map the segment vmo to root_vmar
|
||||
fn map_segment_vmo(
|
||||
program_header: &ProgramHeader64,
|
||||
vmo: Vmo,
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf_file: Arc<FileHandle>,
|
||||
) -> Result<()> {
|
||||
let perms = VmPerms::from(parse_segment_perm(program_header.flags)?);
|
||||
let offset = (program_header.virtual_addr as Vaddr).align_down(PAGE_SIZE);
|
||||
let vm_map_options = root_vmar.new_map(vmo, perms)?.offset(offset);
|
||||
let map_addr = vm_map_options.build()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// create vmo for each segment
|
||||
fn init_segment_vmo(program_header: &ProgramHeader64, elf_file: Arc<FileHandle>) -> Result<Vmo> {
|
||||
let vmo_start = (program_header.virtual_addr as Vaddr).align_down(PAGE_SIZE);
|
||||
let vmo_end = (program_header.virtual_addr as Vaddr + program_header.mem_size as Vaddr)
|
||||
.align_up(PAGE_SIZE);
|
||||
let segment_len = vmo_end - vmo_start;
|
||||
let pager = Arc::new(ElfSegmentPager::new(elf_file, &program_header)) as Arc<dyn Pager>;
|
||||
let vmo_alloc_options: VmoOptions<Full> = VmoOptions::new(segment_len).pager(pager);
|
||||
Ok(vmo_alloc_options.alloc()?.to_dyn())
|
||||
}
|
||||
|
||||
fn parse_segment_perm(flags: xmas_elf::program::Flags) -> Result<VmPerm> {
|
||||
if !flags.is_read() {
|
||||
return_errno_with_message!(Errno::ENOEXEC, "unreadable segment");
|
||||
}
|
||||
let mut vm_perm = VmPerm::R;
|
||||
if flags.is_write() {
|
||||
vm_perm |= VmPerm::W;
|
||||
}
|
||||
if flags.is_execute() {
|
||||
vm_perm |= VmPerm::X;
|
||||
}
|
||||
Ok(vm_perm)
|
||||
}
|
||||
|
@ -1,26 +1,8 @@
|
||||
pub mod aux_vec;
|
||||
pub mod elf_file;
|
||||
pub mod elf_segment_pager;
|
||||
pub mod init_stack;
|
||||
pub mod load_elf;
|
||||
mod aux_vec;
|
||||
mod elf_file;
|
||||
mod elf_segment_pager;
|
||||
mod init_stack;
|
||||
mod load_elf;
|
||||
|
||||
use self::load_elf::ElfLoadInfo;
|
||||
use crate::{prelude::*, rights::Full, vm::vmar::Vmar};
|
||||
|
||||
/// load elf to the root vmar. this function will
|
||||
/// 1. read the vaddr of each segment to get all elf pages.
|
||||
/// 2. create a vmo for each elf segment, create a backup pager for each segment. Then map the vmo to the root vmar.
|
||||
/// 3. write proper content to the init stack.
|
||||
pub fn load_elf_to_root_vmar(
|
||||
elf_file_content: &'static [u8],
|
||||
root_vmar: &Vmar<Full>,
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
) -> Result<ElfLoadInfo> {
|
||||
let mut elf_load_info = ElfLoadInfo::parse_elf_data(elf_file_content, argv, envp)?;
|
||||
elf_load_info.map_segment_vmos(root_vmar, elf_file_content)?;
|
||||
elf_load_info.init_stack(root_vmar, elf_file_content)?;
|
||||
debug!("load elf succeeds.");
|
||||
|
||||
Ok(elf_load_info)
|
||||
}
|
||||
pub use init_stack::INIT_STACK_SIZE;
|
||||
pub use load_elf::{load_elf_to_root_vmar, ElfLoadInfo};
|
||||
|
@ -1,5 +1,6 @@
|
||||
use core::sync::atomic::{AtomicI32, Ordering};
|
||||
|
||||
use self::elf::{ElfLoadInfo, load_elf_to_root_vmar};
|
||||
use self::posix_thread::posix_thread_ext::PosixThreadExt;
|
||||
use self::process_group::ProcessGroup;
|
||||
use self::process_vm::user_heap::UserHeap;
|
||||
@ -10,16 +11,18 @@ use self::signal::sig_disposition::SigDispositions;
|
||||
use self::signal::sig_queues::SigQueues;
|
||||
use self::signal::signals::kernel::KernelSignal;
|
||||
use self::status::ProcessStatus;
|
||||
use crate::fs::file_handle::FileHandle;
|
||||
use crate::fs::file_table::FileTable;
|
||||
use crate::fs::fs_resolver::AT_FDCWD;
|
||||
use crate::fs::fs_resolver::{FsPath, FsResolver};
|
||||
use crate::fs::utils::AccessMode;
|
||||
use crate::fs::utils::{AccessMode, SeekFrom};
|
||||
use crate::prelude::*;
|
||||
use crate::rights::Full;
|
||||
use crate::thread::{thread_table, Thread};
|
||||
use crate::tty::get_n_tty;
|
||||
use crate::vm::vmar::Vmar;
|
||||
use alloc::string::String;
|
||||
use jinux_frame::sync::WaitQueue;
|
||||
use jinux_frame::task::Task;
|
||||
|
||||
pub mod clone;
|
||||
pub mod elf;
|
||||
@ -45,7 +48,7 @@ const INIT_PROCESS_PID: Pid = 1;
|
||||
pub struct Process {
|
||||
// Immutable Part
|
||||
pid: Pid,
|
||||
elf_path: Option<CString>,
|
||||
executable_path: Option<String>,
|
||||
user_vm: Option<UserVm>,
|
||||
root_vmar: Arc<Vmar<Full>>,
|
||||
/// wait for child status changed
|
||||
@ -96,7 +99,7 @@ impl Process {
|
||||
pid: Pid,
|
||||
parent: Weak<Process>,
|
||||
threads: Vec<Arc<Thread>>,
|
||||
elf_path: Option<CString>,
|
||||
executable_path: Option<String>,
|
||||
user_vm: Option<UserVm>,
|
||||
root_vmar: Arc<Vmar<Full>>,
|
||||
process_group: Weak<ProcessGroup>,
|
||||
@ -111,7 +114,7 @@ impl Process {
|
||||
Self {
|
||||
pid,
|
||||
threads: Mutex::new(threads),
|
||||
elf_path,
|
||||
executable_path,
|
||||
user_vm,
|
||||
root_vmar,
|
||||
waiting_children,
|
||||
@ -139,12 +142,11 @@ impl Process {
|
||||
|
||||
/// init a user process and run the process
|
||||
pub fn spawn_user_process(
|
||||
filename: CString,
|
||||
elf_file_content: &'static [u8],
|
||||
filename: String,
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
) -> Arc<Self> {
|
||||
let process = Process::create_user_process(filename, elf_file_content, argv, envp);
|
||||
let process = Process::create_user_process(filename, argv, envp);
|
||||
// FIXME: How to determine the fg process group?
|
||||
let pgid = process.pgid();
|
||||
// FIXME: tty should be a parameter?
|
||||
@ -155,24 +157,19 @@ impl Process {
|
||||
}
|
||||
|
||||
fn create_user_process(
|
||||
elf_path: CString,
|
||||
elf_file_content: &'static [u8],
|
||||
executable_path: String,
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
) -> Arc<Self> {
|
||||
let user_process = Arc::new_cyclic(|weak_process_ref| {
|
||||
let weak_process = weak_process_ref.clone();
|
||||
let cloned_filename = Some(elf_path.clone());
|
||||
let cloned_filename = Some(executable_path.clone());
|
||||
let root_vmar = Vmar::<Full>::new_root().unwrap();
|
||||
<<<<<<< HEAD
|
||||
let thread = Thread::new_posix_thread_from_elf(
|
||||
=======
|
||||
let fs = FsResolver::new();
|
||||
let thread = Thread::new_posix_thread_from_executable(
|
||||
>>>>>>> 0255134... fix
|
||||
&root_vmar,
|
||||
elf_path,
|
||||
elf_file_content,
|
||||
&fs,
|
||||
executable_path,
|
||||
weak_process,
|
||||
argv,
|
||||
envp,
|
||||
@ -362,8 +359,8 @@ impl Process {
|
||||
self.children.lock().len() != 0
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> Option<&CString> {
|
||||
self.elf_path.as_ref()
|
||||
pub fn executable_path(&self) -> Option<&String> {
|
||||
self.executable_path.as_ref()
|
||||
}
|
||||
|
||||
pub fn status(&self) -> &Mutex<ProcessStatus> {
|
||||
@ -387,77 +384,3 @@ impl Process {
|
||||
pub fn get_init_process() -> Option<Arc<Process>> {
|
||||
process_table::pid_to_process(INIT_PROCESS_PID)
|
||||
}
|
||||
|
||||
/// Set up root vmar for an executable.
|
||||
/// About recursion_limit: recursion limit is used to limit th recursion depth of shebang executables.
|
||||
/// If the interpreter program(the program behind !#) of shebang executable is also a shebang,
|
||||
/// then it will trigger recursion. We will try to setup root vmar for the interpreter program.
|
||||
/// I guess for most cases, setting the recursion_limit as 1 should be enough.
|
||||
/// because the interpreter game is usually an elf binary(e.g., /bin/bash)
|
||||
pub fn setup_root_vmar(
|
||||
executable_path: String,
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
fs_resolver: &FsResolver,
|
||||
root_vmar: Vmar<Full>,
|
||||
recursion_limit: usize,
|
||||
) -> Result<()> {
|
||||
use crate::fs::fs_resolver::AT_FDCWD;
|
||||
let fs_path = FsPath::new(AT_FDCWD, &executable_path)?;
|
||||
let file = fs_resolver.open(&fs_path, AccessMode::O_RDONLY as u32, 0)?;
|
||||
// read the first page of file header
|
||||
let mut file_header_buffer = [0u8; PAGE_SIZE];
|
||||
file.read(&mut file_header_buffer)?;
|
||||
if recursion_limit > 0
|
||||
&& file_header_buffer.starts_with(b"!#")
|
||||
&& file_header_buffer.contains(&b'\n')
|
||||
{
|
||||
return set_up_root_vmar_for_shebang(
|
||||
argv,
|
||||
envp,
|
||||
&file_header_buffer,
|
||||
fs_resolver,
|
||||
root_vmar,
|
||||
recursion_limit,
|
||||
);
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_up_root_vmar_for_shebang(
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
file_header_buffer: &[u8],
|
||||
fs_resolver: &FsResolver,
|
||||
root_vmar: Vmar<Full>,
|
||||
recursion_limit: usize,
|
||||
) -> Result<()> {
|
||||
let first_line_len = file_header_buffer.iter().position(|&c| c == b'\n').unwrap();
|
||||
// skip !#
|
||||
let shebang_header = &file_header_buffer[2..first_line_len];
|
||||
let mut shebang_argv = Vec::new();
|
||||
for arg in shebang_header.split(|&c| c == b' ') {
|
||||
let arg = CString::new(arg)?;
|
||||
shebang_argv.push(arg);
|
||||
}
|
||||
if shebang_argv.len() != 1 {
|
||||
return_errno_with_message!(
|
||||
Errno::EINVAL,
|
||||
"One and only one intpreter program should be specified"
|
||||
);
|
||||
}
|
||||
for origin_arg in argv.into_iter() {
|
||||
shebang_argv.push(origin_arg);
|
||||
}
|
||||
use alloc::string::ToString;
|
||||
let shebang_path = shebang_argv[0].to_str()?.to_string();
|
||||
setup_root_vmar(
|
||||
shebang_path,
|
||||
shebang_argv,
|
||||
envp,
|
||||
fs_resolver,
|
||||
root_vmar,
|
||||
recursion_limit - 1,
|
||||
)
|
||||
}
|
||||
|
@ -14,10 +14,9 @@ impl ThreadName {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_elf_path(elf_path: &CStr) -> Result<Self> {
|
||||
pub fn new_from_executable_path(elf_path: &str) -> Result<Self> {
|
||||
let mut thread_name = ThreadName::new();
|
||||
let elf_file_name = elf_path
|
||||
.to_str()?
|
||||
.split('/')
|
||||
.last()
|
||||
.ok_or(Error::with_message(Errno::EINVAL, "invalid elf path"))?;
|
||||
|
@ -1,8 +1,10 @@
|
||||
use alloc::string::String;
|
||||
use jinux_frame::{cpu::CpuContext, user::UserSpace};
|
||||
|
||||
use crate::{
|
||||
fs::fs_resolver::FsResolver,
|
||||
prelude::*,
|
||||
process::{elf::load_elf_to_root_vmar, Process},
|
||||
process::{setup_root_vmar, Process},
|
||||
rights::Full,
|
||||
thread::{allocate_tid, Thread},
|
||||
vm::vmar::Vmar,
|
||||
@ -13,8 +15,8 @@ pub trait PosixThreadExt {
|
||||
fn as_posix_thread(&self) -> Option<&PosixThread>;
|
||||
fn new_posix_thread_from_executable(
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf_path: CString,
|
||||
elf_file_content: &'static [u8],
|
||||
fs_resolver: &FsResolver,
|
||||
executable_path: String,
|
||||
process: Weak<Process>,
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
@ -25,20 +27,28 @@ impl PosixThreadExt for Thread {
|
||||
/// This function should only be called when launch shell()
|
||||
fn new_posix_thread_from_executable(
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf_path: CString,
|
||||
elf_file_content: &'static [u8],
|
||||
fs_resolver: &FsResolver,
|
||||
executable_path: String,
|
||||
process: Weak<Process>,
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
) -> Arc<Self> {
|
||||
let elf_load_info = load_elf_to_root_vmar(elf_file_content, &root_vmar, argv, envp)
|
||||
.expect("Load Elf failed");
|
||||
let elf_load_info = setup_root_vmar(
|
||||
executable_path.clone(),
|
||||
argv,
|
||||
envp,
|
||||
fs_resolver,
|
||||
root_vmar,
|
||||
1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vm_space = root_vmar.vm_space().clone();
|
||||
let mut cpu_ctx = CpuContext::default();
|
||||
cpu_ctx.set_rip(elf_load_info.entry_point());
|
||||
cpu_ctx.set_rsp(elf_load_info.user_stack_top());
|
||||
cpu_ctx.set_rip(elf_load_info.entry_point() as _);
|
||||
cpu_ctx.set_rsp(elf_load_info.user_stack_top() as _);
|
||||
let user_space = Arc::new(UserSpace::new(vm_space, cpu_ctx));
|
||||
let thread_name = Some(ThreadName::new_from_elf_path(&elf_path).unwrap());
|
||||
let thread_name = Some(ThreadName::new_from_executable_path(&executable_path).unwrap());
|
||||
let tid = allocate_tid();
|
||||
let thread_builder = PosixThreadBuilder::new(tid, user_space)
|
||||
.thread_name(thread_name)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use super::{elf::init_stack::INIT_STACK_SIZE, process_vm::user_heap::USER_HEAP_SIZE_LIMIT};
|
||||
use super::{elf::INIT_STACK_SIZE, process_vm::user_heap::USER_HEAP_SIZE_LIMIT};
|
||||
|
||||
pub struct ResourceLimits {
|
||||
rlimits: [RLimit64; RLIMIT_COUNT],
|
||||
|
@ -31,7 +31,7 @@ pub fn handle_pending_signal(context: &mut CpuContext) -> Result<()> {
|
||||
let current_thread = current_thread!();
|
||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||
let pid = current.pid();
|
||||
let process_name = current.filename().unwrap();
|
||||
let process_name = current.executable_path().unwrap();
|
||||
let sig_mask = posix_thread.sig_mask().lock().clone();
|
||||
let mut thread_sig_queues = posix_thread.sig_queues().lock();
|
||||
let mut proc_sig_queues = current.sig_queues().lock();
|
||||
|
@ -2,9 +2,9 @@ use jinux_frame::cpu::CpuContext;
|
||||
|
||||
use super::{constants::*, SyscallReturn};
|
||||
use crate::log_syscall_entry;
|
||||
use crate::process::elf::load_elf_to_root_vmar;
|
||||
use crate::process::posix_thread::name::ThreadName;
|
||||
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt;
|
||||
use crate::process::setup_root_vmar;
|
||||
use crate::util::{read_cstring_from_user, read_val_from_user};
|
||||
use crate::{prelude::*, syscall::SYS_EXECVE};
|
||||
|
||||
@ -15,24 +15,22 @@ pub fn sys_execve(
|
||||
context: &mut CpuContext,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_EXECVE);
|
||||
let elf_path = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?;
|
||||
let executable_path = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?;
|
||||
let executable_path = executable_path.into_string().unwrap();
|
||||
let argv = read_cstring_vec(argv_ptr_ptr, MAX_ARGV_NUMBER, MAX_ARG_LEN)?;
|
||||
let envp = read_cstring_vec(envp_ptr_ptr, MAX_ENVP_NUMBER, MAX_ENV_LEN)?;
|
||||
debug!(
|
||||
"filename: {:?}, argv = {:?}, envp = {:?}",
|
||||
elf_path, argv, envp
|
||||
executable_path, argv, envp
|
||||
);
|
||||
if elf_path != CString::new("./hello").unwrap() {
|
||||
panic!("Unknown filename.");
|
||||
}
|
||||
// FIXME: should we set thread name in execve?
|
||||
let current_thread = current_thread!();
|
||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||
let mut thread_name = posix_thread.thread_name().lock();
|
||||
let new_thread_name = ThreadName::new_from_elf_path(&elf_path)?;
|
||||
let new_thread_name = ThreadName::new_from_executable_path(&executable_path)?;
|
||||
*thread_name = Some(new_thread_name);
|
||||
|
||||
let elf_file_content = crate::user_apps::read_execve_hello_content();
|
||||
// let elf_file_content = crate::user_apps::read_execve_hello_content();
|
||||
let current = current!();
|
||||
// destroy root vmars
|
||||
let root_vmar = current.root_vmar();
|
||||
@ -42,8 +40,8 @@ pub fn sys_execve(
|
||||
.expect("[Internal Error] User process should have user vm");
|
||||
user_vm.set_default();
|
||||
// load elf content to new vm space
|
||||
let elf_load_info =
|
||||
load_elf_to_root_vmar(elf_file_content, root_vmar, argv, envp).expect("load elf failed");
|
||||
let fs_resolver = &*current.fs().read();
|
||||
let elf_load_info = setup_root_vmar(executable_path, argv, envp, fs_resolver, root_vmar, 1)?;
|
||||
debug!("load elf in execve succeeds");
|
||||
// set signal disposition to default
|
||||
current.sig_dispositions().lock().inherit();
|
||||
@ -53,10 +51,10 @@ pub fn sys_execve(
|
||||
context.fs_base = defalut_content.fs_base;
|
||||
context.fp_regs = defalut_content.fp_regs;
|
||||
// set new entry point
|
||||
context.gp_regs.rip = elf_load_info.entry_point();
|
||||
context.gp_regs.rip = elf_load_info.entry_point() as _;
|
||||
debug!("entry_point: 0x{:x}", elf_load_info.entry_point());
|
||||
// set new user stack top
|
||||
context.gp_regs.rsp = elf_load_info.user_stack_top();
|
||||
context.gp_regs.rsp = elf_load_info.user_stack_top() as _;
|
||||
debug!("user stack top: 0x{:x}", elf_load_info.user_stack_top());
|
||||
Ok(SyscallReturn::NoReturn)
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ pub fn sys_readlinkat(
|
||||
let current = current!();
|
||||
if pathname == CString::new("/proc/self/exe")? {
|
||||
// "proc/self/exe" is used to read the filename of current executable
|
||||
let process_file_name = current.filename().unwrap();
|
||||
let process_file_name = current.executable_path().unwrap();
|
||||
debug!("process exec filename= {:?}", process_file_name);
|
||||
// readlink does not append a terminating null byte to buf
|
||||
let bytes = process_file_name.as_bytes();
|
||||
|
@ -1,44 +1,21 @@
|
||||
use crate::fs::{
|
||||
fs_resolver::{FsPath, FsResolver},
|
||||
utils::AccessMode,
|
||||
};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct UserApp {
|
||||
pub elf_path: CString,
|
||||
pub app_content: Vec<u8>,
|
||||
pub executable_path: String,
|
||||
pub argv: Vec<CString>,
|
||||
pub envp: Vec<CString>,
|
||||
}
|
||||
|
||||
impl UserApp {
|
||||
pub fn new(elf_path: &str) -> Result<Self> {
|
||||
let app_name = CString::new(elf_path).unwrap();
|
||||
let app_content = {
|
||||
let fs = FsResolver::new();
|
||||
let file = fs.open(&FsPath::try_from(elf_path)?, AccessMode::O_RDONLY as u32, 0)?;
|
||||
let mut content = Vec::new();
|
||||
let len = file.read_to_end(&mut content)?;
|
||||
if len != file.len() {
|
||||
return_errno_with_message!(Errno::EINVAL, "read len is not equal to file size");
|
||||
}
|
||||
content
|
||||
};
|
||||
pub fn new(executable_path: &str) -> Result<Self> {
|
||||
let app_name = String::from(executable_path);
|
||||
let arg0 = CString::new(executable_path)?;
|
||||
Ok(UserApp {
|
||||
elf_path: app_name,
|
||||
app_content,
|
||||
argv: Vec::new(),
|
||||
executable_path: app_name,
|
||||
argv: vec![arg0],
|
||||
envp: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_argv(&mut self, argv: Vec<CString>) {
|
||||
self.argv = argv;
|
||||
}
|
||||
|
||||
pub fn set_envp(&mut self, envp: Vec<CString>) {
|
||||
self.envp = envp;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_all_apps() -> Result<Vec<UserApp>> {
|
||||
@ -81,7 +58,7 @@ pub fn get_busybox_app() -> Result<UserApp> {
|
||||
// busybox
|
||||
let mut busybox = UserApp::new("/busybox/busybox")?;
|
||||
// -l option means the busybox is running as logging shell
|
||||
let argv = ["/busybox", "sh", "-l"];
|
||||
let argv = ["sh", "-l"];
|
||||
let envp = [
|
||||
"SHELL=/bin/sh",
|
||||
"PWD=/",
|
||||
@ -92,21 +69,13 @@ pub fn get_busybox_app() -> Result<UserApp> {
|
||||
"OLDPWD=/",
|
||||
];
|
||||
|
||||
let argv = to_vec_cstring(&argv)?;
|
||||
let envp = to_vec_cstring(&envp)?;
|
||||
busybox.set_argv(argv);
|
||||
busybox.set_envp(envp);
|
||||
let mut argv = to_vec_cstring(&argv)?;
|
||||
let mut envp = to_vec_cstring(&envp)?;
|
||||
busybox.argv.append(&mut argv);
|
||||
busybox.envp.append(&mut envp);
|
||||
Ok(busybox)
|
||||
}
|
||||
|
||||
fn read_execve_content() -> &'static [u8] {
|
||||
include_bytes!("../../../../apps/execve/execve")
|
||||
}
|
||||
|
||||
pub fn read_execve_hello_content() -> &'static [u8] {
|
||||
include_bytes!("../../../../apps/execve/hello")
|
||||
}
|
||||
|
||||
fn to_vec_cstring(raw_strs: &[&str]) -> Result<Vec<CString>> {
|
||||
let mut res = Vec::new();
|
||||
for raw_str in raw_strs {
|
||||
|
Reference in New Issue
Block a user