From 0cd69e1c705e41b8f008a3379e53ab8abe4a30a6 Mon Sep 17 00:00:00 2001 From: schoettner Date: Sat, 31 Aug 2024 11:26:43 +0200 Subject: [PATCH] Syscalls refined - user mode: only one assembly function returning SyscallResult - adopted all runtime functions to handle SyscallResult - user mode runtime crate 'io' renamed to 'terminal' - kernel mode: split up syscall/mod.rs to group related syscalls in one file --- os/application/date/Cargo.toml | 2 +- os/application/date/Makefile.toml | 2 +- os/application/date/src/date.rs | 2 +- os/application/hello/Cargo.toml | 2 +- os/application/hello/Makefile.toml | 2 +- os/application/hello/src/hello.rs | 7 +- os/application/mkentry/Cargo.toml | 2 +- os/application/mkentry/Makefile.toml | 2 +- os/application/mkentry/src/mkentry.rs | 6 +- os/application/shell/Cargo.toml | 2 +- os/application/shell/Makefile.toml | 2 +- os/application/shell/src/shell.rs | 45 ++- os/application/uptime/Cargo.toml | 2 +- os/application/uptime/Makefile.toml | 2 +- os/application/uptime/src/uptime.rs | 2 +- os/kernel/src/naming/mod.rs | 1 + os/kernel/src/naming/name_service.rs | 49 ++- os/kernel/src/naming/name_service_internal.rs | 4 +- os/kernel/src/naming/name_service_tests.rs | 22 +- os/kernel/src/syscall/mod.rs | 238 +-------------- os/kernel/src/syscall/sys_concurrent.rs | 66 ++++ os/kernel/src/syscall/sys_naming.rs | 48 +++ .../src/syscall/sys_terminal.rs} | 34 +-- os/kernel/src/syscall/sys_time.rs | 82 +++++ os/kernel/src/syscall/sys_vmem.rs | 28 ++ os/kernel/src/syscall/syscall_dispatcher.rs | 26 +- os/library/concurrent/src/process.rs | 25 +- os/library/concurrent/src/thread.rs | 50 ++- os/library/io/src/read.rs | 5 - os/library/io/src/write.rs | 38 --- os/library/naming/Cargo.toml | 2 +- os/library/naming/src/lib.rs | 45 ++- os/library/runtime/Cargo.toml | 2 +- os/library/runtime/src/lib.rs | 35 ++- os/library/syscall/src/lib.rs | 289 ++---------------- os/library/syscall/src/return_vals.rs | 44 +++ os/library/{io => terminal}/Cargo.toml | 2 +- os/library/{io => terminal}/src/lib.rs | 0 os/library/terminal/src/read.rs | 17 ++ os/library/terminal/src/write.rs | 52 ++++ os/library/time/src/lib.rs | 32 +- 41 files changed, 602 insertions(+), 716 deletions(-) create mode 100644 os/kernel/src/syscall/sys_concurrent.rs create mode 100644 os/kernel/src/syscall/sys_naming.rs rename os/{library/syscall/src/consts.rs => kernel/src/syscall/sys_terminal.rs} (55%) create mode 100644 os/kernel/src/syscall/sys_time.rs create mode 100644 os/kernel/src/syscall/sys_vmem.rs delete mode 100644 os/library/io/src/read.rs delete mode 100644 os/library/io/src/write.rs create mode 100644 os/library/syscall/src/return_vals.rs rename os/library/{io => terminal}/Cargo.toml (93%) rename os/library/{io => terminal}/src/lib.rs (100%) create mode 100644 os/library/terminal/src/read.rs create mode 100644 os/library/terminal/src/write.rs diff --git a/os/application/date/Cargo.toml b/os/application/date/Cargo.toml index 71d8ad1..253fdaf 100644 --- a/os/application/date/Cargo.toml +++ b/os/application/date/Cargo.toml @@ -13,7 +13,7 @@ path = "src/date.rs" [dependencies] # Local dependencies runtime = { path = "../../library/runtime" } -io = { path = "../../library/io" } +terminal = { path = "../../library/terminal" } time = { path = "../../library/time" } chrono = { version = "0.4.38", default-features = false, features = ["alloc"] } \ No newline at end of file diff --git a/os/application/date/Makefile.toml b/os/application/date/Makefile.toml index f6895f8..7b1ab12 100644 --- a/os/application/date/Makefile.toml +++ b/os/application/date/Makefile.toml @@ -28,7 +28,7 @@ args = [ "build", "-Z", "build-std=core,alloc", "-Z", "build-std-features=compil condition = { files_modified = { input = [ "${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml", "${SOURCE_DIRECTORY}/**/*.rs", "${LIBRARY_DIRECTORY}/runtime/Cargo.toml", "${LIBRARY_DIRECTORY}/runtime/src/**/*.rs", - "${LIBRARY_DIRECTORY}/io/Cargo.toml", "${LIBRARY_DIRECTORY}/io/src/**/*.rs", + "${LIBRARY_DIRECTORY}/terminal/Cargo.toml", "${LIBRARY_DIRECTORY}/terminal/src/**/*.rs", "${LIBRARY_DIRECTORY}/time/Cargo.toml", "${LIBRARY_DIRECTORY}/time/src/**/*.rs", "${LIBRARY_DIRECTORY}/concurrent/Cargo.toml", "${LIBRARY_DIRECTORY}/concurrent/src/**/*.rs", "${LIBRARY_DIRECTORY}/syscall/Cargo.toml", "${LIBRARY_DIRECTORY}/syscall/src/**/*.rs" ], output = [ "${BUILD_DIRECTORY}/lib${CARGO_MAKE_PROJECT_NAME}*" ] } } diff --git a/os/application/date/src/date.rs b/os/application/date/src/date.rs index a69f14f..8d90ce1 100644 --- a/os/application/date/src/date.rs +++ b/os/application/date/src/date.rs @@ -4,7 +4,7 @@ extern crate alloc; #[allow(unused_imports)] use runtime::*; -use io::{print, println}; +use terminal::{print, println}; use time::date; #[unsafe(no_mangle)] diff --git a/os/application/hello/Cargo.toml b/os/application/hello/Cargo.toml index 24d8525..2dc1a65 100644 --- a/os/application/hello/Cargo.toml +++ b/os/application/hello/Cargo.toml @@ -13,5 +13,5 @@ path = "src/hello.rs" [dependencies] # Local dependencies runtime = { path = "../../library/runtime" } -io = { path = "../../library/io" } +terminal = { path = "../../library/terminal" } concurrent = { path = "../../library/concurrent" } \ No newline at end of file diff --git a/os/application/hello/Makefile.toml b/os/application/hello/Makefile.toml index 0b3388e..6adb7b6 100644 --- a/os/application/hello/Makefile.toml +++ b/os/application/hello/Makefile.toml @@ -28,7 +28,7 @@ args = [ "build", "-Z", "build-std=core,alloc", "-Z", "build-std-features=compil condition = { files_modified = { input = [ "${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml", "${SOURCE_DIRECTORY}/**/*.rs", "${LIBRARY_DIRECTORY}/runtime/Cargo.toml", "${LIBRARY_DIRECTORY}/runtime/src/**/*.rs", - "${LIBRARY_DIRECTORY}/io/Cargo.toml", "${LIBRARY_DIRECTORY}/io/src/**/*.rs", + "${LIBRARY_DIRECTORY}/terminal/Cargo.toml", "${LIBRARY_DIRECTORY}/terminal/src/**/*.rs", "${LIBRARY_DIRECTORY}/concurrent/Cargo.toml", "${LIBRARY_DIRECTORY}/concurrent/src/**/*.rs", "${LIBRARY_DIRECTORY}/syscall/Cargo.toml", "${LIBRARY_DIRECTORY}/syscall/src/**/*.rs" ], output = [ "${BUILD_DIRECTORY}/lib${CARGO_MAKE_PROJECT_NAME}*" ] } } diff --git a/os/application/hello/src/hello.rs b/os/application/hello/src/hello.rs index 3ca061e..246f9b7 100644 --- a/os/application/hello/src/hello.rs +++ b/os/application/hello/src/hello.rs @@ -5,12 +5,13 @@ extern crate alloc; use concurrent::{process, thread}; #[allow(unused_imports)] use runtime::*; -use io::{print, println}; +use terminal::{print, println}; #[unsafe(no_mangle)] pub fn main() { - let process = process::current(); - let thread = thread::current(); + let process = process::current().unwrap(); + let thread = thread::current().unwrap(); + println!("Hello from Thread [{}] in Process [{}]!", thread.id(), process.id()); let args = env::args(); diff --git a/os/application/mkentry/Cargo.toml b/os/application/mkentry/Cargo.toml index 7cacb87..16d6e03 100644 --- a/os/application/mkentry/Cargo.toml +++ b/os/application/mkentry/Cargo.toml @@ -12,7 +12,7 @@ path = "src/mkentry.rs" [dependencies] # Local dependencies -io = { path = "../../library/io" } +terminal = { path = "../../library/terminal" } runtime = { path = "../../library/runtime" } naming = { path = "../../library/naming" } diff --git a/os/application/mkentry/Makefile.toml b/os/application/mkentry/Makefile.toml index f6895f8..7b1ab12 100644 --- a/os/application/mkentry/Makefile.toml +++ b/os/application/mkentry/Makefile.toml @@ -28,7 +28,7 @@ args = [ "build", "-Z", "build-std=core,alloc", "-Z", "build-std-features=compil condition = { files_modified = { input = [ "${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml", "${SOURCE_DIRECTORY}/**/*.rs", "${LIBRARY_DIRECTORY}/runtime/Cargo.toml", "${LIBRARY_DIRECTORY}/runtime/src/**/*.rs", - "${LIBRARY_DIRECTORY}/io/Cargo.toml", "${LIBRARY_DIRECTORY}/io/src/**/*.rs", + "${LIBRARY_DIRECTORY}/terminal/Cargo.toml", "${LIBRARY_DIRECTORY}/terminal/src/**/*.rs", "${LIBRARY_DIRECTORY}/time/Cargo.toml", "${LIBRARY_DIRECTORY}/time/src/**/*.rs", "${LIBRARY_DIRECTORY}/concurrent/Cargo.toml", "${LIBRARY_DIRECTORY}/concurrent/src/**/*.rs", "${LIBRARY_DIRECTORY}/syscall/Cargo.toml", "${LIBRARY_DIRECTORY}/syscall/src/**/*.rs" ], output = [ "${BUILD_DIRECTORY}/lib${CARGO_MAKE_PROJECT_NAME}*" ] } } diff --git a/os/application/mkentry/src/mkentry.rs b/os/application/mkentry/src/mkentry.rs index 2b2e33b..bc2a988 100644 --- a/os/application/mkentry/src/mkentry.rs +++ b/os/application/mkentry/src/mkentry.rs @@ -4,11 +4,15 @@ extern crate alloc; #[allow(unused_imports)] use runtime::*; -use io::{print, println}; +use terminal::{print, println}; use naming::mkentry; #[unsafe(no_mangle)] pub fn main() { + let args = env::args(); + for (i, arg) in args.enumerate() { + println!("Arg[{}]: {}", i, arg); + } let res = mkentry("/home/schoettner", "test.txt", 1); diff --git a/os/application/shell/Cargo.toml b/os/application/shell/Cargo.toml index 6778d00..bbd931d 100644 --- a/os/application/shell/Cargo.toml +++ b/os/application/shell/Cargo.toml @@ -13,5 +13,5 @@ path = "src/shell.rs" [dependencies] # Local dependencies runtime = { path = "../../library/runtime" } -io = { path = "../../library/io" } +terminal = { path = "../../library/terminal" } concurrent = { path = "../../library/concurrent" } \ No newline at end of file diff --git a/os/application/shell/Makefile.toml b/os/application/shell/Makefile.toml index 0b3388e..6adb7b6 100644 --- a/os/application/shell/Makefile.toml +++ b/os/application/shell/Makefile.toml @@ -28,7 +28,7 @@ args = [ "build", "-Z", "build-std=core,alloc", "-Z", "build-std-features=compil condition = { files_modified = { input = [ "${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml", "${SOURCE_DIRECTORY}/**/*.rs", "${LIBRARY_DIRECTORY}/runtime/Cargo.toml", "${LIBRARY_DIRECTORY}/runtime/src/**/*.rs", - "${LIBRARY_DIRECTORY}/io/Cargo.toml", "${LIBRARY_DIRECTORY}/io/src/**/*.rs", + "${LIBRARY_DIRECTORY}/terminal/Cargo.toml", "${LIBRARY_DIRECTORY}/terminal/src/**/*.rs", "${LIBRARY_DIRECTORY}/concurrent/Cargo.toml", "${LIBRARY_DIRECTORY}/concurrent/src/**/*.rs", "${LIBRARY_DIRECTORY}/syscall/Cargo.toml", "${LIBRARY_DIRECTORY}/syscall/src/**/*.rs" ], output = [ "${BUILD_DIRECTORY}/lib${CARGO_MAKE_PROJECT_NAME}*" ] } } diff --git a/os/application/shell/src/shell.rs b/os/application/shell/src/shell.rs index a85dc53..5d693f9 100644 --- a/os/application/shell/src/shell.rs +++ b/os/application/shell/src/shell.rs @@ -5,10 +5,34 @@ extern crate alloc; use alloc::string::String; use alloc::vec::Vec; use concurrent::thread; +use terminal::read::read; +use terminal::{print, println}; #[allow(unused_imports)] use runtime::*; -use io::{print, println}; -use io::read::read; + + +fn process_next_char(line: &mut String, ch: char) { + match ch { + '\n' => { + let split = line.split_whitespace().collect::>(); + if !split.is_empty() { + match thread::start_application(split[0], split[1..].iter().map(|&s| s).collect()) { + Some(app) => app.join(), + None => println!("Command not found!"), + } + } + + line.clear(); + print!("> "); + }, + '\x08' => { + line.pop(); + }, + _ => { + line.push(ch); + }, + } +} #[unsafe(no_mangle)] pub fn main() { @@ -17,19 +41,8 @@ pub fn main() { loop { match read() { - '\n' => { - let split = line.split_whitespace().collect::>(); - if !split.is_empty() { - match thread::start_application(split[0], split[1..].iter().map(|&s| s).collect()) { - Some(app) => app.join(), - None => println!("Command not found!") - } - } - - line.clear(); - print!("> ") - }, - c => line.push(char::from_u32(c as u32).unwrap()) + Some(ch) => process_next_char(&mut line, ch), + None => (), } } -} \ No newline at end of file +} diff --git a/os/application/uptime/Cargo.toml b/os/application/uptime/Cargo.toml index 2104ed4..9405915 100644 --- a/os/application/uptime/Cargo.toml +++ b/os/application/uptime/Cargo.toml @@ -13,5 +13,5 @@ path = "src/uptime.rs" [dependencies] # Local dependencies runtime = { path = "../../library/runtime" } -io = { path = "../../library/io" } +terminal = { path = "../../library/terminal" } time = { path = "../../library/time" } \ No newline at end of file diff --git a/os/application/uptime/Makefile.toml b/os/application/uptime/Makefile.toml index f6895f8..7b1ab12 100644 --- a/os/application/uptime/Makefile.toml +++ b/os/application/uptime/Makefile.toml @@ -28,7 +28,7 @@ args = [ "build", "-Z", "build-std=core,alloc", "-Z", "build-std-features=compil condition = { files_modified = { input = [ "${CARGO_MAKE_WORKING_DIRECTORY}/Cargo.toml", "${SOURCE_DIRECTORY}/**/*.rs", "${LIBRARY_DIRECTORY}/runtime/Cargo.toml", "${LIBRARY_DIRECTORY}/runtime/src/**/*.rs", - "${LIBRARY_DIRECTORY}/io/Cargo.toml", "${LIBRARY_DIRECTORY}/io/src/**/*.rs", + "${LIBRARY_DIRECTORY}/terminal/Cargo.toml", "${LIBRARY_DIRECTORY}/terminal/src/**/*.rs", "${LIBRARY_DIRECTORY}/time/Cargo.toml", "${LIBRARY_DIRECTORY}/time/src/**/*.rs", "${LIBRARY_DIRECTORY}/concurrent/Cargo.toml", "${LIBRARY_DIRECTORY}/concurrent/src/**/*.rs", "${LIBRARY_DIRECTORY}/syscall/Cargo.toml", "${LIBRARY_DIRECTORY}/syscall/src/**/*.rs" ], output = [ "${BUILD_DIRECTORY}/lib${CARGO_MAKE_PROJECT_NAME}*" ] } } diff --git a/os/application/uptime/src/uptime.rs b/os/application/uptime/src/uptime.rs index bdd3008..ab88576 100644 --- a/os/application/uptime/src/uptime.rs +++ b/os/application/uptime/src/uptime.rs @@ -4,7 +4,7 @@ extern crate alloc; #[allow(unused_imports)] use runtime::*; -use io::{print, println}; +use terminal::{print, println}; use time::systime; #[unsafe(no_mangle)] diff --git a/os/kernel/src/naming/mod.rs b/os/kernel/src/naming/mod.rs index 91c067f..888feed 100644 --- a/os/kernel/src/naming/mod.rs +++ b/os/kernel/src/naming/mod.rs @@ -2,3 +2,4 @@ pub mod stat; pub mod name_service; mod name_service_internal; pub mod name_service_tests; + diff --git a/os/kernel/src/naming/name_service.rs b/os/kernel/src/naming/name_service.rs index b5abbd6..ac9f6b7 100644 --- a/os/kernel/src/naming/name_service.rs +++ b/os/kernel/src/naming/name_service.rs @@ -3,38 +3,29 @@ ╟─────────────────────────────────────────────────────────────────────────╢ ║ Descr.: API of name service. ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Michael Schoettner, 1.8.2024, HHU ║ + ║ Author: Michael Schoettner, 30.8.2024, HHU ║ ╚═════════════════════════════════════════════════════════════════════════╝ */ use alloc::sync::Arc; use alloc::vec::Vec; -//use core::result::Result; -use syscall::consts::Errno; -use syscall::consts::Result; - +use syscall::return_vals::{SyscallResult,Errno}; use ::log::info; use crate::naming::name_service_internal; use crate::naming::name_service_internal::get_root_dir; use crate::naming::stat::Stat; +pub type Result = ::core::result::Result; -/// -/// Description: -/// Add an entry (with or without data) -/// -/// Parameters: \ -/// `path` path (must exist) \ -/// `name` name for the new entry \ -/// `content` data bytes -/// -pub fn mkentry_new(path: &str, name: &str, content: Vec) -> ::core::result::Result { - let r = get_root_dir().mkentry(path, name, content); - info!("mkentry: res = {:?}", r); - return Ok(0) -} +// Wrapper function to convert Result<(), Errno> to SyscallResult +fn convert_result(result: core::result::Result<(), Errno>) -> SyscallResult { + match result { + Ok(()) => Ok(0), // Convert the success case to a meaningful u64, e.g., 0 + Err(e) => Err(e), // Forward the error directly + } +} /// /// Description: @@ -45,13 +36,11 @@ pub fn mkentry_new(path: &str, name: &str, content: Vec) -> ::core::result:: /// `name` name for the new entry \ /// `content` data bytes /// -pub fn mkentry(path: &str, name: &str, content: Vec) -> Result<()> { - let r = get_root_dir().mkentry(path, name, content); - - info!("mkentry: res = {:?}", r); - r +pub fn mkentry(path: &str, name: &str, content: Vec) -> SyscallResult { + convert_result(get_root_dir().mkentry(path, name, content)) } + /// /// Description: /// Add a directory. Creates all sub directories for the given path (if they do not exist already) @@ -59,8 +48,8 @@ pub fn mkentry(path: &str, name: &str, content: Vec) -> Result<()> { /// Parameters: \ /// `path` path to be created /// -pub fn mkdir(path: &str) -> Result<()> { - get_root_dir().mkdir(path) +pub fn mkdir(path: &str) -> SyscallResult { + convert_result(get_root_dir().mkdir(path)) } /// @@ -104,8 +93,8 @@ pub fn dir(path: &str) -> Result> { /// `path` path&entry name \ /// `new_name` new name /// -pub fn rename(path: &str, new_name: &str) -> Result<()> { - get_root_dir().rename(path, new_name) +pub fn rename(path: &str, new_name: &str) -> SyscallResult { + convert_result(get_root_dir().rename(path, new_name)) } /// @@ -115,8 +104,8 @@ pub fn rename(path: &str, new_name: &str) -> Result<()> { /// Parameters: \ /// `path` path&entry name /// -pub fn del(path: &str) -> Result<()> { - get_root_dir().del(path) +pub fn del(path: &str) -> SyscallResult { + convert_result(get_root_dir().del(path)) } /// diff --git a/os/kernel/src/naming/name_service_internal.rs b/os/kernel/src/naming/name_service_internal.rs index 85b5a30..b6deb75 100644 --- a/os/kernel/src/naming/name_service_internal.rs +++ b/os/kernel/src/naming/name_service_internal.rs @@ -6,11 +6,11 @@ ║ Author: Michael Schoettner, 29.8.2024, HHU ║ ╚═════════════════════════════════════════════════════════════════════════╝ */ -use syscall::consts::Result; -use syscall::consts::Errno; +use syscall::return_vals::Errno; use crate::naming::stat; use crate::naming::stat::Mode; use crate::naming::stat::Stat; +use crate::naming::name_service::Result; use alloc::boxed::Box; use alloc::string::ToString; diff --git a/os/kernel/src/naming/name_service_tests.rs b/os/kernel/src/naming/name_service_tests.rs index 4a57878..579f185 100644 --- a/os/kernel/src/naming/name_service_tests.rs +++ b/os/kernel/src/naming/name_service_tests.rs @@ -10,7 +10,7 @@ use alloc::vec; use ::log::info; use crate::naming::name_service::{cont, del, dir, mkdir, mkentry, rename, stat}; -use syscall::consts::Errno; +use syscall::return_vals::Errno; /// /// Description: @@ -40,12 +40,12 @@ fn test_mkdir() { // Create directory & subdirectory -> should work let path = "/home/schoettner"; let r = mkdir(path); - assert!(r == Ok(()), "mkdir(\"{}\") -> {:?}", path, r); + assert!(r == Ok(0), "mkdir(\"{}\") -> {:?}", path, r); // Create directory & subdirectory -> should work let path = "/home/ruhland"; let r = mkdir("/home/ruhland"); - assert!(r == Ok(()), "mkdir(\"{}\") -> {:?}", path, r); + assert!(r == Ok(0), "mkdir(\"{}\") -> {:?}", path, r); // Create same directory & subdirectory -> should fail let r = mkdir("/home/schoettner"); @@ -79,13 +79,13 @@ fn test_mkentry() { let path = "/home/schoettner"; let name = "brief.txt"; let r = mkentry(path, name, vec![1, 1, 1, 1, 1]); - assert!(r == Ok(()), "mkdir(\"{}\", \"{}\") -> {:?}", path, name, r); + assert!(r == Ok(0), "mkdir(\"{}\", \"{}\") -> {:?}", path, name, r); // Create container entry in existing directory -> should work let path = "/home/ruhland"; let name = "klausur.txt"; let r = mkentry(path, name, vec![1, 1, 1, 1, 1]); - assert!(r == Ok(()), "mkdir(\"{}\", \"{}\") -> {:?}", path, name, r); + assert!(r == Ok(0), "mkdir(\"{}\", \"{}\") -> {:?}", path, name, r); // Create container in non-existing directory -> should fail let path = "/home/krakowski"; @@ -211,14 +211,14 @@ fn test_del() { // Delete empty existing subdirectory -> should work let pathname = "/home/krakowski"; let r = mkdir(pathname); - assert!(r == Ok(()), "mkdir(\"{}\") -> {:?}", pathname, r); + assert!(r == Ok(0), "mkdir(\"{}\") -> {:?}", pathname, r); let r = del(pathname); - assert!(r == Ok(()), "del(\"{}\") -> {:?}", pathname, r); + assert!(r == Ok(0), "del(\"{}\") -> {:?}", pathname, r); // Delete existing container -> should work let pathname = "/home/schoettner/brief.txt"; let r = del(pathname); - assert!(r == Ok(()), "del(\"{}\") -> {:?}", pathname, r); + assert!(r == Ok(0), "del(\"{}\") -> {:?}", pathname, r); info!(" test 'del': passed"); } @@ -232,14 +232,14 @@ fn test_rename() { let path = "/home/schoettner"; let name = "brief.txt"; let r = mkentry(path, name, vec![1, 1, 1, 1, 1]); - assert!(r == Ok(()), "mkdir(\"{}\", \"{}\") -> {:?}", path, name, r); + assert!(r == Ok(0), "mkdir(\"{}\", \"{}\") -> {:?}", path, name, r); // Rename existing container -> should work let pathname = "/home/schoettner/brief.txt"; let new_name = "email.txt"; let r = rename(pathname, new_name); assert!( - r == Ok(()), + r == Ok(0), "rename(\"{}\", \"{}\") -> {:?}", pathname, new_name, @@ -251,7 +251,7 @@ fn test_rename() { let new_name = "krakowski"; let r = rename(pathname, new_name); assert!( - r == Ok(()), + r == Ok(0), "rename(\"{}\", \"{}\") -> {:?}", pathname, new_name, diff --git a/os/kernel/src/syscall/mod.rs b/os/kernel/src/syscall/mod.rs index c1bf4c9..499c7d2 100644 --- a/os/kernel/src/syscall/mod.rs +++ b/os/kernel/src/syscall/mod.rs @@ -1,238 +1,16 @@ /* ╔═════════════════════════════════════════════════════════════════════════╗ ║ Module: lib ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Descr.: All system calls (starting with sys_). ║ + ║ Descr.: All system call counterparts in kernel, starting with 'sys_'. ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Fabian Ruhland & Michael Schoettner, 29.8.2024, HHU ║ + ║ Author: Fabian Ruhland & Michael Schoettner, 30.8.2024, HHU ║ ╚═════════════════════════════════════════════════════════════════════════╝ */ -use crate::memory::r#virtual::{VirtualMemoryArea, VmaType}; -use crate::memory::{MemorySpace, PAGE_SIZE}; -use crate::naming::name_service; -use crate::process::thread::Thread; -use crate::{efi_system_table, initrd, process_manager, scheduler, terminal, timer}; -use alloc::format; -use alloc::rc::Rc; -use alloc::string::ToString; -use alloc::vec; -use alloc::vec::Vec; -use chrono::{DateTime, Datelike, TimeDelta, Timelike}; -use core::ptr; -use core::ptr::slice_from_raw_parts; -use core::str::from_utf8; -use uefi::table::runtime::{Time, TimeParams}; -use x86_64::structures::paging::PageTableFlags; -use x86_64::VirtAddr; // for naming service, for the time being -pub mod syscall_dispatcher; - - -/// -/// Description: Used by `convert_syscall_result_to_codes` -/// -/// Parameters: `t` data to be returned -/// -/// Return: `(0, t)` -#[inline] -fn zero_ok>(t: T) -> (usize, usize) { - (0, t.into()) -} - -#[inline] -fn one_err>(e: E) -> (usize, usize) { - (1, e.into()) -} - - -/// -/// Description: -/// Converts a Result to a (usize,usize) tuple -/// -/// Parameters: \ -/// `result` Result to be converted \ -/// `ok_f` function to produce the content for `Ok` \ -/// `err_f` function to produce the content for `Err` -#[inline] -fn convert_syscall_result_to_codes( - result: Result, - ok_f: F, - err_f: G, -) -> (usize, usize) -where - F: Fn(T) -> (usize, usize), - G: Fn(E) -> (usize, usize), -{ - match result { - Ok(t) => ok_f(t), - Err(e) => err_f(e), - } -} - -pub fn sys_read() -> usize { - let terminal = terminal(); - match terminal.read_byte() { - -1 => panic!("Input stream closed!"), - c => c as usize - } -} - -pub fn sys_write(buffer: *const u8, length: usize) { - let string = from_utf8(unsafe { slice_from_raw_parts(buffer, length).as_ref().unwrap() }).unwrap(); - let terminal = terminal(); - terminal.write_str(string); -} - -pub fn sys_map_user_heap(size: usize) -> usize { - let process = process_manager().read().current_process(); - let code_areas = process.find_vmas(VmaType::Code); - let code_area = code_areas.get(0).expect("Process does not have code area!"); - let heap_start = code_area.end().align_up(PAGE_SIZE as u64); - let heap_area = VirtualMemoryArea::from_address(heap_start, size, VmaType::Heap); - - process.address_space().map(heap_area.range(), MemorySpace::User, PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE); - process.add_vma(heap_area); - - heap_start.as_u64() as usize -} - -pub fn sys_process_id() -> usize { - process_manager().read().current_process().id() -} - -pub fn sys_process_exit() { - scheduler().current_thread().process().exit(); - scheduler().exit(); -} - -#[allow(improper_ctypes_definitions)] // 'entry' takes no arguments and has no return value, so we just assume that the "C" and "Rust" ABIs act the same way in this case -pub fn sys_thread_create(kickoff_addr: u64, entry: fn()) -> usize { - let thread = Thread::new_user_thread(process_manager().read().current_process(), VirtAddr::new(kickoff_addr), entry); - let id = thread.id(); - - scheduler().ready(thread); - id -} - -pub fn sys_thread_id() -> usize { - scheduler().current_thread().id() -} +pub mod sys_naming; +pub mod sys_terminal; +pub mod sys_concurrent; +pub mod sys_time; +pub mod sys_vmem; -pub fn sys_thread_switch() { - scheduler().switch_thread_no_interrupt(); -} - -pub fn sys_thread_sleep(ms: usize) { - scheduler().sleep(ms); -} - -pub fn sys_thread_join(id: usize) { - scheduler().join(id); -} - -pub fn sys_thread_exit() { - scheduler().exit(); -} - -pub fn sys_process_execute_binary(name_buffer: *const u8, name_length: usize, args: *const Vec<&str>) -> usize { - let app_name = from_utf8(unsafe { slice_from_raw_parts(name_buffer, name_length).as_ref().unwrap() }).unwrap(); - match initrd().entries().find(|entry| entry.filename().as_str().unwrap() == app_name) { - Some(app) => { - let thread = Thread::load_application(app.data(), app_name, unsafe { args.as_ref().unwrap() }); - scheduler().ready(Rc::clone(&thread)); - thread.id() - } - None => 0, - } -} - -pub fn sys_get_system_time() -> usize { - timer().systime_ms() -} - -pub fn sys_get_date() -> usize { - if let Some(efi_system_table) = efi_system_table() { - let system_table = efi_system_table.read(); - let runtime_services = unsafe { system_table.runtime_services() }; - - return match runtime_services.get_time() { - Ok(time) => { - if time.is_valid().is_ok() { - let timezone = match time.time_zone() { - Some(timezone) => { - let delta = TimeDelta::try_minutes(timezone as i64).expect("Failed to create TimeDelta struct from timezone"); - if timezone >= 0 { - format!("+{:0>2}:{:0>2}", delta.num_hours(), delta.num_minutes() % 60) - } else { - format!("-{:0>2}:{:0>2}", delta.num_hours(), delta.num_minutes() % 60) - } - } - None => "Z".to_string(), - }; - - DateTime::parse_from_rfc3339(format!("{}-{:0>2}-{:0>2}T{:0>2}:{:0>2}:{:0>2}.{:0>9}{}", time.year(), time.month(), time.day(), time.hour(), time.minute(), time.second(), time.nanosecond(), timezone).as_str()) - .expect("Failed to parse date from EFI runtime services") - .timestamp_millis() as usize - } else { - 0 - } - } - Err(_) => 0 - } - } - - 0 -} - -pub fn sys_set_date(date_ms: usize) -> usize { - if let Some(efi_system_table) = efi_system_table() { - let system_table = efi_system_table.write(); - let runtime_services_read = unsafe { system_table.runtime_services() }; - let runtime_services = unsafe { ptr::from_ref(runtime_services_read).cast_mut().as_mut().unwrap() }; - - let date = DateTime::from_timestamp_millis(date_ms as i64).expect("Failed to parse date from milliseconds"); - let uefi_date = Time::new(TimeParams { - year: date.year() as u16, - month: date.month() as u8, - day: date.day() as u8, - hour: date.hour() as u8, - minute: date.minute() as u8, - second: date.second() as u8, - nanosecond: date.nanosecond(), - time_zone: None, - daylight: Default::default(), - }).expect("Failed to create EFI date"); - - return match unsafe { runtime_services.set_time(&uefi_date) } { - Ok(_) => true as usize, - Err(_) => false as usize, - }; - } - - false as usize -} - -pub fn sys_mkentry( - path_buff: *const u8, - path_buff_len: usize, - name_buff: *const u8, - name_buff_len: usize, - data: usize, -) -> (usize, usize) { - let path = from_utf8(unsafe { - slice_from_raw_parts(path_buff, path_buff_len) - .as_ref() - .unwrap() - }) - .unwrap(); - let name = from_utf8(unsafe { - slice_from_raw_parts(name_buff, name_buff_len) - .as_ref() - .unwrap() - }) - .unwrap(); - let r = name_service::mkentry_new(path, name, vec![1]); - convert_syscall_result_to_codes(r, zero_ok, one_err) - - //info!("sys_mkentry({}, {}, {}, {}, {})", arg1, arg2, arg3, arg4, arg5); -// return (0xAA, 0xBB); -} +pub mod syscall_dispatcher; diff --git a/os/kernel/src/syscall/sys_concurrent.rs b/os/kernel/src/syscall/sys_concurrent.rs new file mode 100644 index 0000000..91d6ae2 --- /dev/null +++ b/os/kernel/src/syscall/sys_concurrent.rs @@ -0,0 +1,66 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: sys_concurrent ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: All system calls related to processes and threads. ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Fabian Ruhland, 30.8.2024, HHU ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ +use alloc::vec::Vec; +use alloc::rc::Rc; +use core::ptr::slice_from_raw_parts; +use core::str::from_utf8; +use x86_64::VirtAddr; +use crate::{initrd, process_manager, scheduler}; +use crate::process::thread::Thread; + + +pub fn sys_process_id() -> usize { + process_manager().read().current_process().id() +} + +pub fn sys_process_exit() { + scheduler().current_thread().process().exit(); + scheduler().exit(); +} + +#[allow(improper_ctypes_definitions)] // 'entry' takes no arguments and has no return value, so we just assume that the "C" and "Rust" ABIs act the same way in this case +pub fn sys_thread_create(kickoff_addr: u64, entry: fn()) -> usize { + let thread = Thread::new_user_thread(process_manager().read().current_process(), VirtAddr::new(kickoff_addr), entry); + let id = thread.id(); + + scheduler().ready(thread); + id +} + +pub fn sys_thread_id() -> usize { + scheduler().current_thread().id() +} + +pub fn sys_thread_switch() { + scheduler().switch_thread_no_interrupt(); +} + +pub fn sys_thread_sleep(ms: usize) { + scheduler().sleep(ms); +} + +pub fn sys_thread_join(id: usize) { + scheduler().join(id); +} + +pub fn sys_thread_exit() { + scheduler().exit(); +} + +pub fn sys_process_execute_binary(name_buffer: *const u8, name_length: usize, args: *const Vec<&str>) -> usize { + let app_name = from_utf8(unsafe { slice_from_raw_parts(name_buffer, name_length).as_ref().unwrap() }).unwrap(); + match initrd().entries().find(|entry| entry.filename().as_str().unwrap() == app_name) { + Some(app) => { + let thread = Thread::load_application(app.data(), app_name, unsafe { args.as_ref().unwrap() }); + scheduler().ready(Rc::clone(&thread)); + thread.id() + } + None => 0, + } +} diff --git a/os/kernel/src/syscall/sys_naming.rs b/os/kernel/src/syscall/sys_naming.rs new file mode 100644 index 0000000..41395a4 --- /dev/null +++ b/os/kernel/src/syscall/sys_naming.rs @@ -0,0 +1,48 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: sys_naming ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: All system calls for the naming service. ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Michael Schoettner, 30.8.2024, HHU ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ +use alloc::vec; +use core::ptr::slice_from_raw_parts; +use core::str::from_utf8; +use syscall::return_vals::{convert_syscall_result_to_ret_code,SyscallResult,Errno}; + +use crate::naming::name_service; + + + +pub fn sys_mkentry( + path_buff: *const u8, + path_buff_len: usize, + name_buff: *const u8, + name_buff_len: usize, + data: usize, +) -> i64 { + let path = from_utf8(unsafe { + slice_from_raw_parts(path_buff, path_buff_len) + .as_ref() + .unwrap() + }) + .unwrap(); + let name = from_utf8(unsafe { + slice_from_raw_parts(name_buff, name_buff_len) + .as_ref() + .unwrap() + }) + .unwrap(); + + let r = name_service::mkentry(path, name, vec![1]); + return convert_syscall_result_to_ret_code(r); +} + +// Wrapper function to convert Result<(), Errno> to SyscallResult +fn convert_result(result: Result<(), Errno>) -> SyscallResult { + match result { + Ok(()) => Ok(0), // Convert the success case to a meaningful u64, e.g., 0 + Err(e) => Err(e), // Forward the error directly + } +} diff --git a/os/library/syscall/src/consts.rs b/os/kernel/src/syscall/sys_terminal.rs similarity index 55% rename from os/library/syscall/src/consts.rs rename to os/kernel/src/syscall/sys_terminal.rs index 6244c31..cc84adf 100644 --- a/os/library/syscall/src/consts.rs +++ b/os/kernel/src/syscall/sys_terminal.rs @@ -1,25 +1,25 @@ /* ╔═════════════════════════════════════════════════════════════════════════╗ - ║ Module: lib ║ + ║ Module: sys_terminal ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Descr.: Syscalls for the naming service. ║ + ║ Descr.: All system calls for terminal. ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Michael Schoettner, 29.8.2024, HHU ║ + ║ Author: Fabian Ruhland, 30.8.2024, HHU ║ ╚═════════════════════════════════════════════════════════════════════════╝ */ +use core::ptr::slice_from_raw_parts; +use core::str::from_utf8; +use crate::terminal; -use num_enum::{FromPrimitive,IntoPrimitive}; - -#[derive(Debug, Copy, Clone, Eq, PartialEq, IntoPrimitive, FromPrimitive)] -#[repr(usize)] -pub enum Errno { - #[num_enum(default)] - ENOENT = 2, /* No such file or directory */ - EACCES = 13, /* Permission denied */ - EEXIST = 17, /* File/directory exists */ - ENOTDIR = 20, /* Not a directory */ - EINVAL = 22, /* Invalid argument */ - ENOTEMPTY = 90, /* Directory not empty */ +pub fn sys_terminal_read() -> usize { + let terminal = terminal(); + match terminal.read_byte() { + -1 => panic!("Input stream closed!"), + c => c as usize + } } -pub type SyscallResult = ::core::result::Result; -pub type Result = ::core::result::Result; +pub fn sys_terminal_write(buffer: *const u8, length: usize) { + let string = from_utf8(unsafe { slice_from_raw_parts(buffer, length).as_ref().unwrap() }).unwrap(); + let terminal = terminal(); + terminal.write_str(string); +} diff --git a/os/kernel/src/syscall/sys_time.rs b/os/kernel/src/syscall/sys_time.rs new file mode 100644 index 0000000..6532ba7 --- /dev/null +++ b/os/kernel/src/syscall/sys_time.rs @@ -0,0 +1,82 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: lib ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: All system calls (starting with sys_). ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Fabian Ruhland & Michael Schoettner, 30.8.2024, HHU ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ + +use alloc::format; +use alloc::string::ToString; +use chrono::{DateTime, Datelike, TimeDelta, Timelike}; +use core::ptr; +use uefi::table::runtime::{Time, TimeParams}; +use crate::{efi_system_table, timer}; + + +pub fn sys_get_system_time() -> usize { + timer().systime_ms() +} + +pub fn sys_get_date() -> usize { + if let Some(efi_system_table) = efi_system_table() { + let system_table = efi_system_table.read(); + let runtime_services = unsafe { system_table.runtime_services() }; + + return match runtime_services.get_time() { + Ok(time) => { + if time.is_valid().is_ok() { + let timezone = match time.time_zone() { + Some(timezone) => { + let delta = TimeDelta::try_minutes(timezone as i64).expect("Failed to create TimeDelta struct from timezone"); + if timezone >= 0 { + format!("+{:0>2}:{:0>2}", delta.num_hours(), delta.num_minutes() % 60) + } else { + format!("-{:0>2}:{:0>2}", delta.num_hours(), delta.num_minutes() % 60) + } + } + None => "Z".to_string(), + }; + + DateTime::parse_from_rfc3339(format!("{}-{:0>2}-{:0>2}T{:0>2}:{:0>2}:{:0>2}.{:0>9}{}", time.year(), time.month(), time.day(), time.hour(), time.minute(), time.second(), time.nanosecond(), timezone).as_str()) + .expect("Failed to parse date from EFI runtime services") + .timestamp_millis() as usize + } else { + 0 + } + } + Err(_) => 0 + } + } + + 0 +} + +pub fn sys_set_date(date_ms: usize) -> usize { + if let Some(efi_system_table) = efi_system_table() { + let system_table = efi_system_table.write(); + let runtime_services_read = unsafe { system_table.runtime_services() }; + let runtime_services = unsafe { ptr::from_ref(runtime_services_read).cast_mut().as_mut().unwrap() }; + + let date = DateTime::from_timestamp_millis(date_ms as i64).expect("Failed to parse date from milliseconds"); + let uefi_date = Time::new(TimeParams { + year: date.year() as u16, + month: date.month() as u8, + day: date.day() as u8, + hour: date.hour() as u8, + minute: date.minute() as u8, + second: date.second() as u8, + nanosecond: date.nanosecond(), + time_zone: None, + daylight: Default::default(), + }).expect("Failed to create EFI date"); + + return match unsafe { runtime_services.set_time(&uefi_date) } { + Ok(_) => true as usize, + Err(_) => false as usize, + }; + } + + false as usize +} diff --git a/os/kernel/src/syscall/sys_vmem.rs b/os/kernel/src/syscall/sys_vmem.rs new file mode 100644 index 0000000..d79b738 --- /dev/null +++ b/os/kernel/src/syscall/sys_vmem.rs @@ -0,0 +1,28 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: sys_vmem ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: All system calls related to virtual memory management. ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Fabian Ruhland & Michael Schoettner, 30.8.2024, HHU ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ + +use crate::memory::r#virtual::{VirtualMemoryArea, VmaType}; +use crate::memory::{MemorySpace, PAGE_SIZE}; +use crate::process_manager; +use x86_64::structures::paging::PageTableFlags; + + +pub fn sys_map_user_heap(size: usize) -> usize { + let process = process_manager().read().current_process(); + let code_areas = process.find_vmas(VmaType::Code); + let code_area = code_areas.get(0).expect("Process does not have code area!"); + let heap_start = code_area.end().align_up(PAGE_SIZE as u64); + let heap_area = VirtualMemoryArea::from_address(heap_start, size, VmaType::Heap); + + process.address_space().map(heap_area.range(), MemorySpace::User, PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE); + process.add_vma(heap_area); + + heap_start.as_u64() as usize +} + diff --git a/os/kernel/src/syscall/syscall_dispatcher.rs b/os/kernel/src/syscall/syscall_dispatcher.rs index 731849b..024cb8d 100644 --- a/os/kernel/src/syscall/syscall_dispatcher.rs +++ b/os/kernel/src/syscall/syscall_dispatcher.rs @@ -1,17 +1,11 @@ /* ╔═════════════════════════════════════════════════════════════════════════╗ ║ Module: syscall_dispatcher ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Descr.: Dispatcher for system calls. ║ + ║ Descr.: Low-level dispatcher for system calls. ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Fabian Ruhland & Michael Schoettner, 27.8.2024, HHU ║ + ║ Author: Fabian Ruhland, 30.8.2024, HHU ║ ╚═════════════════════════════════════════════════════════════════════════╝ */ -use crate::syscall::{ - sys_get_date, sys_get_system_time, sys_map_user_heap, sys_process_execute_binary, - sys_process_exit, sys_process_id, sys_read, sys_set_date, sys_thread_create, sys_thread_exit, - sys_thread_id, sys_thread_join, sys_thread_sleep, sys_thread_switch, sys_write, sys_mkentry, -}; -use crate::{core_local_storage, tss}; use core::arch::asm; use core::mem::size_of; use core::ops::Deref; @@ -21,6 +15,14 @@ use x86_64::registers::control::{Efer, EferFlags}; use x86_64::registers::model_specific::{KernelGsBase, LStar, Star}; use x86_64::structures::gdt::SegmentSelector; use x86_64::{PrivilegeLevel, VirtAddr}; +use crate::syscall::sys_vmem::sys_map_user_heap; +use crate::syscall::sys_time::{sys_get_date, sys_get_system_time, sys_set_date, }; +use crate::syscall::sys_concurrent::{sys_process_execute_binary, sys_process_exit, sys_process_id, sys_thread_create, sys_thread_exit, + sys_thread_id, sys_thread_join, sys_thread_sleep, sys_thread_switch,}; +use crate::syscall::sys_terminal::{sys_terminal_read, sys_terminal_write}; +use crate::syscall::sys_naming::sys_mkentry; + +use crate::{core_local_storage, tss}; pub const CORE_LOCAL_STORAGE_TSS_RSP0_PTR_INDEX: u64 = 0x00; pub const CORE_LOCAL_STORAGE_USER_RSP_INDEX: u64 = 0x08; @@ -81,8 +83,8 @@ impl SyscallTable { pub const fn new() -> Self { SyscallTable { handle: [ - sys_read as *const _, - sys_write as *const _, + sys_terminal_read as *const _, + sys_terminal_write as *const _, sys_map_user_heap as *const _, sys_process_execute_binary as *const _, sys_process_id as *const _, @@ -134,7 +136,7 @@ unsafe extern "C" fn syscall_handler() { // Store registers (except rax, which is used for system call ID and return value) "push rbx", "push rcx", // Contains rip for returning to ring 3 - // "push rdx", // Contains 2nd return value -> do not save & restore + "push rdx", "push rdi", "push rsi", "push r8", @@ -170,7 +172,7 @@ unsafe extern "C" fn syscall_handler() { "pop r8", "pop rsi", "pop rdi", - // "pop rdx", // Contains 2nd return value -> do not save & restore + "pop rdx", "pop rcx", // Contains rip for returning to ring 3 "pop rbx", diff --git a/os/library/concurrent/src/process.rs b/os/library/concurrent/src/process.rs index 183d2e3..12a605a 100644 --- a/os/library/concurrent/src/process.rs +++ b/os/library/concurrent/src/process.rs @@ -1,7 +1,15 @@ -use syscall::{syscall0, SystemCall}; +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: process ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Syscalls for process functions. ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Fabian Ruhland, Michael Schoettner, 31.8.2024, HHU ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ +use syscall::{syscall, SystemCall}; pub struct Process { - id: usize + id: usize, } impl Process { @@ -14,11 +22,14 @@ impl Process { } } -pub fn current() -> Process { - let id = syscall0(SystemCall::ProcessId); - Process::new(id) +pub fn current() -> Option { + let res = syscall(SystemCall::ProcessId, &[]); + match res { + Ok(id) => Some(Process::new(id as usize)), + Err(e) => None, + } } pub fn exit() { - syscall0(SystemCall::ProcessExit); -} \ No newline at end of file + syscall(SystemCall::ProcessExit, &[]); +} diff --git a/os/library/concurrent/src/thread.rs b/os/library/concurrent/src/thread.rs index 3b26131..897c430 100644 --- a/os/library/concurrent/src/thread.rs +++ b/os/library/concurrent/src/thread.rs @@ -1,9 +1,17 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: thread ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Syscalls for thread functions. ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Fabian Ruhland, Michael Schoettner, 31.8.2024, HHU ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ use alloc::vec::Vec; use core::ptr; -use syscall::{syscall0, syscall1, syscall2, syscall3, SystemCall}; +use syscall::{syscall, SystemCall}; pub struct Thread { - id: usize + id: usize, } impl Thread { @@ -16,7 +24,7 @@ impl Thread { } pub fn join(&self) { - syscall1(SystemCall::ThreadJoin, self.id); + let _ = syscall(SystemCall::ThreadJoin, &[self.id]); } } @@ -25,34 +33,44 @@ fn kickoff_user_thread(entry: fn()) { exit(); } -pub fn create(entry: fn()) -> Thread { - let id = syscall2(SystemCall::ThreadCreate, kickoff_user_thread as usize, entry as usize); - Thread::new(id) +pub fn create(entry: fn()) -> Option { + let res = syscall(SystemCall::ThreadCreate, &[kickoff_user_thread as usize, + entry as usize,]); + match res { + Ok(id) => Some(Thread::new(id as usize)), + Err(_) => None, + } } -pub fn current() -> Thread { - let id = syscall0(SystemCall::ThreadId); - Thread::new(id) +pub fn current() -> Option { + let res = syscall(SystemCall::ThreadId, &[]); + match res { + Ok(id) => Some(Thread::new(id as usize)), + Err(_) => None, + } } #[allow(dead_code)] pub fn switch() { - syscall0(SystemCall::ThreadSwitch); + let _ = syscall(SystemCall::ThreadSwitch, &[]); } #[allow(dead_code)] pub fn sleep(ms: usize) { - syscall1(SystemCall::ThreadSleep, ms); + let _ = syscall(SystemCall::ThreadSleep, &[ms]); } pub fn exit() -> ! { - syscall0(SystemCall::ThreadExit); + let _ = syscall(SystemCall::ThreadExit, &[]); panic!("System call 'ThreadExit' has returned!") } pub fn start_application(name: &str, args: Vec<&str>) -> Option { - match syscall3(SystemCall::ProcessExecuteBinary, name.as_bytes().as_ptr() as usize, name.len(), ptr::from_ref(&args) as usize) { - 0 => None, - id => Some(Thread::new(id)) - } + let res = syscall(SystemCall::ProcessExecuteBinary, &[name.as_bytes().as_ptr() as usize, + name.len(), + ptr::from_ref(&args) as usize,]); + match res { + Ok(id) => Some(Thread::new(id as usize)), + Err(_) => None, + } } diff --git a/os/library/io/src/read.rs b/os/library/io/src/read.rs deleted file mode 100644 index e4408da..0000000 --- a/os/library/io/src/read.rs +++ /dev/null @@ -1,5 +0,0 @@ -use syscall::{syscall0, SystemCall}; - -pub fn read() -> char { - char::from_u32(syscall0(SystemCall::Read) as u32).unwrap() -} \ No newline at end of file diff --git a/os/library/io/src/write.rs b/os/library/io/src/write.rs deleted file mode 100644 index 7b31794..0000000 --- a/os/library/io/src/write.rs +++ /dev/null @@ -1,38 +0,0 @@ -use core::fmt; -use core::fmt::Write; -use spin::Mutex; -use syscall::{syscall2, SystemCall}; - -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ({ - $crate::write::print(format_args!($($arg)*)); - }); -} - -#[macro_export] -macro_rules! println { - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); -} - -static WRITER: Mutex = Mutex::new(Writer::new()); - -pub fn print(args: fmt::Arguments) { - WRITER.lock().write_fmt(args).unwrap(); -} - -struct Writer {} - -impl Writer { - const fn new() -> Self { - Self {} - } -} - -impl Write for Writer { - fn write_str(&mut self, s: &str) -> fmt::Result { - syscall2(SystemCall::Write, s.as_bytes().as_ptr() as usize, s.len()); - return Ok(()); - } -} \ No newline at end of file diff --git a/os/library/naming/Cargo.toml b/os/library/naming/Cargo.toml index c0d697a..320f0b2 100644 --- a/os/library/naming/Cargo.toml +++ b/os/library/naming/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Michael Schöttner , Fabian Ruhland Result { - let (code, val) = syscall( - SystemCall::Mkentry, - &[ - path.as_bytes().as_ptr() as usize, - path.len(), - name.as_bytes().as_ptr() as usize, - name.len(), - data, // place holder, to be replaced by pointer to container - ], - ); - - let v:Result = convert_syscall_codes_to_result( - code, - val, - |c, _| c != 0, - |_, _| val.into(), - |_, v| val.into(), - ); - - println!("lib/mkentry: result = {:?}", v); - - return v; +pub fn mkentry(path: &str, name: &str, data: usize) -> Result { + // Check if params are valid + if path.is_empty() || name.is_empty() { + Err(Errno::EINVAL) // Abort, if not + } else { + // params OK, do the syscall + syscall( + SystemCall::Mkentry, + &[ + path.as_bytes().as_ptr() as usize, + path.len(), + name.as_bytes().as_ptr() as usize, + name.len(), + data, // place holder, to be replaced by pointer to container + ], + ) + } } diff --git a/os/library/runtime/Cargo.toml b/os/library/runtime/Cargo.toml index 7b8378c..7eecd60 100644 --- a/os/library/runtime/Cargo.toml +++ b/os/library/runtime/Cargo.toml @@ -6,7 +6,7 @@ authors = ["Michael Schöttner , Fabian Ruhland ! { #[unsafe(no_mangle)] extern "C" fn entry() { - let heap_start = syscall1(SystemCall::MapUserHeap, HEAP_SIZE) as *mut u8; - unsafe { ALLOCATOR.lock().init(heap_start, HEAP_SIZE); } + let heap_start: *mut u8; + + let res = syscall(SystemCall::MapUserHeap, &[HEAP_SIZE]); + match res { + Ok(hs) => heap_start = hs as *mut u8, + Err(_) => panic!("Could not create user heap."), + } - unsafe { main(); } + unsafe { + ALLOCATOR.lock().init(heap_start, HEAP_SIZE); + } + + unsafe { + main(); + } process::exit(); -} \ No newline at end of file +} diff --git a/os/library/syscall/src/lib.rs b/os/library/syscall/src/lib.rs index cb83810..f30293c 100644 --- a/os/library/syscall/src/lib.rs +++ b/os/library/syscall/src/lib.rs @@ -3,20 +3,21 @@ ╟─────────────────────────────────────────────────────────────────────────╢ ║ Descr.: Syscall interface in user mode. ║ ╟─────────────────────────────────────────────────────────────────────────╢ - ║ Author: Fabian Ruhland, Michael Schoettner, 28.8.2024, HHU ║ + ║ Author: Fabian Ruhland, Michael Schoettner, 30.8.2024, HHU ║ ╚═════════════════════════════════════════════════════════════════════════╝ */ #![no_std] +pub mod return_vals; use core::arch::asm; +use return_vals::{SyscallResult, convert_ret_code_to_syscall_result}; -pub mod consts; - +/// Enum with all known system calls #[repr(usize)] #[allow(dead_code)] pub enum SystemCall { - Read = 0, - Write, + TerminalRead = 0, + TerminalWrite, MapUserHeap, ProcessExecuteBinary, ProcessId, @@ -41,169 +42,17 @@ pub const NUM_SYSCALLS: usize = SystemCall::LastEntryMarker as usize; /// /// Description: -/// Converts return values from a syscall to a Rust `Result` +/// All syscalls are fired here. Parameters are passed in +/// registers according to the AMD 64 bit ABI. /// -/// Parameters: \ -/// `code` first return value of a syscall \ -/// `val` second return value of a syscall \ -/// `is_ok` function to termine if the result was `Ok` or `Err` \ -/// `ok_f` function to produce the content for `Ok` \ -/// `err_f` function to produce the content for `Err` -#[inline] -pub fn convert_syscall_codes_to_result( - code: usize, - val: usize, - is_ok_f: D, - ok_f: F, - err_f: G, -) -> Result -where - F: Fn(usize, usize) -> T, - G: Fn(usize, usize) -> E, - D: Fn(usize, usize) -> bool, -{ - if is_ok_f(code, val) { - Err(err_f(code, val)) - } else { - Ok(ok_f(code, val)) - } -} - -#[inline(always)] -pub fn syscall0(call: SystemCall) -> usize { - let ret: usize; - - unsafe { - asm!( - "syscall", - inlateout("rax") call as usize => ret, - out("rcx") _, - out("r11") _, - options(preserves_flags, nostack) - ); - } - - ret -} - -#[inline(always)] -pub fn syscall1(call: SystemCall, arg1: usize) -> usize { - let ret: usize; - - unsafe { - asm!( - "syscall", - inlateout("rax") call as usize => ret, - in("rdi") arg1, - out("rcx") _, - out("r11") _, - options(preserves_flags, nostack) - ); - } - - ret -} - -#[inline(always)] -#[allow(dead_code)] -pub fn syscall2(call: SystemCall, arg1: usize, arg2: usize) -> usize { - let ret: usize; - - unsafe { - asm!( - "syscall", - inlateout("rax") call as usize => ret, - in("rdi") arg1, - in("rsi") arg2, - out("rcx") _, - out("r11") _, - options(preserves_flags, nostack) - ); - } - - ret -} - -#[inline(always)] -#[allow(dead_code)] -pub fn syscall3(call: SystemCall, arg1: usize, arg2: usize, arg3: usize) -> usize { - let ret: usize; - - unsafe { - asm!( - "syscall", - inlateout("rax") call as usize => ret, - in("rdi") arg1, - in("rsi") arg2, - in("rdx") arg3, - out("rcx") _, - out("r11") _, - options(preserves_flags, nostack) - ); - } - - ret -} - -#[inline(always)] -#[allow(dead_code)] -pub fn syscall4(call: SystemCall, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize { - let ret: usize; - - unsafe { - asm!( - "syscall", - inlateout("rax") call as usize => ret, - in("rdi") arg1, - in("rsi") arg2, - in("rdx") arg3, - in("r10") arg4, - out("rcx") _, - out("r11") _, - options(preserves_flags, nostack) - ); - } - - ret -} - -#[inline(always)] -#[allow(dead_code)] -pub fn syscall5( - call: SystemCall, - arg1: usize, - arg2: usize, - arg3: usize, - arg4: usize, - arg5: usize, -) -> (usize, usize) { - let code: usize; - let val: usize; - - unsafe { - asm!( - "syscall", - inlateout("rax") call as usize => code, - in("rdi") arg1, - in("rsi") arg2, - inlateout("rdx") arg3 => val, - in("r10") arg4, - in("r8") arg5, - out("rcx") _, - out("r11") _, - options(preserves_flags, nostack) - ); - } - - (code, val) -} - -pub fn syscall(call: SystemCall, args: &[usize]) -> (usize, usize) { - let code: usize; - let val: usize; +/// Return: Result \ +/// success >= 0 \ +/// error, codes defined in consts.rs +pub fn syscall(call: SystemCall, args: &[usize]) -> SyscallResult { + let ret_code: i64; if args.len() > 6 { - panic!("System call with more than six params is not supported."); + panic!("System calls with more than 6 params are not supported."); } let a0 = *args.first().unwrap_or(&0usize); @@ -216,10 +65,10 @@ pub fn syscall(call: SystemCall, args: &[usize]) -> (usize, usize) { unsafe { asm!( "syscall", - inlateout("rax") call as usize => code, + inlateout("rax") call as i64 => ret_code, in("rdi") a0, in("rsi") a1, - inlateout("rdx") a2 => val, + in("rdx") a2, in("r10") a3, in("r8") a4, in("r9") a5, @@ -227,110 +76,6 @@ pub fn syscall(call: SystemCall, args: &[usize]) -> (usize, usize) { lateout("r11") _, clobber_abi("system")); } - (code, val) -} - -/* -/// Tizzler, kernel -pub unsafe fn raw_syscall(call: Syscall, args: &[u64]) -> (u64, u64) { - if core::intrinsics::unlikely(args.len() > 6) { - crate::print_err("too many arguments to raw_syscall"); - crate::internal_abort(); - } - let a0 = *args.first().unwrap_or(&0u64); - let a1 = *args.get(1).unwrap_or(&0u64); - let mut a2 = *args.get(2).unwrap_or(&0u64); - let a3 = *args.get(3).unwrap_or(&0u64); - let a4 = *args.get(4).unwrap_or(&0u64); - let a5 = *args.get(5).unwrap_or(&0u64); - - let mut num = call.num(); - core::arch::asm!("syscall", inout("rax") num, in("rdi") a0, in("rsi") a1, inout("rdx") a2, in("r10") a3, in("r9") a4, in("r8") a5, lateout("rcx") _, lateout("r11") _, clobber_abi("system")); - (num, a2) -} - - - -// im user mode -pub struct ClockInfo { - current: TimeSpan, - precision: FemtoSeconds, - resolution: FemtoSeconds, - flags: ClockFlags, -} - - -#[repr(u64)] -// im user mode -/// Possible error returns for [sys_read_clock_info]. -pub enum ReadClockInfoError { - /// An unknown error occurred. - #[num_enum(default)] - #[error("unknown error")] - Unknown = 0, - /// One of the arguments was invalid. - #[error("invalid argument")] - InvalidArgument = 1, -} - -// im user mode -pub fn sys_read_clock_info( - clock_source: ClockSource, - flags: ReadClockFlags, -) -> Result { - let mut clock_info = MaybeUninit::uninit(); - let (code, val) = unsafe { - raw_syscall( - Syscall::ReadClockInfo, - &[ - clock_source.into(), - &mut clock_info as *mut MaybeUninit as usize as u64, - flags.bits() as u64, - ], - ) - }; - convert_codes_to_result( - code, - val, - |c, _| c != 0, - |_, _| unsafe { clock_info.assume_init() }, - |_, v| v.into(), - ) -} - -// im user mode -#[inline] -fn convert_codes_to_result(code: u64, val: u64, d: D, f: F, g: G) -> Result -where - F: Fn(u64, u64) -> T, - G: Fn(u64, u64) -> E, - D: Fn(u64, u64) -> bool, -{ - if d(code, val) { - Err(g(code, val)) - } else { - Ok(f(code, val)) - } -} -// im kernel -Syscall::ReadClockInfo => { - let result = type_read_clock_info(context.arg0(), context.arg1(), context.arg2()); - let (code, val) = convert_result_to_codes(result, zero_ok, one_err); - context.set_return_values(code, val); + convert_ret_code_to_syscall_result(ret_code) } - -// im kernel -#[inline] -fn convert_result_to_codes(result: Result, f: F, g: G) -> (u64, u64) -where - F: Fn(T) -> (u64, u64), - G: Fn(E) -> (u64, u64), -{ - match result { - Ok(t) => f(t), - Err(e) => g(e), - } -} - -*/ diff --git a/os/library/syscall/src/return_vals.rs b/os/library/syscall/src/return_vals.rs new file mode 100644 index 0000000..e2ec489 --- /dev/null +++ b/os/library/syscall/src/return_vals.rs @@ -0,0 +1,44 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: consts.rs ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Consts and types for syscall return values. ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Michael Schoettner, 31.8.2024, HHU ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ + +use num_enum::{FromPrimitive, IntoPrimitive}; + +#[derive(Debug, Copy, Clone, Eq, PartialEq, IntoPrimitive, FromPrimitive)] +#[repr(i64)] +pub enum Errno { + #[num_enum(default)] + EUNKN = -1, // Unknown error + ENOENT = -2, // No such file or directory + EACCES = -13, // Permission denied + EEXIST = -17, // File/directory exists + ENOTDIR = -20, // Not a directory + EINVAL = -22, // Invalid argument + ENOTEMPTY = -90, // Directory not empty +} + +pub type SyscallResult = ::core::result::Result; + +pub fn convert_ret_code_to_syscall_result(ret_code: i64) -> SyscallResult { + if ret_code < 0 { + return Err(Errno::from(ret_code)); + } else { + return Ok(ret_code as u64); + } +} + +pub fn convert_syscall_result_to_ret_code(syscall_result: SyscallResult) -> i64 { + let ret_val: i64; + match syscall_result { + Ok(t) => ret_val = t as i64, + Err(e) => ret_val = e.into(), + } + ret_val +} + + diff --git a/os/library/io/Cargo.toml b/os/library/terminal/Cargo.toml similarity index 93% rename from os/library/io/Cargo.toml rename to os/library/terminal/Cargo.toml index cdc8ae4..1981493 100644 --- a/os/library/io/Cargo.toml +++ b/os/library/terminal/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "io" +name = "terminal" version = "0.1.0" authors = ["Michael Schöttner , Fabian Ruhland "] diff --git a/os/library/io/src/lib.rs b/os/library/terminal/src/lib.rs similarity index 100% rename from os/library/io/src/lib.rs rename to os/library/terminal/src/lib.rs diff --git a/os/library/terminal/src/read.rs b/os/library/terminal/src/read.rs new file mode 100644 index 0000000..343356f --- /dev/null +++ b/os/library/terminal/src/read.rs @@ -0,0 +1,17 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: read ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Read a input char from terminal. ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Fabian Ruhland, 31.8.2024, HHU ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ +use syscall::{syscall, SystemCall}; + +pub fn read() -> Option { + let res = syscall(SystemCall::TerminalRead, &[]); + match res { + Ok(ch) => Some(char::from_u32(ch as u32).unwrap()), + Err(_) => None, + } +} \ No newline at end of file diff --git a/os/library/terminal/src/write.rs b/os/library/terminal/src/write.rs new file mode 100644 index 0000000..b77d878 --- /dev/null +++ b/os/library/terminal/src/write.rs @@ -0,0 +1,52 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: write ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Write a char to the terminal. ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Fabian Ruhland, 31.8.2024, HHU ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ +use core::fmt; +use core::fmt::Write; +use spin::Mutex; +use syscall::{syscall, SystemCall}; + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ({ + $crate::write::print(format_args!($($arg)*)); + }); +} + +#[macro_export] +macro_rules! println { + ($fmt:expr) => (print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); +} + +static WRITER: Mutex = Mutex::new(Writer::new()); + +pub fn print(args: fmt::Arguments) { + WRITER.lock().write_fmt(args).unwrap(); +} + +struct Writer {} + +impl Writer { + const fn new() -> Self { + Self {} + } +} + +impl Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + let res = syscall( + SystemCall::TerminalWrite, + &[s.as_bytes().as_ptr() as usize, s.len()], + ); + match res { + Ok(_) => Ok(()), + Err(_) => Err(fmt::Error), + } + } +} diff --git a/os/library/time/src/lib.rs b/os/library/time/src/lib.rs index 35b0eba..ad6fa24 100644 --- a/os/library/time/src/lib.rs +++ b/os/library/time/src/lib.rs @@ -1,21 +1,39 @@ +/* ╔═════════════════════════════════════════════════════════════════════════╗ + ║ Module: lib ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Descr.: Syscalls for everything related to time. ║ + ╟─────────────────────────────────────────────────────────────────────────╢ + ║ Author: Fabian Ruhland, 31.8.2024, HHU ║ + ╚═════════════════════════════════════════════════════════════════════════╝ +*/ #![no_std] use chrono::{DateTime, TimeDelta, Utc}; -use syscall::{syscall0, syscall1, SystemCall}; +use syscall::{syscall, SystemCall}; pub fn systime() -> TimeDelta { - let systime = syscall0(SystemCall::GetSystemTime); - TimeDelta::try_milliseconds(systime as i64).expect("Failed to create TimeDelta struct from systime") + let res = syscall(SystemCall::GetSystemTime, &[]); + match res { + Ok(systime) => TimeDelta::try_milliseconds(systime as i64).expect("Failed to create TimeDelta struct from systime"), + Err(_) => panic!("Syscall: GetSystemTime failed."), + } } pub fn date() -> DateTime { - let date_ms = syscall0(SystemCall::GetDate); - DateTime::from_timestamp_millis(date_ms as i64).expect("Failed to parse date from milliseconds returned by system call") + let res = syscall(SystemCall::GetDate, &[]); + match res { + Ok(date_ms) => DateTime::from_timestamp_millis(date_ms as i64).expect("Failed to parse date from milliseconds returned by system call"), + Err(_) => panic!("Syscall: GetDate failed."), + } } pub fn set_date(date: DateTime) -> bool { let date_ms = date.timestamp_millis(); - let success = syscall1(SystemCall::SetDate, date_ms as usize); - return success != 0; + let res = syscall(SystemCall::SetDate, &[date_ms as usize, ]); + match res { + Ok(_) => true, + Err(_) => false, + } + } \ No newline at end of file