diff --git a/Cargo.lock b/Cargo.lock index 412485c1..43e0a7bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -350,6 +350,7 @@ dependencies = [ "oro-mem", "oro-sync", "oro-sysabi", + "stash", ] [[package]] @@ -495,6 +496,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "stash" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e90803f7d6354f81ce56045759c8631d3fa49ddb9c08c3d948e5a3afb4d03af1" +dependencies = [ + "unreachable", +] + [[package]] name = "syn" version = "2.0.76" @@ -529,12 +539,27 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + [[package]] name = "vcell" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "volatile-register" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 8b999de4..e93375b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,7 @@ limine = "0.2.0" uart_16550 = "0.3.0" volatile-register = "0.2.2" buddy_system_allocator = "0.11.0" +stash = { version = "0.1.6", default-features = false } bindgen = { git = "https://github.com/oro-os/dep.rust-bindgen.git" } syn = { version = "2.0.60", features = ["full", "printing"] } diff --git a/oro-arch-x86_64/src/syscall.rs b/oro-arch-x86_64/src/syscall.rs index be373ef2..400f32fb 100644 --- a/oro-arch-x86_64/src/syscall.rs +++ b/oro-arch-x86_64/src/syscall.rs @@ -2,7 +2,7 @@ use core::arch::{asm, naked_asm}; -use oro_kernel::{scheduler::Switch, thread::SystemCallRequest}; +use oro_kernel::scheduler::{Switch, SystemCallRequest}; use oro_mem::mapper::AddressSegment; use oro_sync::Lock; use oro_sysabi::syscall::Opcode; @@ -132,7 +132,7 @@ unsafe extern "C" fn syscall_enter_noncompat_rust() -> ! { current_thread.lock().handle_mut().irq_stack_ptr = stack_ptr; - let switch = scheduler.event_system_call(syscall_request); + let switch = scheduler.event_system_call(&syscall_request); drop(scheduler); diff --git a/oro-kernel/Cargo.toml b/oro-kernel/Cargo.toml index d5c437b2..d6a66382 100644 --- a/oro-kernel/Cargo.toml +++ b/oro-kernel/Cargo.toml @@ -19,5 +19,7 @@ oro-debug.workspace = true oro-sync.workspace = true oro-sysabi.workspace = true +stash = { workspace = true, default-features = false } + [lints] workspace = true diff --git a/oro-kernel/src/instance.rs b/oro-kernel/src/instance.rs index 824f006d..f7725947 100644 --- a/oro-kernel/src/instance.rs +++ b/oro-kernel/src/instance.rs @@ -7,13 +7,14 @@ use oro_mem::{ }, mapper::{AddressSegment, AddressSpace as _, MapError}, }; -use oro_sync::{Lock, Mutex}; +use oro_sync::{Lock, ReentrantMutex}; use crate::{ AddressSpace, Kernel, UserHandle, arch::{Arch, InstanceHandle}, module::Module, port::Port, + registry::Registry, ring::Ring, thread::Thread, }; @@ -56,15 +57,17 @@ pub struct Instance { /// Strong reference to prevent the module from being /// deallocated while the instance is still alive, which would /// otherwise reclaim the executable memory pages and wreak havoc. - module: Arc>>, + module: Arc>>, /// The ring on which this instance resides. - ring: Weak>>, + ring: Weak>>, /// The thread list for the instance. - pub(super) threads: Vec>>>, + pub(super) threads: Vec>>>, /// The port list for the instance. - ports: Vec>>, + ports: Vec>>, /// The instance's architecture handle. handle: A::InstanceHandle, + /// The root object registry for the instance. + registry: Arc>, } impl Instance { @@ -72,9 +75,9 @@ impl Instance { /// /// Notably, this does **not** spawn any threads. pub fn new( - module: &Arc>>, - ring: &Arc>>, - ) -> Result>, MapError> { + module: &Arc>>, + ring: &Arc>>, + ) -> Result>, MapError> { let id = Kernel::::get().state().allocate_id(); let mapper = AddressSpace::::new_user_space(Kernel::::get().mapper()) @@ -90,13 +93,14 @@ impl Instance { AddressSpace::::user_rodata() .apply_user_space_shallow(handle.mapper(), module.lock().mapper())?; - let r = Arc::new(Mutex::new(Self { + let r = Arc::new(ReentrantMutex::new(Self { id, module: module.clone(), ring: Arc::downgrade(ring), threads: Vec::new(), ports: Vec::new(), handle, + registry: Arc::default(), })); ring.lock().instances.push(r.clone()); @@ -117,22 +121,22 @@ impl Instance { } /// The handle to the module from which this instance was spawned. - pub fn module(&self) -> Arc>> { + pub fn module(&self) -> Arc>> { self.module.clone() } /// The weak handle to the ring on which this instance resides. - pub fn ring(&self) -> Weak>> { + pub fn ring(&self) -> Weak>> { self.ring.clone() } /// Gets a handle to the list of threads for this instance. - pub fn threads(&self) -> &[Arc>>] { + pub fn threads(&self) -> &[Arc>>] { &self.threads } /// Gets a handle to the list of ports for this instance. - pub fn ports(&self) -> &[Arc>] { + pub fn ports(&self) -> &[Arc>] { &self.ports } @@ -141,4 +145,10 @@ impl Instance { pub fn mapper(&self) -> &UserHandle { self.handle.mapper() } + + /// Returns a handle to the instance's object registry. + #[must_use] + pub fn registry(&self) -> Arc> { + self.registry.clone() + } } diff --git a/oro-kernel/src/lib.rs b/oro-kernel/src/lib.rs index 12e5307d..ed6629c2 100644 --- a/oro-kernel/src/lib.rs +++ b/oro-kernel/src/lib.rs @@ -19,6 +19,7 @@ pub mod arch; pub mod instance; pub mod module; pub mod port; +pub mod registry; pub mod ring; pub mod scheduler; pub mod sync; @@ -43,7 +44,7 @@ use oro_mem::{ mapper::{AddressSegment, MapError, AddressSpace as _}, pfa::Alloc, }; -use oro_sync::{Lock, Mutex, TicketMutex}; +use oro_sync::{Lock, ReentrantMutex, TicketMutex}; use self::{arch::Arch, scheduler::Scheduler}; @@ -200,16 +201,16 @@ impl Kernel { /// core boot/powerdown/bringup cycles. pub struct KernelState { /// List of all modules. - modules: TicketMutex>>>>, + modules: TicketMutex>>>>, /// List of all rings. - rings: TicketMutex>>>>, + rings: TicketMutex>>>>, /// List of all instances. - instances: TicketMutex>>>>, + instances: TicketMutex>>>>, /// List of all threads. - threads: TicketMutex>>>>, + threads: TicketMutex>>>>, /// The root ring. - root_ring: Arc>>, + root_ring: Arc>>, /// The ID counter for resource allocation. id_counter: AtomicU64, @@ -252,14 +253,14 @@ impl KernelState { } /// Returns a handle to the root ring. - pub fn root_ring(&'static self) -> Arc>> { + pub fn root_ring(&'static self) -> Arc>> { self.root_ring.clone() } /// Returns a reference to the mutex-guarded list of threads. pub fn threads( &'static self, - ) -> &'static impl Lock>>>> { + ) -> &'static impl Lock>>>> { &self.threads } diff --git a/oro-kernel/src/module.rs b/oro-kernel/src/module.rs index dba04540..8bf836a5 100644 --- a/oro-kernel/src/module.rs +++ b/oro-kernel/src/module.rs @@ -9,7 +9,7 @@ use oro_mem::{ }, mapper::{AddressSpace as _, MapError}, }; -use oro_sync::{Lock, Mutex}; +use oro_sync::{Lock, ReentrantMutex}; use crate::{AddressSpace, Kernel, UserHandle, arch::Arch, instance::Instance}; @@ -29,7 +29,7 @@ pub struct Module { /// to refer to the module during module loading. module_id: Id<{ IdType::Module }>, /// The list of instances spawned from this module. - pub(super) instances: Vec>>>, + pub(super) instances: Vec>>>, /// The module's address space mapper handle. /// /// Only uninitialized if the module is in the process of being freed. @@ -43,12 +43,12 @@ pub struct Module { impl Module { /// Creates a new module. - pub fn new(module_id: Id<{ IdType::Module }>) -> Result>, MapError> { + pub fn new(module_id: Id<{ IdType::Module }>) -> Result>, MapError> { let id = Kernel::::get().state().allocate_id(); let mapper = AddressSpace::::new_user_space_empty().ok_or(MapError::OutOfMemory)?; - let r = Arc::new(Mutex::new(Self { + let r = Arc::new(ReentrantMutex::new(Self { id, module_id, instances: Vec::new(), @@ -78,7 +78,7 @@ impl Module { } /// Returns a list of weak handles to instances spawned from this module. - pub fn instances(&self) -> &[Weak>>] { + pub fn instances(&self) -> &[Weak>>] { &self.instances } diff --git a/oro-kernel/src/registry.rs b/oro-kernel/src/registry.rs new file mode 100644 index 00000000..6888456d --- /dev/null +++ b/oro-kernel/src/registry.rs @@ -0,0 +1,196 @@ +//! Oro kernel object registry implementation. +#![expect(clippy::inline_always)] + +use oro_mem::alloc::sync::Arc; +use oro_sync::{Lock, ReentrantMutex}; +use oro_sysabi::{ + key, + syscall::{Error, Opcode, Result}, +}; +use stash::Stash; + +use crate::{ + arch::Arch, + scheduler::{SystemCallAction, SystemCallRequest, SystemCallResponse}, + thread::Thread, +}; + +/// The root registry object for the Oro kernel. +/// +/// This structure manages the open object handles and is typically +/// scoped to a module instance. +#[derive(Default)] +pub struct Registry { + /// The list of open object handles. + // TODO(qix-): This stash is a stop-gap solution for now. The conversion to/from `usize` is a hack + // TODO(qix-): and will be remedied in the future - namely, to prevent re-use of handles. + handles: Stash>, Tag>, +} + +impl Registry { + /// Looks up a key in the root of the registry (which is a "logical" object, not backed by a handle). + fn get_root_key( + thread: &Arc>>, + key: u64, + ) -> Result>> { + match key { + key!("thread") => Ok(RootThreadObject::from_thread(thread.clone())), + _ => Err(Error::BadKey), + } + } + + /// Attempts to service an [`Opcode::Open`] system call. + fn try_open( + &mut self, + thread: &Arc>>, + handle: u64, + key: u64, + ) -> Result { + let object = if handle == 0 { + Self::get_root_key(thread, key)? + } else { + self.handles + // SAFETY: We have already checked if handle == 0. + .get(unsafe { handle.unchecked_sub(1) }.into()) + .ok_or(Error::BadHandle)? + .lock() + .try_get_object(key)? + }; + + let handle: u64 = self.handles.put(object).into(); + + // SAFETY(qix-): We add one here to ensure that the handle is not 0. + // SAFETY(qix-): Technically, if you exhaust the entirety of a 64-bit handle space, you will + // SAFETY(qix-): cause UB. I'm choosing not to worry about this. If you exhaust the handle space, + // SAFETY(qix-): you have bigger problems. + Ok(unsafe { handle.unchecked_add(1) }) + } + + /// Handles a system call request dispatched, typically, by the scheduler. + /// + /// This function operates in the context of a thread, taking a _reference_ + /// to an `Arc`-wrapped thread handle in case a clone is _not_ needed (e.g. + /// in cases where early-stage validation fails). + pub fn dispatch_system_call( + &mut self, + thread: &Arc>>, + request: &SystemCallRequest, + ) -> SystemCallAction { + match request.opcode { + Opcode::Open => { + match self.try_open(thread, request.arg1, request.arg2) { + Ok(handle) => { + SystemCallAction::RespondImmediate(SystemCallResponse { + error: Error::Ok, + ret1: handle, + ret2: 0, + }) + } + Err(error) => { + SystemCallAction::RespondImmediate(SystemCallResponse { + error, + ret1: 0, + ret2: 0, + }) + } + } + } + _ => { + SystemCallAction::RespondImmediate(SystemCallResponse { + error: Error::BadOpcode, + ret1: 0, + ret2: 0, + }) + } + } + } +} + +/// Represents an object in the object registry. +trait Object { + /// Attempts to retrieve an object from the registry given its + /// parent and a key. + fn try_get_object(&self, key: u64) -> Result>>; +} + +/// Represents the root `thread` object in the object registry. Contextualized around a given thread. +struct RootThreadObject { + /// The context thread handle. + self_thread: Arc>>, +} + +impl RootThreadObject { + /// Creates a new `RootThreadObject` contextualized around the given thread handle. + fn from_thread(self_thread: Arc>>) -> Arc> { + Arc::new(ReentrantMutex::new(Self { self_thread })) + } +} + +impl Object for RootThreadObject { + fn try_get_object(&self, key: u64) -> Result>> { + match key { + key!("self") => Ok(ThreadObject::from_thread(self.self_thread.clone())), + _ => Err(Error::BadKey), + } + } +} + +/// Wraps a [`Thread`] for interaction via the object registry. +struct ThreadObject { + /// The target thread handle. + #[expect(dead_code)] + thread: Arc>>, +} + +impl ThreadObject { + /// Creates a new `ThreadObject` from a thread handle. + fn from_thread(thread: Arc>>) -> Arc> { + Arc::new(ReentrantMutex::new(Self { thread })) + } +} + +impl Object for ThreadObject { + fn try_get_object(&self, key: u64) -> Result>> { + #[expect(clippy::match_single_binding)] + match key { + _ => Err(Error::BadKey), + } + } +} + +/// Inner type for the handle map keys. +/// +/// Stop-gap solution for now; conversion to/from `usize` is a hack and will be remedied in the future. +#[derive(Clone, Copy)] +#[repr(transparent)] +struct Tag(u64); + +impl From for Tag { + #[inline(always)] + fn from(val: usize) -> Self { + ::oro_macro::assert::size_eq::(); + Self(val as u64) + } +} + +impl From for usize { + #[inline(always)] + fn from(val: Tag) -> Self { + ::oro_macro::assert::size_eq::(); + val.0 as usize + } +} + +impl From for Tag { + #[inline(always)] + fn from(val: u64) -> Self { + Self(val) + } +} + +impl From for u64 { + #[inline(always)] + fn from(val: Tag) -> Self { + val.0 + } +} diff --git a/oro-kernel/src/ring.rs b/oro-kernel/src/ring.rs index 540d3992..f9d3af97 100644 --- a/oro-kernel/src/ring.rs +++ b/oro-kernel/src/ring.rs @@ -7,7 +7,7 @@ use oro_mem::{ }, mapper::{AddressSegment, AddressSpace as _, MapError}, }; -use oro_sync::{Lock, Mutex}; +use oro_sync::{Lock, ReentrantMutex}; use crate::{AddressSpace, Kernel, UserHandle, arch::Arch, instance::Instance}; @@ -36,18 +36,20 @@ pub struct Ring { /// The resource ID. id: u64, /// The parent ring handle, or `None` if this is the root ring. - parent: Option>>>, + parent: Option>>>, /// The module [`Instance`]s on the ring. - pub(super) instances: Vec>>>, + pub(super) instances: Vec>>>, /// The ring's base mapper handle. pub(super) mapper: UserHandle, /// The ring's child rings. - pub(super) children: Vec>>>, + pub(super) children: Vec>>>, } impl Ring { /// Creates a new ring. - pub fn new(parent: &Arc>>) -> Result>, MapError> { + pub fn new( + parent: &Arc>>, + ) -> Result>, MapError> { let id = Kernel::::get().state().allocate_id(); let mapper = AddressSpace::::new_user_space(&Kernel::::get().mapper) @@ -55,7 +57,7 @@ impl Ring { AddressSpace::::sysabi().provision_as_shared(&mapper)?; - let r = Arc::new(Mutex::new(Self { + let r = Arc::new(ReentrantMutex::new(Self { id, parent: Some(Arc::downgrade(parent)), instances: Vec::new(), @@ -84,7 +86,7 @@ impl Ring { /// /// Caller **must** push the ring onto the kernel state's `rings` list itself; /// this method **will not** do it for you. - pub(crate) unsafe fn new_root() -> Result>, MapError> { + pub(crate) unsafe fn new_root() -> Result>, MapError> { // NOTE(qix-): This method CANNOT call `Kernel::::get()` because // NOTE(qix-): core-local kernels are not guaranteed to be initialized // NOTE(qix-): at this point in the kernel's lifetime. @@ -101,7 +103,7 @@ impl Ring { AddressSpace::::sysabi().provision_as_shared(&mapper)?; - let r = Arc::new(Mutex::new(Self { + let r = Arc::new(ReentrantMutex::new(Self { id: 0, parent: None, instances: Vec::new(), @@ -122,13 +124,13 @@ impl Ring { /// /// If the ring is the root ring, this function will return `None`. #[must_use] - pub fn parent(&self) -> Option>>> { + pub fn parent(&self) -> Option>>> { self.parent.clone() } /// Returns a slice of instances on the ring. #[must_use] - pub fn instances(&self) -> &[Arc>>] { + pub fn instances(&self) -> &[Arc>>] { &self.instances } } diff --git a/oro-kernel/src/scheduler.rs b/oro-kernel/src/scheduler.rs index e9068bc2..fca1e5d8 100644 --- a/oro-kernel/src/scheduler.rs +++ b/oro-kernel/src/scheduler.rs @@ -1,12 +1,12 @@ //! Houses types, traits and functionality for the Oro kernel scheduler. use oro_mem::alloc::sync::Arc; -use oro_sync::{Lock, Mutex}; +use oro_sync::{Lock, ReentrantMutex}; use crate::{ Kernel, arch::{Arch, CoreHandle}, - thread::{ScheduleAction, SystemCallAction, SystemCallRequest, SystemCallResponse, Thread}, + thread::{ScheduleAction, Thread}, }; /// Main scheduler state machine. @@ -22,7 +22,7 @@ pub struct Scheduler { /// A reference to the kernel instance. kernel: &'static Kernel, /// The current thread, if there is one being executed. - current: Option>>>, + current: Option>>>, /// The index of the next thread to execute. next_index: usize, } @@ -44,7 +44,7 @@ impl Scheduler { /// Returns a handle to the currently processing thread. #[must_use] - pub fn current_thread(&self) -> Option>>> { + pub fn current_thread(&self) -> Option>>> { self.current.clone() } @@ -65,7 +65,9 @@ impl Scheduler { /// # Safety /// Interrupts MUST be disabled before calling this function. #[must_use] - unsafe fn pick_user_thread(&mut self) -> Option<(Arc>>, ScheduleAction)> { + unsafe fn pick_user_thread( + &mut self, + ) -> Option<(Arc>>, ScheduleAction)> { if let Some(thread) = self.current.take() { thread .lock() @@ -192,16 +194,21 @@ impl Scheduler { /// can other scheduler methods be invoked while this function /// is running. #[must_use] - pub unsafe fn event_system_call(&mut self, request: SystemCallRequest) -> Switch { + pub unsafe fn event_system_call(&mut self, request: &SystemCallRequest) -> Switch { let coming_from_user = if let Some(thread) = self.current.take() { - let mut t = thread.lock(); + let t = thread.lock(); - let Ok(action) = t.try_system_call(self.kernel.id(), request) else { - unreachable!() + let response = { + let instance = t.instance(); + let registry = instance.lock().registry(); + let mut registry_lock = registry.lock(); + let r = registry_lock.dispatch_system_call(&thread, request); + drop(registry_lock); + r }; - match action { - SystemCallAction::Resume(response) => { + match response { + SystemCallAction::RespondImmediate(response) => { drop(t); self.current = Some(thread.clone()); return Switch::UserResume(thread, Some(response)); @@ -236,7 +243,7 @@ pub enum Switch { /// /// If the system call handle is not `None`, the thread had invoked /// a system call and is awaiting a response. - KernelToUser(Arc>>, Option), + KernelToUser(Arc>>, Option), /// Coming from kernel execution, return back to the kernel. KernelResume, /// Coming from a user thread, return to the same user thread. @@ -249,12 +256,12 @@ pub enum Switch { /// /// If the system call handle is not `None`, the thread had invoked /// a system call and is awaiting a response. - UserResume(Arc>>, Option), + UserResume(Arc>>, Option), /// Coming from a user thread, return to the given (different) user thread. /// /// If the system call handle is not `None`, the thread had invoked /// a system call and is awaiting a response. - UserToUser(Arc>>, Option), + UserToUser(Arc>>, Option), } impl Switch { @@ -262,7 +269,7 @@ impl Switch { /// into a switch type. #[must_use] fn from_schedule_action( - action: Option<(Arc>>, ScheduleAction)>, + action: Option<(Arc>>, ScheduleAction)>, coming_from_user: Option, ) -> Self { match (action, coming_from_user) { @@ -289,3 +296,38 @@ impl Switch { } } } + +/// System call request data. +#[derive(Debug, Clone)] +pub struct SystemCallRequest { + /// The opcode. + pub opcode: oro_sysabi::syscall::Opcode, + /// The first argument. + pub arg1: u64, + /// The second argument. + pub arg2: u64, + /// The third argument. + pub arg3: u64, + /// The fourth argument. + pub arg4: u64, +} + +/// System call response data. +#[derive(Debug, Clone)] +pub struct SystemCallResponse { + /// The error code. + pub error: oro_sysabi::syscall::Error, + /// The first return value. + pub ret1: u64, + /// The second return value. + pub ret2: u64, +} + +/// Response action from the registry after dispatching a system call. +#[derive(Debug)] +pub enum SystemCallAction { + /// The system call has been processed and the thread should be resumed. + RespondImmediate(SystemCallResponse), + /// The system call has been processed or is in-flight and the thread should be paused. + Pause, +} diff --git a/oro-kernel/src/thread.rs b/oro-kernel/src/thread.rs index 926da612..2f3e08ea 100644 --- a/oro-kernel/src/thread.rs +++ b/oro-kernel/src/thread.rs @@ -6,12 +6,13 @@ use oro_mem::{ mapper::{AddressSegment, AddressSpace as _, MapError, UnmapError}, pfa::Alloc, }; -use oro_sync::{Lock, Mutex}; +use oro_sync::{Lock, ReentrantMutex}; use crate::{ AddressSpace, Kernel, UserHandle, arch::{Arch, ThreadHandle}, instance::Instance, + scheduler::{SystemCallRequest, SystemCallResponse}, }; /// A thread's state. @@ -53,7 +54,7 @@ pub struct Thread { /// The resource ID. id: u64, /// The module instance to which this thread belongs. - instance: Arc>>, + instance: Arc>>, /// Architecture-specific thread state. handle: A::ThreadHandle, /// The thread's state. @@ -64,9 +65,9 @@ impl Thread { /// Creates a new thread in the given module instance. #[expect(clippy::missing_panics_doc)] pub fn new( - instance: &Arc>>, + instance: &Arc>>, entry_point: usize, - ) -> Result>>, MapError> { + ) -> Result>>, MapError> { let id = Kernel::::get().state().allocate_id(); // Pre-calculate the stack pointer. @@ -152,7 +153,7 @@ impl Thread { AddressSpace::::free_user_space_handle(thread_mapper); - let r = Arc::new(Mutex::new(Self { + let r = Arc::new(ReentrantMutex::new(Self { id, instance: instance.clone(), handle, @@ -177,7 +178,7 @@ impl Thread { } /// Returns module instance handle to which this thread belongs. - pub fn instance(&self) -> Arc>> { + pub fn instance(&self) -> Arc>> { self.instance.clone() } @@ -257,93 +258,6 @@ impl Thread { | State::RespondingSystemCall(_) => Err(PauseError::NotRunning), } } - - /// Signals that the thread has invoked a system call and is now - /// awaiting a response. - #[expect(clippy::needless_pass_by_value)] - pub fn try_system_call( - &mut self, - core_id: u32, - request: SystemCallRequest, - ) -> Result { - match &self.state { - State::Terminated => Err(PauseError::Terminated), - State::Running(core) => { - if *core != core_id { - return Err(PauseError::WrongCore(*core)); - } - - // TODO(qix-): Use registry instead of hardcoding the request. - // TODO(qix-): This is just to make sure syscalls are working. - use oro_sysabi::{ - key, - syscall::{Error as SysErr, Opcode}, - }; - - let mut ret1 = 0; - let mut ret2 = 0; - - let error = match ( - request.opcode, - request.arg1, - request.arg2, - request.arg3, - request.arg4, - ) { - (Opcode::Open, 0, key!("thread"), _, _) => { - ret1 = 1; - SysErr::Ok - } - (Opcode::Open, 1, key!("self"), _, _) => { - ret1 = 2; - SysErr::Ok - } - (Opcode::Close, 1 | 2, _, _, _) => { - // TODO(qix-): Technically we should check the handle here, but for now we just assume - // TODO(qix-): that it's been opened. This is incorrect but easier to test. - SysErr::Ok - } - (Opcode::Get, 2, key!("kill"), _, _) => { - // TODO(qix-): Technically we should check the actual state, but there's no way - // TODO(qix-): a killed thread can be running to even make this syscall. - ret1 = 0; - ret2 = 0; - SysErr::Ok - } - (Opcode::Set, 2, key!("kill"), v, _) => { - if v != 0 { - self.state = State::Terminated; - return Ok(SystemCallAction::Pause); - } - - SysErr::Ok - } - (Opcode::Get | Opcode::Set | Opcode::Open, 1 | 2, _, _, _) => SysErr::BadKey, - (Opcode::Get | Opcode::Set | Opcode::Open | Opcode::Close, _, _, _, _) => { - SysErr::BadHandle - } - (_, _, _, _, _) => SysErr::BadOpcode, - }; - - let response = SystemCallResponse { error, ret1, ret2 }; - - Ok(SystemCallAction::Resume(response)) - } - State::Paused(_) - | State::Stopped - | State::PausedSystemCall(_) - | State::Unallocated - | State::RespondingSystemCall(_) => Err(PauseError::NotRunning), - } - } -} - -/// The action to take after a system call has been processed. -pub enum SystemCallAction { - /// Resume the thread with the given system call handle. - Resume(SystemCallResponse), - /// Pause the thread and await a response. - Pause, } /// Error type for thread scheduling. @@ -401,29 +315,3 @@ impl Drop for Thread { } } } - -/// System call request data. -#[derive(Debug, Clone)] -pub struct SystemCallRequest { - /// The opcode. - pub opcode: oro_sysabi::syscall::Opcode, - /// The first argument. - pub arg1: u64, - /// The second argument. - pub arg2: u64, - /// The third argument. - pub arg3: u64, - /// The fourth argument. - pub arg4: u64, -} - -/// System call response data. -#[derive(Debug, Clone)] -pub struct SystemCallResponse { - /// The error code. - pub error: oro_sysabi::syscall::Error, - /// The first return value. - pub ret1: u64, - /// The second return value. - pub ret2: u64, -}