From fcf672a9697b0424cb4fd2059ac2f3f9e05754a1 Mon Sep 17 00:00:00 2001 From: pjht Date: Sun, 21 Jul 2024 10:56:43 -0500 Subject: [PATCH] Add support for process command-line arguments --- src/interrupts.rs | 27 ++++++++++++++++++--------- src/main.rs | 11 ++++++++--- src/tasking.rs | 45 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/src/interrupts.rs b/src/interrupts.rs index 0683e71..95d9565 100644 --- a/src/interrupts.rs +++ b/src/interrupts.rs @@ -1,15 +1,10 @@ use crate::{ - bootinfo::BOOTINFO, - print, println, - serial::SECOND_PORT, - tasking::SleepReason, - virtual_memory::{ASpaceMutex, AddressSpace, ACTIVE_SPACE, KERNEL_SPACE}, - TASKING, + bootinfo::BOOTINFO, print, println, serial::SECOND_PORT, tasking::SleepReason, virtual_memory::{ASpaceMutex, AddressSpace, ACTIVE_SPACE, KERNEL_SPACE}, TASKING }; use alloc::{boxed::Box, vec::Vec}; use az::WrappingCast; use cast::{u64, usize}; -use core::{arch::asm, ptr, slice, str}; +use core::{arch::asm, ffi::CStr, ptr, slice, str}; use hashbrown::HashMap; use pic8259::ChainedPics; use saturating_cast::SaturatingCast; @@ -364,13 +359,21 @@ extern "C" fn syscall_handler() { } } 8 => { + let args = unsafe { + let argc = usize(regs.rsi); + let argv: &[&[u8]] = slice::from_raw_parts(ptr::with_exposed_provenance(usize(regs.rdi)), argc); + argv.iter().map(|arg| CStr::from_bytes_with_nul_unchecked(arg)).collect::>() + }; #[warn( clippy::arithmetic_side_effects, reason = "FIXME: The current address space should be usize::MAX as that is an invalid index, instead of 0." )] let space = TASKING.lock().address_spaces_mut().remove(usize(regs.rdx - 1)); - let res = - TASKING.lock().new_process(ptr::with_exposed_provenance(usize(regs.rcx)), space); + let res = TASKING.lock().new_process( + ptr::with_exposed_provenance(usize(regs.rcx)), + space, + args.as_slice(), + ); if let Ok(pid) = res { retval = 0; retval2 = u64(pid); @@ -557,6 +560,12 @@ extern "C" fn syscall_handler() { tasking.sleep(SleepReason::WaitingForIPC); } } + 19 => { + let tasking = TASKING.lock(); + let args = tasking.arguments(); + retval = u64(args.0.expose_provenance()); + retval2 = u64(args.1); + } _ => (), }; unsafe { SYSCALL_REGS = regs }; diff --git a/src/main.rs b/src/main.rs index a81623c..a61b5db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -87,6 +87,7 @@ mod virtual_memory; use core::{ptr, slice}; +use alloc::ffi::CString; use bootinfo::BOOTINFO; use cast::usize; use elf::{ @@ -280,11 +281,15 @@ pub fn main() { ]); #[expect( - clippy::expect_used, - reason = "Boot cannot happen if the init process cannot be created" + clippy::unwrap_used, + reason = "Argument does not contain a null byte, thus this cannot panic" )] TASKING .lock() - .new_process(ptr::with_exposed_provenance(usize(init.ehdr.e_entry)), init_addr_space) + .new_process( + ptr::with_exposed_provenance(usize(init.ehdr.e_entry)), + init_addr_space, + &[&CString::new(b"init").unwrap()], + ) .expect("Failed to create init process"); } diff --git a/src/tasking.rs b/src/tasking.rs index cca3413..eaf9afa 100644 --- a/src/tasking.rs +++ b/src/tasking.rs @@ -1,11 +1,8 @@ -//#![allow(clippy::indexing_slicing, reason = "temp")] - use crate::{ - gdt, println, qemu_exit, - virtual_memory::{ASpaceMutex, AddressSpace, PagingError, KERNEL_SPACE}, + gdt, println, qemu_exit, virtual_memory::{ASpaceMutex, AddressSpace, PagingError, KERNEL_SPACE} }; -use alloc::{boxed::Box, collections::VecDeque, vec::Vec}; -use core::{arch::asm, ptr::addr_of}; +use alloc::{borrow::ToOwned, boxed::Box, collections::VecDeque, ffi::CString, vec::Vec}; +use core::{alloc::Layout, arch::asm, ptr::addr_of, ffi::CStr}; use crossbeam_queue::SegQueue; use slab::Slab; use spin::{Lazy, Mutex}; @@ -98,6 +95,7 @@ struct Process { data_buffers: Slab<*mut [u8]>, message_queue: SegQueue<(usize, usize)>, sleeping: Option, + arguments: (*const *const u8, usize), } unsafe impl Send for Process {} @@ -127,6 +125,7 @@ impl Tasking { &mut self, entry_point: *const extern "C" fn() -> !, mut address_space: AddressSpace, + arguments: &[&CStr], ) -> Result { let mut kernel_stack = Vec::new_in(&*KERNEL_SPACE); kernel_stack.resize(0x1_0000 - 0x4, 0); @@ -147,6 +146,33 @@ impl Tasking { 16, PageTableFlags::USER_ACCESSIBLE, )?; + let arguments = arguments.iter().map(|arg| (*arg).to_owned()).collect::>(); + #[expect(clippy::unwrap_used, reason = "This fails if the byte size of the array exceeds isize::MAX, which with 48-bit virtual addresses cannot happen")] + let mut args_layout = Layout::array::<*const u8>(arguments.len()).unwrap(); + let mut arg_offsets = Vec::new(); + for argument in &arguments { + #[expect(clippy::unwrap_used, reason = "This fails if the total size of the layout exceeds isize::MAX, which with 48-bit virtual addresses cannot happen")] + let (new_layout, offset) = + args_layout.extend(Layout::for_value(argument.to_bytes_with_nul())).unwrap(); + args_layout = new_layout; + arg_offsets.push(offset); + } + args_layout = { + #[expect(clippy::unwrap_used, reason = "This fails if the aligned size of the layout exceeds isize::MAX, which with 48-bit virtual addresses cannot happen")] + args_layout.align_to(4096).unwrap().pad_to_align() + }; + let user_arg_mem = address_space + .map_free(args_layout.size() / 4096, PageTableFlags::USER_ACCESSIBLE)?; + address_space.run(|| unsafe { + let mut ptr_ptr: *mut *const u8 = user_arg_mem.cast(); + for (&offset, argument) in arg_offsets.iter().zip(arguments.iter()) { + let arg_ptr = user_arg_mem.add(offset); + #[expect(clippy::arithmetic_side_effects, reason = "This can never overflow as count_bytes is always one less than the bytes used for the string, which can be at most 2^64-1.")] + arg_ptr.copy_from(argument.as_ptr().cast(), argument.count_bytes() + 1); + ptr_ptr.write(arg_ptr); + ptr_ptr = ptr_ptr.add(1); + } + }); let pid = self.processes.insert(Process { #[expect( clippy::indexing_slicing, @@ -164,6 +190,7 @@ impl Tasking { data_buffers: Slab::new(), message_queue: SegQueue::new(), sleeping: None, + arguments: (user_arg_mem.cast(), arguments.len()), }); self.ready_to_run.push_back(pid); Ok(pid) @@ -291,4 +318,10 @@ impl Tasking { } Ok(()) } + + pub fn arguments(&self) -> (*const *const u8, usize) { + #[warn(clippy::unwrap_used, reason = "FIXME")] + #[warn(clippy::indexing_slicing, reason = "FIXME(?)")] + self.processes[self.current_process.unwrap()].arguments + } }