From a611ac416ff07672a14aa57b4db9b2a03d4b6b8c Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Wed, 14 Sep 2022 17:08:34 +0800 Subject: [PATCH] add init stack --- src/kxos-frame/src/config.rs | 2 +- src/kxos-frame/src/lib.rs | 3 +- src/kxos-frame/src/mm/memory_set.rs | 16 +- src/kxos-frame/src/user.rs | 5 + src/kxos-frame/src/vm/io.rs | 2 +- src/kxos-frame/src/vm/pod.rs | 3 + src/kxos-std/src/lib.rs | 10 +- src/kxos-std/src/memory/aux_vec.rs | 93 +++++++++ src/kxos-std/src/memory/elf.rs | 69 +++++-- src/kxos-std/src/memory/init_stack.rs | 276 ++++++++++++++++++++++++++ src/kxos-std/src/memory/mod.rs | 11 +- src/kxos-std/src/memory/user_stack.rs | 54 ----- src/kxos-std/src/process/mod.rs | 9 +- src/kxos-std/src/process/task.rs | 19 +- 14 files changed, 475 insertions(+), 97 deletions(-) create mode 100644 src/kxos-std/src/memory/aux_vec.rs create mode 100644 src/kxos-std/src/memory/init_stack.rs delete mode 100644 src/kxos-std/src/memory/user_stack.rs diff --git a/src/kxos-frame/src/config.rs b/src/kxos-frame/src/config.rs index 99cb14c4a..aa40ab577 100644 --- a/src/kxos-frame/src/config.rs +++ b/src/kxos-frame/src/config.rs @@ -15,4 +15,4 @@ pub const PAGE_SIZE_BITS: usize = 0xc; pub const KVA_START: usize = (usize::MAX) << PAGE_SIZE_BITS; -pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Info; +pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Debug; diff --git a/src/kxos-frame/src/lib.rs b/src/kxos-frame/src/lib.rs index fb48d731b..3f4f2b328 100644 --- a/src/kxos-frame/src/lib.rs +++ b/src/kxos-frame/src/lib.rs @@ -86,7 +86,8 @@ pub fn init(boot_info: &'static mut BootInfo) { } } fn general_handler(trap_frame: TrapFrame) { - debug!("TrapFrame:{:#x?}", trap_frame); + println!("{:?}", trap_frame); + panic!("couldn't handler trap right now"); } #[inline(always)] diff --git a/src/kxos-frame/src/mm/memory_set.rs b/src/kxos-frame/src/mm/memory_set.rs index 9746c47c6..d9315ebe4 100644 --- a/src/kxos-frame/src/mm/memory_set.rs +++ b/src/kxos-frame/src/mm/memory_set.rs @@ -221,13 +221,17 @@ impl MemorySet { let mut current_addr = addr; let mut remain = data.len(); let start_write = false; + let mut offset = 0usize; for (va, area) in self.areas.iter_mut() { if current_addr >= va.0 && current_addr < area.size + va.0 { if !area.flags.contains(PTFlags::WRITABLE) { return Err(Error::PageFault); } - area.write_data(current_addr, data); - remain -= (va.0 + area.size - current_addr).min(remain); + let write_len = remain.min(area.size + va.0 - current_addr); + area.write_data(current_addr, &data[offset..(offset + write_len)]); + offset += write_len; + remain -= write_len; + // remain -= (va.0 + area.size - current_addr).min(remain); if remain == 0 { return Ok(()); } @@ -242,11 +246,15 @@ impl MemorySet { pub fn read_bytes(&self, addr: usize, data: &mut [u8]) -> Result<()> { let mut current_addr = addr; let mut remain = data.len(); + let mut offset = 0usize; let start_read = false; for (va, area) in self.areas.iter() { if current_addr >= va.0 && current_addr < area.size + va.0 { - area.read_data(current_addr, data); - remain -= (va.0 + area.size - current_addr).min(remain); + let read_len = remain.min(area.size + va.0 - current_addr); + area.read_data(current_addr , &mut data[offset..(offset + read_len)]); + remain -= read_len; + offset += read_len; + // remain -= (va.0 + area.size - current_addr).min(remain); if remain == 0 { return Ok(()); } diff --git a/src/kxos-frame/src/user.rs b/src/kxos-frame/src/user.rs index 1c9cd12a6..369f7db1b 100644 --- a/src/kxos-frame/src/user.rs +++ b/src/kxos-frame/src/user.rs @@ -117,6 +117,11 @@ impl<'a> UserMode<'a> { self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip; self.current.syscall_frame().callee.rsp = self.user_space.cpu_ctx.gp_regs.rsp; self.current.syscall_frame().caller.rax = self.user_space.cpu_ctx.gp_regs.rax; + + // set argument registers + self.current.syscall_frame().caller.rdi = self.user_space.cpu_ctx.gp_regs.rdi; + self.current.syscall_frame().caller.rsi = self.user_space.cpu_ctx.gp_regs.rsi; + self.current.syscall_frame().caller.rdx = self.user_space.cpu_ctx.gp_regs.rdx; self.executed = true; } else { if self.current.inner_exclusive_access().is_from_trap { diff --git a/src/kxos-frame/src/vm/io.rs b/src/kxos-frame/src/vm/io.rs index 1f1dc05b9..2be7577d3 100644 --- a/src/kxos-frame/src/vm/io.rs +++ b/src/kxos-frame/src/vm/io.rs @@ -47,7 +47,7 @@ pub trait VmIo: Send + Sync { fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()>; /// Write a value of a specified type at a specified offset. - fn write_val(&mut self, offset: usize, new_val: &T) -> Result<()> { + fn write_val(&self, offset: usize, new_val: &T) -> Result<()> { self.write_bytes(offset, new_val.as_bytes())?; Ok(()) } diff --git a/src/kxos-frame/src/vm/pod.rs b/src/kxos-frame/src/vm/pod.rs index 1216486f5..5a9cb7262 100644 --- a/src/kxos-frame/src/vm/pod.rs +++ b/src/kxos-frame/src/vm/pod.rs @@ -52,6 +52,9 @@ pub unsafe trait Pod: Copy + Sized { } } +/// WorkAround. When implement macro impl_pod_for, this can be removed. +unsafe impl Pod for u64 {} + macro_rules! impl_pod_for { ($($token:tt)*/* define the input */) => { /* define the expansion */ diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs index c63cdbc66..d6f4651a5 100644 --- a/src/kxos-std/src/lib.rs +++ b/src/kxos-std/src/lib.rs @@ -6,6 +6,7 @@ #![feature(const_btree_new)] #![feature(cstr_from_bytes_until_nul)] +use alloc::ffi::CString; use kxos_frame::{debug, info, println}; use process::Process; @@ -36,21 +37,24 @@ pub fn init_process() { ); let hello_world_content = read_hello_world_content(); - let process = Process::spawn_user_process(hello_world_content); + let hello_world_filename = CString::new("hello_world").unwrap(); + let process = Process::spawn_user_process(hello_world_filename, hello_world_content); info!( "[kxos-std/lib.rs] spwan hello world process, pid = {}", process.pid() ); let fork_content = read_fork_content(); - let process = Process::spawn_user_process(fork_content); + let fork_filename = CString::new("fork").unwrap(); + let process = Process::spawn_user_process(fork_filename, fork_content); info!( "[kxos-std/lib.rs] spawn fork process, pid = {}", process.pid() ); let hello_c_content = read_hello_c_content(); - let process = Process::spawn_user_process(hello_c_content); + let hello_c_filename = CString::new("hello_c").unwrap(); + let process = Process::spawn_user_process(hello_c_filename, hello_c_content); info!("spawn hello_c process, pid = {}", process.pid()); loop {} diff --git a/src/kxos-std/src/memory/aux_vec.rs b/src/kxos-std/src/memory/aux_vec.rs new file mode 100644 index 000000000..49ae60747 --- /dev/null +++ b/src/kxos-std/src/memory/aux_vec.rs @@ -0,0 +1,93 @@ +use alloc::collections::BTreeMap; + +/// This implementation is from occlum. + +/// Auxiliary Vector. +/// +/// # What is Auxiliary Vector? +/// +/// Here is a concise description of Auxiliary Vector from GNU's manual: +/// +/// > When a program is executed, it receives information from the operating system +/// about the environment in which it is operating. The form of this information +/// is a table of key-value pairs, where the keys are from the set of ‘AT_’ +/// values in elf.h. + +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[repr(u8)] +pub enum AuxKey { + AT_NULL = 0, /* end of vector */ + AT_IGNORE = 1, /* entry should be ignored */ + AT_EXECFD = 2, /* file descriptor of program */ + AT_PHDR = 3, /* program headers for program */ + AT_PHENT = 4, /* size of program header entry */ + AT_PHNUM = 5, /* number of program headers */ + AT_PAGESZ = 6, /* system page size */ + AT_BASE = 7, /* base address of interpreter */ + AT_FLAGS = 8, /* flags */ + AT_ENTRY = 9, /* entry point of program */ + AT_NOTELF = 10, /* program is not ELF */ + AT_UID = 11, /* real uid */ + AT_EUID = 12, /* effective uid */ + AT_GID = 13, /* real gid */ + AT_EGID = 14, /* effective gid */ + AT_PLATFORM = 15, /* string identifying CPU for optimizations */ + AT_HWCAP = 16, /* arch dependent hints at CPU capabilities */ + AT_CLKTCK = 17, /* frequency at which times() increments */ + + /* 18...22 not used */ + AT_SECURE = 23, /* secure mode boolean */ + AT_BASE_PLATFORM = 24, /* string identifying real platform, may + * differ from AT_PLATFORM. */ + AT_RANDOM = 25, /* address of 16 random bytes */ + AT_HWCAP2 = 26, /* extension of AT_HWCAP */ + + /* 28...30 not used */ + AT_EXECFN = 31, /* filename of program */ + AT_SYSINFO = 32, +} + +impl AuxKey { + pub fn as_u64(&self) -> u64 { + *self as u64 + } +} + +#[derive(Clone, Default, Debug)] +pub struct AuxVec { + table: BTreeMap, +} + +impl AuxVec { + pub const fn new() -> AuxVec { + AuxVec { + table: BTreeMap::new(), + } + } +} + +impl AuxVec { + pub fn set(&mut self, key: AuxKey, val: u64) -> Result<(), &'static str> { + if key == AuxKey::AT_NULL || key == AuxKey::AT_IGNORE { + return Err("Illegal key"); + } + self.table + .entry(key) + .and_modify(|val_mut| *val_mut = val) + .or_insert(val); + Ok(()) + } + + pub fn get(&self, key: AuxKey) -> Option { + self.table.get(&key).map(|val_ref| *val_ref) + } + + pub fn del(&mut self, key: AuxKey) -> Option { + self.table.remove(&key) + } + + pub fn table(&self) -> &BTreeMap { + &self.table + } +} \ No newline at end of file diff --git a/src/kxos-std/src/memory/elf.rs b/src/kxos-std/src/memory/elf.rs index 62acc3053..d35c8d808 100644 --- a/src/kxos-std/src/memory/elf.rs +++ b/src/kxos-std/src/memory/elf.rs @@ -1,10 +1,10 @@ use core::{cmp::Ordering, ops::Range}; +use alloc::ffi::CString; use alloc::vec; use alloc::vec::Vec; use kxos_frame::{ config::PAGE_SIZE, - debug, vm::{Vaddr, VmIo, VmPerm, VmSpace}, Error, }; @@ -14,12 +14,12 @@ use xmas_elf::{ ElfFile, }; -use super::{user_stack::UserStack, vm_page::VmPageRange}; +use super::{init_stack::InitStack, vm_page::VmPageRange}; pub struct ElfLoadInfo<'a> { entry_point: Vaddr, segments: Vec>, - user_stack: UserStack, + init_stack: InitStack, } pub struct ElfSegment<'a> { @@ -85,11 +85,11 @@ impl<'a> ElfSegment<'a> { // return Err(ElfError::SegmentNotPageAligned); // } // map page - debug!( - "map_segment: 0x{:x} - 0x{:x}", - self.start_address(), - self.end_address() - ); + // debug!( + // "map_segment: 0x{:x} - 0x{:x}", + // self.start_address(), + // self.end_address() + // ); let vm_page_range = VmPageRange::new_range(self.start_address()..self.end_address()); for page in vm_page_range.iter() { // map page if the page is not mapped @@ -99,11 +99,11 @@ impl<'a> ElfSegment<'a> { } } - debug!( - "copy_segment: 0x{:x} - 0x{:x}", - self.start_address(), - self.end_address() - ); + // debug!( + // "copy_segment: 0x{:x} - 0x{:x}", + // self.start_address(), + // self.end_address() + // ); // copy segment vm_space.write_bytes(self.start_address(), self.data)?; Ok(()) @@ -115,11 +115,11 @@ impl<'a> ElfSegment<'a> { } impl<'a> ElfLoadInfo<'a> { - fn with_capacity(entry_point: Vaddr, capacity: usize, user_stack: UserStack) -> Self { + fn with_capacity(entry_point: Vaddr, capacity: usize, init_stack: InitStack) -> Self { Self { entry_point, segments: Vec::with_capacity(capacity), - user_stack, + init_stack, } } @@ -127,7 +127,7 @@ impl<'a> ElfLoadInfo<'a> { self.segments.push(elf_segment); } - pub fn parse_elf_data(elf_file_content: &'a [u8]) -> Result { + pub fn parse_elf_data(elf_file_content: &'a [u8], filename: CString) -> Result { let elf_file = match ElfFile::new(elf_file_content) { Err(error_msg) => return Err(ElfError::from(error_msg)), Ok(elf_file) => elf_file, @@ -137,8 +137,8 @@ impl<'a> ElfLoadInfo<'a> { let entry_point = elf_file.header.pt2.entry_point() as Vaddr; // FIXME: only contains load segment? let segments_count = elf_file.program_iter().count(); - let user_stack = UserStack::new_default_config(); - let mut elf_load_info = ElfLoadInfo::with_capacity(entry_point, segments_count, user_stack); + let init_stack = InitStack::new_default_config(filename); + let mut elf_load_info = ElfLoadInfo::with_capacity(entry_point, segments_count, init_stack); // parse each segemnt for segment in elf_file.program_iter() { @@ -177,8 +177,8 @@ impl<'a> ElfLoadInfo<'a> { Ok(()) } - pub fn map_and_clear_user_stack(&self, vm_space: &VmSpace) { - self.user_stack.map_and_zeroed(vm_space); + pub fn init_stack(&mut self, vm_space: &VmSpace) { + self.init_stack.init(vm_space).expect("Init User Stack failed"); } /// return the perm of elf pages @@ -192,7 +192,23 @@ impl<'a> ElfLoadInfo<'a> { } pub fn user_stack_top(&self) -> u64 { - self.user_stack.stack_top() as u64 + self.init_stack.user_stack_top() as u64 + } + + pub fn argc(&self) -> u64 { + self.init_stack.argc() + } + + pub fn argv(&self) -> u64 { + self.init_stack.argv() + } + + pub fn envc(&self) -> u64 { + self.init_stack.envc() + } + + pub fn envp(&self) -> u64 { + self.init_stack.envp() } /// read content from vmspace to ensure elf data is correctly copied to user space @@ -205,6 +221,17 @@ impl<'a> ElfLoadInfo<'a> { .read_bytes(start_address, &mut read_buffer) .expect("read bytes failed"); let res = segment.data.cmp(&read_buffer); + // if res != Ordering::Equal { + // debug!("segment: 0x{:x} - 0x{:x}", segment.start_address(), segment.end_address()); + // debug!("read buffer len: 0x{:x}", read_buffer.len()); + // for i in 0..segment.data.len() { + // if segment.data[i] != read_buffer[i] { + // debug!("i = 0x{:x}", i); + // break; + // } + // } + // } + assert_eq!(res, Ordering::Equal); } } diff --git a/src/kxos-std/src/memory/init_stack.rs b/src/kxos-std/src/memory/init_stack.rs new file mode 100644 index 000000000..c6e7cd843 --- /dev/null +++ b/src/kxos-std/src/memory/init_stack.rs @@ -0,0 +1,276 @@ +use core::mem; + +use alloc::{ffi::CString, vec::Vec}; +use alloc::vec; +use kxos_frame::{config::PAGE_SIZE, debug, vm::{Vaddr, VmIo, VmPerm, VmSpace}}; + +use super::{aux_vec::{AuxKey, AuxVec}, elf::ElfError, vm_page::VmPageRange}; + +pub const INIT_STACK_BASE: Vaddr = 0x0000_0000_1000_0000; +pub const INIT_STACK_SIZE: usize = 0x1000 * 16; // 64KB + +/// The process initial stack, contains arguments, environmental variables and auxiliary vectors +/// The data layout of init stack can be seen in Figure 3.9 in https://uclibc.org/docs/psABI-x86_64.pdf +/* + * The initial stack of a process looks like below(This figure is from occlum): + * + * + * +---------------------+ <------+ Top of stack + * | | (high address) + * | Null-terminated | + * | strings referenced | + * | by variables below | + * | | + * +---------------------+ + * | AT_NULL | + * +---------------------+ + * | AT_NULL | + * +---------------------+ + * | ... | + * +---------------------+ + * | aux_val[0] | + * +---------------------+ + * | aux_key[0] | <------+ Auxiliary table + * +---------------------+ + * | NULL | + * +---------------------+ + * | ... | + * +---------------------+ + * | char* envp[0] | <------+ Environment variabls + * +---------------------+ + * | NULL | + * +---------------------+ + * | char* argv[argc-1] | + * +---------------------+ + * | ... | + * +---------------------+ + * | char* argv[0] | + * +---------------------+ + * | long argc | <------+ Program arguments + * +---------------------+ + * | | + * | | + * + + + * + */ +pub struct InitStack { + /// The high address of init stack + init_stack_top: Vaddr, + init_stack_size: usize, + offset: usize, + /// Command line args + argv: Vec, + /// Environmental variables + envp: Vec, + /// Auxiliary Vector + aux_vec: AuxVec, +} + + +impl InitStack { + /// initialize user stack on base addr + pub fn new(filename: CString, stack_top: Vaddr, stack_size: usize) -> Self { + let argv = vec![filename]; + Self { + init_stack_top: stack_top, + init_stack_size: stack_size, + offset: 0, + argv, + envp: Vec::new(), + aux_vec: AuxVec::new(), + } + } + + /// This function only work for first process + pub fn new_default_config(filename: CString) -> Self { + let argv = vec![filename]; + Self { + // add a guard page at stack top + init_stack_top: INIT_STACK_BASE - PAGE_SIZE, + init_stack_size: INIT_STACK_SIZE, + offset: 0, + argv, + envp: Vec::new(), + aux_vec: AuxVec::new(), + } + } + + /// the user stack top(high address), used to setup rsp + pub fn user_stack_top(&self) -> Vaddr { + let stack_top = self.init_stack_top - self.offset; + debug!("user stack top: 0x{:x}", stack_top); + // ensure stack top is 16-bytes aligned + assert!(stack_top & !0xf == stack_top); + stack_top + } + + /// the user stack bottom(low address) + const fn user_stack_bottom(&self) -> Vaddr { + self.init_stack_top - self.init_stack_size + } + + pub fn init(&mut self, vm_space: &VmSpace) -> Result<(), ElfError> { + self.map_and_zeroed(vm_space); + self.write_stack_content(vm_space); + Ok(()) + } + + fn map_and_zeroed(&self, vm_space: &VmSpace) { + let mut vm_page_range = VmPageRange::new_range(self.user_stack_bottom()..self.user_stack_top()); + let vm_perm = InitStack::perm(); + vm_page_range.map_zeroed(vm_space, vm_perm); + } + + /// Libc ABI requires 16-byte alignment of the stack entrypoint. + /// Current postion of the stack is 8-byte aligned already, insert 8 byte + /// to meet the requirement if necessary. + fn adjust_stack_alignment(&mut self, vm_space: &VmSpace, envp_pointers: &Vec, argv_pointers: &Vec) { + // ensure 8-byte alignment + self.write_u64(0, vm_space); + let auxvec_size = (self.aux_vec.table().len() + 1) * (mem::size_of::() * 2); + let envp_pointers_size = (envp_pointers.len() + 1) * mem::size_of::(); + let argv_pointers_size = (argv_pointers.len() + 1) * mem::size_of::(); + let argc_size = mem::size_of::(); + let to_write_size = auxvec_size + envp_pointers_size + argv_pointers_size + argc_size; + if (self.init_stack_top - self.offset - to_write_size) % 16 != 0 { + self.write_u64(0, vm_space); + } + } + + fn write_stack_content(&mut self, vm_space: &VmSpace) { + // write envp string + let envp_pointers = self.write_envp_strings(vm_space); + // write argv string + let argv_pointers = self.write_argv_strings(vm_space); + // write random value + let random_value = generate_random_for_aux_vec(); + let random_value_pointer = self.write_bytes(&random_value, vm_space); + self.aux_vec.set(AuxKey::AT_RANDOM, random_value_pointer).expect("Set random value failed"); + self.adjust_stack_alignment(vm_space, &envp_pointers, &argv_pointers); + self.write_aux_vec(vm_space); + self.write_envp_pointers(vm_space, envp_pointers); + self.write_argv_pointers(vm_space, argv_pointers); + // write argc + let argc = self.argc(); + self.write_u64(argc, vm_space); + } + + + fn write_envp_strings(&mut self, vm_space: &VmSpace) -> Vec { + let envp = self.envp.iter().map(|envp| envp.clone()).collect::>(); + let mut envp_pointers = Vec::with_capacity(envp.len()); + for envp in envp.iter() { + let pointer = self.write_cstring(envp, vm_space); + envp_pointers.push(pointer); + } + envp_pointers + } + + fn write_argv_strings(&mut self, vm_space: &VmSpace) -> Vec { + let argv = self.argv.iter().map(|argv| argv.clone()).collect::>(); + let mut argv_pointers = Vec::with_capacity(argv.len()); + for argv in argv.iter().rev() { + let pointer = self.write_cstring(argv, vm_space); + argv_pointers.push(pointer); + } + argv_pointers.reverse(); + argv_pointers + } + + fn write_aux_vec(&mut self, vm_space: &VmSpace) { + // Write NULL auxilary + self.write_u64(0, vm_space); + self.write_u64(AuxKey::AT_NULL as u64, vm_space); + // Write Auxiliary vectors + let aux_vec: Vec<_> = self.aux_vec.table().iter().map(|(aux_key, aux_value)| (*aux_key, *aux_value)).collect(); + for (aux_key, aux_value) in aux_vec.iter() { + self.write_u64(*aux_value, vm_space); + self.write_u64(*aux_key as u64, vm_space); + } + } + + fn write_envp_pointers(&mut self, vm_space: &VmSpace, mut envp_pointers: Vec) { + // write NULL pointer + self.write_u64(0, vm_space); + // write envp pointers + envp_pointers.reverse(); + for envp_pointer in envp_pointers { + self.write_u64(envp_pointer, vm_space); + } + } + + fn write_argv_pointers(&mut self, vm_space: &VmSpace, mut argv_pointers: Vec) { + // write 0 + self.write_u64(0, vm_space); + // write argv pointers + argv_pointers.reverse(); + for argv_pointer in argv_pointers { + self.write_u64(argv_pointer, vm_space); + } + } + + /// Command line argument counter + pub fn argc(&self) -> u64 { + 1 + self.argv.len() as u64 + } + + /// Command linke argument start address + pub fn argv(&self) -> u64{ + self.user_stack_top() as u64 + 8 + } + + /// Environmental variables counter + pub fn envc(&self) -> u64 { + self.envp.len() as u64 + } + + /// Environmental variables pointers + pub fn envp(&self) -> u64 { + 0 + } + /// returns the u64 start address + fn write_u64(&mut self, val: u64, vm_space: &VmSpace) -> u64 { + let start_address = align_down(self.init_stack_top - self.offset - 8, 8); + self.offset = self.init_stack_top - start_address; + debug!("start_address: 0x{:x}", start_address); + vm_space.write_val(start_address, &val).expect("Write u64 failed"); + (self.init_stack_top - self.offset) as u64 + } + + fn write_bytes(&mut self, bytes: &[u8], vm_space: &VmSpace) -> u64 { + let len = bytes.len(); + self.offset += len; + vm_space.write_bytes(self.init_stack_top - self.offset, bytes).expect("Write String failed"); + (self.init_stack_top - self.offset) as u64 + } + + /// returns the string start address + fn write_cstring(&mut self, val: &CString, vm_space: &VmSpace) -> u64 { + let bytes = val.as_bytes(); + self.write_bytes(bytes, vm_space) + } + + pub const fn perm() -> VmPerm { + VmPerm::RWU + } +} + +fn is_power_of_two(val: usize) -> bool { + (val != 0) && ((val & (val - 1)) == 0) +} + +/// align should be the pow of 2 +fn align_down(vaddr: usize, align: usize) -> usize { + assert!(is_power_of_two(align)); + vaddr & !(align - 1) +} + +/// generate random [u8; 16]. +/// FIXME: generate really random value +fn generate_random_for_aux_vec() -> [u8; 16] { + let mut rand_val = [0; 16]; + for i in 0..16u8 { + rand_val[i as usize] = 0xff - i; + } + rand_val +} diff --git a/src/kxos-std/src/memory/mod.rs b/src/kxos-std/src/memory/mod.rs index ee143c31b..e3c3baeb3 100644 --- a/src/kxos-std/src/memory/mod.rs +++ b/src/kxos-std/src/memory/mod.rs @@ -1,6 +1,8 @@ pub mod elf; -pub mod user_stack; +pub mod init_stack; pub mod vm_page; +pub mod aux_vec; +use alloc::ffi::CString; use kxos_frame::{debug, vm::VmSpace}; use self::elf::{ElfError, ElfLoadInfo}; @@ -11,15 +13,14 @@ use self::elf::{ElfError, ElfLoadInfo}; /// 3. map frames to the correct vaddr /// 4. (allocate frams and) map the user stack pub fn load_elf_to_vm_space<'a>( + filename: CString, elf_file_content: &'a [u8], vm_space: &VmSpace, ) -> Result, ElfError> { - let elf_load_info = ElfLoadInfo::parse_elf_data(elf_file_content)?; - debug!("parse data success"); + let mut elf_load_info = ElfLoadInfo::parse_elf_data(elf_file_content, filename)?; elf_load_info.copy_data(vm_space)?; - debug!("copy_data success"); elf_load_info.debug_check_map_result(vm_space); debug!("map elf success"); - elf_load_info.map_and_clear_user_stack(vm_space); + elf_load_info.init_stack(vm_space); Ok(elf_load_info) } diff --git a/src/kxos-std/src/memory/user_stack.rs b/src/kxos-std/src/memory/user_stack.rs deleted file mode 100644 index a53a9ec00..000000000 --- a/src/kxos-std/src/memory/user_stack.rs +++ /dev/null @@ -1,54 +0,0 @@ -use kxos_frame::{ - config::PAGE_SIZE, - vm::{Vaddr, VmPerm, VmSpace}, -}; - -use super::vm_page::VmPageRange; - -pub const USER_STACK_BASE: Vaddr = 0x0000_0000_1000_0000; -pub const USER_STACK_SIZE: usize = 0x1000 * 16; // 64KB - -pub struct UserStack { - /// The high address of user stack - stack_top: Vaddr, - stack_size: usize, -} - -impl UserStack { - /// initialize user stack on base addr - pub const fn new(stack_top: Vaddr, stack_size: usize) -> Self { - Self { - stack_top, - stack_size, - } - } - - /// This function only work for first process - pub const fn new_default_config() -> Self { - Self { - // add a guard page at stack top - stack_top: USER_STACK_BASE - PAGE_SIZE, - stack_size: USER_STACK_SIZE, - } - } - - /// the user stack top(high address), used to setup rsp - pub const fn stack_top(&self) -> Vaddr { - self.stack_top - } - - /// the user stack bottom(low address) - const fn stack_bottom(&self) -> Vaddr { - self.stack_top - self.stack_size - } - - pub fn map_and_zeroed(&self, vm_space: &VmSpace) { - let mut vm_page_range = VmPageRange::new_range(self.stack_bottom()..self.stack_top()); - let vm_perm = UserStack::perm(); - vm_page_range.map_zeroed(vm_space, vm_perm); - } - - pub const fn perm() -> VmPerm { - VmPerm::RWU - } -} diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index 453ec30b7..13002dfa3 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -1,5 +1,6 @@ use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering}; +use alloc::ffi::CString; use alloc::vec; use alloc::{ sync::{Arc, Weak}, @@ -70,8 +71,8 @@ impl Process { } /// init a user process and send the process to scheduler - pub fn spawn_user_process(elf_file_content: &'static [u8]) -> Arc { - let process = Process::create_user_process(elf_file_content); + pub fn spawn_user_process(filename: CString, elf_file_content: &'static [u8]) -> Arc { + let process = Process::create_user_process(filename, elf_file_content); process.send_to_scheduler(); process } @@ -86,12 +87,12 @@ impl Process { process } - fn create_user_process(elf_file_content: &'static [u8]) -> Arc { + fn create_user_process(filename: CString, elf_file_content: &'static [u8]) -> Arc { let pid = new_pid(); Arc::new_cyclic(|weak_process_ref| { let weak_process = weak_process_ref.clone(); - let task = create_user_task_from_elf(elf_file_content, weak_process); + let task = create_user_task_from_elf(filename, elf_file_content, weak_process); let user_space = task.user_space().map(|user_space| user_space.clone()); Process::new(pid, task, user_space) diff --git a/src/kxos-std/src/process/task.rs b/src/kxos-std/src/process/task.rs index c3b41d764..442425d8a 100644 --- a/src/kxos-std/src/process/task.rs +++ b/src/kxos-std/src/process/task.rs @@ -1,6 +1,6 @@ use core::sync::atomic::AtomicUsize; -use alloc::sync::{Arc, Weak}; +use alloc::{ffi::CString, sync::{Arc, Weak}}; use kxos_frame::{ cpu::CpuContext, debug, @@ -19,16 +19,29 @@ use super::Process; static COUNTER: AtomicUsize = AtomicUsize::new(0); -pub fn create_user_task_from_elf(elf_file_content: &[u8], process: Weak) -> Arc { +pub fn create_user_task_from_elf(filename: CString, elf_file_content: &[u8], process: Weak) -> Arc { let vm_space = VmSpace::new(); - let elf_load_info = load_elf_to_vm_space(elf_file_content, &vm_space).expect("Load Elf failed"); + let elf_load_info = load_elf_to_vm_space(filename, elf_file_content, &vm_space).expect("Load Elf failed"); let mut cpu_ctx = CpuContext::default(); // FIXME: correct regs? // set entry point cpu_ctx.gp_regs.rip = elf_load_info.entry_point(); + debug!("entry point: 0x{:x}", elf_load_info.entry_point()); // set user stack cpu_ctx.gp_regs.rsp = elf_load_info.user_stack_top(); + // See document: https://embeddedartistry.com/blog/2019/04/08/a-general-overview-of-what-happens-before-main/ + // set argc + // cpu_ctx.gp_regs.rdi = elf_load_info.argc(); + // debug!("rdi, argc = {}", elf_load_info.argc()); + // // set argv + // cpu_ctx.gp_regs.rsi = elf_load_info.argv(); + // debug!("rsi, argv = 0x{:x}", elf_load_info.argv()); + // // set envc + // cpu_ctx.gp_regs.rdx = elf_load_info.envc(); + // // set envp + // cpu_ctx.gp_regs.rcx = elf_load_info.envp(); + let user_space = Arc::new(UserSpace::new(vm_space, cpu_ctx)); fn user_task_entry() { let cur = Task::current();