diff --git a/os/Makefile b/os/Makefile index 568a2779..4d86c124 100644 --- a/os/Makefile +++ b/os/Makefile @@ -6,7 +6,7 @@ KERNEL_BIN := $(KERNEL_ELF).bin DISASM_TMP := target/$(TARGET)/$(MODE)/asm FS_IMG := ../user/target/$(TARGET)/$(MODE)/fs.img SDCARD := /dev/sdb -APPS := ../user/src/bin +APPS := ../user/src/bin/* # BOARD BOARD ?= qemu diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index f9e02805..d5828ed2 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -115,6 +115,11 @@ impl VirtPageNum { } impl PhysAddr { + pub fn get_ref(&self) -> &'static T { + unsafe { + (self.0 as *const T).as_ref().unwrap() + } + } pub fn get_mut(&self) -> &'static mut T { unsafe { (self.0 as *mut T).as_mut().unwrap() diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 2242eecb..dbd47fe7 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -13,6 +13,7 @@ pub use page_table::{ PageTableEntry, translated_byte_buffer, translated_str, + translated_ref, translated_refmut, UserBuffer, UserBufferIterator, diff --git a/os/src/mm/page_table.rs b/os/src/mm/page_table.rs index 47f39a76..b1a227fa 100644 --- a/os/src/mm/page_table.rs +++ b/os/src/mm/page_table.rs @@ -174,6 +174,7 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<& v } +/// Load a string from other address spaces into kernel space without an end `\0`. pub fn translated_str(token: usize, ptr: *const u8) -> String { let page_table = PageTable::from_token(token); let mut string = String::new(); @@ -182,14 +183,18 @@ pub fn translated_str(token: usize, ptr: *const u8) -> String { let ch: u8 = *(page_table.translate_va(VirtAddr::from(va)).unwrap().get_mut()); if ch == 0 { break; - } else { - string.push(ch as char); - va += 1; } + string.push(ch as char); + va += 1; } string } +pub fn translated_ref(token: usize, ptr: *const T) -> &'static T { + let page_table = PageTable::from_token(token); + page_table.translate_va(VirtAddr::from(ptr as usize)).unwrap().get_ref() +} + pub fn translated_refmut(token: usize, ptr: *mut T) -> &'static mut T { let page_table = PageTable::from_token(token); let va = ptr as usize; diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index f4a67538..4a3952b4 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -29,7 +29,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_GET_TIME => sys_get_time(), SYSCALL_GETPID => sys_getpid(), SYSCALL_FORK => sys_fork(), - SYSCALL_EXEC => sys_exec(args[0] as *const u8), + SYSCALL_EXEC => sys_exec(args[0] as *const u8, args[1] as *const usize), SYSCALL_WAITPID => sys_waitpid(args[0] as isize, args[1] as *mut i32), _ => panic!("Unsupported syscall_id: {}", syscall_id), } diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index 370ae9cb..bfd592d6 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -9,12 +9,15 @@ use crate::timer::get_time_ms; use crate::mm::{ translated_str, translated_refmut, + translated_ref, }; use crate::fs::{ open_file, OpenFlags, }; use alloc::sync::Arc; +use alloc::vec::Vec; +use alloc::string::String; pub fn sys_exit(exit_code: i32) -> ! { exit_current_and_run_next(exit_code); @@ -48,14 +51,25 @@ pub fn sys_fork() -> isize { new_pid as isize } -pub fn sys_exec(path: *const u8) -> isize { +pub fn sys_exec(path: *const u8, mut args: *const usize) -> isize { let token = current_user_token(); let path = translated_str(token, path); + let mut args_vec: Vec = Vec::new(); + loop { + let arg_str_ptr = *translated_ref(token, args); + if arg_str_ptr == 0 { + break; + } + args_vec.push(translated_str(token, arg_str_ptr as *const u8)); + unsafe { args = args.add(1); } + } if let Some(app_inode) = open_file(path.as_str(), OpenFlags::RDONLY) { let all_data = app_inode.read_all(); let task = current_task().unwrap(); - task.exec(all_data.as_slice()); - 0 + let argc = args_vec.len(); + task.exec(all_data.as_slice(), args_vec); + // return argc because cx.x[10] will be covered with it later + argc as isize } else { -1 } diff --git a/os/src/task/task.rs b/os/src/task/task.rs index 1c733da1..4edd5cef 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -1,4 +1,10 @@ -use crate::mm::{MemorySet, PhysPageNum, KERNEL_SPACE, VirtAddr}; +use crate::mm::{ + MemorySet, + PhysPageNum, + KERNEL_SPACE, + VirtAddr, + translated_refmut, +}; use crate::trap::{TrapContext, trap_handler}; use crate::config::{TRAP_CONTEXT}; use super::TaskContext; @@ -6,6 +12,7 @@ use super::{PidHandle, pid_alloc, KernelStack}; use alloc::sync::{Weak, Arc}; use alloc::vec; use alloc::vec::Vec; +use alloc::string::String; use spin::{Mutex, MutexGuard}; use crate::fs::{File, Stdin, Stdout}; @@ -106,13 +113,35 @@ impl TaskControlBlock { ); task_control_block } - pub fn exec(&self, elf_data: &[u8]) { + pub fn exec(&self, elf_data: &[u8], args: Vec) { // memory_set with elf program headers/trampoline/trap context/user stack - let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data); + let (memory_set, mut user_sp, entry_point) = MemorySet::from_elf(elf_data); let trap_cx_ppn = memory_set .translate(VirtAddr::from(TRAP_CONTEXT).into()) .unwrap() .ppn(); + // push arguments on user stack + user_sp -= (args.len() + 1) * core::mem::size_of::(); + let argv_base = user_sp; + let mut argv: Vec<_> = (0..=args.len()) + .map(|arg| { + translated_refmut( + memory_set.token(), + (argv_base + arg * core::mem::size_of::()) as *mut usize + ) + }) + .collect(); + *argv[args.len()] = 0; + for i in 0..args.len() { + user_sp -= args[i].len() + 1; + *argv[i] = user_sp; + let mut p = user_sp; + for c in args[i].as_bytes() { + *translated_refmut(memory_set.token(), p as *mut u8) = *c; + p += 1; + } + *translated_refmut(memory_set.token(), p as *mut u8) = 0; + } // **** hold current PCB lock let mut inner = self.acquire_inner_lock(); @@ -121,14 +150,16 @@ impl TaskControlBlock { // update trap_cx ppn inner.trap_cx_ppn = trap_cx_ppn; // initialize trap_cx - let trap_cx = inner.get_trap_cx(); - *trap_cx = TrapContext::app_init_context( + let mut trap_cx = TrapContext::app_init_context( entry_point, user_sp, KERNEL_SPACE.lock().token(), self.kernel_stack.get_top(), trap_handler as usize, ); + trap_cx.x[10] = args.len(); + trap_cx.x[11] = argv_base; + *inner.get_trap_cx() = trap_cx; // **** release current PCB lock } pub fn fork(self: &Arc) -> Arc { diff --git a/os/src/trap/context.rs b/os/src/trap/context.rs index 8c5175f7..16f81415 100644 --- a/os/src/trap/context.rs +++ b/os/src/trap/context.rs @@ -1,6 +1,7 @@ use riscv::register::sstatus::{Sstatus, self, SPP}; #[repr(C)] +#[derive(Debug)] pub struct TrapContext { pub x: [usize; 32], pub sstatus: Sstatus, diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 4f5126b2..f83560b2 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -88,6 +88,7 @@ pub fn trap_handler() -> ! { panic!("Unsupported trap {:?}, stval = {:#x}!", scause.cause(), stval); } } + //println!("before trap_return"); trap_return(); } diff --git a/user/src/bin/cmdline_args.rs b/user/src/bin/cmdline_args.rs new file mode 100644 index 00000000..18b0112e --- /dev/null +++ b/user/src/bin/cmdline_args.rs @@ -0,0 +1,16 @@ +#![no_std] +#![no_main] + +extern crate alloc; + +#[macro_use] +extern crate user_lib; + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + println!("argc = {}", argc); + for i in 0..argc { + println!("argc[{}] = {}", i, argv[i]); + } + 0 +} \ No newline at end of file diff --git a/user/src/bin/initproc.rs b/user/src/bin/initproc.rs index 6d30fdb6..99563f47 100644 --- a/user/src/bin/initproc.rs +++ b/user/src/bin/initproc.rs @@ -14,7 +14,7 @@ use user_lib::{ #[no_mangle] fn main() -> i32 { if fork() == 0 { - exec("user_shell\0"); + exec("user_shell\0", &[0 as *const u8]); } else { loop { let mut exit_code: i32 = 0; diff --git a/user/src/bin/run_pipe_test.rs b/user/src/bin/run_pipe_test.rs index ca2afd15..000b82d5 100644 --- a/user/src/bin/run_pipe_test.rs +++ b/user/src/bin/run_pipe_test.rs @@ -10,7 +10,7 @@ use user_lib::{fork, exec, wait}; pub fn main() -> i32 { for i in 0..1000 { if fork() == 0 { - exec("pipe_large_test\0"); + exec("pipe_large_test\0", &[0 as *const u8]); } else { let mut _unused: i32 = 0; wait(&mut _unused); diff --git a/user/src/bin/user_shell.rs b/user/src/bin/user_shell.rs index 796bddb5..d1838cae 100644 --- a/user/src/bin/user_shell.rs +++ b/user/src/bin/user_shell.rs @@ -12,6 +12,7 @@ const DL: u8 = 0x7fu8; const BS: u8 = 0x08u8; use alloc::string::String; +use alloc::vec::Vec; use user_lib::{fork, exec, waitpid}; use user_lib::console::getchar; @@ -26,11 +27,29 @@ pub fn main() -> i32 { LF | CR => { println!(""); if !line.is_empty() { - line.push('\0'); + let args: Vec<_> = line.as_str().split(' ').collect(); + let mut args_copy: Vec = args + .iter() + .map(|&arg| { + let mut string = String::new(); + string.push_str(arg); + string + }) + .collect(); + args_copy + .iter_mut() + .for_each(|string| { + string.push('\0'); + }); + let mut args_addr: Vec<*const u8> = args_copy + .iter() + .map(|arg| arg.as_ptr()) + .collect(); + args_addr.push(0 as *const u8); let pid = fork(); if pid == 0 { // child process - if exec(line.as_str()) == -1 { + if exec(args_copy[0].as_str(), args_addr.as_slice()) == -1 { println!("Error when executing!"); return -4; } diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index 7a4a6d7b..e8be6c45 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -26,7 +26,7 @@ pub fn main() -> i32 { println!("Usertests: Running {}", test); let pid = fork(); if pid == 0 { - exec(*test); + exec(*test, &[0 as *const u8]); panic!("unreachable!"); } else { let mut exit_code: i32 = Default::default(); diff --git a/user/src/lib.rs b/user/src/lib.rs index 244baaea..f711ee66 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -15,6 +15,7 @@ extern crate bitflags; use syscall::*; use buddy_system_allocator::LockedHeap; +use alloc::vec::Vec; const USER_HEAP_SIZE: usize = 16384; @@ -30,17 +31,31 @@ pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { #[no_mangle] #[link_section = ".text.entry"] -pub extern "C" fn _start() -> ! { +pub extern "C" fn _start(argc: usize, argv: usize) -> ! { unsafe { HEAP.lock() .init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE); } - exit(main()); + let mut v: Vec<&'static str> = Vec::new(); + for i in 0..argc { + let str_start = unsafe { + ((argv + i * core::mem::size_of::()) as *const usize).read_volatile() + }; + let len = (0usize..).find(|i| unsafe { + ((str_start + *i) as *const u8).read_volatile() == 0 + }).unwrap(); + v.push( + core::str::from_utf8(unsafe { + core::slice::from_raw_parts(str_start as *const u8, len) + }).unwrap() + ); + } + exit(main(argc, v.as_slice())); } #[linkage = "weak"] #[no_mangle] -fn main() -> i32 { +fn main(_argc: usize, _argv: &[&str]) -> i32 { panic!("Cannot find main!"); } @@ -64,7 +79,7 @@ pub fn yield_() -> isize { sys_yield() } pub fn get_time() -> isize { sys_get_time() } pub fn getpid() -> isize { sys_getpid() } pub fn fork() -> isize { sys_fork() } -pub fn exec(path: &str) -> isize { sys_exec(path) } +pub fn exec(path: &str, args: &[*const u8]) -> isize { sys_exec(path, args) } pub fn wait(exit_code: &mut i32) -> isize { loop { match sys_waitpid(-1, exit_code as *mut _) { diff --git a/user/src/syscall.rs b/user/src/syscall.rs index a1101e1b..99e16df9 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -65,8 +65,8 @@ pub fn sys_fork() -> isize { syscall(SYSCALL_FORK, [0, 0, 0]) } -pub fn sys_exec(path: &str) -> isize { - syscall(SYSCALL_EXEC, [path.as_ptr() as usize, 0, 0]) +pub fn sys_exec(path: &str, args: &[*const u8]) -> isize { + syscall(SYSCALL_EXEC, [path.as_ptr() as usize, args.as_ptr() as usize, 0]) } pub fn sys_waitpid(pid: isize, exit_code: *mut i32) -> isize {