diff --git a/kernel/src/arch/aarch64/interrupt/context.rs b/kernel/src/arch/aarch64/interrupt/context.rs index 87f3a4e..03b4414 100644 --- a/kernel/src/arch/aarch64/interrupt/context.rs +++ b/kernel/src/arch/aarch64/interrupt/context.rs @@ -32,7 +32,7 @@ impl TrapFrame { tf.spsr = 0b1101_00_0101; // To EL 1, enable IRQ tf } - fn new_user_thread(entry_addr: usize, sp: usize) -> Self { + pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; tf.sp = sp; @@ -40,9 +40,6 @@ impl TrapFrame { tf.spsr = 0b1101_00_0000; // To EL 0, enable IRQ tf } - pub fn is_user(&self) -> bool { - unimplemented!() - } } /// 新线程的内核栈初始内容 @@ -201,11 +198,6 @@ impl Context { } .push_at(kstack_top, ttbr) } - /// Called at a new user context - /// To get the init TrapFrame in sys_exec - pub unsafe fn get_init_tf(&self) -> TrapFrame { - (*(self.stack_top as *const InitStack)).tf.clone() - } } const ASID_MASK: u16 = 0xffff; diff --git a/kernel/src/arch/mipsel/context.rs b/kernel/src/arch/mipsel/context.rs index ab4e5aa..606fbad 100644 --- a/kernel/src/arch/mipsel/context.rs +++ b/kernel/src/arch/mipsel/context.rs @@ -76,7 +76,7 @@ impl TrapFrame { /// /// The new thread starts at `entry_addr`. /// The stack pointer will be set to `sp`. - fn new_user_thread(entry_addr: usize, sp: usize) -> Self { + pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; tf.sp = sp; @@ -269,9 +269,4 @@ impl Context { } .push_at(kstack_top) } - - /// Used for getting the init TrapFrame of a new user context in `sys_exec`. - pub unsafe fn get_init_tf(&self) -> TrapFrame { - (*(self.sp as *const InitStack)).tf.clone() - } } diff --git a/kernel/src/arch/riscv32/context.rs b/kernel/src/arch/riscv32/context.rs index 51df0c1..c8ac7ea 100644 --- a/kernel/src/arch/riscv32/context.rs +++ b/kernel/src/arch/riscv32/context.rs @@ -40,7 +40,7 @@ impl TrapFrame { /// /// The new thread starts at `entry_addr`. /// The stack pointer will be set to `sp`. - fn new_user_thread(entry_addr: usize, sp: usize) -> Self { + pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; tf.x[2] = sp; @@ -289,9 +289,4 @@ impl Context { } .push_at(kstack_top) } - - /// Used for getting the init TrapFrame of a new user context in `sys_exec`. - pub unsafe fn get_init_tf(&self) -> TrapFrame { - (*(self.sp as *const InitStack)).tf.clone() - } } diff --git a/kernel/src/arch/x86_64/interrupt/trapframe.rs b/kernel/src/arch/x86_64/interrupt/trapframe.rs index d9ab7f7..fe01ee2 100644 --- a/kernel/src/arch/x86_64/interrupt/trapframe.rs +++ b/kernel/src/arch/x86_64/interrupt/trapframe.rs @@ -73,7 +73,7 @@ impl TrapFrame { tf.fpstate_offset = 16; // skip restoring for first time tf } - fn new_user_thread(entry_addr: usize, rsp: usize) -> Self { + pub fn new_user_thread(entry_addr: usize, rsp: usize) -> Self { use crate::arch::gdt; let mut tf = TrapFrame::default(); tf.cs = gdt::UCODE_SELECTOR.0 as usize; @@ -234,9 +234,4 @@ 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() - } } diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 8ef01bc..103e300 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -126,13 +126,14 @@ impl Thread { }) } - /// Make a new user process from ELF `data` - pub fn new_user( + /// Construct virtual memory of a new user process from ELF `data`. + /// Return `(MemorySet, entry_point, ustack_top)` + pub fn new_user_vm( data: &[u8], exec_path: &str, mut args: Vec, envs: Vec, - ) -> Box { + ) -> (MemorySet, usize, usize) { // Parse ELF let elf = ElfFile::new(data).expect("failed to read elf"); @@ -159,22 +160,16 @@ impl Thread { // Check interpreter (for dynamic link) if let Ok(loader_path) = elf.get_interpreter() { // assuming absolute path - if let Ok(inode) = crate::fs::ROOT_INODE.lookup_follow(loader_path, FOLLOW_MAX_DEPTH) { - if let Ok(buf) = inode.read_as_vec() { - // Elf loader should not have INTERP - // No infinite loop - args.insert(0, loader_path.into()); - args.insert(1, exec_path.into()); - args.remove(2); - //info!("loader args: {:?}", args); - //info!("loader envs: {:?}", envs); - return Thread::new_user(buf.as_slice(), exec_path, args, envs); - } else { - warn!("loader specified as {} but failed to read", &loader_path); - } - } else { - warn!("loader specified as {} but not found", &loader_path); - } + let inode = crate::fs::ROOT_INODE + .lookup_follow(loader_path, FOLLOW_MAX_DEPTH) + .expect("interpreter not found"); + let buf = inode.read_as_vec().expect("failed to load interpreter"); + // modify args for loader + args[0] = exec_path.into(); + args.insert(0, loader_path.into()); + // Elf loader should not have INTERP + // No infinite loop + return Thread::new_user_vm(buf.as_slice(), exec_path, args, envs); } // Make page table @@ -216,6 +211,19 @@ impl Thread { trace!("{:#x?}", vm); + let entry_addr = elf.header.pt2.entry_point() as usize; + (vm, entry_addr, ustack_top) + } + + /// Make a new user process from ELF `data` + pub fn new_user( + data: &[u8], + exec_path: &str, + mut args: Vec, + envs: Vec, + ) -> Box { + let (vm, entry_addr, ustack_top) = Self::new_user_vm(data, exec_path, args, envs); + let kstack = KernelStack::new(); let mut files = BTreeMap::new(); @@ -253,8 +261,6 @@ impl Thread { )), ); - let entry_addr = elf.header.pt2.entry_point() as usize; - Box::new(Thread { context: unsafe { Context::new_user_thread(entry_addr, ustack_top, kstack.top(), vm.token()) @@ -377,13 +383,6 @@ impl Process { } self.futexes.get(&uaddr).unwrap().clone() } - pub fn clone_for_exec(&mut self, other: &Self) { - self.files = other.files.clone(); - self.cwd = other.cwd.clone(); - self.pid = other.pid.clone(); - self.parent = other.parent.clone(); - self.threads = other.threads.clone(); - } } trait ToMemoryAttr { diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index b962d4c..8114b06 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -143,7 +143,7 @@ pub fn sys_exec( "exec:BEG: path: {:?}, argv: {:?}, envp: {:?}", path, argv, envp ); - let proc = process(); + let mut proc = process(); let path = unsafe { proc.vm.check_and_clone_cstr(path)? }; let args = unsafe { proc.vm.check_and_clone_cstr_array(argv)? }; let envs = unsafe { proc.vm.check_and_clone_cstr_array(envp)? }; @@ -158,25 +158,29 @@ pub fn sys_exec( path, args, envs ); + // Kill other threads + proc.threads.retain(|&tid| { + if tid != processor().tid() { + processor().manager().exit(tid, 1); + } + tid == processor().tid() + }); + // Read program file let inode = proc.lookup_inode(&path)?; - let buf = inode.read_as_vec()?; + let data = inode.read_as_vec()?; // Make new Thread - let mut thread = Thread::new_user(buf.as_slice(), &path, args, envs); - thread.proc.lock().clone_for_exec(&proc); + let (mut vm, entry_addr, ustack_top) = Thread::new_user_vm(data.as_slice(), &path, args, envs); // Activate new page table unsafe { - thread.proc.lock().vm.activate(); + vm.activate(); } + core::mem::swap(&mut proc.vm, &mut vm); // Modify the TrapFrame - *tf = unsafe { thread.context.get_init_tf() }; - - // Swap Context but keep KStack - ::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack); - ::core::mem::swap(current_thread(), &mut *thread); + *tf = TrapFrame::new_user_thread(entry_addr, ustack_top); info!("exec:END: path: {:?}", path); Ok(0)