|
@@ -1,24 +1,34 @@
|
|
|
use core::ffi::c_void;
|
|
|
|
|
|
-use alloc::{ffi::CString, string::ToString, sync::Arc, vec::Vec};
|
|
|
+use alloc::{
|
|
|
+ ffi::CString,
|
|
|
+ string::{String, ToString},
|
|
|
+ sync::Arc,
|
|
|
+ vec::Vec,
|
|
|
+};
|
|
|
use log::error;
|
|
|
use system_error::SystemError;
|
|
|
|
|
|
use super::{
|
|
|
abi::WaitOption,
|
|
|
cred::{Kgid, Kuid},
|
|
|
+ exec::{load_binary_file, ExecParam, ExecParamFlags},
|
|
|
exit::kernel_wait4,
|
|
|
fork::{CloneFlags, KernelCloneArgs},
|
|
|
resource::{RLimit64, RLimitID, RUsage, RUsageWho},
|
|
|
KernelStack, Pid, ProcessManager,
|
|
|
};
|
|
|
use crate::{
|
|
|
- arch::{interrupt::TrapFrame, MMArch},
|
|
|
+ arch::{interrupt::TrapFrame, CurrentIrqArch, MMArch},
|
|
|
+ exception::InterruptArch,
|
|
|
filesystem::{
|
|
|
procfs::procfs_register_pid,
|
|
|
vfs::{file::FileDescriptorVec, MAX_PATHLEN},
|
|
|
},
|
|
|
- mm::{ucontext::UserStack, verify_area, MemoryManagementArch, VirtAddr},
|
|
|
+ mm::{
|
|
|
+ ucontext::{AddressSpace, UserStack},
|
|
|
+ verify_area, MemoryManagementArch, VirtAddr,
|
|
|
+ },
|
|
|
process::ProcessControlBlock,
|
|
|
sched::completion::Completion,
|
|
|
syscall::{
|
|
@@ -139,6 +149,54 @@ impl Syscall {
|
|
|
return Ok(());
|
|
|
}
|
|
|
|
|
|
+ pub fn do_execve(
|
|
|
+ path: String,
|
|
|
+ argv: Vec<CString>,
|
|
|
+ envp: Vec<CString>,
|
|
|
+ regs: &mut TrapFrame,
|
|
|
+ ) -> Result<(), SystemError> {
|
|
|
+ let address_space = AddressSpace::new(true).expect("Failed to create new address space");
|
|
|
+ // debug!("to load binary file");
|
|
|
+ let mut param = ExecParam::new(path.as_str(), address_space.clone(), ExecParamFlags::EXEC)?;
|
|
|
+ let old_vm = do_execve_switch_user_vm(address_space.clone());
|
|
|
+
|
|
|
+ // 加载可执行文件
|
|
|
+ let load_result = load_binary_file(&mut param).inspect_err(|_| {
|
|
|
+ if let Some(old_vm) = old_vm {
|
|
|
+ do_execve_switch_user_vm(old_vm);
|
|
|
+ }
|
|
|
+ })?;
|
|
|
+
|
|
|
+ // debug!("load binary file done");
|
|
|
+ // debug!("argv: {:?}, envp: {:?}", argv, envp);
|
|
|
+ param.init_info_mut().args = argv;
|
|
|
+ param.init_info_mut().envs = envp;
|
|
|
+
|
|
|
+ // 把proc_init_info写到用户栈上
|
|
|
+ let mut ustack_message = unsafe {
|
|
|
+ address_space
|
|
|
+ .write()
|
|
|
+ .user_stack_mut()
|
|
|
+ .expect("No user stack found")
|
|
|
+ .clone_info_only()
|
|
|
+ };
|
|
|
+ let (user_sp, argv_ptr) = unsafe {
|
|
|
+ param
|
|
|
+ .init_info()
|
|
|
+ .push_at(
|
|
|
+ // address_space
|
|
|
+ // .write()
|
|
|
+ // .user_stack_mut()
|
|
|
+ // .expect("No user stack found"),
|
|
|
+ &mut ustack_message,
|
|
|
+ )
|
|
|
+ .expect("Failed to push proc_init_info to user stack")
|
|
|
+ };
|
|
|
+ address_space.write().user_stack = Some(ustack_message);
|
|
|
+
|
|
|
+ Self::arch_do_execve(regs, ¶m, &load_result, user_sp, argv_ptr)
|
|
|
+ }
|
|
|
+
|
|
|
pub fn wait4(
|
|
|
pid: i64,
|
|
|
wstatus: *mut i32,
|
|
@@ -499,3 +557,57 @@ impl Syscall {
|
|
|
return Ok(0);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/// 切换用户虚拟内存空间
|
|
|
+///
|
|
|
+/// 该函数用于在执行系统调用 `execve` 时切换用户进程的虚拟内存空间。
|
|
|
+///
|
|
|
+/// # 参数
|
|
|
+/// - `new_vm`: 新的用户地址空间,类型为 `Arc<AddressSpace>`。
|
|
|
+///
|
|
|
+/// # 返回值
|
|
|
+/// - 返回旧的用户地址空间的引用,类型为 `Option<Arc<AddressSpace>>`。
|
|
|
+///
|
|
|
+/// # 错误处理
|
|
|
+/// 如果地址空间切换失败,函数会触发断言失败,并输出错误信息。
|
|
|
+fn do_execve_switch_user_vm(new_vm: Arc<AddressSpace>) -> Option<Arc<AddressSpace>> {
|
|
|
+ // 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。
|
|
|
+ let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
|
|
+ let pcb = ProcessManager::current_pcb();
|
|
|
+ // log::debug!(
|
|
|
+ // "pid: {:?} do_execve: path: {:?}, argv: {:?}, envp: {:?}\n",
|
|
|
+ // pcb.pid(),
|
|
|
+ // path,
|
|
|
+ // argv,
|
|
|
+ // envp
|
|
|
+ // );
|
|
|
+
|
|
|
+ let mut basic_info = pcb.basic_mut();
|
|
|
+ // 暂存原本的用户地址空间的引用(因为如果在切换页表之前释放了它,可能会造成内存use after free)
|
|
|
+ let old_address_space = basic_info.user_vm();
|
|
|
+
|
|
|
+ // 在pcb中原来的用户地址空间
|
|
|
+ unsafe {
|
|
|
+ basic_info.set_user_vm(None);
|
|
|
+ }
|
|
|
+ // 创建新的地址空间并设置为当前地址空间
|
|
|
+ unsafe {
|
|
|
+ basic_info.set_user_vm(Some(new_vm.clone()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // to avoid deadlock
|
|
|
+ drop(basic_info);
|
|
|
+
|
|
|
+ assert!(
|
|
|
+ AddressSpace::is_current(&new_vm),
|
|
|
+ "Failed to set address space"
|
|
|
+ );
|
|
|
+ // debug!("Switch to new address space");
|
|
|
+
|
|
|
+ // 切换到新的用户地址空间
|
|
|
+ unsafe { new_vm.read().user_mapper.utable.make_current() };
|
|
|
+
|
|
|
+ drop(irq_guard);
|
|
|
+
|
|
|
+ old_address_space
|
|
|
+}
|