proc: reimplement argument passing
This commit is contained in:
parent
aae4874f35
commit
de63a0456b
@ -16,7 +16,8 @@
|
||||
rustc_private,
|
||||
allocator_api,
|
||||
trait_alias,
|
||||
strict_provenance
|
||||
strict_provenance,
|
||||
slice_ptr_get
|
||||
)]
|
||||
#![allow(
|
||||
clippy::new_without_default,
|
||||
|
146
src/proc/exec.rs
146
src/proc/exec.rs
@ -1,7 +1,11 @@
|
||||
//! Binary execution functions
|
||||
use core::mem::size_of;
|
||||
use core::alloc::Layout;
|
||||
|
||||
use abi::error::Error;
|
||||
use abi::{
|
||||
error::Error,
|
||||
pass::{Place, Placer},
|
||||
process::ProgramArgumentInner,
|
||||
};
|
||||
use alloc::{string::String, sync::Arc};
|
||||
use vfs::FileRef;
|
||||
|
||||
@ -14,105 +18,79 @@ use crate::{
|
||||
task::{context::TaskContextImpl, process::Process, TaskContext},
|
||||
};
|
||||
|
||||
pub struct EnvWriter<'a> {
|
||||
data: &'a mut [u8],
|
||||
pub struct BufferPlacer<'a> {
|
||||
buffer: &'a mut [u8],
|
||||
virtual_offset: usize,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<'a> EnvWriter<'a> {
|
||||
pub fn new(data: &'a mut [u8]) -> Self {
|
||||
Self { data, offset: 0 }
|
||||
}
|
||||
|
||||
pub fn write_usize(&mut self, value: usize) -> Result<(), Error> {
|
||||
self.write_bytes(&value.to_ne_bytes())
|
||||
}
|
||||
|
||||
pub fn write_bytes(&mut self, value: &[u8]) -> Result<(), Error> {
|
||||
if value.len() + self.offset > self.data.len() {
|
||||
return Err(Error::InvalidArgument);
|
||||
impl<'a> BufferPlacer<'a> {
|
||||
pub fn new(virtual_offset: usize, buffer: &'a mut [u8]) -> Self {
|
||||
Self {
|
||||
buffer,
|
||||
virtual_offset,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn alloc_layout(&mut self, layout: Layout) -> Result<(*mut u8, usize), Error> {
|
||||
// TODO checks
|
||||
let aligned = (self.offset + layout.align() - 1) & !(layout.align() - 1);
|
||||
self.offset = aligned + layout.size();
|
||||
Ok((
|
||||
self.buffer.as_mut_ptr().add(aligned),
|
||||
self.virtual_offset + aligned,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Placer for BufferPlacer<'a> {
|
||||
fn place_ref<T: Place>(&mut self, r: &T) -> Result<*const T::Output, Error> {
|
||||
let layout = Layout::new::<T::Output>();
|
||||
unsafe {
|
||||
let (ptr, addr) = self.alloc_layout(layout)?;
|
||||
let ptr = ptr as *mut T::Output;
|
||||
ptr.write(r.place(self)?);
|
||||
Ok(&*(addr as *const T::Output))
|
||||
}
|
||||
}
|
||||
|
||||
fn place_slice<T: Place>(&mut self, r: &[T]) -> Result<*const [T::Output], Error> {
|
||||
let layout = Layout::array::<T>(r.len()).unwrap();
|
||||
unsafe {
|
||||
let (ptr, addr) = self.alloc_layout(layout)?;
|
||||
let ptr_slice = core::ptr::slice_from_raw_parts_mut(ptr as *mut T::Output, r.len());
|
||||
for (i, elem) in r.iter().enumerate() {
|
||||
ptr_slice.get_unchecked_mut(i).write(elem.place(self)?);
|
||||
}
|
||||
Ok(core::slice::from_raw_parts(
|
||||
addr as *const T::Output,
|
||||
r.len(),
|
||||
))
|
||||
}
|
||||
debugln!("write_bytes {:#x} {:x?}", self.offset, value);
|
||||
self.data[self.offset..self.offset + value.len()].copy_from_slice(value);
|
||||
self.offset += value.len();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO I hate this function, it's ugly
|
||||
fn setup_program_env(
|
||||
space: &ProcessAddressSpace,
|
||||
virt: usize,
|
||||
args: &[&str],
|
||||
envs: &[&str],
|
||||
) -> Result<(), Error> {
|
||||
const fn str_array_size(n: usize) -> usize {
|
||||
// length of the array itself (1 usize) + ptr:len pairs (2x usize * n)
|
||||
(1 + n * 2) * size_of::<usize>()
|
||||
}
|
||||
|
||||
const HEADER_SIZE: usize = 2 * size_of::<usize>();
|
||||
|
||||
// arg data len
|
||||
let args_data_size: usize = args.iter().map(|x| x.len()).sum();
|
||||
let envs_data_size: usize = envs.iter().map(|x| x.len()).sum();
|
||||
let ptrs_size = str_array_size(args.len()) + str_array_size(envs.len());
|
||||
let total_size = args_data_size + envs_data_size + ptrs_size + HEADER_SIZE;
|
||||
|
||||
if total_size > 0x1000 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
// debugln!("arg data size = {}", args_size);
|
||||
// debugln!("env data size = {}", envs_size);
|
||||
|
||||
env: &[&str],
|
||||
) -> Result<usize, Error> {
|
||||
// TODO growing buffer
|
||||
let phys_page = phys::alloc_page()?;
|
||||
space.map_single(
|
||||
virt,
|
||||
phys_page,
|
||||
MapAttributes::USER_READ | MapAttributes::USER_WRITE | MapAttributes::NON_GLOBAL,
|
||||
)?;
|
||||
let mut slice = unsafe { PhysicalRefMut::map_slice(phys_page, 4096) };
|
||||
let mut writer = EnvWriter::new(&mut slice);
|
||||
let mut buffer = unsafe { PhysicalRefMut::map_slice(phys_page, 4096) };
|
||||
let mut placer = BufferPlacer::new(virt, &mut buffer);
|
||||
|
||||
let args_array_offset = HEADER_SIZE;
|
||||
let envs_array_offset = args_array_offset + str_array_size(args.len());
|
||||
let args_data_offset = envs_array_offset + str_array_size(envs.len());
|
||||
let envs_data_offset = args_data_offset + args_data_size;
|
||||
let in_kernel = ProgramArgumentInner { args, env };
|
||||
let in_user = in_kernel.place_ref(&mut placer)?;
|
||||
|
||||
// Header
|
||||
writer.write_usize(virt + args_array_offset)?;
|
||||
writer.write_usize(virt + envs_array_offset)?;
|
||||
|
||||
// Args array
|
||||
writer.write_usize(args.len())?;
|
||||
|
||||
let mut offset = args_data_offset;
|
||||
for arg in args.iter() {
|
||||
writer.write_usize(arg.len())?;
|
||||
writer.write_usize(virt + offset)?;
|
||||
offset += arg.len();
|
||||
}
|
||||
|
||||
// Envs array
|
||||
writer.write_usize(envs.len())?;
|
||||
|
||||
let mut offset = envs_data_offset;
|
||||
for env in envs.iter() {
|
||||
writer.write_usize(env.len())?;
|
||||
writer.write_usize(virt + offset)?;
|
||||
offset += env.len();
|
||||
}
|
||||
|
||||
// String data
|
||||
for arg in args.iter() {
|
||||
writer.write_bytes(arg.as_bytes())?;
|
||||
}
|
||||
for env in envs.iter() {
|
||||
writer.write_bytes(env.as_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(in_user as *const _ as usize)
|
||||
}
|
||||
|
||||
fn setup_binary<S: Into<String>>(
|
||||
@ -135,7 +113,7 @@ fn setup_binary<S: Into<String>>(
|
||||
MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NON_GLOBAL,
|
||||
)?;
|
||||
|
||||
setup_program_env(&space, virt_args_base, args, envs)?;
|
||||
let arg = setup_program_env(&space, virt_args_base, args, envs)?;
|
||||
|
||||
debugln!(
|
||||
"Entry: {:#x}, Stack: {:#x}..{:#x}, Args: {:#x}",
|
||||
@ -157,7 +135,7 @@ fn setup_binary<S: Into<String>>(
|
||||
}
|
||||
}
|
||||
|
||||
let context = TaskContext::user(entry, virt_args_base, space.as_address_with_asid(), user_sp)?;
|
||||
let context = TaskContext::user(entry, arg, space.as_address_with_asid(), user_sp)?;
|
||||
|
||||
Ok(Process::new_with_context(name, Some(space), context))
|
||||
}
|
||||
|
@ -277,7 +277,6 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
|
||||
SyscallFunction::Spawn => {
|
||||
let options = arg_user_ref::<SpawnOptions>(args[0] as usize)?;
|
||||
|
||||
debugln!("Spawn {:#?}", options);
|
||||
let proc = Process::current();
|
||||
|
||||
run_with_io(|mut io| {
|
||||
|
Loading…
x
Reference in New Issue
Block a user