mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
add init stack
This commit is contained in:
parent
73f66d54b9
commit
a611ac416f
@ -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;
|
||||
|
@ -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)]
|
||||
|
@ -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(());
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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<T: Pod>(&mut self, offset: usize, new_val: &T) -> Result<()> {
|
||||
fn write_val<T: Pod>(&self, offset: usize, new_val: &T) -> Result<()> {
|
||||
self.write_bytes(offset, new_val.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 {}
|
||||
|
93
src/kxos-std/src/memory/aux_vec.rs
Normal file
93
src/kxos-std/src/memory/aux_vec.rs
Normal file
@ -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<AuxKey, u64>,
|
||||
}
|
||||
|
||||
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<u64> {
|
||||
self.table.get(&key).map(|val_ref| *val_ref)
|
||||
}
|
||||
|
||||
pub fn del(&mut self, key: AuxKey) -> Option<u64> {
|
||||
self.table.remove(&key)
|
||||
}
|
||||
|
||||
pub fn table(&self) -> &BTreeMap<AuxKey, u64> {
|
||||
&self.table
|
||||
}
|
||||
}
|
@ -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<ElfSegment<'a>>,
|
||||
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<Self, ElfError> {
|
||||
pub fn parse_elf_data(elf_file_content: &'a [u8], filename: CString) -> Result<Self, ElfError> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
276
src/kxos-std/src/memory/init_stack.rs
Normal file
276
src/kxos-std/src/memory/init_stack.rs
Normal file
@ -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<CString>,
|
||||
/// Environmental variables
|
||||
envp: Vec<CString>,
|
||||
/// 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<u64>, argv_pointers: &Vec<u64>) {
|
||||
// ensure 8-byte alignment
|
||||
self.write_u64(0, vm_space);
|
||||
let auxvec_size = (self.aux_vec.table().len() + 1) * (mem::size_of::<u64>() * 2);
|
||||
let envp_pointers_size = (envp_pointers.len() + 1) * mem::size_of::<u64>();
|
||||
let argv_pointers_size = (argv_pointers.len() + 1) * mem::size_of::<u64>();
|
||||
let argc_size = mem::size_of::<u64>();
|
||||
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<u64> {
|
||||
let envp = self.envp.iter().map(|envp| envp.clone()).collect::<Vec<_>>();
|
||||
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<u64> {
|
||||
let argv = self.argv.iter().map(|argv| argv.clone()).collect::<Vec<_>>();
|
||||
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<u64>) {
|
||||
// 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<u64>) {
|
||||
// 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
|
||||
}
|
@ -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<ElfLoadInfo<'a>, 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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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<Self> {
|
||||
let process = Process::create_user_process(elf_file_content);
|
||||
pub fn spawn_user_process(filename: CString, elf_file_content: &'static [u8]) -> Arc<Self> {
|
||||
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<Self> {
|
||||
fn create_user_process(filename: CString, elf_file_content: &'static [u8]) -> Arc<Self> {
|
||||
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)
|
||||
|
@ -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<Process>) -> Arc<Task> {
|
||||
pub fn create_user_task_from_elf(filename: CString, elf_file_content: &[u8], process: Weak<Process>) -> Arc<Task> {
|
||||
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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user