diff --git a/kernel/src/process/abi.rs b/kernel/src/process/abi.rs new file mode 100644 index 0000000..cace76f --- /dev/null +++ b/kernel/src/process/abi.rs @@ -0,0 +1,62 @@ +use alloc::string::String; +use alloc::vec::Vec; +use alloc::collections::btree_map::BTreeMap; +use core::ptr::null; + +pub struct ProcInitInfo { + pub args: Vec, + pub envs: BTreeMap, +// pub auxv: Vec, +} + +impl ProcInitInfo { + pub unsafe fn push_at(&self, stack_top: usize) -> usize { + let mut writer = StackWriter { sp: stack_top }; + // from stack_top: + // program name + writer.push_str(&self.args[0]); + // environment strings + let envs: Vec<_> = self.envs.iter().map(|(key, value)| { + writer.push_str(value.as_str()); + writer.push_slice(&[b"="]); + writer.push_slice(key.as_bytes()); + writer.sp + }).collect(); + // argv strings + let argv: Vec<_> = self.args.iter().map(|arg| { + writer.push_str(arg.as_str()); + writer.sp + }).collect(); + // TODO: auxiliary vector entries + writer.push_slice(&[null::()]); + // envionment pointers + writer.push_slice(&[null::()]); + writer.push_slice(envs.as_slice()); + // argv pointers + writer.push_slice(&[null::()]); + writer.push_slice(argv.as_slice()); + // argc + writer.push_slice(&[argv.len()]); + writer.sp + } +} + +struct StackWriter { + sp: usize, +} + +impl StackWriter { + fn push_slice(&mut self, vs: &[T]) { + use core::{mem::{size_of, align_of}, slice}; + self.sp -= vs.len() * size_of::(); + self.sp -= self.sp % align_of::(); + unsafe { slice::from_raw_parts_mut(self.sp as *mut T, vs.len()) } + .copy_from_slice(vs); + } + fn push_str(&mut self, s: &str) { + self.push_slice(&[b'\0']); + self.push_slice(s.as_bytes()); + } +} + + diff --git a/kernel/src/process/context.rs b/kernel/src/process/context.rs index 71f63d5..3d5b8bc 100644 --- a/kernel/src/process/context.rs +++ b/kernel/src/process/context.rs @@ -9,6 +9,8 @@ use xmas_elf::{ElfFile, header, program::{Flags, Type}}; use crate::arch::interrupt::{Context as ArchContext, TrapFrame}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; +use super::abi::ProcInitInfo; + // TODO: avoid pub pub struct Process { pub arch: ArchContext, @@ -86,8 +88,12 @@ impl Process { #[cfg(feature = "no_mmu")] let mut ustack_top = memory_set.push(USER_STACK_SIZE).as_ptr() as usize + USER_STACK_SIZE; + let init_info = ProcInitInfo { + args: args.map(|s| String::from(s)).collect(), + envs: BTreeMap::new(), + }; unsafe { - memory_set.with(|| { ustack_top = push_args_at_stack(args, ustack_top) }); + memory_set.with(|| { ustack_top = init_info.push_at(ustack_top) }); } trace!("{:#x?}", memory_set); @@ -136,31 +142,6 @@ impl Process { } } -/// Push a slice at the stack. Return the new sp. -unsafe fn push_slice(mut sp: usize, vs: &[T]) -> usize { - use core::{mem::{size_of, align_of}, slice}; - sp -= vs.len() * size_of::(); - sp -= sp % align_of::(); - slice::from_raw_parts_mut(sp as *mut T, vs.len()) - .copy_from_slice(vs); - sp -} - -unsafe fn push_args_at_stack<'a, Iter>(args: Iter, stack_top: usize) -> usize - where Iter: Iterator -{ - let mut sp = stack_top; - let mut argv = Vec::new(); - for arg in args { - sp = push_slice(sp, &[0u8]); - sp = push_slice(sp, arg.as_bytes()); - argv.push(sp); - } - sp = push_slice(sp, argv.as_slice()); - sp = push_slice(sp, &[argv.len()]); - sp -} - /// Generate a MemorySet according to the ELF file. /// Also return the real entry point address. diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 2f59994..d5479b9 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -6,6 +6,7 @@ use alloc::{boxed::Box, sync::Arc}; use log::*; pub mod context; +mod abi; pub fn init() { // NOTE: max_time_slice <= 5 to ensure 'priority' test pass