diff --git a/kernel/src/arch/riscv32/context.rs b/kernel/src/arch/riscv32/context.rs index 0d41298..3faef9e 100644 --- a/kernel/src/arch/riscv32/context.rs +++ b/kernel/src/arch/riscv32/context.rs @@ -180,4 +180,9 @@ impl Context { }, }.push_at(kstack_top) } + /// Called at a new user context + /// To get the init TrapFrame in sys_exec + pub unsafe fn get_init_tf(&self) -> TrapFrame { + (*(self.0 as *const InitStack)).tf.clone() + } } \ No newline at end of file diff --git a/kernel/src/arch/x86_64/interrupt/trapframe.rs b/kernel/src/arch/x86_64/interrupt/trapframe.rs index 6f14349..0500134 100644 --- a/kernel/src/arch/x86_64/interrupt/trapframe.rs +++ b/kernel/src/arch/x86_64/interrupt/trapframe.rs @@ -183,4 +183,9 @@ impl Context { }, }.push_at(kstack_top) } + /// Called at a new user context + /// To get the init TrapFrame in sys_exec + pub unsafe fn get_init_tf(&self) -> TrapFrame { + (*(self.0 as *const InitStack)).tf.clone() + } } \ No newline at end of file diff --git a/kernel/src/fs.rs b/kernel/src/fs.rs index bb8c965..3ffb3e6 100644 --- a/kernel/src/fs.rs +++ b/kernel/src/fs.rs @@ -40,12 +40,9 @@ pub fn shell() { let files = ROOT_INODE.list().unwrap(); println!("Available programs: {:?}", files); - // Avoid stack overflow in release mode - // Equal to: `buf = Box::new([0; 64 << 12])` - use alloc::alloc::{alloc, dealloc, Layout}; const BUF_SIZE: usize = 0x40000; - let layout = Layout::from_size_align(BUF_SIZE, 0x1000).unwrap(); - let buf = unsafe{ slice::from_raw_parts_mut(alloc(layout), BUF_SIZE) }; + let mut buf = Vec::with_capacity(BUF_SIZE); + unsafe { buf.set_len(BUF_SIZE); } loop { print!(">> "); use console::get_line; @@ -57,14 +54,13 @@ pub fn shell() { if let Ok(file) = ROOT_INODE.lookup(name) { use process::*; let len = file.read_at(0, &mut *buf).unwrap(); - let pid = processor().manager().add(ContextImpl::new_user(&buf[..len], cmd.as_str())); + let pid = processor().manager().add(ContextImpl::new_user(&buf[..len], cmd.split(' '))); processor().manager().wait(thread::current().id(), pid); processor().yield_now(); } else { println!("Program not exist"); } } - unsafe { dealloc(buf.as_mut_ptr(), layout) }; } struct MemBuf(&'static [u8]); @@ -89,6 +85,7 @@ impl Device for MemBuf { } use core::slice; +use alloc::vec::Vec; #[cfg(target_arch = "x86_64")] impl BlockedDevice for ide::IDE { diff --git a/kernel/src/process/context.rs b/kernel/src/process/context.rs index 6171202..a2e9127 100644 --- a/kernel/src/process/context.rs +++ b/kernel/src/process/context.rs @@ -7,10 +7,11 @@ use simple_filesystem::file::File; use alloc::{boxed::Box, collections::BTreeMap, vec::Vec, sync::Arc, string::String}; use spin::Mutex; +// TODO: avoid pub pub struct ContextImpl { - arch: ArchContext, - memory_set: MemorySet, - kstack: KernelStack, + pub arch: ArchContext, + pub memory_set: MemorySet, + pub kstack: KernelStack, pub files: BTreeMap>>, pub cwd: String, } @@ -47,7 +48,9 @@ impl ContextImpl { } /// Make a new user thread from ELF data - pub fn new_user(data: &[u8], cmd: &str) -> Box { + pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box + where Iter: Iterator + { // Parse elf let elf = ElfFile::new(data).expect("failed to read elf"); let is32 = match elf.header.pt2 { @@ -84,7 +87,7 @@ impl ContextImpl { let target = unsafe { slice::from_raw_parts_mut(virt_addr as *mut u8, file_size) }; target.copy_from_slice(&data[offset..offset + file_size]); } - ustack_top = push_args_at_stack(cmd, ustack_top); + ustack_top = push_args_at_stack(args, ustack_top); }); } @@ -150,11 +153,13 @@ unsafe fn push_slice(mut sp: usize, vs: &[T]) -> usize { sp } -unsafe fn push_args_at_stack(cmd: &str, stack_top: usize) -> usize { +unsafe fn push_args_at_stack<'a, Iter>(args: Iter, stack_top: usize) -> usize + where Iter: Iterator +{ use core::{ptr, slice}; let mut sp = stack_top; let mut argv = Vec::new(); - for arg in cmd.split(' ') { + for arg in args { sp = push_slice(sp, &[0u8]); sp = push_slice(sp, arg.as_bytes()); argv.push(sp); diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index 6a330e0..3d2a7f7 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -8,9 +8,11 @@ use simple_filesystem::{INode, file::File, FileInfo, FileType}; use core::{slice, str}; use alloc::sync::Arc; use spin::Mutex; +use alloc::vec::Vec; +use alloc::string::String; /// System call dispatcher -pub fn syscall(id: usize, args: [usize; 6], tf: &TrapFrame) -> i32 { +pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> i32 { let ret = match id { // file 100 => sys_open(args[0] as *const u8, args[1]), @@ -29,7 +31,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &TrapFrame) -> i32 { 001 => sys_exit(args[0] as i32), 002 => sys_fork(tf), 003 => sys_wait(args[0], args[1] as *mut i32), -// 004 => sys_exec(), + 004 => sys_exec(args[0] as *const u8, args[1] as usize, args[2] as *const *const u8, tf), // 005 => sys_clone(), 010 => sys_yield(), 011 => sys_sleep(args[0]), @@ -183,6 +185,42 @@ fn sys_wait(pid: usize, code: *mut i32) -> SysResult { } } +fn sys_exec(name: *const u8, argc: usize, argv: *const *const u8, tf: &mut TrapFrame) -> SysResult { + // TODO: check ptr + let name = if name.is_null() { "" } else { unsafe { util::from_cstr(name) } }; + info!("exec: {:?}, argc: {}, argv: {:?}", name, argc, argv); + // Copy args to kernel + let args: Vec = unsafe { + slice::from_raw_parts(argv, argc).iter() + .map(|&arg| String::from(util::from_cstr(arg))) + .collect() + }; + + // Read program file + let path = args[0].as_str(); + let inode = ::fs::ROOT_INODE.lookup(path)?; + let size = inode.info()?.size; + let mut buf = Vec::with_capacity(size); + unsafe { buf.set_len(size); } + inode.read_at(0, buf.as_mut_slice())?; + + // Make new Context + let iter = args.iter().map(|s| s.as_str()); + let mut context = ContextImpl::new_user(buf.as_slice(), iter); + + // Activate new page table + unsafe { context.memory_set.activate(); } + + // Modify the TrapFrame + *tf = unsafe { context.arch.get_init_tf() }; + + // Swap Context but keep KStack + ::core::mem::swap(&mut process().kstack, &mut context.kstack); + ::core::mem::swap(process(), &mut *context); + + Ok(0) +} + fn sys_yield() -> SysResult { thread::yield_now(); Ok(0)