From 12b5ee104b5825043213a6a467fc06583026b9d0 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 12 Sep 2024 00:43:08 +0200 Subject: [PATCH] kernel: initial thread, module, instance data structures --- oro-kernel/src/instance.rs | 67 +++++++++++++++++++++++++++++++ oro-kernel/src/lib.rs | 2 + oro-kernel/src/module.rs | 80 ++++++++++++++------------------------ oro-kernel/src/port.rs | 2 +- oro-kernel/src/registry.rs | 9 +++-- oro-kernel/src/ring.rs | 2 +- oro-kernel/src/thread.rs | 52 +++++++++++++++++++++++++ 7 files changed, 159 insertions(+), 55 deletions(-) create mode 100644 oro-kernel/src/instance.rs create mode 100644 oro-kernel/src/thread.rs diff --git a/oro-kernel/src/instance.rs b/oro-kernel/src/instance.rs new file mode 100644 index 0000000..7b05d13 --- /dev/null +++ b/oro-kernel/src/instance.rs @@ -0,0 +1,67 @@ +//! Module instance types and functionality. + +use crate::{module::Module, registry::Handle, ring::Ring}; + +/// A singular module instance. +/// +/// Modules are effectively executables in the Oro ecosystem, +/// loading similarly to processes in a traditional operating system. +/// By themselves, modules do not do anything - it is when they are +/// mounted onto a ring as an instance (hence "module instance") +/// that they are effectively spawned and executed. +/// +/// The kernel does not keep modules in memory; only module instances. +/// +/// Further, not every module instance comes from a discrete module; +/// on the root ring, the kernel mounts several built-in modules +/// as instances to interact with system resources at a very low level. +/// These are often referred to as "built-in modules" or "kernel modules". +/// Unlike e.g. Linux, kernel modules are not extensible nor can they be +/// added via user configuration; they are hard-coded into the kernel, +/// and are often architecture-specific. +/// +/// Typically the bootloader will have some means by which to load modules +/// as instances onto the root ring, since without any additional application- +/// specific modules, the kernel is effectively useless (will do nothing on +/// boot). The preboot routine (that jumps to the kernel, see `oro_boot::boot_to_kernel()`) +/// provides a means for memory-mapped portable executables (PEs) to be loaded +/// onto the root ring as instances. +/// +/// Those instances will have the highest privilege level, and will be able +/// to interact with the kernel directly via the built-in modules, and +/// from there can spawn additional rings and instances as needed to +/// bootstrap the rest of the system as they see fit. +pub struct Instance { + /// The module instance ID. + id: usize, + /// The module from which this instance was spawned. + module: Handle, + /// The ring on which this instance resides. + ring: Handle, +} + +impl Instance { + /// Returns the instance ID. + /// + /// # Safety + /// **DO NOT USE THIS ID FOR ANYTHING SECURITY RELATED.** + /// + /// IDs are recycled when instances are dropped from the registry, + /// meaning functions that accept numeric IDs might return or work + /// with [`Handle`]s that refer to unintended instances that have + /// been inserted into the same slot. + #[must_use] + pub unsafe fn id(&self) -> usize { + self.id + } + + /// The [`Handle`] to the module from which this instance was spawned. + pub fn module(&self) -> Handle { + self.module.clone() + } + + /// The [`Handle`] to the ring on which this instance resides. + pub fn ring(&self) -> Handle { + self.ring.clone() + } +} diff --git a/oro-kernel/src/lib.rs b/oro-kernel/src/lib.rs index 1687dbe..38a802f 100644 --- a/oro-kernel/src/lib.rs +++ b/oro-kernel/src/lib.rs @@ -17,10 +17,12 @@ use oro_mem::{ use oro_sync::spinlock::unfair_critical::{InterruptController, UnfairCriticalSpinlock}; pub mod id; +pub mod instance; pub mod module; pub mod port; pub mod registry; pub mod ring; +pub mod thread; /// Core-local instance of the Oro kernel. /// diff --git a/oro-kernel/src/module.rs b/oro-kernel/src/module.rs index 80cf633..54274ae 100644 --- a/oro-kernel/src/module.rs +++ b/oro-kernel/src/module.rs @@ -1,59 +1,39 @@ //! Implements Oro module instances in the kernel. -#![expect(clippy::module_name_repetitions)] use crate::id::{Id, IdType}; -/// A singular module instance. -/// -/// Modules are effectively executables in the Oro ecosystem, -/// loading similarly to processes in a traditional operating system. -/// By themselves, modules do not do anything - it is when they are -/// mounted onto a ring as an instance (hence "module instance") -/// that they are effectively spawned and executed. -/// -/// The kernel does not keep modules in memory; only module instances. -/// -/// Further, not every module instance comes from a discrete module; -/// on the root ring, the kernel mounts several built-in modules -/// as instances to interact with system resources at a very low level. -/// These are often referred to as "built-in modules" or "kernel modules". -/// Unlike e.g. Linux, kernel modules are not extensible nor can they be -/// added via user configuration; they are hard-coded into the kernel, -/// and are often architecture-specific. -/// -/// Typically the bootloader will have some means by which to load modules -/// as instances onto the root ring, since without any additional application- -/// specific modules, the kernel is effectively useless (will do nothing on -/// boot). The preboot routine (that jumps to the kernel, see `oro_boot::boot_to_kernel()`) -/// provides a means for memory-mapped portable executables (PEs) to be loaded -/// onto the root ring as instances. -/// -/// Those instances will have the highest privilege level, and will be able -/// to interact with the kernel directly via the built-in modules, and -/// from there can spawn additional rings and instances as needed to -/// bootstrap the rest of the system as they see fit. -/// -/// # Module IDs -/// Module IDs internally are just the offset of the module instance -/// in the arena pool, divided by the size of the arena slot. Put simply, -/// if you think of the arena pool as an array of module instances, -/// the module ID is the index of the module instance in that array. -/// -/// Module instances, rings, and ports all have their own ID spaces. -/// This means that a module instance, ring, and port can all have the -/// same ID, and they will not conflict with each other. -/// -/// In no case should a module's ID be used to indicate its functionality, -/// version, or other metadata. It is purely an internal identifier, and -/// should be treated as random. It is only valid for the lifetime of the -/// module instance, and should not be stored or used outside of that context. -/// They should be treated like process IDs in a traditional operating system. -pub struct ModuleInstance { +/// Module metadata. +pub struct Module { /// The instance ID. This is unique for each module instance, /// but can be re-used if instances are destroyed. /// /// It is the offset of the arena slot into the arena pool. - pub id: u32, - /// The module ID from which this instance was spawned. - pub module_id: Id<{ IdType::Module }>, + /// + /// **DO NOT USE THIS ID FOR ANYTHING SECURITY RELATED.** + pub(crate) id: usize, + /// The module ID. Provided by the ring spawner and used + /// to refer to the module during module loading. + pub(crate) module_id: Id<{ IdType::Module }>, +} + +impl Module { + /// Returns the instance ID. + /// + /// # Safety + /// **DO NOT USE THIS ID FOR ANYTHING SECURITY RELATED.** + /// + /// IDs are re-used by registries when items are dropped, so + /// functions that take numeric IDs to return [`crate::registry::Handle`]s + /// may return a new item unexpectedly if the old one was dropped + /// and the slot was re-used. + #[must_use] + pub unsafe fn id(&self) -> usize { + self.id + } + + /// Returns the module ID. + #[must_use] + pub fn module_id(&self) -> &Id<{ IdType::Module }> { + &self.module_id + } } diff --git a/oro-kernel/src/port.rs b/oro-kernel/src/port.rs index d4eb599..2c40274 100644 --- a/oro-kernel/src/port.rs +++ b/oro-kernel/src/port.rs @@ -5,7 +5,7 @@ use crate::id::{Id, IdType}; /// A singular port. /// /// Ports are unidirectional communication channels between -/// [`crate::module::ModuleInstance`]s. They are implemented +/// [`crate::instance::Instance`]s. They are implemented /// as ring buffers of slotted messages of fixed size, the size /// being determined by metadata associated with the port's type. /// diff --git a/oro-kernel/src/registry.rs b/oro-kernel/src/registry.rs index ecb655d..9c7dc7d 100644 --- a/oro-kernel/src/registry.rs +++ b/oro-kernel/src/registry.rs @@ -150,7 +150,7 @@ where segment.provision_as_shared(&mapper, pfa, &pat)?; Ok(Self { - base: segment.range().0 as *mut _, + base: segment.range(&mapper).0 as *mut _, bookkeeping: UnfairCriticalSpinlock::new(RegistryBookkeeping::new()), pat, segment, @@ -185,7 +185,10 @@ where let byte_offset = bk.total_count * size_of::>>(); let byte_offset_end = byte_offset + size_of::>>(); - if unlikely!((self.segment.range().0 + byte_offset_end - 1) > self.segment.range().1) { + if unlikely!( + (self.segment.range(&self.mapper).0 + byte_offset_end - 1) + > self.segment.range(&self.mapper).1 + ) { return Err(MapError::VirtOutOfRange); } @@ -201,7 +204,7 @@ where let page = pfa.allocate().ok_or(MapError::OutOfMemory)?; // TODO(qix-): If PFAs ever support more than 4K pages, this will need to be updated. - let virt = self.segment.range().0 + page_id * 4096; + let virt = self.segment.range(&self.mapper).0 + page_id * 4096; if let Err(err) = self.segment .map(&self.mapper, &mut *pfa, &self.pat, virt, page) diff --git a/oro-kernel/src/ring.rs b/oro-kernel/src/ring.rs index b5babdd..78366cd 100644 --- a/oro-kernel/src/ring.rs +++ b/oro-kernel/src/ring.rs @@ -4,7 +4,7 @@ use crate::registry::Handle; /// A singular ring. /// -/// Rings are collections of [`crate::module::ModuleInstance`]s. +/// Rings are collections of [`crate::instance::Instance`]s. /// They also form the primary security boundary in the Oro ecosystem. /// /// Module instances are mounted onto rings, allowing the instances to diff --git a/oro-kernel/src/thread.rs b/oro-kernel/src/thread.rs new file mode 100644 index 0000000..a75f625 --- /dev/null +++ b/oro-kernel/src/thread.rs @@ -0,0 +1,52 @@ +//! Thread management types and functions. + +use crate::{instance::Instance, registry::Handle}; +use oro_mem::mapper::AddressSpace; + +/// A singular system thread. +/// +/// Threads are the primary unit of 'execution' in the +/// Oro kernel. They are scheduled by the kernel, +/// owned by a single core's [`crate::Kernel`] instance's +/// scheduler at any given time. +/// +/// Threads belong to module [`Instance`]s and, unlike +/// other OSes, are not nested (i.e. a thread does not +/// have a parent thread). +pub struct Thread { + /// The thread's ID. + pub(crate) id: usize, + /// The module instance to which this thread belongs. + pub(crate) instance: Handle, + /// The thread's address space handle. + pub(crate) space: AddrSpace::UserHandle, +} + +impl Thread { + /// Returns the thread's ID. + /// + /// # Safety + /// **DO NOT USE THIS FUNCTION FOR ANYTHING SECURITY RELATED.** + /// + /// IDs are re-used by registries when items are dropped, so + /// multiple calls to an ID lookup function may return handles to + /// different thread items as the IDs get recycled. + /// + /// Only use this function for debugging or logging purposes, or + /// for handing IDs to the user. + #[must_use] + pub unsafe fn id(&self) -> usize { + self.id + } + + /// Returns module instance [`Handle`] to which this thread belongs. + pub fn instance(&self) -> Handle { + self.instance.clone() + } + + /// Returns the thread's address space handle. + #[must_use] + pub fn space(&self) -> &AddrSpace::UserHandle { + &self.space + } +}