feature: passing args to execve()
This commit is contained in:
+1
-1
@@ -59,6 +59,6 @@ pub extern "C" fn init_fn(_arg: usize) -> ! {
|
||||
|
||||
drop(cfg);
|
||||
|
||||
Process::execve(|space| elf::load_elf(space, file), 0).unwrap();
|
||||
Process::execve(|space| elf::load_elf(space, file), &["/init"]).unwrap();
|
||||
panic!("Unreachable");
|
||||
}
|
||||
|
||||
@@ -210,6 +210,23 @@ impl Space {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO extract attributes
|
||||
pub fn translate(&mut self, virt: usize) -> Result<usize, Errno> {
|
||||
let l0i = virt >> 30;
|
||||
let l1i = (virt >> 21) & 0x1FF;
|
||||
let l2i = (virt >> 12) & 0x1FF;
|
||||
|
||||
let l1_table = self.0.next_level_table(l0i).ok_or(Errno::DoesNotExist)?;
|
||||
let l2_table = l1_table.next_level_table(l1i).ok_or(Errno::DoesNotExist)?;
|
||||
|
||||
let entry = l2_table[l2i];
|
||||
if entry.is_present() {
|
||||
Ok(unsafe { entry.address_unchecked() })
|
||||
} else {
|
||||
Err(Errno::DoesNotExist)
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to resolve a page fault at `virt` address by copying the
|
||||
/// underlying Copy-on-Write mapping (if any is present)
|
||||
pub fn try_cow_copy(&mut self, virt: usize) -> Result<(), Errno> {
|
||||
|
||||
+98
-14
@@ -10,13 +10,16 @@ use crate::proc::{
|
||||
};
|
||||
use crate::sync::{IrqSafeSpinLock, IrqSafeSpinLockGuard};
|
||||
use alloc::{rc::Rc, vec::Vec};
|
||||
use core::alloc::Layout;
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
use libsys::{
|
||||
error::Errno,
|
||||
proc::{ExitCode, Pid},
|
||||
signal::Signal,
|
||||
mem::memcpy,
|
||||
ProgramArgs,
|
||||
};
|
||||
use vfs::{VnodeRef, VnodeKind};
|
||||
use vfs::{VnodeKind, VnodeRef};
|
||||
|
||||
/// Wrapper type for a process struct reference
|
||||
pub type ProcessRef = Rc<Process>;
|
||||
@@ -134,8 +137,7 @@ impl Process {
|
||||
/// Sets a pending signal for a process
|
||||
pub fn set_signal(&self, signal: Signal) {
|
||||
let mut lock = self.inner.lock();
|
||||
let ttbr0 =
|
||||
lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
let main_thread = Thread::get(lock.threads[0]).unwrap();
|
||||
drop(lock);
|
||||
|
||||
@@ -164,8 +166,7 @@ impl Process {
|
||||
|
||||
pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) {
|
||||
let mut lock = self.inner.lock();
|
||||
let ttbr0 =
|
||||
lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
thread.enter_signal(signal, ttbr0);
|
||||
}
|
||||
|
||||
@@ -210,7 +211,7 @@ impl Process {
|
||||
id: dst_id,
|
||||
pgid: src_inner.pgid,
|
||||
ppid: Some(src_inner.id),
|
||||
sid: src_inner.sid
|
||||
sid: src_inner.sid,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -319,10 +320,96 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_paged<T>(space: &mut Space, dst: usize, src: T) -> Result<(), Errno> {
|
||||
let size = core::mem::size_of::<T>();
|
||||
if (size + (dst % 4096)) > 4096 {
|
||||
todo!("Object crossed page boundary");
|
||||
}
|
||||
|
||||
let page_virt = dst & !4095;
|
||||
let page_phys = if let Ok(phys) = space.translate(dst) {
|
||||
phys
|
||||
} else {
|
||||
let page = phys::alloc_page(PageUsage::UserPrivate)?;
|
||||
let flags = MapAttributes::SH_OUTER |
|
||||
MapAttributes::NOT_GLOBAL |
|
||||
MapAttributes::UXN |
|
||||
MapAttributes::PXN |
|
||||
MapAttributes::AP_BOTH_READONLY;
|
||||
space.map(page_virt, page, flags)?;
|
||||
page
|
||||
};
|
||||
|
||||
unsafe {
|
||||
core::ptr::write((mem::virtualize(page_phys) + (dst % 4096)) as *mut T, src);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_paged_bytes(space: &mut Space, dst: usize, src: &[u8]) -> Result<(), Errno> {
|
||||
if (src.len() + (dst % 4096)) > 4096 {
|
||||
todo!("Object crossed page boundary");
|
||||
}
|
||||
let page_virt = dst & !4095;
|
||||
let page_phys = if let Ok(phys) = space.translate(dst) {
|
||||
phys
|
||||
} else {
|
||||
let page = phys::alloc_page(PageUsage::UserPrivate)?;
|
||||
let flags = MapAttributes::SH_OUTER |
|
||||
MapAttributes::NOT_GLOBAL |
|
||||
MapAttributes::UXN |
|
||||
MapAttributes::PXN |
|
||||
MapAttributes::AP_BOTH_READONLY;
|
||||
space.map(page_virt, page, flags)?;
|
||||
page
|
||||
};
|
||||
|
||||
unsafe {
|
||||
memcpy((mem::virtualize(page_phys) + (dst % 4096)) as *mut u8, src.as_ptr(), src.len());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn store_arguments(space: &mut Space, argv: &[&str]) -> Result<usize, Errno> {
|
||||
let mut offset = 0usize;
|
||||
// TODO vmalloc?
|
||||
let base = 0x60000000;
|
||||
|
||||
// 1. Store program argument string bytes
|
||||
for arg in argv.iter() {
|
||||
Self::write_paged_bytes(space, base + offset, arg.as_bytes())?;
|
||||
offset += arg.len();
|
||||
}
|
||||
// Align
|
||||
offset = (offset + 15) & !15;
|
||||
let argv_offset = offset;
|
||||
|
||||
// 2. Store arg pointers
|
||||
let mut data_offset = 0usize;
|
||||
for arg in argv.iter() {
|
||||
// XXX this is really unsafe and I am not really sure ABI will stay like this XXX
|
||||
Self::write_paged(space, base + offset + 0, base + data_offset)?;
|
||||
Self::write_paged(space, base + offset + 8, arg.len())?;
|
||||
offset += 16;
|
||||
data_offset += arg.len();
|
||||
}
|
||||
|
||||
// 3. Store ProgramArgs
|
||||
let data = ProgramArgs {
|
||||
argc: argv.len(),
|
||||
argv: base + argv_offset,
|
||||
storage: base,
|
||||
size: offset + core::mem::size_of::<ProgramArgs>()
|
||||
};
|
||||
Self::write_paged(space, base + offset, data)?;
|
||||
|
||||
Ok(base + offset)
|
||||
}
|
||||
|
||||
/// Loads a new program into current process address space
|
||||
pub fn execve<F: FnOnce(&mut Space) -> Result<usize, Errno>>(
|
||||
loader: F,
|
||||
arg: usize,
|
||||
argv: &[&str],
|
||||
) -> Result<(), Errno> {
|
||||
unsafe {
|
||||
// Run with interrupts disabled
|
||||
@@ -351,12 +438,6 @@ impl Process {
|
||||
process_lock.sid = new_pid;
|
||||
let r = processes.insert(new_pid, proc.clone());
|
||||
assert!(r.is_none());
|
||||
} else {
|
||||
// Invalidate user ASID
|
||||
let input = (process_lock.id.asid() as usize) << 48;
|
||||
unsafe {
|
||||
asm!("tlbi aside1, {}", in(reg) input);
|
||||
}
|
||||
}
|
||||
|
||||
thread.set_owner(process_lock.id);
|
||||
@@ -380,6 +461,7 @@ impl Process {
|
||||
}
|
||||
|
||||
let entry = loader(new_space)?;
|
||||
let arg = Self::store_arguments(new_space, argv)?;
|
||||
|
||||
debugln!("Will now enter at {:#x}", entry);
|
||||
// TODO drop old address space
|
||||
@@ -388,11 +470,13 @@ impl Process {
|
||||
unsafe {
|
||||
// TODO drop old context
|
||||
let ctx = thread.ctx.get();
|
||||
let asid = (process_lock.id.asid() as usize) << 48;
|
||||
asm!("tlbi aside1, {}", in(reg) asid);
|
||||
|
||||
ctx.write(Context::user(
|
||||
entry,
|
||||
arg,
|
||||
new_space_phys | ((process_lock.id.asid() as usize) << 48),
|
||||
new_space_phys | asid,
|
||||
Self::USTACK_VIRT_TOP,
|
||||
));
|
||||
|
||||
|
||||
@@ -62,6 +62,19 @@ pub fn struct_mut<'a, T>(base: usize) -> Result<&'a mut T, Errno> {
|
||||
Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) })
|
||||
}
|
||||
|
||||
pub fn struct_buf_ref<'a, T>(base: usize, count: usize) -> Result<&'a [T], Errno> {
|
||||
let layout = Layout::array::<T>(count).unwrap();
|
||||
if base % layout.align() != 0 {
|
||||
invalid_memory!(
|
||||
"Structure pointer is misaligned: base={:#x}, expected {:?}",
|
||||
base,
|
||||
layout
|
||||
);
|
||||
}
|
||||
let bytes = buf_ref(base, layout.size())?;
|
||||
Ok(unsafe { core::slice::from_raw_parts(bytes.as_ptr() as *const T, count) })
|
||||
}
|
||||
|
||||
pub fn struct_buf_mut<'a, T>(base: usize, count: usize) -> Result<&'a mut [T], Errno> {
|
||||
let layout = Layout::array::<T>(count).unwrap();
|
||||
if base % layout.align() != 0 {
|
||||
@@ -91,7 +104,7 @@ pub fn option_struct_mut<'a, T>(base: usize) -> Result<Option<&'a mut T>, Errno>
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> {
|
||||
pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> {
|
||||
if base > mem::KERNEL_OFFSET || base + len > mem::KERNEL_OFFSET {
|
||||
invalid_memory!(
|
||||
"User region refers to kernel memory: base={:#x}, len={:#x}",
|
||||
@@ -111,8 +124,7 @@ fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> {
|
||||
space.try_cow_copy(i * mem::PAGE_SIZE)
|
||||
})
|
||||
} else {
|
||||
todo!();
|
||||
// Err(Errno::DoesNotExist)
|
||||
Err(Errno::DoesNotExist)
|
||||
};
|
||||
|
||||
if res.is_ok() {
|
||||
|
||||
@@ -54,7 +54,6 @@ fn find_at_node<T: DerefMut<Target = ProcessIo>>(
|
||||
|
||||
/// Main system call dispatcher function
|
||||
pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
||||
// debugln!("syscall {:?}", num);
|
||||
match num {
|
||||
// I/O
|
||||
SystemCall::Read => {
|
||||
@@ -165,17 +164,22 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
||||
.map(|e| e as usize)
|
||||
}
|
||||
SystemCall::Exec => {
|
||||
let filename = arg::str_ref(args[0], args[1])?;
|
||||
let argv = arg::struct_buf_ref::<&str>(args[2], args[3])?;
|
||||
// Validate each argument as well
|
||||
for item in argv.iter() {
|
||||
arg::validate_ptr(item.as_ptr() as usize, item.len(), false)?;
|
||||
}
|
||||
let node = {
|
||||
let proc = Process::current();
|
||||
let mut io = proc.io.lock();
|
||||
let filename = arg::str_ref(args[0], args[1])?;
|
||||
// TODO argv, envp array passing ABI?
|
||||
let node = io.ioctx().find(None, filename, true)?;
|
||||
drop(io);
|
||||
node
|
||||
};
|
||||
let file = node.open(OpenFlags::O_RDONLY)?;
|
||||
Process::execve(move |space| elf::load_elf(space, file), 0).unwrap();
|
||||
Process::execve(move |space| elf::load_elf(space, file), argv).unwrap();
|
||||
panic!();
|
||||
}
|
||||
SystemCall::Exit => {
|
||||
|
||||
Reference in New Issue
Block a user