Merge branch 'cleanup_exec4' into 'master'
Use non-fixed and anonymous remote mmap and get rid of BTreeMap in redox-rt See merge request redox-os/relibc!789
This commit is contained in:
+59
-79
@@ -1,5 +1,6 @@
|
||||
use core::{
|
||||
cell::SyncUnsafeCell,
|
||||
cmp,
|
||||
fmt::Debug,
|
||||
mem::{MaybeUninit, size_of},
|
||||
};
|
||||
@@ -13,7 +14,7 @@ use crate::{
|
||||
sys::{proc_call, thread_call},
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, collections::BTreeMap, vec};
|
||||
use alloc::{boxed::Box, vec};
|
||||
|
||||
//TODO: allow use of either 32-bit or 64-bit programs
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
@@ -47,7 +48,6 @@ pub struct InterpOverride {
|
||||
at_phnum: usize,
|
||||
at_phent: usize,
|
||||
name: Box<[u8]>,
|
||||
tree: BTreeMap<usize, usize>,
|
||||
}
|
||||
|
||||
pub struct ExtraInfo<'a> {
|
||||
@@ -68,12 +68,11 @@ pub fn fexec_impl(
|
||||
image_file: FdGuardUpper,
|
||||
thread_fd: &FdGuardUpper,
|
||||
proc_fd: &FdGuardUpper,
|
||||
memory_scheme_fd: &FdGuardUpper,
|
||||
path: &[u8],
|
||||
args: &[&[u8]],
|
||||
envs: &[&[u8]],
|
||||
extrainfo: &ExtraInfo,
|
||||
mut interp_override: Option<InterpOverride>,
|
||||
interp_override: Option<InterpOverride>,
|
||||
) -> Result<FexecResult> {
|
||||
// Here, we do the minimum part of loading an application, which is what the kernel used to do.
|
||||
// We load the executable into memory (albeit at different offsets in this executable), fix
|
||||
@@ -104,10 +103,10 @@ pub fn fexec_impl(
|
||||
let phs = &mut phs_raw[size_of::<Header>()..];
|
||||
|
||||
// TODO: Remove clone, but this would require more as_refs and as_muts
|
||||
let mut tree = interp_override.as_mut().map_or_else(
|
||||
|| core::iter::once((0, PAGE_SIZE)).collect::<BTreeMap<_, _>>(),
|
||||
|o| core::mem::take(&mut o.tree),
|
||||
);
|
||||
let mut min_mmap_addr = PAGE_SIZE;
|
||||
let mut update_min_mmap_addr = |addr: usize, size: usize| {
|
||||
min_mmap_addr = cmp::min(min_mmap_addr, (addr + size).next_multiple_of(PAGE_SIZE));
|
||||
};
|
||||
|
||||
pread_all(&image_file, u64::from(header.e_phoff), phs).map_err(|_| Error::new(EIO))?;
|
||||
|
||||
@@ -143,7 +142,6 @@ pub fn fexec_impl(
|
||||
at_phent: phentsize,
|
||||
phs: phs_raw.into_boxed_slice(),
|
||||
name: path.into(),
|
||||
tree,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -161,12 +159,12 @@ pub fn fexec_impl(
|
||||
return Err(Error::new(ENOEXEC));
|
||||
}
|
||||
|
||||
allocate_remote(
|
||||
mmap_anon_remote(
|
||||
&grants_fd,
|
||||
memory_scheme_fd,
|
||||
0,
|
||||
vaddr,
|
||||
total_page_count * PAGE_SIZE,
|
||||
flags,
|
||||
flags | MapFlags::MAP_FIXED_NOREPLACE,
|
||||
)?;
|
||||
|
||||
// TODO: Attempt to mmap with MAP_PRIVATE directly from the image file instead.
|
||||
@@ -186,30 +184,20 @@ pub fn fexec_impl(
|
||||
)?;
|
||||
}
|
||||
|
||||
// file_page_count..file_page_count + zero_page_count are already zero-initialized
|
||||
// by the kernel.
|
||||
|
||||
if !tree
|
||||
.range(..=vaddr)
|
||||
.next_back()
|
||||
.filter(|(start, size)| **start + **size > vaddr)
|
||||
.is_some()
|
||||
{
|
||||
tree.insert(vaddr, total_page_count * PAGE_SIZE);
|
||||
}
|
||||
update_min_mmap_addr(vaddr, total_page_count * PAGE_SIZE);
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
allocate_remote(
|
||||
mmap_anon_remote(
|
||||
&grants_fd,
|
||||
memory_scheme_fd,
|
||||
0,
|
||||
STACK_TOP - STACK_SIZE,
|
||||
STACK_SIZE,
|
||||
MapFlags::PROT_READ | MapFlags::PROT_WRITE,
|
||||
MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_FIXED_NOREPLACE,
|
||||
)?;
|
||||
tree.insert(STACK_TOP - STACK_SIZE, STACK_SIZE);
|
||||
update_min_mmap_addr(STACK_TOP - STACK_SIZE, STACK_SIZE);
|
||||
|
||||
let mut sp = STACK_TOP;
|
||||
let mut stack_page = Option::<MmapGuard>::None;
|
||||
@@ -258,15 +246,14 @@ pub fn fexec_impl(
|
||||
&*phs_raw
|
||||
};
|
||||
let pheaders_size_aligned = pheaders_to_convey.len().next_multiple_of(PAGE_SIZE);
|
||||
let pheaders = find_free_target_addr(&tree, pheaders_size_aligned).ok_or(Error::new(ENOMEM))?;
|
||||
tree.insert(pheaders, pheaders_size_aligned);
|
||||
allocate_remote(
|
||||
let pheaders = mmap_anon_remote(
|
||||
&grants_fd,
|
||||
memory_scheme_fd,
|
||||
pheaders,
|
||||
0,
|
||||
0,
|
||||
pheaders_size_aligned,
|
||||
MapFlags::PROT_READ | MapFlags::PROT_WRITE,
|
||||
)?;
|
||||
update_min_mmap_addr(pheaders, pheaders_size_aligned);
|
||||
unsafe {
|
||||
let (_guard, memory) =
|
||||
MmapGuard::map_mut_anywhere(&grants_fd, pheaders, pheaders_size_aligned)?;
|
||||
@@ -307,16 +294,14 @@ pub fn fexec_impl(
|
||||
+ envs.iter().map(|env| env.len() + 1).sum::<usize>()
|
||||
+ extrainfo.cwd.map_or(0, |s| s.len() + 1);
|
||||
let args_envs_size_aligned = total_args_envs_auxvpointee_size.next_multiple_of(PAGE_SIZE);
|
||||
let target_args_env_address =
|
||||
find_free_target_addr(&tree, args_envs_size_aligned).ok_or(Error::new(ENOMEM))?;
|
||||
allocate_remote(
|
||||
let target_args_env_address = mmap_anon_remote(
|
||||
&grants_fd,
|
||||
memory_scheme_fd,
|
||||
target_args_env_address,
|
||||
0,
|
||||
0,
|
||||
args_envs_size_aligned,
|
||||
MapFlags::PROT_READ | MapFlags::PROT_WRITE,
|
||||
)?;
|
||||
tree.insert(target_args_env_address, args_envs_size_aligned);
|
||||
update_min_mmap_addr(target_args_env_address, args_envs_size_aligned);
|
||||
|
||||
let mut offset = 0;
|
||||
|
||||
@@ -425,9 +410,7 @@ pub fn fexec_impl(
|
||||
|
||||
if interp_override.is_some() {
|
||||
let mmap_min_fd = grants_fd.dup(b"mmap-min-addr")?;
|
||||
let last_addr = tree.iter().rev().nth(1).map_or(0, |(off, len)| *off + *len);
|
||||
let aligned_last_addr = last_addr.next_multiple_of(PAGE_SIZE);
|
||||
let _ = mmap_min_fd.write(&usize::to_ne_bytes(aligned_last_addr));
|
||||
let _ = mmap_min_fd.write(&usize::to_ne_bytes(min_mmap_addr));
|
||||
}
|
||||
|
||||
let addrspace_selection_fd = thread_fd.dup(b"current-addrspace")?.to_upper()?;
|
||||
@@ -474,18 +457,8 @@ pub fn fexec_impl(
|
||||
|
||||
unreachable!();
|
||||
}
|
||||
fn write_usizes<const N: usize>(fd: &FdGuardUpper, usizes: [usize; N]) -> Result<()> {
|
||||
fd.write(unsafe { plain::as_bytes(&usizes) })?;
|
||||
Ok(())
|
||||
}
|
||||
fn allocate_remote(
|
||||
addrspace_fd: &FdGuardUpper,
|
||||
memory_scheme_fd: &FdGuardUpper,
|
||||
dst_addr: usize,
|
||||
len: usize,
|
||||
flags: MapFlags,
|
||||
) -> Result<()> {
|
||||
mmap_remote(addrspace_fd, memory_scheme_fd, 0, dst_addr, len, flags)
|
||||
fn write_usizes<const N: usize>(fd: &FdGuardUpper, usizes: [usize; N]) -> Result<usize> {
|
||||
fd.write(unsafe { plain::as_bytes(&usizes) })
|
||||
}
|
||||
pub fn mmap_remote(
|
||||
addrspace_fd: &FdGuardUpper,
|
||||
@@ -494,7 +467,7 @@ pub fn mmap_remote(
|
||||
dst_addr: usize,
|
||||
len: usize,
|
||||
flags: MapFlags,
|
||||
) -> Result<()> {
|
||||
) -> Result<usize> {
|
||||
write_usizes(
|
||||
addrspace_fd,
|
||||
[
|
||||
@@ -509,7 +482,32 @@ pub fn mmap_remote(
|
||||
// size
|
||||
len,
|
||||
// flags
|
||||
(flags | MapFlags::MAP_FIXED_NOREPLACE).bits(),
|
||||
flags.bits(),
|
||||
],
|
||||
)
|
||||
}
|
||||
pub fn mmap_anon_remote(
|
||||
addrspace_fd: &FdGuardUpper,
|
||||
offset: usize,
|
||||
dst_addr: usize,
|
||||
len: usize,
|
||||
flags: MapFlags,
|
||||
) -> Result<usize> {
|
||||
write_usizes(
|
||||
addrspace_fd,
|
||||
[
|
||||
// op
|
||||
syscall::flag::ADDRSPACE_OP_MMAP,
|
||||
// fd
|
||||
!0,
|
||||
// "offset"
|
||||
offset,
|
||||
// address
|
||||
dst_addr,
|
||||
// size
|
||||
len,
|
||||
// flags
|
||||
flags.bits(),
|
||||
],
|
||||
)
|
||||
}
|
||||
@@ -531,7 +529,8 @@ pub fn mprotect_remote(
|
||||
// flags
|
||||
flags.bits(),
|
||||
],
|
||||
)
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn munmap_remote(addrspace_fd: &FdGuardUpper, addr: usize, len: usize) -> Result<()> {
|
||||
write_usizes(
|
||||
@@ -544,7 +543,8 @@ pub fn munmap_remote(addrspace_fd: &FdGuardUpper, addr: usize, len: usize) -> Re
|
||||
// size
|
||||
len,
|
||||
],
|
||||
)
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn munmap_transfer(
|
||||
src: &FdGuardUpper,
|
||||
@@ -570,7 +570,8 @@ pub fn munmap_transfer(
|
||||
// flags
|
||||
(flags | MapFlags::MAP_FIXED_NOREPLACE).bits(),
|
||||
],
|
||||
)
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
fn pread_all(fd: &FdGuardUpper, offset: u64, buf: &mut [u8]) -> Result<()> {
|
||||
fd.lseek(offset as isize, SEEK_SET)?;
|
||||
@@ -586,27 +587,6 @@ fn pread_all(fd: &FdGuardUpper, offset: u64, buf: &mut [u8]) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: With the introduction of remote mmaps, remove this and let the kernel handle address
|
||||
// allocation.
|
||||
fn find_free_target_addr(tree: &BTreeMap<usize, usize>, size: usize) -> Option<usize> {
|
||||
let mut iterator = tree.iter().peekable();
|
||||
|
||||
// Ignore the space between zero and the first region, to avoid null pointers.
|
||||
while let Some((cur_address, entry_size)) = iterator.next() {
|
||||
let end = *cur_address + entry_size;
|
||||
|
||||
if let Some((next_address, _)) = iterator.peek() {
|
||||
if **next_address - end > size {
|
||||
return Some(end);
|
||||
}
|
||||
}
|
||||
// No need to check last entry, since the stack will always be put at the highest
|
||||
// possible address.
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub struct MmapGuard<'a> {
|
||||
fd: &'a FdGuardUpper,
|
||||
base: usize,
|
||||
|
||||
@@ -29,8 +29,6 @@ fn fexec_impl(
|
||||
extrainfo: &ExtraInfo,
|
||||
interp_override: Option<InterpOverride>,
|
||||
) -> Result<Infallible> {
|
||||
let memory = FdGuard::open("/scheme/memory", O_CLOEXEC)?.to_upper()?;
|
||||
|
||||
let FexecResult::Interp {
|
||||
image_file,
|
||||
path,
|
||||
@@ -39,7 +37,6 @@ fn fexec_impl(
|
||||
exec_file,
|
||||
&RtTcb::current().thread_fd(),
|
||||
redox_rt::current_proc_fd(),
|
||||
&memory,
|
||||
path,
|
||||
args,
|
||||
envs,
|
||||
@@ -48,7 +45,6 @@ fn fexec_impl(
|
||||
)?;
|
||||
|
||||
drop(image_file);
|
||||
drop(memory);
|
||||
|
||||
// According to elf(5), PT_INTERP requires that the interpreter path be
|
||||
// null-terminated. Violating this should therefore give the "format error" ENOEXEC.
|
||||
|
||||
Reference in New Issue
Block a user