From b21dbca0f903590d4a9b99162ba3308877f4f267 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 14 Nov 2023 12:26:12 +0200 Subject: [PATCH] proc: pass env along with args to spawn() --- src/init.rs | 2 +- src/proc/exec.rs | 131 +++++++++++++++++++++++++++++++++------------ src/syscall/mod.rs | 7 ++- 3 files changed, 104 insertions(+), 36 deletions(-) diff --git a/src/init.rs b/src/init.rs index 5cb9e73b..2ebda395 100644 --- a/src/init.rs +++ b/src/init.rs @@ -60,7 +60,7 @@ pub fn kinit() { let stderr = stdout.clone(); { - let user_init = proc::exec::load_elf("init", file, &["/init", "xxx"]).unwrap(); + let user_init = proc::exec::load_elf("init", file, &["/init", "xxx"], &[]).unwrap(); let mut io = user_init.io.lock(); io.set_ioctx(ioctx); io.set_file(RawFd::STDIN, stdin).unwrap(); diff --git a/src/proc/exec.rs b/src/proc/exec.rs index 735da9e4..653c930e 100644 --- a/src/proc/exec.rs +++ b/src/proc/exec.rs @@ -7,26 +7,78 @@ use vfs::FileRef; use crate::{ mem::{ - address::AsPhysicalAddress, phys, process::ProcessAddressSpace, table::MapAttributes, - ForeignPointer, + address::AsPhysicalAddress, phys, pointer::PhysicalRefMut, process::ProcessAddressSpace, + table::MapAttributes, ForeignPointer, }, proc, task::{context::TaskContextImpl, process::Process, TaskContext}, }; -fn setup_args(space: &ProcessAddressSpace, virt: usize, args: &[&str]) -> Result<(), Error> { - // arg data len - let args_size: usize = args.iter().map(|x| x.len()).sum(); - // 1 + arg ptr:len count - let args_ptr_size = (1 + args.len() * 2) * size_of::(); +pub struct EnvWriter<'a> { + data: &'a mut [u8], + offset: usize, +} - let total_size = args_size + args_ptr_size; +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); + } + 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(()) + } +} + +fn write_2d_str_array( + space: &ProcessAddressSpace, + virt: usize, + array: &[&str], +) -> Result<(), Error> { + todo!() +} + +// 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; + // 1 + arg ptr:len count + // let args_ptr_size = (1 + args.len() * 2) * size_of::(); + // let envs_ptr_size = (1 + envs.len() * 2) * size_of::(); + + // Total size: offset arrays + data + args/env split position + // let total_size = args_size + args_ptr_size + envs_size + envs_ptr_size + size_of::(); if total_size > 0x1000 { todo!(); } - debugln!("arg data size = {}", args_size); + // debugln!("arg data size = {}", args_size); + // debugln!("env data size = {}", envs_size); let phys_page = phys::alloc_page()?; space.map_single( @@ -34,35 +86,44 @@ fn setup_args(space: &ProcessAddressSpace, virt: usize, args: &[&str]) -> Result phys_page, MapAttributes::USER_READ | MapAttributes::USER_WRITE | MapAttributes::NON_GLOBAL, )?; - let write = phys_page.virtualize_raw(); + let mut slice = unsafe { PhysicalRefMut::map_slice(phys_page, 4096) }; + let mut writer = EnvWriter::new(&mut *slice); - let mut offset = args_ptr_size; + 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; - unsafe { - (write as *mut usize).write_volatile(args.len()); - } + // Header + writer.write_usize(virt + args_array_offset); + writer.write_usize(virt + envs_array_offset); - for (i, arg) in args.iter().enumerate() { - // Place the argument pointer - let ptr_place = write + (i * 2 + 1) * size_of::(); - let len_place = ptr_place + size_of::(); - unsafe { - (ptr_place as *mut usize).write_volatile(virt + offset); - (len_place as *mut usize).write_volatile(arg.len()); - } + // 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(); } - // Place the argument data - // TODO rewrite using write_foreign - unsafe { - let arg_data_slice = - core::slice::from_raw_parts_mut((write + args_ptr_size) as *mut u8, args_size); - let mut offset = 0; - for &s in args { - arg_data_slice[offset..offset + s.len()].copy_from_slice(s.as_bytes()); - offset += s.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(()) @@ -73,6 +134,7 @@ fn setup_binary>( space: ProcessAddressSpace, entry: usize, args: &[&str], + envs: &[&str], ) -> Result, Error> { const USER_STACK_PAGES: usize = 16; @@ -87,7 +149,7 @@ fn setup_binary>( MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NON_GLOBAL, )?; - setup_args(&space, virt_args_base, args)?; + setup_program_env(&space, virt_args_base, args, envs)?; debugln!( "Entry: {:#x}, Stack: {:#x}..{:#x}, Args: {:#x}", @@ -124,9 +186,10 @@ pub fn load_elf>( name: S, file: FileRef, args: &[&str], + envs: &[&str], ) -> Result, Error> { let space = ProcessAddressSpace::new()?; let elf_entry = proc::elf::load_elf_from_file(&space, file)?; - setup_binary(name, space, elf_entry, args) + setup_binary(name, space, elf_entry, args, envs) } diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index 40860ad6..2b2c0b4d 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -287,7 +287,12 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result // Setup a new process from the file let file = node.open(OpenOptions::READ, FileMode::empty())?; - let child = proc::exec::load_elf(options.program, file, options.arguments)?; + let child = proc::exec::load_elf( + options.program, + file, + options.arguments, + options.environment, + )?; let pid = child.id() as u32; // Inherit group and session from the creator