From 9fa940f01121e6886df50bdea6187cc709c8806e Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 12 Jan 2025 14:42:52 +0200 Subject: [PATCH] abi: change set/get_thread/process_option() --- kernel/libk/src/task/process.rs | 43 ++++++- kernel/libk/src/task/thread.rs | 65 ++++++++-- kernel/src/fs/mod.rs | 2 +- kernel/src/syscall/imp/mod.rs | 13 +- kernel/src/syscall/imp/sys_process.rs | 90 +++---------- lib/abi-serde/src/impls/base.rs | 37 +++++- lib/abi-serde/src/impls/net.rs | 57 ++------- lib/abi-serde/src/lib.rs | 83 ++++++++++++ lib/abi/def/yggdrasil.abi | 16 ++- lib/abi/src/io/device.rs | 28 +---- lib/abi/src/io/terminal.rs | 118 ++---------------- lib/abi/src/net/mod.rs | 34 +---- lib/abi/src/net/types/mod.rs | 22 +--- lib/abi/src/process/mod.rs | 31 +---- lib/abi/src/process/options.rs | 13 ++ lib/abi/src/process/thread.rs | 32 +++-- lib/abi/src/system.rs | 17 ++- lib/runtime/src/io/paths.rs | 21 ++-- lib/runtime/src/io/terminal.rs | 2 +- lib/runtime/src/lib.rs | 7 +- lib/runtime/src/process/mod.rs | 75 ++++++++++- lib/runtime/src/process/options.rs | 0 lib/runtime/src/process/signal.rs | 40 +++--- lib/runtime/src/process/thread.rs | 10 +- lib/runtime/src/process/thread_local/i686.rs | 6 +- .../src/process/thread_local/x86_64.rs | 4 +- lib/runtime/src/system.rs | 16 +++ userspace/sysutils/src/sysmon.rs | 11 +- 28 files changed, 458 insertions(+), 435 deletions(-) create mode 100644 lib/abi/src/process/options.rs create mode 100644 lib/runtime/src/process/options.rs create mode 100644 lib/runtime/src/system.rs diff --git a/kernel/libk/src/task/process.rs b/kernel/libk/src/task/process.rs index a78e9927..9904a784 100644 --- a/kernel/libk/src/task/process.rs +++ b/kernel/libk/src/task/process.rs @@ -24,7 +24,11 @@ use libk_util::{ }; use yggdrasil_abi::{ error::Error, - process::{ExitCode, ProcessGroupId, ProcessId, Signal, ThreadSpawnOptions, WaitFlags}, + option::OptionValue, + process::{ + options::ProcessOptionVariant, ExitCode, ProcessGroupId, ProcessId, Signal, + ThreadSpawnOptions, WaitFlags, + }, }; use crate::{ @@ -281,6 +285,43 @@ impl Process { // unreachable!() } + pub fn get_option( + &self, + option: ProcessOptionVariant, + buffer: &mut [u8], + ) -> Result { + use yggdrasil_abi::process::options; + match option { + ProcessOptionVariant::Name => options::Name::store(&self.name.as_str(), buffer), + ProcessOptionVariant::Directory => { + let io = self.io.lock(); + let path = io.ioctx().cwd_path(); + options::Directory::store(&path.as_str(), buffer) + } + ProcessOptionVariant::SignalEntry => { + options::SignalEntry::store(&self.signal_entry(), buffer) + } + } + } + + pub fn set_option(&self, option: ProcessOptionVariant, buffer: &[u8]) -> Result<(), Error> { + use yggdrasil_abi::process::options; + + match option { + ProcessOptionVariant::Name => Err(Error::ReadOnly), + ProcessOptionVariant::Directory => { + let value = options::Directory::load(buffer)?; + let mut io = self.io.lock(); + io.ioctx_mut().set_cwd(value) + } + ProcessOptionVariant::SignalEntry => { + let value = options::SignalEntry::load(buffer)?; + self.set_signal_entry(value); + Ok(()) + } + } + } + /// Returns the address space of the process pub fn space(&self) -> Arc { self.inner.read().space.clone().unwrap() diff --git a/kernel/libk/src/task/thread.rs b/kernel/libk/src/task/thread.rs index 207ae06a..c7e9fd56 100644 --- a/kernel/libk/src/task/thread.rs +++ b/kernel/libk/src/task/thread.rs @@ -20,7 +20,11 @@ use yggdrasil_abi::{ arch::SavedFrame, debug::DebugFrame, error::Error, - process::{ExitCode, ProcessId, Signal, SignalEntryData}, + option::OptionValue, + process::{ + thread::{ThreadOptionVariant, ThreadSignalStack}, + ExitCode, ProcessId, Signal, SignalEntryData, + }, }; use crate::task::{ @@ -54,14 +58,8 @@ pub struct ThreadDebuggingInfo { pub breakpoints: BTreeMap, } -#[derive(Default, Clone, Copy, Debug)] -pub struct SignalStack { - pub base: usize, - pub size: usize, -} - pub struct ThreadInfo { - pub signal_stack: SignalStack, + pub signal_stack: ThreadSignalStack, } /// Describes a single thread within the system @@ -136,7 +134,7 @@ impl Thread { space, info: IrqSafeRwLock::new(ThreadInfo { - signal_stack: SignalStack::default(), + signal_stack: ThreadSignalStack::default(), }), signal_queue: SegQueue::new(), exit: Arc::new(BoolEvent::new()), @@ -177,6 +175,51 @@ impl Thread { ) } + pub fn get_option( + &self, + option: ThreadOptionVariant, + buffer: &mut [u8], + ) -> Result { + use yggdrasil_abi::process::thread as options; + + match option { + ThreadOptionVariant::Name => { + let name = self.name.read(); + options::Name::store(&name.as_str(), buffer) + } + ThreadOptionVariant::SignalStack => { + options::SignalStack::store(&self.signal_stack(), buffer) + } + // There're better ways to do this, don't ask the kernel + ThreadOptionVariant::ThreadPointer => Err(Error::InvalidOperation), + } + } + + pub fn set_option(&self, option: ThreadOptionVariant, buffer: &[u8]) -> Result<(), Error> { + use yggdrasil_abi::process::thread as options; + + match option { + ThreadOptionVariant::Name => { + let value = options::Name::load(buffer)?; + self.set_name(value); + Ok(()) + } + ThreadOptionVariant::SignalStack => { + let value = options::SignalStack::load(buffer)?; + if value.base.checked_add(value.size).is_none() { + return Err(Error::InvalidArgument); + } + self.set_signal_stack(value); + Ok(()) + } + ThreadOptionVariant::ThreadPointer => { + let value = options::ThreadPointer::load(buffer)?; + self.set_thread_pointer(value); + Ok(()) + } + } + } + /// Sets up arguments on the task's stack, if needed by the ABI. /// /// # Safety @@ -230,13 +273,13 @@ impl Thread { } /// Updates the thread signal stack information - pub fn set_signal_stack(&self, stack: SignalStack) -> SignalStack { + pub fn set_signal_stack(&self, stack: ThreadSignalStack) -> ThreadSignalStack { let mut info = self.info.write(); core::mem::replace(&mut info.signal_stack, stack) } /// Returns the currently set signal stack - pub fn signal_stack(&self) -> SignalStack { + pub fn signal_stack(&self) -> ThreadSignalStack { self.info.read().signal_stack } diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index 0c2a16d1..ef885854 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -116,7 +116,7 @@ pub fn global_control(option: u32, buffer: &mut [u8], len: usize) -> Result) -> R Ok(()) } -pub(crate) fn get_system_info(element: &mut SystemInfo) -> Result<(), Error> { - match element { - SystemInfo::MemoryStats(stats) => { - *stats = phys::stats(); - Ok(()) - } +pub(crate) fn get_system_info(option: u32, buffer: &mut [u8]) -> Result { + let option = SystemInfoVariant::try_from(option)?; + match option { + SystemInfoVariant::MemoryUsage => system::MemoryUsage::store(&phys::stats(), buffer), } } diff --git a/kernel/src/syscall/imp/sys_process.rs b/kernel/src/syscall/imp/sys_process.rs index 450f0af7..38408808 100644 --- a/kernel/src/syscall/imp/sys_process.rs +++ b/kernel/src/syscall/imp/sys_process.rs @@ -1,25 +1,19 @@ -use core::{ - mem::MaybeUninit, num::NonZeroUsize, str::FromStr, sync::atomic::AtomicU32, time::Duration, -}; +use core::{mem::MaybeUninit, num::NonZeroUsize, sync::atomic::AtomicU32, time::Duration}; use abi::{ error::Error, mem::{MappingFlags, MappingSource}, process::{ - ExitCode, MutexOperation, ProcessGroupId, ProcessId, ProcessOption, ProcessWait, Signal, - SpawnFlags, SpawnOption, SpawnOptions, ThreadOption, ThreadSpawnOptions, WaitFlags, + options::ProcessOptionVariant, thread::ThreadOptionVariant, ExitCode, MutexOperation, + ProcessGroupId, ProcessId, ProcessWait, Signal, SpawnFlags, SpawnOption, SpawnOptions, + ThreadSpawnOptions, WaitFlags, }, - util::FixedString, }; use alloc::sync::Arc; use libk::{ block, task::{ - binary::LoadOptions, - debug::ThreadDebugger, - process::Process, - runtime, - thread::{SignalStack, Thread}, + binary::LoadOptions, debug::ThreadDebugger, process::Process, runtime, thread::Thread, ThreadId, }, time::monotonic_time, @@ -330,78 +324,28 @@ pub(crate) fn wait_thread(id: u32) -> Result<(), Error> { block!(process.wait_for_thread(tid).await)? } -pub(crate) fn get_thread_option(option: &mut ThreadOption) -> Result<(), Error> { +pub(crate) fn get_thread_option(option: u32, buffer: &mut [u8]) -> Result { + let option = ThreadOptionVariant::try_from(option)?; let thread = Thread::current(); - match option { - // There're better ways to do this, don't ask the kernel - ThreadOption::ThreadPointer(_) => Err(Error::InvalidOperation), - ThreadOption::SignalStack(base, size) => { - let stack = thread.signal_stack(); - *base = stack.base; - *size = stack.size; - Ok(()) - } - ThreadOption::Name(_) => todo!(), - } + thread.get_option(option, buffer) } -pub(crate) fn set_thread_option(option: &mut ThreadOption) -> Result<(), Error> { +pub(crate) fn set_thread_option(option: u32, buffer: &[u8]) -> Result<(), Error> { + let option = ThreadOptionVariant::try_from(option)?; let thread = Thread::current(); - match option { - ThreadOption::ThreadPointer(tp) => { - log::debug!("{:?}: set thread pointer: {:#x}", thread.id, tp); - thread.set_thread_pointer(*tp); - Ok(()) - } - ThreadOption::SignalStack(base, size) => { - if base.checked_add(*size).is_none() { - return Err(Error::InvalidArgument); - } - let old = thread.set_signal_stack(SignalStack { - base: *base, - size: *size, - }); - *base = old.base; - *size = old.size; - Ok(()) - } - ThreadOption::Name(name) => { - // Make a kernel-owned string - log::debug!("{:?}: set thread name: {name:?}", thread.id); - thread.set_name(*name); - Ok(()) - } - } + thread.set_option(option, buffer) } -pub(crate) fn get_process_option(option: &mut ProcessOption) -> Result<(), Error> { +pub(crate) fn get_process_option(option: u32, buffer: &mut [u8]) -> Result { + let option = ProcessOptionVariant::try_from(option)?; let thread = Thread::current(); let process = thread.process(); - match option { - ProcessOption::SignalEntry(entry) => { - *entry = process.signal_entry(); - Ok(()) - } - ProcessOption::Directory(dst) => run_with_io(&process, |io| { - let path = io.ioctx().cwd_path(); - *dst = FixedString::from_str(path.as_str())?; - Ok(()) - }), - } + process.get_option(option, buffer) } -pub(crate) fn set_process_option(option: &mut ProcessOption) -> Result<(), Error> { +pub(crate) fn set_process_option(option: u32, buffer: &[u8]) -> Result<(), Error> { + let option = ProcessOptionVariant::try_from(option)?; let thread = Thread::current(); let process = thread.process(); - match option { - ProcessOption::SignalEntry(entry) => { - *entry = process.set_signal_entry(*entry); - Ok(()) - } - ProcessOption::Directory(path) => run_with_io(&process, |mut io| { - let path = path.as_ref(); - io.ioctx_mut().set_cwd(path)?; - Ok(()) - }), - } + process.set_option(option, buffer) } diff --git a/lib/abi-serde/src/impls/base.rs b/lib/abi-serde/src/impls/base.rs index 21913e3d..484601b9 100644 --- a/lib/abi-serde/src/impls/base.rs +++ b/lib/abi-serde/src/impls/base.rs @@ -29,10 +29,12 @@ impl_primitive_serde!( i16: [read_i16, write_i16], i32: [read_i32, write_i32], i64: [read_i64, write_i64], + isize: [read_isize, write_isize], u8: [read_u8, write_u8], u16: [read_u16, write_u16], u32: [read_u32, write_u32], - u64: [read_u64, write_u64] + u64: [read_u64, write_u64], + usize: [read_usize, write_usize] ); impl Serialize for () { @@ -49,6 +51,39 @@ impl<'de> Deserialize<'de> for () { } } +impl Serialize for &str { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { + serializer.write_str(self) + } +} + +impl<'de> Deserialize<'de> for &'de str { + fn deserialize>(deserializer: &mut D) -> Result { + deserializer.read_str() + } +} + +impl Serialize for [u8; N] +where + [u8; N]: Sized, +{ + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { + serializer.write_bytes(self) + } +} + +impl<'de, const N: usize> Deserialize<'de> for [u8; N] +where + [u8; N]: Sized, +{ + fn deserialize>(deserializer: &mut D) -> Result { + deserializer + .read_bytes()? + .try_into() + .map_err(|_| D::Error::INVALID_ARRAY_LEN) + } +} + impl Serialize for Option { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { match self { diff --git a/lib/abi-serde/src/impls/net.rs b/lib/abi-serde/src/impls/net.rs index 9874f438..f4fdd0b1 100644 --- a/lib/abi-serde/src/impls/net.rs +++ b/lib/abi-serde/src/impls/net.rs @@ -70,52 +70,11 @@ impl Serialize for SocketAddrV6 { } } -impl<'de> Deserialize<'de> for IpAddr { - fn deserialize>(deserializer: &mut D) -> Result { - match deserializer.read_enum_variant()? { - 4 => Ipv4Addr::deserialize(deserializer).map(Self::V4), - 6 => Ipv6Addr::deserialize(deserializer).map(Self::V6), - _ => Err(D::Error::INVALID_ENUM_VARIANT), - } - } -} - -impl<'de> Deserialize<'de> for SocketAddr { - fn deserialize>(deserializer: &mut D) -> Result { - match deserializer.read_enum_variant()? { - 4 => SocketAddrV4::deserialize(deserializer).map(Self::V4), - 6 => SocketAddrV6::deserialize(deserializer).map(Self::V6), - _ => Err(D::Error::INVALID_ENUM_VARIANT), - } - } -} - -impl Serialize for IpAddr { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - match self { - Self::V4(v4) => { - serializer.write_enum_variant(4)?; - v4.serialize(serializer) - } - Self::V6(v6) => { - serializer.write_enum_variant(6)?; - v6.serialize(serializer) - } - } - } -} - -impl Serialize for SocketAddr { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - match self { - Self::V4(v4) => { - serializer.write_enum_variant(4)?; - v4.serialize(serializer) - } - Self::V6(v6) => { - serializer.write_enum_variant(6)?; - v6.serialize(serializer) - } - } - } -} +crate::impl_enum_serde!(IpAddr: [ + V4 => 4, + V6 => 6 +]); +crate::impl_enum_serde!(SocketAddr: [ + V4 => 4, + V6 => 6 +]); diff --git a/lib/abi-serde/src/lib.rs b/lib/abi-serde/src/lib.rs index e3bd68a9..f5287551 100644 --- a/lib/abi-serde/src/lib.rs +++ b/lib/abi-serde/src/lib.rs @@ -10,3 +10,86 @@ pub mod wire; pub use des::Deserialize; pub use ser::Serialize; + +#[macro_export] +macro_rules! impl_enum_serde { + ( + $name:ident $(<$lifetime:lifetime>)? : [ + $( + $variant:ident => $discriminant:literal + ),* $(,)? + ] + ) => { + impl $(<$lifetime>)? $crate::Serialize for $name $(<$lifetime>)? { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { + match self { + $( + Self::$variant(value) => { + serializer.write_enum_variant($discriminant)?; + $crate::Serialize::serialize(value, serializer) + } + )* + } + } + } + + impl<'de> $crate::Deserialize<'de> for $name $(<$lifetime>)? { + fn deserialize>(deserializer: &mut D) -> Result { + let variant = deserializer.read_enum_variant()?; + match variant { + $( + $discriminant => $crate::Deserialize::deserialize(deserializer).map(Self::$variant), + )* + _ => Err(::INVALID_ENUM_VARIANT) + } + } + } + }; +} + +#[macro_export] +macro_rules! impl_struct_serde { + ( + $name:ident $(<$lifetime:lifetime>)? : [$($field:ident),* $(,)?] + ) => { + impl $(<$lifetime>)? $crate::Serialize for $name $(<$lifetime>)? { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { + $( + $crate::Serialize::serialize(&self.$field, serializer)?; + )* + Ok(()) + } + } + + impl<'de> $crate::Deserialize<'de> for $name $(<$lifetime:lifetime>)? { + fn deserialize>(deserializer: &mut D) -> Result { + $( + let $field = $crate::Deserialize::deserialize(deserializer)?; + )* + Ok(Self {$($field),*}) + } + } + } +} + +#[macro_export] +macro_rules! impl_newtype_serde { + ($name:ident) => { + impl $crate::Serialize for $name { + fn serialize( + &self, + serializer: &mut S, + ) -> Result<(), S::Error> { + $crate::Serialize::serialize(&self.0, serializer) + } + } + + impl<'de> $crate::Deserialize<'de> for $name { + fn deserialize>( + deserializer: &mut D, + ) -> Result { + $crate::Deserialize::deserialize(deserializer).map(Self) + } + } + }; +} diff --git a/lib/abi/def/yggdrasil.abi b/lib/abi/def/yggdrasil.abi index c1ef673e..82015701 100644 --- a/lib/abi/def/yggdrasil.abi +++ b/lib/abi/def/yggdrasil.abi @@ -11,14 +11,10 @@ extern { // TODO "tagged union" enums are not yet implemented type MappingSource; - type SystemInfo = yggdrasil_abi::system::SystemInfo; - type SignalEntryData = yggdrasil_abi::process::SignalEntryData; type MutexOperation = yggdrasil_abi::process::MutexOperation; #[thin] type ExitCode = yggdrasil_abi::process::ExitCode; - type ThreadOption = yggdrasil_abi::process::ThreadOption; - type ProcessOption = yggdrasil_abi::process::ProcessOption; type ProcessWait = yggdrasil_abi::process::ProcessWait; type SocketAddr = core::net::SocketAddr; @@ -72,12 +68,14 @@ bitfield MappingFlags(u32) { syscall get_random(buffer: &mut [u8]); syscall get_clock(clock: ClockType, out: &mut MaybeUninit) -> Result<()>; -syscall get_system_info(info: &mut SystemInfo) -> Result<()>; syscall mount(opts: &MountOptions<'_>) -> Result<()>; syscall unmount(opts: &UnmountOptions) -> Result<()>; syscall load_module(path: &str) -> Result<()>; + syscall filesystem_control(fd: Option, option: u32, value: &mut [u8], len: usize) -> Result; +syscall get_system_info(option: u32, value: &mut [u8]) -> Result; + // Memory management syscall map_memory( hint: Option, @@ -101,10 +99,10 @@ syscall get_tid() -> u32; syscall spawn_thread(options: &ThreadSpawnOptions) -> Result; syscall exit_thread() -> !; syscall wait_thread(tid: u32) -> Result<()>; -syscall get_thread_option(option: &mut ThreadOption<'_>) -> Result<()>; -syscall set_thread_option(option: &mut ThreadOption<'_>) -> Result<()>; -syscall get_process_option(option: &mut ProcessOption) -> Result<()>; -syscall set_process_option(option: &mut ProcessOption) -> Result<()>; +syscall get_thread_option(option: u32, value: &mut [u8]) -> Result; +syscall set_thread_option(option: u32, value: &[u8]) -> Result<()>; +syscall get_process_option(option: u32, value: &mut [u8]) -> Result; +syscall set_process_option(option: u32, value: &[u8]) -> Result<()>; syscall nanosleep(duration: &Duration, remaining: &mut MaybeUninit) -> Result<()>; diff --git a/lib/abi/src/io/device.rs b/lib/abi/src/io/device.rs index 0cccffc4..d1f3ed25 100644 --- a/lib/abi/src/io/device.rs +++ b/lib/abi/src/io/device.rs @@ -1,5 +1,4 @@ //! Device data structures and options -use abi_serde::{des::Deserializer, ser::Serializer, Deserialize, Serialize}; use crate::{io::terminal, process::ProcessGroupId}; @@ -56,27 +55,6 @@ request_group!( } ); -impl<'de> Deserialize<'de> for Framebuffer { - fn deserialize>(deserializer: &mut D) -> Result { - let width = deserializer.read_u32()?; - let height = deserializer.read_u32()?; - let stride = deserializer.read_usize()?; - let size = deserializer.read_usize()?; - Ok(Self { - width, - height, - stride, - size, - }) - } -} - -impl Serialize for Framebuffer { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - serializer.write_u32(self.width)?; - serializer.write_u32(self.height)?; - serializer.write_usize(self.stride)?; - serializer.write_usize(self.size)?; - Ok(()) - } -} +abi_serde::impl_struct_serde!(Framebuffer: [ + width, height, stride, size +]); diff --git a/lib/abi/src/io/terminal.rs b/lib/abi/src/io/terminal.rs index 44e906d6..8d59d371 100644 --- a/lib/abi/src/io/terminal.rs +++ b/lib/abi/src/io/terminal.rs @@ -1,5 +1,3 @@ -use abi_serde::{des::Deserializer, ser::Serializer, Deserialize, Serialize}; - pub use crate::generated::{ TerminalControlCharacters, TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions, TerminalSize, @@ -65,107 +63,15 @@ impl Default for TerminalOptions { } } -impl<'de> Deserialize<'de> for TerminalLineOptions { - fn deserialize>(deserializer: &mut D) -> Result { - Ok(unsafe { Self::from_raw(deserializer.read_u32()?) }) - } -} - -impl Serialize for TerminalLineOptions { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - serializer.write_u32(self.bits()) - } -} - -impl<'de> Deserialize<'de> for TerminalInputOptions { - fn deserialize>(deserializer: &mut D) -> Result { - Ok(unsafe { Self::from_raw(deserializer.read_u32()?) }) - } -} - -impl Serialize for TerminalInputOptions { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - serializer.write_u32(self.bits()) - } -} - -impl<'de> Deserialize<'de> for TerminalOutputOptions { - fn deserialize>(deserializer: &mut D) -> Result { - Ok(unsafe { Self::from_raw(deserializer.read_u32()?) }) - } -} - -impl Serialize for TerminalOutputOptions { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - serializer.write_u32(self.bits()) - } -} - -impl<'de> Deserialize<'de> for TerminalControlCharacters { - fn deserialize>(deserializer: &mut D) -> Result { - let eof = deserializer.read_u8()?; - let interrupt = deserializer.read_u8()?; - let erase = deserializer.read_u8()?; - let werase = deserializer.read_u8()?; - let kill = deserializer.read_u8()?; - Ok(Self { - eof, - interrupt, - erase, - werase, - kill, - }) - } -} - -impl Serialize for TerminalControlCharacters { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - serializer.write_u8(self.eof)?; - serializer.write_u8(self.interrupt)?; - serializer.write_u8(self.erase)?; - serializer.write_u8(self.werase)?; - serializer.write_u8(self.kill)?; - Ok(()) - } -} - -impl<'de> Deserialize<'de> for TerminalOptions { - fn deserialize>(deserializer: &mut D) -> Result { - let line = TerminalLineOptions::deserialize(deserializer)?; - let input = TerminalInputOptions::deserialize(deserializer)?; - let output = TerminalOutputOptions::deserialize(deserializer)?; - let chars = TerminalControlCharacters::deserialize(deserializer)?; - Ok(Self { - line, - input, - output, - chars, - }) - } -} - -impl Serialize for TerminalOptions { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - self.line.serialize(serializer)?; - self.input.serialize(serializer)?; - self.output.serialize(serializer)?; - self.chars.serialize(serializer)?; - Ok(()) - } -} - -impl<'de> Deserialize<'de> for TerminalSize { - fn deserialize>(deserializer: &mut D) -> Result { - let rows = deserializer.read_usize()?; - let columns = deserializer.read_usize()?; - Ok(Self { rows, columns }) - } -} - -impl Serialize for TerminalSize { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - serializer.write_usize(self.rows)?; - serializer.write_usize(self.columns)?; - Ok(()) - } -} +abi_serde::impl_newtype_serde!(TerminalLineOptions); +abi_serde::impl_newtype_serde!(TerminalInputOptions); +abi_serde::impl_newtype_serde!(TerminalOutputOptions); +abi_serde::impl_struct_serde!(TerminalControlCharacters: [ + eof, kill, erase, werase, interrupt +]); +abi_serde::impl_struct_serde!(TerminalOptions: [ + line, input, output, chars +]); +abi_serde::impl_struct_serde!(TerminalSize: [ + rows, columns +]); diff --git a/lib/abi/src/net/mod.rs b/lib/abi/src/net/mod.rs index 2ab2e1a9..0de948b3 100644 --- a/lib/abi/src/net/mod.rs +++ b/lib/abi/src/net/mod.rs @@ -1,11 +1,5 @@ //! Defines data types for network operations -use abi_serde::{ - des::{DeserializeError, Deserializer}, - ser::Serializer, - Deserialize, Serialize, -}; - #[cfg(any(feature = "alloc", feature = "rustc_std_alloc"))] pub mod dns; #[cfg(feature = "alloc")] @@ -46,30 +40,10 @@ impl From for SocketInterfaceQuery<'_> { } } -impl<'de> Deserialize<'de> for SocketInterfaceQuery<'de> { - fn deserialize>(deserializer: &mut D) -> Result { - match deserializer.read_enum_variant()? { - 1 => deserializer.read_u32().map(Self::ById), - 2 => deserializer.read_str().map(Self::ByName), - _ => Err(D::Error::INVALID_ENUM_VARIANT), - } - } -} - -impl Serialize for SocketInterfaceQuery<'_> { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - match *self { - Self::ById(id) => { - serializer.write_enum_variant(1)?; - serializer.write_u32(id) - } - Self::ByName(name) => { - serializer.write_enum_variant(2)?; - serializer.write_str(name) - } - } - } -} +abi_serde::impl_enum_serde!(SocketInterfaceQuery<'de>: [ + ById => 1, + ByName => 2 +]); #[cfg(test)] mod tests { diff --git a/lib/abi/src/net/types/mod.rs b/lib/abi/src/net/types/mod.rs index fcea4414..38d9a62f 100644 --- a/lib/abi/src/net/types/mod.rs +++ b/lib/abi/src/net/types/mod.rs @@ -2,12 +2,6 @@ use core::fmt; -use abi_serde::{ - des::{DeserializeError, Deserializer}, - ser::Serializer, - Deserialize, Serialize, -}; - pub mod ip_addr; pub mod net_value; pub mod socket_addr; @@ -54,18 +48,4 @@ impl fmt::Display for MacAddress { } } -impl<'de> Deserialize<'de> for MacAddress { - fn deserialize>(deserializer: &mut D) -> Result { - deserializer - .read_bytes()? - .try_into() - .map_err(|_| D::Error::INVALID_ARRAY_LEN) - .map(Self) - } -} - -impl Serialize for MacAddress { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - serializer.write_bytes(&self.0) - } -} +abi_serde::impl_newtype_serde!(MacAddress); diff --git a/lib/abi/src/process/mod.rs b/lib/abi/src/process/mod.rs index 2c4b4fdb..36cd0153 100644 --- a/lib/abi/src/process/mod.rs +++ b/lib/abi/src/process/mod.rs @@ -2,21 +2,17 @@ use core::{ffi::CStr, fmt, marker::PhantomData, time::Duration}; -use crate::{ - io::{FileMode, RawFd}, - util::FixedString, -}; +use crate::io::{FileMode, RawFd}; mod exit; +pub mod options; pub mod thread; pub use crate::generated::{ ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnFlags, SpawnOptions, ThreadId, ThreadSpawnOptions, WaitFlags, }; -use abi_serde::{des::Deserializer, ser::Serializer, Deserialize, Serialize}; pub use exit::ExitCode; -pub use thread::ThreadOption; // TODO this is ugly pub mod auxv { @@ -47,16 +43,6 @@ pub enum ProcessWait { AnyChild, } -/// Represents a process option being set/retrieved -#[allow(clippy::large_enum_variant)] -#[derive(Debug)] -pub enum ProcessOption { - /// Signal entry point address - SignalEntry(usize), - /// Current working directory - Directory(FixedString<4096>), -} - /// Defines an optional argument for controlling process creation #[derive(Debug)] pub enum SpawnOption { @@ -229,14 +215,5 @@ impl Signal { } } -impl<'de> Deserialize<'de> for ProcessGroupId { - fn deserialize>(deserializer: &mut D) -> Result { - deserializer.read_u32().map(Self) - } -} - -impl Serialize for ProcessGroupId { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { - serializer.write_u32(self.0) - } -} +abi_serde::impl_newtype_serde!(ProcessGroupId); +abi_serde::impl_newtype_serde!(ProcessId); diff --git a/lib/abi/src/process/options.rs b/lib/abi/src/process/options.rs new file mode 100644 index 00000000..b336d91a --- /dev/null +++ b/lib/abi/src/process/options.rs @@ -0,0 +1,13 @@ +//! Process option definitions + +option_group!( + #[doc = "Process options"] + pub enum ProcessOptionVariant<'a> { + #[doc = "Process signal entry point address"] + 0x1000: SignalEntry # 8 (usize), + #[doc = "Current working directory"] + 0x1001: Directory(&'a str), + #[doc = "Process name"] + 0x1002: Name(&'a str) + } +); diff --git a/lib/abi/src/process/thread.rs b/lib/abi/src/process/thread.rs index e1428466..658c5723 100644 --- a/lib/abi/src/process/thread.rs +++ b/lib/abi/src/process/thread.rs @@ -1,12 +1,24 @@ -//! Thread data structures +//! Thread option definitions -/// Represents a thread option being set/retrieved -#[derive(Debug)] -pub enum ThreadOption<'a> { - /// Thread-local storage base pointer - ThreadPointer(usize), - /// Thread signal entry stack base and size - SignalStack(usize, usize), - /// Thread display name - Name(&'a str), +/// Thread signal stack +#[derive(Clone, Copy, Debug, Default)] +pub struct ThreadSignalStack { + /// Base address + pub base: usize, + /// Size + pub size: usize, } + +option_group!( + #[doc = "Thread options"] + pub enum ThreadOptionVariant<'a> { + #[doc = "Thread-local storage pointer"] + 0x1000: ThreadPointer # 8(usize), + #[doc = "Signal stack information"] + 0x1001: SignalStack # 16(ThreadSignalStack), + #[doc = "Thread display name"] + 0x1002: Name(&'a str), + } +); + +abi_serde::impl_struct_serde!(ThreadSignalStack: [base, size]); diff --git a/lib/abi/src/system.rs b/lib/abi/src/system.rs index 2af29296..f37443d2 100644 --- a/lib/abi/src/system.rs +++ b/lib/abi/src/system.rs @@ -13,9 +13,14 @@ pub struct SystemMemoryStats { pub page_size: usize, } -/// Describes a piece of system information -#[derive(Clone, Debug)] -pub enum SystemInfo { - /// Memory usage stats - MemoryStats(SystemMemoryStats), -} +option_group!( + #[doc = "System information requests"] + pub enum SystemInfoVariant<'de> { + #[doc = "Memory usage information"] + 0x1000: MemoryUsage # 64 (SystemMemoryStats), + } +); + +abi_serde::impl_struct_serde!( + SystemMemoryStats: [total_usable_pages, allocated_pages, free_pages, page_size] +); diff --git a/lib/runtime/src/io/paths.rs b/lib/runtime/src/io/paths.rs index f9173646..ff693642 100644 --- a/lib/runtime/src/io/paths.rs +++ b/lib/runtime/src/io/paths.rs @@ -1,8 +1,8 @@ -use core::str::FromStr; - -use abi::{error::Error, process::ProcessOption, util::FixedString}; +use abi::error::Error; use alloc::string::String; +use crate::process; + pub fn current_exe T>(_mapper: F) -> Result { todo!() } @@ -12,13 +12,9 @@ pub fn home_directory T>(_mapper: F) -> Result { } pub fn current_directory T>(mapper: F) -> Result { - let mut option = ProcessOption::Directory(FixedString::empty()); - unsafe { crate::sys::get_process_option(&mut option) }?; - let ProcessOption::Directory(path) = &option else { - unreachable!() - }; - - Ok(mapper(path.as_ref())) + let mut buffer = [0; 512]; + let path = process::get_process_option::(&mut buffer)?; + Ok(mapper(path)) } pub fn current_directory_string() -> Result { @@ -26,9 +22,8 @@ pub fn current_directory_string() -> Result { } pub fn set_current_directory(path: &str) -> Result<(), Error> { - let mut option = ProcessOption::Directory(FixedString::from_str(path)?); - unsafe { crate::sys::set_process_option(&mut option) }?; - Ok(()) + let mut buffer = [0; 512]; + process::set_process_option_with::(&mut buffer, &path) } pub fn make_temp_directory(_template: &mut [u8]) -> Result<(), Error> { diff --git a/lib/runtime/src/io/terminal.rs b/lib/runtime/src/io/terminal.rs index 2cb9bed8..88f856a2 100644 --- a/lib/runtime/src/io/terminal.rs +++ b/lib/runtime/src/io/terminal.rs @@ -30,7 +30,7 @@ pub fn get_terminal_size(fd: RawFd) -> Result { } pub fn set_terminal_size(fd: RawFd, size: &TerminalSize) -> Result<(), Error> { let mut buffer = [0; 32]; - device_request::(fd, &mut buffer, &size) + device_request::(fd, &mut buffer, size) } pub fn is_terminal(fd: RawFd) -> bool { diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 3fac5000..49e30199 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -32,10 +32,5 @@ pub mod net; pub mod process; pub mod sync; pub mod sys; +pub mod system; pub mod time; - -pub mod system { - //! System-related data structures - - pub use abi::system::*; -} diff --git a/lib/runtime/src/process/mod.rs b/lib/runtime/src/process/mod.rs index aad947e6..b33e4659 100644 --- a/lib/runtime/src/process/mod.rs +++ b/lib/runtime/src/process/mod.rs @@ -2,12 +2,15 @@ use core::{mem::MaybeUninit, time::Duration}; -use abi::error::Error; pub use abi::process::{ auxv, AuxValue, AuxValueIter, ExecveOptions, ExitCode, MutexOperation, ProcessGroupId, ProcessId, ProcessInfoElement, ProcessWait, ProgramArgumentInner, Signal, SignalEntryData, SpawnFlags, SpawnOption, SpawnOptions, StringArgIter, ThreadId, ThreadSpawnOptions, WaitFlags, }; +use abi::{ + error::Error, + option::{OptionSizeHint, OptionValue}, +}; use crate::sys; @@ -15,6 +18,8 @@ pub mod signal; pub mod thread; pub mod thread_local; +pub use abi::process::options; + /// Makes the current thread wait until *at least* the amount of time specified in `duration` /// passes. /// @@ -39,3 +44,71 @@ pub fn uninterruptible_sleep(mut duration: Duration) { } } } + +/// Helper macro for [get_process_option]. +pub macro get_process_option($variant_ty:ty) {{ + let mut buffer = [0; <$variant_ty as $crate::io::OptionSizeHint>::SIZE_HINT]; + $crate::process::get_process_option::<$variant_ty>(&mut buffer) +}} + +/// Retrieves a process option value. +pub fn get_process_option<'de, T: OptionValue<'de>>( + buffer: &'de mut [u8], +) -> Result { + let len = unsafe { crate::sys::get_process_option(T::VARIANT.into(), buffer) }?; + T::load(&buffer[..len]) +} + +/// Helper macro for [get_thread_option]. +pub macro get_thread_option($variant_ty:ty) {{ + let mut buffer = [0; <$variant_ty as $crate::io::OptionSizeHint>::SIZE_HINT]; + $crate::process::get_thread_option::<$variant_ty>(&mut buffer) +}} + +/// Retrieves a thread option value. +pub fn get_thread_option<'de, T: OptionValue<'de>>( + buffer: &'de mut [u8], +) -> Result { + let len = unsafe { crate::sys::get_thread_option(T::VARIANT.into(), buffer) }?; + T::load(&buffer[..len]) +} + +/// Update a process option value. Requires `T`: [OptionSizeHint]. +pub fn set_process_option<'de, T: OptionValue<'de> + OptionSizeHint>( + value: &T::Value, +) -> Result<(), Error> +where + [u8; T::SIZE_HINT]: Sized, +{ + let mut buffer = [0; T::SIZE_HINT]; + set_process_option_with::(&mut buffer, value) +} + +/// Update a process option value, using provided buffer for serialization. +pub fn set_process_option_with<'de, T: OptionValue<'de>>( + buffer: &mut [u8], + value: &T::Value, +) -> Result<(), Error> { + let len = T::store(value, buffer)?; + unsafe { crate::sys::set_process_option(T::VARIANT.into(), &buffer[..len]) } +} + +/// Update a thread option value. Requires `T`: [OptionSizeHint]. +pub fn set_thread_option<'de, T: OptionValue<'de> + OptionSizeHint>( + value: &T::Value, +) -> Result<(), Error> +where + [u8; T::SIZE_HINT]: Sized, +{ + let mut buffer = [0; T::SIZE_HINT]; + set_thread_option_with::(&mut buffer, value) +} + +/// Update a thread option value, using provided buffer for serialization. +pub fn set_thread_option_with<'de, T: OptionValue<'de>>( + buffer: &mut [u8], + value: &T::Value, +) -> Result<(), Error> { + let len = T::store(value, buffer)?; + unsafe { crate::sys::set_thread_option(T::VARIANT.into(), &buffer[..len]) } +} diff --git a/lib/runtime/src/process/options.rs b/lib/runtime/src/process/options.rs new file mode 100644 index 00000000..e69de29b diff --git a/lib/runtime/src/process/signal.rs b/lib/runtime/src/process/signal.rs index 536f743b..1346b5a7 100644 --- a/lib/runtime/src/process/signal.rs +++ b/lib/runtime/src/process/signal.rs @@ -4,10 +4,13 @@ use core::ffi::c_int; use abi::{ error::Error, mem::{MappingFlags, MappingSource}, - process::{ExitCode, ProcessOption, Signal, SignalEntryData, ThreadOption}, + process::{ExitCode, Signal, SignalEntryData}, }; -use crate::sync::rwlock::RwLock; +use crate::{ + process::{self, thread}, + sync::rwlock::RwLock, +}; /// Describes how a signal should be handled #[derive(Debug, Clone, Copy)] @@ -76,23 +79,18 @@ pub unsafe fn set_handler(signal: Signal, handler: SignalHandler) -> SignalHandl /// below it. It is up to the caller to make sure `sp` points to a proper stack's top. /// /// TLDR: just use [setup_signal_stack]. -pub unsafe fn set_signal_stack(base: usize, size: usize) -> (usize, usize) { - let mut option = ThreadOption::SignalStack(base, size); - crate::sys::set_thread_option(&mut option).expect("set_signal_stack() failed"); - let ThreadOption::SignalStack(base, size) = option else { - unreachable!() - }; - (base, size) +pub unsafe fn set_signal_stack(base: usize, size: usize) { + process::set_thread_option::( + &thread::options::ThreadSignalStack { base, size }, + ) + .expect("set_signal_stack() failed") } /// Returns the currently set signal stack base:size. pub fn get_signal_stack() -> (usize, usize) { - let mut option = ThreadOption::SignalStack(0, 0); - unsafe { crate::sys::get_thread_option(&mut option) }.expect("get_signal_stack() failed"); - let ThreadOption::SignalStack(base, size) = option else { - unreachable!() - }; - (base, size) + let stack = process::get_thread_option!(thread::options::SignalStack) + .expect("get_signal_stack() failed"); + (stack.base, stack.size) } /// Sets the program's signal entry function. @@ -103,15 +101,9 @@ pub fn get_signal_stack() -> (usize, usize) { /// /// 1. It must not return, it must call `exit_thread` instead. /// 2. It must conform to the kernel's signal entry ABI. -pub unsafe fn set_signal_entry(entry: usize) -> usize { - let mut option = ProcessOption::SignalEntry(entry); - crate::sys::set_process_option(&mut option).expect("set_signal_entry() failed"); - #[allow(irrefutable_let_patterns)] - let ProcessOption::SignalEntry(entry) = option - else { - unreachable!() - }; - entry +pub unsafe fn set_signal_entry(entry: usize) { + process::set_process_option::(&entry) + .expect("set_signal_entry() failed"); } fn allocate_signal_stack(mut size: usize) -> Result<(usize, usize), Error> { diff --git a/lib/runtime/src/process/thread.rs b/lib/runtime/src/process/thread.rs index f8f6ded1..c63eaaa0 100644 --- a/lib/runtime/src/process/thread.rs +++ b/lib/runtime/src/process/thread.rs @@ -8,7 +8,7 @@ use core::{ use abi::{ error::Error, mem::{MappingFlags, MappingSource}, - process::{ThreadOption, ThreadSpawnOptions}, + process::ThreadSpawnOptions, }; use alloc::{boxed::Box, sync::Arc}; @@ -16,6 +16,11 @@ use crate::{process::thread_local, sync::rwlock::RwLock}; use super::{signal, thread_local::TlsImage}; +pub mod options { + //! Thread option definitions + pub use abi::process::thread::*; +} + /// Describes a runtime thread. /// /// `R` generic parameter denotes the thread's return type. @@ -135,7 +140,8 @@ impl Thread { /// Sets the current thread name. pub fn set_name(name: &str) { - unsafe { crate::sys::set_thread_option(&mut ThreadOption::Name(name)).ok() }; + let mut buffer = [0; 256]; + crate::process::set_thread_option_with::(&mut buffer, &name).ok(); } /// # Safety diff --git a/lib/runtime/src/process/thread_local/i686.rs b/lib/runtime/src/process/thread_local/i686.rs index dcdc5687..6d1f3b0b 100644 --- a/lib/runtime/src/process/thread_local/i686.rs +++ b/lib/runtime/src/process/thread_local/i686.rs @@ -1,6 +1,8 @@ #![allow(missing_docs)] -use abi::{error::Error, process::ThreadOption}; +use abi::error::Error; + +use crate::process::{self, thread}; pub fn get_thread_pointer() -> usize { let tp: usize; @@ -17,7 +19,7 @@ pub fn get_thread_pointer() -> usize { /// `value` must hold an address to a structure, first element of which is a pointer to itself. /// Usual pointer safety requirements apply. pub unsafe fn set_thread_pointer(value: usize) -> Result<(), Error> { - crate::sys::set_thread_option(&mut ThreadOption::ThreadPointer(value)) + process::set_process_option::(&value) } // ___tls_get_addr, TLS_index structure address gets passed in the %eax register diff --git a/lib/runtime/src/process/thread_local/x86_64.rs b/lib/runtime/src/process/thread_local/x86_64.rs index 1de440bc..efab9015 100644 --- a/lib/runtime/src/process/thread_local/x86_64.rs +++ b/lib/runtime/src/process/thread_local/x86_64.rs @@ -1,6 +1,6 @@ #![allow(missing_docs)] -use abi::{error::Error, process::ThreadOption}; +use abi::{error::Error, process::thread}; pub fn get_thread_pointer() -> usize { let tp: usize; @@ -17,5 +17,5 @@ pub fn get_thread_pointer() -> usize { /// `value` must hold an address to a structure, first element of which is a pointer to itself. /// Usual pointer safety requirements apply. pub unsafe fn set_thread_pointer(value: usize) -> Result<(), Error> { - crate::sys::set_thread_option(&mut ThreadOption::ThreadPointer(value)) + crate::process::set_thread_option::(&value) } diff --git a/lib/runtime/src/system.rs b/lib/runtime/src/system.rs new file mode 100644 index 00000000..13b6edcd --- /dev/null +++ b/lib/runtime/src/system.rs @@ -0,0 +1,16 @@ +//! System-related parameters + +pub use abi::system::*; +use abi::{error::Error, option::OptionValue}; + +/// Helper macro for [get_system_info] +pub macro get_system_info($variant_ty:ty) {{ + let mut buffer = [0; <$variant_ty as $crate::io::OptionSizeHint>::SIZE_HINT]; + $crate::system::get_system_info::<$variant_ty>(&mut buffer) +}} + +/// Retrieves a system information object +pub fn get_system_info<'de, T: OptionValue<'de>>(buffer: &'de mut [u8]) -> Result { + let len = unsafe { crate::sys::get_system_info(T::VARIANT.into(), buffer) }?; + T::load(&buffer[..len]) +} diff --git a/userspace/sysutils/src/sysmon.rs b/userspace/sysutils/src/sysmon.rs index f73d5dc2..b37ab1d5 100644 --- a/userspace/sysutils/src/sysmon.rs +++ b/userspace/sysutils/src/sysmon.rs @@ -2,18 +2,15 @@ use std::{ collections::VecDeque, - fmt::Write, - os::yggdrasil::{get_system_info, SystemInfo, SystemMemoryStats}, + fmt::Write }; use humansize::FormatSize; use libterm::{Clear, Term}; +use yggdrasil_rt::system; -fn get_memory_stats() -> SystemMemoryStats { - let mut info = SystemInfo::MemoryStats(SystemMemoryStats::default()); - get_system_info(&mut info).unwrap(); - let SystemInfo::MemoryStats(stats) = info; - stats +fn get_memory_stats() -> system::SystemMemoryStats { + system::get_system_info!(system::MemoryUsage).unwrap() } fn main() {