Skip to content

Commit

Permalink
kernel: initial thread, module, instance data structures
Browse files Browse the repository at this point in the history
  • Loading branch information
Qix- committed Sep 11, 2024
1 parent 6261606 commit 12b5ee1
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 55 deletions.
67 changes: 67 additions & 0 deletions oro-kernel/src/instance.rs
Original file line number Diff line number Diff line change
@@ -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<Module>,
/// The ring on which this instance resides.
ring: Handle<Ring>,
}

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<Module> {
self.module.clone()
}

/// The [`Handle`] to the ring on which this instance resides.
pub fn ring(&self) -> Handle<Ring> {
self.ring.clone()
}
}
2 changes: 2 additions & 0 deletions oro-kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
80 changes: 30 additions & 50 deletions oro-kernel/src/module.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
2 changes: 1 addition & 1 deletion oro-kernel/src/port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
9 changes: 6 additions & 3 deletions oro-kernel/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -185,7 +185,10 @@ where
let byte_offset = bk.total_count * size_of::<MaybeUninit<ItemFrame<T>>>();
let byte_offset_end = byte_offset + size_of::<MaybeUninit<ItemFrame<T>>>();

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);
}

Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion oro-kernel/src/ring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 52 additions & 0 deletions oro-kernel/src/thread.rs
Original file line number Diff line number Diff line change
@@ -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<AddrSpace: AddressSpace> {
/// The thread's ID.
pub(crate) id: usize,
/// The module instance to which this thread belongs.
pub(crate) instance: Handle<Instance>,
/// The thread's address space handle.
pub(crate) space: AddrSpace::UserHandle,
}

impl<AddrSpace: AddressSpace> Thread<AddrSpace> {
/// 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<Instance> {
self.instance.clone()
}

/// Returns the thread's address space handle.
#[must_use]
pub fn space(&self) -> &AddrSpace::UserHandle {
&self.space
}
}

0 comments on commit 12b5ee1

Please sign in to comment.