From 7649212c1f4f09cdab60ef0fb23ab29293041ce6 Mon Sep 17 00:00:00 2001 From: Maurice Hieronymus Date: Mon, 6 Jan 2025 17:20:21 +0100 Subject: [PATCH] echo: Implement simple echo version We had to implement argument passing to processes. I'm not really satisfied with the solution because the api is crappy. However, let's leave it like that for now and improve it in the future. --- common/src/syscalls/definition.rs | 14 ++++++++- kernel/src/cpu.rs | 2 +- kernel/src/processes/process.rs | 19 ++++++++++++ kernel/src/processes/scheduler.rs | 7 +++-- kernel/src/syscalls/handler.rs | 49 +++++++++++++++++++++++++++++-- userspace/Cargo.toml | 5 ++++ userspace/src/bin/echo.rs | 19 ++++++++++++ userspace/src/bin/sesh.rs | 20 +++++++++++-- 8 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 userspace/src/bin/echo.rs diff --git a/common/src/syscalls/definition.rs b/common/src/syscalls/definition.rs index e1365cd0..ffbe79b1 100644 --- a/common/src/syscalls/definition.rs +++ b/common/src/syscalls/definition.rs @@ -20,6 +20,14 @@ pub enum SysExecuteError { ValidationError(ValidationError), } +#[derive(Debug)] +#[repr(usize)] +pub enum SysArgError { + InvalidIndex, + ValidationError(ValidationError), + SpaceTooSmall, +} + #[derive(Debug)] #[repr(usize)] pub enum SysSocketError { @@ -41,6 +49,7 @@ macro_rules! impl_from_validation_error { impl_from_validation_error!(SysExecuteError); impl_from_validation_error!(SysSocketError); +impl_from_validation_error!(SysArgError); scalar_enum! { #[repr(usize)] @@ -58,8 +67,11 @@ syscalls!( sys_read_input() -> Option; sys_read_input_wait() -> u8; sys_exit(status: isize) -> (); - // TODO: Implement slice as argument using a wrapper sys_execute<'a>(name: &'a str) -> Result; + sys_execute_add_arg<'a>(arg: &'a str) -> Result<(), ValidationError>; + sys_execute_arg_clear() -> (); + sys_execute_number_of_args() -> usize; + sys_execute_get_arg<'a>(index: usize, buffer: &'a mut [u8]) -> Result; sys_wait(pid: u64) -> Result<(), SysWaitError>; sys_mmap_pages(number_of_pages: usize) -> *mut u8; sys_open_udp_socket(port: u16) -> Result; diff --git a/kernel/src/cpu.rs b/kernel/src/cpu.rs index 9aae4834..1124d0fd 100644 --- a/kernel/src/cpu.rs +++ b/kernel/src/cpu.rs @@ -152,7 +152,7 @@ impl Cpu { unsafe { CpuRefHolder(&mut *ptr) } } - pub fn with_scheduler(mut f: impl FnMut(&mut CpuScheduler) -> R) -> R { + pub fn with_scheduler(f: impl FnOnce(&mut CpuScheduler) -> R) -> R { let mut cpu = Self::current(); let scheduler = cpu.scheduler_mut(); f(scheduler) diff --git a/kernel/src/processes/process.rs b/kernel/src/processes/process.rs index 5fbf6b5b..cf4b4fd2 100644 --- a/kernel/src/processes/process.rs +++ b/kernel/src/processes/process.rs @@ -58,6 +58,7 @@ pub struct Process { in_kernel_mode: bool, notify_on_die: BTreeSet, waiting_on_syscall: Option, + sys_exec_args: Vec, } impl Debug for Process { @@ -125,6 +126,7 @@ impl Process { in_kernel_mode: true, notify_on_die: BTreeSet::new(), waiting_on_syscall: None, + sys_exec_args: Vec::new(), })) } @@ -132,6 +134,18 @@ impl Process { self.notify_on_die.iter() } + pub fn add_sys_exec_arg(&mut self, arg: String) { + self.sys_exec_args.push(arg.to_string()); + } + + pub fn clear_sys_exec_arg(&mut self) { + self.sys_exec_args.clear(); + } + + pub fn get_sys_exec_args(&self) -> &Vec { + &self.sys_exec_args + } + pub fn mmap_pages(&mut self, number_of_pages: usize) -> *mut u8 { let pages = PinnedHeapPages::new(number_of_pages); self.page_table.map_userspace( @@ -249,6 +263,7 @@ impl Process { in_kernel_mode: false, notify_on_die: BTreeSet::new(), waiting_on_syscall: None, + sys_exec_args: Vec::new(), } } @@ -270,6 +285,10 @@ impl Process { ) -> Option<&mut SharedAssignedSocket> { self.open_udp_sockets.get_mut(&descriptor) } + + pub(crate) fn set_sys_exec_args(&mut self, args: Vec) { + self.sys_exec_args = args; + } } impl Drop for Process { diff --git a/kernel/src/processes/scheduler.rs b/kernel/src/processes/scheduler.rs index 7818f85d..6c0acf4e 100644 --- a/kernel/src/processes/scheduler.rs +++ b/kernel/src/processes/scheduler.rs @@ -1,7 +1,7 @@ use common::unwrap_or_return; use core::mem::offset_of; -use alloc::sync::Arc; +use alloc::{string::String, sync::Arc, vec::Vec}; use common::syscalls::trap_frame::TrapFrame; use crate::{ @@ -95,11 +95,12 @@ impl CpuScheduler { self.schedule(); } - pub fn start_program(&mut self, name: &str) -> Option { + pub fn start_program(&mut self, name: &str, args: Vec) -> Option { for (prog_name, elf) in PROGRAMS { if name == *prog_name { let elf = ElfFile::parse(elf).expect("Cannot parse ELF file"); - let process = Process::from_elf(&elf, prog_name); + let mut process = Process::from_elf(&elf, prog_name); + process.set_sys_exec_args(args); let pid = process.get_pid(); process_table::THE.lock().add_process(process); return Some(pid); diff --git a/kernel/src/syscalls/handler.rs b/kernel/src/syscalls/handler.rs index 575f863c..09ddc00f 100644 --- a/kernel/src/syscalls/handler.rs +++ b/kernel/src/syscalls/handler.rs @@ -3,17 +3,20 @@ use common::{ pointer::Pointer, ref_conversion::RefToPointer, syscalls::{ - kernel::KernelSyscalls, SysExecuteError, SysSocketError, SysWaitError, SyscallStatus, - ValidationError, + kernel::KernelSyscalls, SysArgError, SysExecuteError, SysSocketError, SysWaitError, + SyscallStatus, ValidationError, }, unwrap_or_return, }; +use alloc::string::ToString; + use crate::{ autogenerated::userspace_programs::PROGRAMS, cpu::Cpu, debug, io::stdin_buf::STDIN_BUFFER, + klibc::util::copy_slice, net::{udp::UdpHeader, ARP_CACHE, OPEN_UDP_SOCKETS}, print, println, processes::{process::Pid, process_table::ProcessRef}, @@ -92,7 +95,9 @@ impl KernelSyscalls for SyscallHandler { fn sys_execute(&mut self, name: UserspaceArgument<&str>) -> Result { let name = name.validate(self)?; - if let Some(pid) = Cpu::with_scheduler(|s| s.start_program(name)) { + let args = self.current_process.lock().get_sys_exec_args().clone(); + + if let Some(pid) = Cpu::with_scheduler(|s| s.start_program(name, args)) { Ok(pid) } else { Err(SysExecuteError::InvalidProgram) @@ -183,6 +188,44 @@ impl KernelSyscalls for SyscallHandler { Some(physical_address) }) } + + fn sys_execute_add_arg(&mut self, arg: Self::ArgWrapper<&str>) -> Result<(), ValidationError> { + let arg = arg.validate(self)?; + self.current_process + .lock() + .add_sys_exec_arg(arg.to_string()); + Ok(()) + } + + fn sys_execute_arg_clear(&mut self) { + self.current_process.lock().clear_sys_exec_arg(); + } + + fn sys_execute_number_of_args(&mut self) -> usize { + self.current_process.lock().get_sys_exec_args().len() + } + + fn sys_execute_get_arg( + &mut self, + index: Self::ArgWrapper, + buffer: Self::ArgWrapper<&mut [u8]>, + ) -> Result { + let buffer = buffer.validate(self)?; + self.current_process.with_lock(|p| { + let argument = p.get_sys_exec_args().get(*index); + if let Some(argument) = argument { + let len = argument.len(); + if buffer.len() < len { + Err(SysArgError::SpaceTooSmall) + } else { + copy_slice(argument.as_bytes(), buffer); + Ok(len) + } + } else { + Err(SysArgError::InvalidIndex) + } + }) + } } pub fn handle_syscall(nr: usize, arg: usize, ret: usize) -> Option { diff --git a/userspace/Cargo.toml b/userspace/Cargo.toml index 95f1b1d0..4f324c93 100644 --- a/userspace/Cargo.toml +++ b/userspace/Cargo.toml @@ -62,3 +62,8 @@ bench = false name = "stress" test = false bench = false + +[[bin]] +name = "echo" +test = false +bench = false \ No newline at end of file diff --git a/userspace/src/bin/echo.rs b/userspace/src/bin/echo.rs new file mode 100644 index 00000000..5741fb4d --- /dev/null +++ b/userspace/src/bin/echo.rs @@ -0,0 +1,19 @@ +#![no_std] +#![no_main] + +use common::syscalls::{sys_execute_get_arg, sys_execute_number_of_args}; +use userspace::{print, println}; + +extern crate userspace; + +#[unsafe(no_mangle)] +fn main() { + let args = sys_execute_number_of_args(); + for index in 0..args { + let mut buf = [0u8; 1024]; + let len = sys_execute_get_arg(index, &mut buf).expect("Could not read arg"); + let s = core::str::from_utf8(&buf[0..len]).expect("Argument must be utf8"); + print!("{s} "); + } + println!(""); +} diff --git a/userspace/src/bin/sesh.rs b/userspace/src/bin/sesh.rs index 9f2a797c..ecb0d9de 100644 --- a/userspace/src/bin/sesh.rs +++ b/userspace/src/bin/sesh.rs @@ -1,8 +1,13 @@ #![no_std] #![no_main] -use alloc::string::{String, ToString}; -use common::syscalls::{sys_execute, sys_exit, sys_print_programs, sys_wait}; +use alloc::{ + string::{String, ToString}, + vec::Vec, +}; +use common::syscalls::{ + sys_execute, sys_execute_add_arg, sys_execute_arg_clear, sys_exit, sys_print_programs, sys_wait, +}; use userspace::{print, println, util::read_line}; extern crate alloc; @@ -45,7 +50,16 @@ fn parse_command_and_execute(mut command: String) { command = command.trim().to_string(); } - let execute_result = sys_execute(&command); + // Process arguments + let split: Vec<&str> = command.split(' ').collect(); + + sys_execute_arg_clear(); + + for arg in split.iter().skip(1) { + sys_execute_add_arg(arg).expect("Succeed"); + } + + let execute_result = sys_execute(split[0]); match execute_result { Ok(pid) => { if !background {