diff --git a/src/main.rs b/src/main.rs index a783262e..bd3f75e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,8 @@ rustc_private, allocator_api, trait_alias, - strict_provenance + strict_provenance, + slice_ptr_get )] #![allow( clippy::new_without_default, diff --git a/src/proc/exec.rs b/src/proc/exec.rs index 793b2813..94d7afc8 100644 --- a/src/proc/exec.rs +++ b/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(&mut self, r: &T) -> Result<*const T::Output, Error> { + let layout = Layout::new::(); + 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(&mut self, r: &[T]) -> Result<*const [T::Output], Error> { + let layout = Layout::array::(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::() - } - - const HEADER_SIZE: usize = 2 * size_of::(); - - // 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 { + // 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>( @@ -135,7 +113,7 @@ fn setup_binary>( 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>( } } - 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)) } diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index 053aab3c..1817665b 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -277,7 +277,6 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result SyscallFunction::Spawn => { let options = arg_user_ref::(args[0] as usize)?; - debugln!("Spawn {:#?}", options); let proc = Process::current(); run_with_io(|mut io| {