use core::{fmt::Debug, ptr::null}; use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec}; use crate::{ filesystem::vfs::{ file::{File, FileMode}, ROOT_INODE, }, io::SeekFrom, libs::elf::ELF_LOADER, mm::{ ucontext::{AddressSpace, UserStack}, VirtAddr, }, syscall::SystemError, }; /// 系统支持的所有二进制文件加载器的列表 const BINARY_LOADERS: [&'static dyn BinaryLoader; 1] = [&ELF_LOADER]; pub trait BinaryLoader: 'static + Debug { /// 检查二进制文件是否为当前加载器支持的格式 fn probe(self: &'static Self, param: &ExecParam, buf: &[u8]) -> Result<(), ExecError>; fn load( self: &'static Self, param: &mut ExecParam, head_buf: &[u8], ) -> Result; } /// 二进制文件加载结果 #[derive(Debug)] pub struct BinaryLoaderResult { /// 程序入口地址 entry_point: VirtAddr, } impl BinaryLoaderResult { pub fn new(entry_point: VirtAddr) -> Self { Self { entry_point } } pub fn entry_point(&self) -> VirtAddr { self.entry_point } } #[allow(dead_code)] #[derive(Debug)] pub enum ExecError { /// 二进制文件不可执行 NotExecutable, /// 二进制文件不是当前架构的 WrongArchitecture, /// 访问权限不足 PermissionDenied, /// 不支持的操作 NotSupported, /// 解析文件本身的时候出现错误(比如一些字段本身不合法) ParseError, /// 内存不足 OutOfMemory, /// 参数错误 InvalidParemeter, /// 无效的地址 BadAddress(Option), Other(String), } impl Into for ExecError { fn into(self) -> SystemError { match self { ExecError::NotExecutable => SystemError::ENOEXEC, ExecError::WrongArchitecture => SystemError::EOPNOTSUPP_OR_ENOTSUP, ExecError::PermissionDenied => SystemError::EACCES, ExecError::NotSupported => SystemError::EOPNOTSUPP_OR_ENOTSUP, ExecError::ParseError => SystemError::ENOEXEC, ExecError::OutOfMemory => SystemError::ENOMEM, ExecError::InvalidParemeter => SystemError::EINVAL, ExecError::BadAddress(_addr) => SystemError::EFAULT, ExecError::Other(_msg) => SystemError::ENOEXEC, } } } bitflags! { pub struct ExecParamFlags: u32 { // 是否以可执行文件的形式加载 const EXEC = 1 << 0; } } #[derive(Debug)] pub struct ExecParam<'a> { file_path: &'a str, file: Option, vm: Arc, /// 一些标志位 flags: ExecParamFlags, /// 用来初始化进程的一些信息。这些信息由二进制加载器和exec机制来共同填充 init_info: ProcInitInfo, } #[derive(Debug, Eq, PartialEq)] pub enum ExecLoadMode { /// 以可执行文件的形式加载 Exec, /// 以动态链接库的形式加载 DSO, } #[allow(dead_code)] impl<'a> ExecParam<'a> { pub fn new(file_path: &'a str, vm: Arc, flags: ExecParamFlags) -> Self { Self { file_path, file: None, vm, flags, init_info: ProcInitInfo::new(), } } pub fn file_path(&self) -> &'a str { self.file_path } pub fn vm(&self) -> &Arc { &self.vm } pub fn flags(&self) -> &ExecParamFlags { &self.flags } pub fn init_info(&self) -> &ProcInitInfo { &self.init_info } pub fn init_info_mut(&mut self) -> &mut ProcInitInfo { &mut self.init_info } /// 获取加载模式 pub fn load_mode(&self) -> ExecLoadMode { if self.flags.contains(ExecParamFlags::EXEC) { ExecLoadMode::Exec } else { ExecLoadMode::DSO } } pub fn file_mut(&mut self) -> &mut File { self.file.as_mut().unwrap() } } /// ## 加载二进制文件 pub fn load_binary_file(param: &mut ExecParam) -> Result { let inode = ROOT_INODE().lookup(param.file_path)?; // 读取文件头部,用于判断文件类型 let file = File::new(inode, FileMode::O_RDONLY)?; param.file = Some(file); let mut head_buf = [0u8; 512]; param.file_mut().lseek(SeekFrom::SeekSet(0))?; let _bytes = param.file_mut().read(512, &mut head_buf)?; // kdebug!("load_binary_file: read {} bytes", _bytes); let mut loader = None; for bl in BINARY_LOADERS.iter() { let probe_result = bl.probe(param, &head_buf); if probe_result.is_ok() { loader = Some(bl); break; } } // kdebug!("load_binary_file: loader: {:?}", loader); if loader.is_none() { return Err(SystemError::ENOEXEC); } let loader: &&dyn BinaryLoader = loader.unwrap(); assert!(param.vm().is_current()); // kdebug!("load_binary_file: to load with param: {:?}", param); let result: BinaryLoaderResult = loader .load(param, &head_buf) .unwrap_or_else(|e| panic!("load_binary_file failed: error: {e:?}, param: {param:?}")); // kdebug!("load_binary_file: load success"); return Ok(result); } /// 程序初始化信息,这些信息会被压入用户栈中 #[derive(Debug)] pub struct ProcInitInfo { pub args: Vec, pub envs: Vec, pub auxv: BTreeMap, } impl ProcInitInfo { pub fn new() -> Self { Self { args: Vec::new(), envs: Vec::new(), auxv: BTreeMap::new(), } } /// 把程序初始化信息压入用户栈中 /// 这个函数会把参数、环境变量、auxv等信息压入用户栈中 /// /// ## 返回值 /// /// 返回值是一个元组,第一个元素是最终的用户栈顶地址,第二个元素是环境变量pointer数组的起始地址 pub unsafe fn push_at( &self, ustack: &mut UserStack, ) -> Result<(VirtAddr, VirtAddr), SystemError> { // 先把程序的名称压入栈中 self.push_str(ustack, self.args[0].as_str())?; // 然后把环境变量压入栈中 let envps = self .envs .iter() .map(|s| { self.push_str(ustack, s.as_str()).expect("push_str failed"); ustack.sp() }) .collect::>(); // 然后把参数压入栈中 let argps = self .args .iter() .map(|s| { self.push_str(ustack, s.as_str()).expect("push_str failed"); ustack.sp() }) .collect::>(); // 压入auxv self.push_slice(ustack, &[null::(), null::()])?; for (&k, &v) in self.auxv.iter() { self.push_slice(ustack, &[k as usize, v])?; } // 把环境变量指针压入栈中 self.push_slice(ustack, &[null::()])?; self.push_slice(ustack, envps.as_slice())?; // 把参数指针压入栈中 self.push_slice(ustack, &[null::()])?; self.push_slice(ustack, argps.as_slice())?; let argv_ptr = ustack.sp(); // 把argc压入栈中 self.push_slice(ustack, &[self.args.len()])?; return Ok((ustack.sp(), argv_ptr)); } fn push_slice(&self, ustack: &mut UserStack, slice: &[T]) -> Result<(), SystemError> { let mut sp = ustack.sp(); sp -= slice.len() * core::mem::size_of::(); sp -= sp.data() % core::mem::align_of::(); unsafe { core::slice::from_raw_parts_mut(sp.data() as *mut T, slice.len()) } .copy_from_slice(slice); unsafe { ustack.set_sp(sp); } return Ok(()); } fn push_str(&self, ustack: &mut UserStack, s: &str) -> Result<(), SystemError> { self.push_slice(ustack, &[b'\0'])?; self.push_slice(ustack, s.as_bytes())?; return Ok(()); } }