mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 10:53:25 +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
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:c04094e4c0da36e9f8cc5059f540dbc2123d5e4caa1d0b7427577ee734710b23
|
oid sha256:c7cc90df87ade7ff2cb494e13678aceaf93542883558fda947bd2fc01e2d73a6
|
||||||
size 871952
|
size 871952
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
int main() {
|
int main() {
|
||||||
char* argv[] = { "argv1", "argv2", NULL };
|
char* argv[] = { "argv1", "argv2", NULL };
|
||||||
char* envp[] = { "home=/", "version=1.1", 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
|
// flush the stdout content to ensure the content print to console
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
execve("./hello", argv, envp);
|
execve("/execve/hello", argv, envp);
|
||||||
printf("Should not print\n");
|
printf("Should not print\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -6,7 +6,6 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn limine_build_script() -> 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.
|
// 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-changed=boot/limine/conf/linker.ld");
|
||||||
println!("cargo:rerun-if-env-changed=CARGO_PKG_NAME");
|
println!("cargo:rerun-if-env-changed=CARGO_PKG_NAME");
|
||||||
|
@ -68,17 +68,30 @@ pub fn init_thread() {
|
|||||||
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
|
// Run busybox ash
|
||||||
let UserApp {
|
let UserApp {
|
||||||
elf_path: app_name,
|
executable_path: app_name,
|
||||||
app_content,
|
|
||||||
argv,
|
argv,
|
||||||
envp,
|
envp,
|
||||||
} = get_busybox_app().unwrap();
|
} = get_busybox_app().unwrap();
|
||||||
let app_content = app_content.into_boxed_slice();
|
|
||||||
println!("");
|
println!("");
|
||||||
println!("BusyBox v1.35.0 built-in shell (ash)\n");
|
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 {
|
loop {
|
||||||
// We don't have preemptive scheduler now.
|
// 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::LinkedList;
|
||||||
pub(crate) use alloc::collections::VecDeque;
|
pub(crate) use alloc::collections::VecDeque;
|
||||||
pub(crate) use alloc::ffi::CString;
|
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::Arc;
|
||||||
pub(crate) use alloc::sync::Weak;
|
pub(crate) use alloc::sync::Weak;
|
||||||
pub(crate) use alloc::vec;
|
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 system V semaphore
|
||||||
clone_sysvsem(clone_flags)?;
|
clone_sysvsem(clone_flags)?;
|
||||||
|
|
||||||
let child_elf_path = current.filename().unwrap().clone();
|
let child_elf_path = current.executable_path().unwrap().clone();
|
||||||
let child_thread_name = ThreadName::new_from_elf_path(&child_elf_path)?;
|
let child_thread_name = ThreadName::new_from_executable_path(&child_elf_path)?;
|
||||||
|
|
||||||
// inherit parent's sig mask
|
// inherit parent's sig mask
|
||||||
let current_thread = current_thread!();
|
let current_thread = current_thread!();
|
||||||
|
@ -45,6 +45,42 @@ impl Elf {
|
|||||||
program_headers,
|
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 {
|
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::prelude::*;
|
||||||
use crate::vm::vmar::{get_intersected_range, is_intersected};
|
use crate::vm::vmar::{get_intersected_range, is_intersected};
|
||||||
use jinux_frame::vm::{VmAllocOptions, VmFrameVec, VmIo};
|
use jinux_frame::vm::{VmAllocOptions, VmFrameVec, VmIo};
|
||||||
use jinux_frame::AlignExt;
|
use jinux_frame::AlignExt;
|
||||||
|
use xmas_elf::program::ProgramHeader64;
|
||||||
|
|
||||||
use crate::vm::vmo::Pager;
|
use crate::vm::vmo::Pager;
|
||||||
|
|
||||||
use super::load_elf::ElfSegment;
|
// use super::load_elf::ElfSegment;
|
||||||
|
|
||||||
/// The pager behind a elf segment
|
/// The pager behind a elf segment
|
||||||
pub struct ElfSegmentPager {
|
pub struct ElfSegmentPager {
|
||||||
/// The pager size
|
/// The pager size
|
||||||
pager_size: usize,
|
pager_size: usize,
|
||||||
/// data for current segment
|
/// the back up file
|
||||||
segment_data: &'static [u8],
|
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 offset for the segment data.
|
||||||
/// The pager always starts at page-align address, while the segment data may start at any address.
|
/// 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
|
/// So the offset will be the segment data start address % PAGE_SIZE
|
||||||
offset: usize,
|
page_offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElfSegmentPager {
|
impl ElfSegmentPager {
|
||||||
pub fn new(elf_file_content: &'static [u8], elf_segment: &ElfSegment) -> Self {
|
pub fn new(file: Arc<FileHandle>, program_header: &ProgramHeader64) -> Self {
|
||||||
let start = elf_segment.start_address().align_down(PAGE_SIZE);
|
let ph_start = program_header.virtual_addr as Vaddr;
|
||||||
let end = elf_segment.end_address().align_up(PAGE_SIZE);
|
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 pager_size = end - start;
|
||||||
let offset = elf_segment.start_address() % PAGE_SIZE;
|
let offset = ph_start % PAGE_SIZE;
|
||||||
let elf_file_segment =
|
|
||||||
&elf_file_content[elf_segment.offset..elf_segment.offset + elf_segment.file_size];
|
|
||||||
Self {
|
Self {
|
||||||
pager_size,
|
pager_size,
|
||||||
segment_data: elf_file_segment,
|
file,
|
||||||
offset,
|
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 {
|
if offset >= self.pager_size {
|
||||||
return_errno_with_message!(Errno::EINVAL, "offset exceeds pager size");
|
return_errno_with_message!(Errno::EINVAL, "offset exceeds pager size");
|
||||||
}
|
}
|
||||||
|
|
||||||
let vm_alloc_option = VmAllocOptions::new(1);
|
let vm_alloc_option = VmAllocOptions::new(1);
|
||||||
let mut vm_frames = VmFrameVec::allocate(&vm_alloc_option)?;
|
let mut vm_frames = VmFrameVec::allocate(&vm_alloc_option)?;
|
||||||
vm_frames.zero();
|
vm_frames.zero();
|
||||||
|
|
||||||
let page_start = offset.align_down(PAGE_SIZE);
|
let page_start = offset.align_down(PAGE_SIZE);
|
||||||
let page_end = page_start + PAGE_SIZE;
|
let page_end = page_start + PAGE_SIZE;
|
||||||
let page_range = page_start..page_end;
|
let page_range = page_start..page_end;
|
||||||
let data_range = self.offset..self.offset + self.segment_data.len();
|
let segment_range = self.page_offset..self.page_offset + self.file_size;
|
||||||
if is_intersected(&page_range, &data_range) {
|
if is_intersected(&page_range, &segment_range) {
|
||||||
let intersected_range = get_intersected_range(&page_range, &data_range);
|
let intersected_range = get_intersected_range(&page_range, &segment_range);
|
||||||
let data_write_range =
|
let segment_from_file_range = (intersected_range.start - self.page_offset)
|
||||||
(intersected_range.start - self.offset)..(intersected_range.end - self.offset);
|
..(intersected_range.end - self.page_offset);
|
||||||
let write_content = &self.segment_data[data_write_range];
|
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;
|
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();
|
let vm_frame = vm_frames.pop().unwrap();
|
||||||
Ok(vm_frame)
|
Ok(vm_frame)
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ use jinux_frame::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::aux_vec::{AuxKey, AuxVec};
|
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_BASE: Vaddr = 0x0000_0000_2000_0000;
|
||||||
pub const INIT_STACK_SIZE: usize = 0x1000 * 16; // 64KB
|
pub const INIT_STACK_SIZE: usize = 0x1000 * 16; // 64KB
|
||||||
@ -79,7 +79,6 @@ pub struct InitStack {
|
|||||||
impl InitStack {
|
impl InitStack {
|
||||||
/// initialize user stack on base addr
|
/// initialize user stack on base addr
|
||||||
pub fn new(
|
pub fn new(
|
||||||
// filename: CString,
|
|
||||||
init_stack_top: Vaddr,
|
init_stack_top: Vaddr,
|
||||||
init_stack_size: usize,
|
init_stack_size: usize,
|
||||||
argv: Vec<CString>,
|
argv: Vec<CString>,
|
||||||
@ -115,14 +114,9 @@ impl InitStack {
|
|||||||
self.init_stack_top - self.init_stack_size
|
self.init_stack_top - self.init_stack_size
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(&mut self, root_vmar: &Vmar<Full>, elf: &Elf) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
root_vmar: &Vmar<Full>,
|
|
||||||
elf_header_info: &ElfHeaderInfo,
|
|
||||||
ph_addr: Vaddr,
|
|
||||||
) -> Result<()> {
|
|
||||||
self.map_and_zeroed(root_vmar)?;
|
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);
|
self.debug_print_stack_content(root_vmar);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -161,12 +155,7 @@ impl InitStack {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_stack_content(
|
fn write_stack_content(&mut self, root_vmar: &Vmar<Full>, elf: &Elf) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
root_vmar: &Vmar<Full>,
|
|
||||||
elf_header_info: &ElfHeaderInfo,
|
|
||||||
ph_addr: Vaddr,
|
|
||||||
) -> Result<()> {
|
|
||||||
// write envp string
|
// write envp string
|
||||||
let envp_pointers = self.write_envp_strings(root_vmar)?;
|
let envp_pointers = self.write_envp_strings(root_vmar)?;
|
||||||
// write argv string
|
// write argv string
|
||||||
@ -176,11 +165,9 @@ impl InitStack {
|
|||||||
let random_value_pointer = self.write_bytes(&random_value, root_vmar)?;
|
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_RANDOM, random_value_pointer)?;
|
||||||
self.aux_vec.set(AuxKey::AT_PAGESZ, PAGE_SIZE as _)?;
|
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_PHDR, elf.ph_addr()? as u64)?;
|
||||||
self.aux_vec
|
self.aux_vec.set(AuxKey::AT_PHNUM, elf.ph_count() as u64)?;
|
||||||
.set(AuxKey::AT_PHNUM, elf_header_info.ph_num as u64)?;
|
self.aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?;
|
||||||
self.aux_vec
|
|
||||||
.set(AuxKey::AT_PHENT, elf_header_info.ph_ent as u64)?;
|
|
||||||
self.adjust_stack_alignment(root_vmar, &envp_pointers, &argv_pointers)?;
|
self.adjust_stack_alignment(root_vmar, &envp_pointers, &argv_pointers)?;
|
||||||
self.write_aux_vec(root_vmar)?;
|
self.write_aux_vec(root_vmar)?;
|
||||||
self.write_envp_pointers(root_vmar, envp_pointers)?;
|
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.
|
//! 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
|
//! 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::perms::VmPerms;
|
||||||
use crate::vm::vmo::VmoRightsOp;
|
use crate::vm::vmo::VmoRightsOp;
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -17,60 +19,93 @@ use xmas_elf::program::{self, ProgramHeader64};
|
|||||||
|
|
||||||
use super::elf_file::Elf;
|
use super::elf_file::Elf;
|
||||||
use super::elf_segment_pager::ElfSegmentPager;
|
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 {
|
pub struct ElfLoadInfo {
|
||||||
segments: Vec<ElfSegment>,
|
entry_point: Vaddr,
|
||||||
init_stack: InitStack,
|
user_stack_top: Vaddr,
|
||||||
elf_header_info: ElfHeaderInfo,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ElfSegment {
|
impl ElfLoadInfo {
|
||||||
/// The virtual addr where to put the segment.
|
pub fn new(entry_point: Vaddr, user_stack_top: Vaddr) -> Self {
|
||||||
pub virtual_addr: Vaddr,
|
Self {
|
||||||
/// The segment's size in memory, in bytes.
|
entry_point,
|
||||||
pub mem_size: usize,
|
user_stack_top,
|
||||||
/// 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,
|
pub fn entry_point(&self) -> Vaddr {
|
||||||
type_: program::Type,
|
self.entry_point
|
||||||
vm_perm: VmPerm,
|
}
|
||||||
|
|
||||||
|
pub fn user_stack_top(&self) -> Vaddr {
|
||||||
|
self.user_stack_top
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
/// init vmo for each segment and then map segment to root vmar
|
||||||
/// Info parsed from elf header. The entry point is used to set rip
|
pub fn map_segment_vmos(
|
||||||
/// The other info is used to set auxv vectors.
|
elf: &Elf,
|
||||||
pub struct ElfHeaderInfo {
|
root_vmar: &Vmar<Full>,
|
||||||
/// the entry point of the elf
|
elf_file: Arc<FileHandle>,
|
||||||
pub entry_point: Vaddr,
|
) -> Result<()> {
|
||||||
/// page header table offset
|
for program_header in &elf.program_headers {
|
||||||
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
|
let type_ = program_header
|
||||||
.get_type()
|
.get_type()
|
||||||
.map_err(|_| Error::new(Errno::ENOEXEC))?;
|
.map_err(|_| Error::new(Errno::ENOEXEC))?;
|
||||||
let vm_perm = Self::parse_segment_perm(program_header.flags)?;
|
if type_ == program::Type::Load {
|
||||||
Ok(Self {
|
let vmo = init_segment_vmo(program_header, elf_file.clone())?;
|
||||||
virtual_addr: program_header.virtual_addr as _,
|
map_segment_vmo(program_header, vmo, root_vmar, elf_file.clone())?;
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_segment_perm(flags: xmas_elf::program::Flags) -> Result<VmPerm> {
|
/// 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() {
|
if !flags.is_read() {
|
||||||
return_errno_with_message!(Errno::ENOEXEC, "unreadable segment");
|
return_errno_with_message!(Errno::ENOEXEC, "unreadable segment");
|
||||||
}
|
}
|
||||||
@ -82,169 +117,4 @@ impl ElfSegment {
|
|||||||
vm_perm |= VmPerm::X;
|
vm_perm |= VmPerm::X;
|
||||||
}
|
}
|
||||||
Ok(vm_perm)
|
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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElfLoadInfo {
|
|
||||||
fn with_capacity(
|
|
||||||
capacity: usize,
|
|
||||||
init_stack: InitStack,
|
|
||||||
elf_header_info: ElfHeaderInfo,
|
|
||||||
) -> 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,8 @@
|
|||||||
pub mod aux_vec;
|
mod aux_vec;
|
||||||
pub mod elf_file;
|
mod elf_file;
|
||||||
pub mod elf_segment_pager;
|
mod elf_segment_pager;
|
||||||
pub mod init_stack;
|
mod init_stack;
|
||||||
pub mod load_elf;
|
mod load_elf;
|
||||||
|
|
||||||
use self::load_elf::ElfLoadInfo;
|
pub use init_stack::INIT_STACK_SIZE;
|
||||||
use crate::{prelude::*, rights::Full, vm::vmar::Vmar};
|
pub use load_elf::{load_elf_to_root_vmar, ElfLoadInfo};
|
||||||
|
|
||||||
/// 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)
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use core::sync::atomic::{AtomicI32, Ordering};
|
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::posix_thread::posix_thread_ext::PosixThreadExt;
|
||||||
use self::process_group::ProcessGroup;
|
use self::process_group::ProcessGroup;
|
||||||
use self::process_vm::user_heap::UserHeap;
|
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::sig_queues::SigQueues;
|
||||||
use self::signal::signals::kernel::KernelSignal;
|
use self::signal::signals::kernel::KernelSignal;
|
||||||
use self::status::ProcessStatus;
|
use self::status::ProcessStatus;
|
||||||
|
use crate::fs::file_handle::FileHandle;
|
||||||
use crate::fs::file_table::FileTable;
|
use crate::fs::file_table::FileTable;
|
||||||
|
use crate::fs::fs_resolver::AT_FDCWD;
|
||||||
use crate::fs::fs_resolver::{FsPath, FsResolver};
|
use crate::fs::fs_resolver::{FsPath, FsResolver};
|
||||||
use crate::fs::utils::AccessMode;
|
use crate::fs::utils::{AccessMode, SeekFrom};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::rights::Full;
|
use crate::rights::Full;
|
||||||
use crate::thread::{thread_table, Thread};
|
use crate::thread::{thread_table, Thread};
|
||||||
use crate::tty::get_n_tty;
|
use crate::tty::get_n_tty;
|
||||||
use crate::vm::vmar::Vmar;
|
use crate::vm::vmar::Vmar;
|
||||||
use alloc::string::String;
|
|
||||||
use jinux_frame::sync::WaitQueue;
|
use jinux_frame::sync::WaitQueue;
|
||||||
|
use jinux_frame::task::Task;
|
||||||
|
|
||||||
pub mod clone;
|
pub mod clone;
|
||||||
pub mod elf;
|
pub mod elf;
|
||||||
@ -45,7 +48,7 @@ const INIT_PROCESS_PID: Pid = 1;
|
|||||||
pub struct Process {
|
pub struct Process {
|
||||||
// Immutable Part
|
// Immutable Part
|
||||||
pid: Pid,
|
pid: Pid,
|
||||||
elf_path: Option<CString>,
|
executable_path: Option<String>,
|
||||||
user_vm: Option<UserVm>,
|
user_vm: Option<UserVm>,
|
||||||
root_vmar: Arc<Vmar<Full>>,
|
root_vmar: Arc<Vmar<Full>>,
|
||||||
/// wait for child status changed
|
/// wait for child status changed
|
||||||
@ -96,7 +99,7 @@ impl Process {
|
|||||||
pid: Pid,
|
pid: Pid,
|
||||||
parent: Weak<Process>,
|
parent: Weak<Process>,
|
||||||
threads: Vec<Arc<Thread>>,
|
threads: Vec<Arc<Thread>>,
|
||||||
elf_path: Option<CString>,
|
executable_path: Option<String>,
|
||||||
user_vm: Option<UserVm>,
|
user_vm: Option<UserVm>,
|
||||||
root_vmar: Arc<Vmar<Full>>,
|
root_vmar: Arc<Vmar<Full>>,
|
||||||
process_group: Weak<ProcessGroup>,
|
process_group: Weak<ProcessGroup>,
|
||||||
@ -111,7 +114,7 @@ impl Process {
|
|||||||
Self {
|
Self {
|
||||||
pid,
|
pid,
|
||||||
threads: Mutex::new(threads),
|
threads: Mutex::new(threads),
|
||||||
elf_path,
|
executable_path,
|
||||||
user_vm,
|
user_vm,
|
||||||
root_vmar,
|
root_vmar,
|
||||||
waiting_children,
|
waiting_children,
|
||||||
@ -139,12 +142,11 @@ impl Process {
|
|||||||
|
|
||||||
/// init a user process and run the process
|
/// init a user process and run the process
|
||||||
pub fn spawn_user_process(
|
pub fn spawn_user_process(
|
||||||
filename: CString,
|
filename: String,
|
||||||
elf_file_content: &'static [u8],
|
|
||||||
argv: Vec<CString>,
|
argv: Vec<CString>,
|
||||||
envp: Vec<CString>,
|
envp: Vec<CString>,
|
||||||
) -> Arc<Self> {
|
) -> 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?
|
// FIXME: How to determine the fg process group?
|
||||||
let pgid = process.pgid();
|
let pgid = process.pgid();
|
||||||
// FIXME: tty should be a parameter?
|
// FIXME: tty should be a parameter?
|
||||||
@ -155,24 +157,19 @@ impl Process {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_user_process(
|
fn create_user_process(
|
||||||
elf_path: CString,
|
executable_path: String,
|
||||||
elf_file_content: &'static [u8],
|
|
||||||
argv: Vec<CString>,
|
argv: Vec<CString>,
|
||||||
envp: Vec<CString>,
|
envp: Vec<CString>,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
let user_process = Arc::new_cyclic(|weak_process_ref| {
|
let user_process = Arc::new_cyclic(|weak_process_ref| {
|
||||||
let weak_process = weak_process_ref.clone();
|
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();
|
let root_vmar = Vmar::<Full>::new_root().unwrap();
|
||||||
<<<<<<< HEAD
|
|
||||||
let thread = Thread::new_posix_thread_from_elf(
|
|
||||||
=======
|
|
||||||
let fs = FsResolver::new();
|
let fs = FsResolver::new();
|
||||||
let thread = Thread::new_posix_thread_from_executable(
|
let thread = Thread::new_posix_thread_from_executable(
|
||||||
>>>>>>> 0255134... fix
|
|
||||||
&root_vmar,
|
&root_vmar,
|
||||||
elf_path,
|
&fs,
|
||||||
elf_file_content,
|
executable_path,
|
||||||
weak_process,
|
weak_process,
|
||||||
argv,
|
argv,
|
||||||
envp,
|
envp,
|
||||||
@ -362,8 +359,8 @@ impl Process {
|
|||||||
self.children.lock().len() != 0
|
self.children.lock().len() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filename(&self) -> Option<&CString> {
|
pub fn executable_path(&self) -> Option<&String> {
|
||||||
self.elf_path.as_ref()
|
self.executable_path.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn status(&self) -> &Mutex<ProcessStatus> {
|
pub fn status(&self) -> &Mutex<ProcessStatus> {
|
||||||
@ -387,77 +384,3 @@ impl Process {
|
|||||||
pub fn get_init_process() -> Option<Arc<Process>> {
|
pub fn get_init_process() -> Option<Arc<Process>> {
|
||||||
process_table::pid_to_process(INIT_PROCESS_PID)
|
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 mut thread_name = ThreadName::new();
|
||||||
let elf_file_name = elf_path
|
let elf_file_name = elf_path
|
||||||
.to_str()?
|
|
||||||
.split('/')
|
.split('/')
|
||||||
.last()
|
.last()
|
||||||
.ok_or(Error::with_message(Errno::EINVAL, "invalid elf path"))?;
|
.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 jinux_frame::{cpu::CpuContext, user::UserSpace};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
fs::fs_resolver::FsResolver,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{elf::load_elf_to_root_vmar, Process},
|
process::{setup_root_vmar, Process},
|
||||||
rights::Full,
|
rights::Full,
|
||||||
thread::{allocate_tid, Thread},
|
thread::{allocate_tid, Thread},
|
||||||
vm::vmar::Vmar,
|
vm::vmar::Vmar,
|
||||||
@ -13,8 +15,8 @@ pub trait PosixThreadExt {
|
|||||||
fn as_posix_thread(&self) -> Option<&PosixThread>;
|
fn as_posix_thread(&self) -> Option<&PosixThread>;
|
||||||
fn new_posix_thread_from_executable(
|
fn new_posix_thread_from_executable(
|
||||||
root_vmar: &Vmar<Full>,
|
root_vmar: &Vmar<Full>,
|
||||||
elf_path: CString,
|
fs_resolver: &FsResolver,
|
||||||
elf_file_content: &'static [u8],
|
executable_path: String,
|
||||||
process: Weak<Process>,
|
process: Weak<Process>,
|
||||||
argv: Vec<CString>,
|
argv: Vec<CString>,
|
||||||
envp: Vec<CString>,
|
envp: Vec<CString>,
|
||||||
@ -25,20 +27,28 @@ impl PosixThreadExt for Thread {
|
|||||||
/// This function should only be called when launch shell()
|
/// This function should only be called when launch shell()
|
||||||
fn new_posix_thread_from_executable(
|
fn new_posix_thread_from_executable(
|
||||||
root_vmar: &Vmar<Full>,
|
root_vmar: &Vmar<Full>,
|
||||||
elf_path: CString,
|
fs_resolver: &FsResolver,
|
||||||
elf_file_content: &'static [u8],
|
executable_path: String,
|
||||||
process: Weak<Process>,
|
process: Weak<Process>,
|
||||||
argv: Vec<CString>,
|
argv: Vec<CString>,
|
||||||
envp: Vec<CString>,
|
envp: Vec<CString>,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
let elf_load_info = load_elf_to_root_vmar(elf_file_content, &root_vmar, argv, envp)
|
let elf_load_info = setup_root_vmar(
|
||||||
.expect("Load Elf failed");
|
executable_path.clone(),
|
||||||
|
argv,
|
||||||
|
envp,
|
||||||
|
fs_resolver,
|
||||||
|
root_vmar,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let vm_space = root_vmar.vm_space().clone();
|
let vm_space = root_vmar.vm_space().clone();
|
||||||
let mut cpu_ctx = CpuContext::default();
|
let mut cpu_ctx = CpuContext::default();
|
||||||
cpu_ctx.set_rip(elf_load_info.entry_point());
|
cpu_ctx.set_rip(elf_load_info.entry_point() as _);
|
||||||
cpu_ctx.set_rsp(elf_load_info.user_stack_top());
|
cpu_ctx.set_rsp(elf_load_info.user_stack_top() as _);
|
||||||
let user_space = Arc::new(UserSpace::new(vm_space, cpu_ctx));
|
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 tid = allocate_tid();
|
||||||
let thread_builder = PosixThreadBuilder::new(tid, user_space)
|
let thread_builder = PosixThreadBuilder::new(tid, user_space)
|
||||||
.thread_name(thread_name)
|
.thread_name(thread_name)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use crate::prelude::*;
|
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 {
|
pub struct ResourceLimits {
|
||||||
rlimits: [RLimit64; RLIMIT_COUNT],
|
rlimits: [RLimit64; RLIMIT_COUNT],
|
||||||
|
@ -31,7 +31,7 @@ pub fn handle_pending_signal(context: &mut CpuContext) -> Result<()> {
|
|||||||
let current_thread = current_thread!();
|
let current_thread = current_thread!();
|
||||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
let pid = current.pid();
|
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 sig_mask = posix_thread.sig_mask().lock().clone();
|
||||||
let mut thread_sig_queues = posix_thread.sig_queues().lock();
|
let mut thread_sig_queues = posix_thread.sig_queues().lock();
|
||||||
let mut proc_sig_queues = current.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 super::{constants::*, SyscallReturn};
|
||||||
use crate::log_syscall_entry;
|
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::name::ThreadName;
|
||||||
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt;
|
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::util::{read_cstring_from_user, read_val_from_user};
|
||||||
use crate::{prelude::*, syscall::SYS_EXECVE};
|
use crate::{prelude::*, syscall::SYS_EXECVE};
|
||||||
|
|
||||||
@ -15,24 +15,22 @@ pub fn sys_execve(
|
|||||||
context: &mut CpuContext,
|
context: &mut CpuContext,
|
||||||
) -> Result<SyscallReturn> {
|
) -> Result<SyscallReturn> {
|
||||||
log_syscall_entry!(SYS_EXECVE);
|
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 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)?;
|
let envp = read_cstring_vec(envp_ptr_ptr, MAX_ENVP_NUMBER, MAX_ENV_LEN)?;
|
||||||
debug!(
|
debug!(
|
||||||
"filename: {:?}, argv = {:?}, envp = {:?}",
|
"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?
|
// FIXME: should we set thread name in execve?
|
||||||
let current_thread = current_thread!();
|
let current_thread = current_thread!();
|
||||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
let mut thread_name = posix_thread.thread_name().lock();
|
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);
|
*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!();
|
let current = current!();
|
||||||
// destroy root vmars
|
// destroy root vmars
|
||||||
let root_vmar = current.root_vmar();
|
let root_vmar = current.root_vmar();
|
||||||
@ -42,8 +40,8 @@ pub fn sys_execve(
|
|||||||
.expect("[Internal Error] User process should have user vm");
|
.expect("[Internal Error] User process should have user vm");
|
||||||
user_vm.set_default();
|
user_vm.set_default();
|
||||||
// load elf content to new vm space
|
// load elf content to new vm space
|
||||||
let elf_load_info =
|
let fs_resolver = &*current.fs().read();
|
||||||
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, argv, envp, fs_resolver, root_vmar, 1)?;
|
||||||
debug!("load elf in execve succeeds");
|
debug!("load elf in execve succeeds");
|
||||||
// set signal disposition to default
|
// set signal disposition to default
|
||||||
current.sig_dispositions().lock().inherit();
|
current.sig_dispositions().lock().inherit();
|
||||||
@ -53,10 +51,10 @@ pub fn sys_execve(
|
|||||||
context.fs_base = defalut_content.fs_base;
|
context.fs_base = defalut_content.fs_base;
|
||||||
context.fp_regs = defalut_content.fp_regs;
|
context.fp_regs = defalut_content.fp_regs;
|
||||||
// set new entry point
|
// 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());
|
debug!("entry_point: 0x{:x}", elf_load_info.entry_point());
|
||||||
// set new user stack top
|
// 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());
|
debug!("user stack top: 0x{:x}", elf_load_info.user_stack_top());
|
||||||
Ok(SyscallReturn::NoReturn)
|
Ok(SyscallReturn::NoReturn)
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ pub fn sys_readlinkat(
|
|||||||
let current = current!();
|
let current = current!();
|
||||||
if pathname == CString::new("/proc/self/exe")? {
|
if pathname == CString::new("/proc/self/exe")? {
|
||||||
// "proc/self/exe" is used to read the filename of current executable
|
// "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);
|
debug!("process exec filename= {:?}", process_file_name);
|
||||||
// readlink does not append a terminating null byte to buf
|
// readlink does not append a terminating null byte to buf
|
||||||
let bytes = process_file_name.as_bytes();
|
let bytes = process_file_name.as_bytes();
|
||||||
|
@ -1,44 +1,21 @@
|
|||||||
use crate::fs::{
|
|
||||||
fs_resolver::{FsPath, FsResolver},
|
|
||||||
utils::AccessMode,
|
|
||||||
};
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct UserApp {
|
pub struct UserApp {
|
||||||
pub elf_path: CString,
|
pub executable_path: String,
|
||||||
pub app_content: Vec<u8>,
|
|
||||||
pub argv: Vec<CString>,
|
pub argv: Vec<CString>,
|
||||||
pub envp: Vec<CString>,
|
pub envp: Vec<CString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserApp {
|
impl UserApp {
|
||||||
pub fn new(elf_path: &str) -> Result<Self> {
|
pub fn new(executable_path: &str) -> Result<Self> {
|
||||||
let app_name = CString::new(elf_path).unwrap();
|
let app_name = String::from(executable_path);
|
||||||
let app_content = {
|
let arg0 = CString::new(executable_path)?;
|
||||||
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
|
|
||||||
};
|
|
||||||
Ok(UserApp {
|
Ok(UserApp {
|
||||||
elf_path: app_name,
|
executable_path: app_name,
|
||||||
app_content,
|
argv: vec![arg0],
|
||||||
argv: Vec::new(),
|
|
||||||
envp: Vec::new(),
|
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>> {
|
pub fn get_all_apps() -> Result<Vec<UserApp>> {
|
||||||
@ -81,7 +58,7 @@ pub fn get_busybox_app() -> Result<UserApp> {
|
|||||||
// busybox
|
// busybox
|
||||||
let mut busybox = UserApp::new("/busybox/busybox")?;
|
let mut busybox = UserApp::new("/busybox/busybox")?;
|
||||||
// -l option means the busybox is running as logging shell
|
// -l option means the busybox is running as logging shell
|
||||||
let argv = ["/busybox", "sh", "-l"];
|
let argv = ["sh", "-l"];
|
||||||
let envp = [
|
let envp = [
|
||||||
"SHELL=/bin/sh",
|
"SHELL=/bin/sh",
|
||||||
"PWD=/",
|
"PWD=/",
|
||||||
@ -92,21 +69,13 @@ pub fn get_busybox_app() -> Result<UserApp> {
|
|||||||
"OLDPWD=/",
|
"OLDPWD=/",
|
||||||
];
|
];
|
||||||
|
|
||||||
let argv = to_vec_cstring(&argv)?;
|
let mut argv = to_vec_cstring(&argv)?;
|
||||||
let envp = to_vec_cstring(&envp)?;
|
let mut envp = to_vec_cstring(&envp)?;
|
||||||
busybox.set_argv(argv);
|
busybox.argv.append(&mut argv);
|
||||||
busybox.set_envp(envp);
|
busybox.envp.append(&mut envp);
|
||||||
Ok(busybox)
|
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>> {
|
fn to_vec_cstring(raw_strs: &[&str]) -> Result<Vec<CString>> {
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
for raw_str in raw_strs {
|
for raw_str in raw_strs {
|
||||||
|
Reference in New Issue
Block a user