proc: pass env along with args to spawn()

This commit is contained in:
Mark Poliakov 2023-11-14 12:26:12 +02:00
parent 639f13eda4
commit b21dbca0f9
3 changed files with 104 additions and 36 deletions

View File

@ -60,7 +60,7 @@ pub fn kinit() {
let stderr = stdout.clone(); 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(); let mut io = user_init.io.lock();
io.set_ioctx(ioctx); io.set_ioctx(ioctx);
io.set_file(RawFd::STDIN, stdin).unwrap(); io.set_file(RawFd::STDIN, stdin).unwrap();

View File

@ -7,26 +7,78 @@ use vfs::FileRef;
use crate::{ use crate::{
mem::{ mem::{
address::AsPhysicalAddress, phys, process::ProcessAddressSpace, table::MapAttributes, address::AsPhysicalAddress, phys, pointer::PhysicalRefMut, process::ProcessAddressSpace,
ForeignPointer, table::MapAttributes, ForeignPointer,
}, },
proc, proc,
task::{context::TaskContextImpl, process::Process, TaskContext}, task::{context::TaskContextImpl, process::Process, TaskContext},
}; };
fn setup_args(space: &ProcessAddressSpace, virt: usize, args: &[&str]) -> Result<(), Error> { pub struct EnvWriter<'a> {
// arg data len data: &'a mut [u8],
let args_size: usize = args.iter().map(|x| x.len()).sum(); offset: usize,
// 1 + arg ptr:len count }
let args_ptr_size = (1 + args.len() * 2) * size_of::<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::<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;
// 1 + arg ptr:len count
// let args_ptr_size = (1 + args.len() * 2) * size_of::<usize>();
// let envs_ptr_size = (1 + envs.len() * 2) * size_of::<usize>();
// Total size: offset arrays + data + args/env split position
// let total_size = args_size + args_ptr_size + envs_size + envs_ptr_size + size_of::<usize>();
if total_size > 0x1000 { if total_size > 0x1000 {
todo!(); 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()?; let phys_page = phys::alloc_page()?;
space.map_single( space.map_single(
@ -34,35 +86,44 @@ fn setup_args(space: &ProcessAddressSpace, virt: usize, args: &[&str]) -> Result
phys_page, phys_page,
MapAttributes::USER_READ | MapAttributes::USER_WRITE | MapAttributes::NON_GLOBAL, 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 { // Header
(write as *mut usize).write_volatile(args.len()); writer.write_usize(virt + args_array_offset);
} writer.write_usize(virt + envs_array_offset);
for (i, arg) in args.iter().enumerate() { // Args array
// Place the argument pointer writer.write_usize(args.len());
let ptr_place = write + (i * 2 + 1) * size_of::<usize>();
let len_place = ptr_place + size_of::<usize>(); let mut offset = args_data_offset;
unsafe { for arg in args.iter() {
(ptr_place as *mut usize).write_volatile(virt + offset); writer.write_usize(arg.len());
(len_place as *mut usize).write_volatile(arg.len()); writer.write_usize(virt + offset);
}
offset += arg.len(); offset += arg.len();
} }
// Place the argument data // Envs array
// TODO rewrite using write_foreign writer.write_usize(envs.len());
unsafe {
let arg_data_slice = let mut offset = envs_data_offset;
core::slice::from_raw_parts_mut((write + args_ptr_size) as *mut u8, args_size); for env in envs.iter() {
let mut offset = 0; writer.write_usize(env.len());
for &s in args { writer.write_usize(virt + offset);
arg_data_slice[offset..offset + s.len()].copy_from_slice(s.as_bytes()); offset += env.len();
offset += s.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(())
@ -73,6 +134,7 @@ fn setup_binary<S: Into<String>>(
space: ProcessAddressSpace, space: ProcessAddressSpace,
entry: usize, entry: usize,
args: &[&str], args: &[&str],
envs: &[&str],
) -> Result<Arc<Process>, Error> { ) -> Result<Arc<Process>, Error> {
const USER_STACK_PAGES: usize = 16; const USER_STACK_PAGES: usize = 16;
@ -87,7 +149,7 @@ fn setup_binary<S: Into<String>>(
MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NON_GLOBAL, 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!( debugln!(
"Entry: {:#x}, Stack: {:#x}..{:#x}, Args: {:#x}", "Entry: {:#x}, Stack: {:#x}..{:#x}, Args: {:#x}",
@ -124,9 +186,10 @@ pub fn load_elf<S: Into<String>>(
name: S, name: S,
file: FileRef, file: FileRef,
args: &[&str], args: &[&str],
envs: &[&str],
) -> Result<Arc<Process>, Error> { ) -> Result<Arc<Process>, Error> {
let space = ProcessAddressSpace::new()?; let space = ProcessAddressSpace::new()?;
let elf_entry = proc::elf::load_elf_from_file(&space, file)?; 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)
} }

View File

@ -287,7 +287,12 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
// Setup a new process from the file // Setup a new process from the file
let file = node.open(OpenOptions::READ, FileMode::empty())?; 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; let pid = child.id() as u32;
// Inherit group and session from the creator // Inherit group and session from the creator