Skip to content

Commit

Permalink
echo: Implement simple echo version
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sysheap committed Jan 6, 2025
1 parent 8e5e244 commit 7649212
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 11 deletions.
14 changes: 13 additions & 1 deletion common/src/syscalls/definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)]
Expand All @@ -58,8 +67,11 @@ syscalls!(
sys_read_input() -> Option<u8>;
sys_read_input_wait() -> u8;
sys_exit(status: isize) -> ();
// TODO: Implement slice as argument using a wrapper
sys_execute<'a>(name: &'a str) -> Result<u64, SysExecuteError>;
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<usize, SysArgError>;
sys_wait(pid: u64) -> Result<(), SysWaitError>;
sys_mmap_pages(number_of_pages: usize) -> *mut u8;
sys_open_udp_socket(port: u16) -> Result<UDPDescriptor, SysSocketError>;
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl Cpu {
unsafe { CpuRefHolder(&mut *ptr) }
}

pub fn with_scheduler<R>(mut f: impl FnMut(&mut CpuScheduler) -> R) -> R {
pub fn with_scheduler<R>(f: impl FnOnce(&mut CpuScheduler) -> R) -> R {
let mut cpu = Self::current();
let scheduler = cpu.scheduler_mut();
f(scheduler)
Expand Down
19 changes: 19 additions & 0 deletions kernel/src/processes/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub struct Process {
in_kernel_mode: bool,
notify_on_die: BTreeSet<Pid>,
waiting_on_syscall: Option<TypeId>,
sys_exec_args: Vec<String>,
}

impl Debug for Process {
Expand Down Expand Up @@ -125,13 +126,26 @@ impl Process {
in_kernel_mode: true,
notify_on_die: BTreeSet::new(),
waiting_on_syscall: None,
sys_exec_args: Vec::new(),
}))
}

pub fn get_notifies_on_die(&self) -> impl Iterator<Item = &Pid> {
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<String> {
&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(
Expand Down Expand Up @@ -249,6 +263,7 @@ impl Process {
in_kernel_mode: false,
notify_on_die: BTreeSet::new(),
waiting_on_syscall: None,
sys_exec_args: Vec::new(),
}
}

Expand All @@ -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<String>) {
self.sys_exec_args = args;
}
}

impl Drop for Process {
Expand Down
7 changes: 4 additions & 3 deletions kernel/src/processes/scheduler.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand Down Expand Up @@ -95,11 +95,12 @@ impl CpuScheduler {
self.schedule();
}

pub fn start_program(&mut self, name: &str) -> Option<Pid> {
pub fn start_program(&mut self, name: &str, args: Vec<String>) -> Option<Pid> {
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);
Expand Down
49 changes: 46 additions & 3 deletions kernel/src/syscalls/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -92,7 +95,9 @@ impl KernelSyscalls for SyscallHandler {
fn sys_execute(&mut self, name: UserspaceArgument<&str>) -> Result<u64, SysExecuteError> {
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)
Expand Down Expand Up @@ -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<usize>,
buffer: Self::ArgWrapper<&mut [u8]>,
) -> Result<usize, SysArgError> {
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<SyscallStatus> {
Expand Down
5 changes: 5 additions & 0 deletions userspace/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,8 @@ bench = false
name = "stress"
test = false
bench = false

[[bin]]
name = "echo"
test = false
bench = false
19 changes: 19 additions & 0 deletions userspace/src/bin/echo.rs
Original file line number Diff line number Diff line change
@@ -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!("");
}
20 changes: 17 additions & 3 deletions userspace/src/bin/sesh.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 7649212

Please sign in to comment.