Skip to content

Commit

Permalink
kernel: dispatch system calls from scheduler to registry
Browse files Browse the repository at this point in the history
  • Loading branch information
Qix- committed Jan 15, 2025
1 parent 28a1956 commit a631fd7
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 74 deletions.
2 changes: 1 addition & 1 deletion oro-kernel/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use oro_mem::mapper::{AddressSpace, MapError};

/// Implements an architecture for the Oro kernel.
pub trait Arch: Sized + 'static {
pub trait Arch: Sized + Send + Sync + 'static {
/// The architecture-specific thread handle.
type ThreadHandle: ThreadHandle<Self>;
/// The architecture-specific address space layout.
Expand Down
41 changes: 27 additions & 14 deletions oro-kernel/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use core::{
};

use oro_mem::alloc::sync::Arc;
use oro_sync::ReentrantMutex;

use crate::{arch::Arch, thread::Thread};

/// Implements an interface, which is a flat namespace of `(index, flay_keyvals)`.
///
Expand All @@ -21,21 +24,40 @@ use oro_mem::alloc::sync::Arc;
/// them as direct interfaces to kernel data structures and machinery. They can also
/// be implemented by userspace applications, which can then be interacted with by
/// system calls or ports (or perhaps other interfaces).
pub trait Interface: Send + Sync {
pub trait Interface<A: Arch>: Send + Sync {
/// Returns the type ID of the interface. Note that IDs with all high 32 bits
/// cleared are reserved for kernel usage.
fn type_id(&self) -> u64;
/// Handles a system call request to this interface.

/// Handles a [`oro_sysabi::syscall::Opcode::Get`] system call request to this interface.
///
/// System call handling must be quick and non-blocking. Either it can be
/// serviced immediately, or can be processed "offline", returning a handle
/// that can be polled for completion.
fn get(
&self,
thread: &Arc<ReentrantMutex<Thread<A>>>,
index: u64,
key: u64,
) -> InterfaceResponse;

/// Handles a [`oro_sysabi::syscall::Opcode::Set`] system call request to this interface.
///
/// System call handling must be quick and non-blocking. Either it can be
/// serviced immediately, or can be processed "offline", returning a handle
/// that can be polled for completion.
fn handle(&self, request: SystemCallRequest) -> InterfaceResponse;
fn set(
&self,
thread: &Arc<ReentrantMutex<Thread<A>>>,
index: u64,
key: u64,
value: u64,
) -> InterfaceResponse;
}

/// Response from an interface after handling a system call.
///
/// When performing a [`Interface::handle`] operation, the interface can either
/// When performing an [`Interface`] syscall operation, the interface can either
/// respond immediately, or defer the response to a later time. In the latter case,
/// a pollable handle is returned.
pub enum InterfaceResponse {
Expand Down Expand Up @@ -68,7 +90,7 @@ unsafe impl Sync for InFlightSystemCallInner {}
unsafe impl Send for InFlightSystemCallInner {}

/// Indicates the state of the in-flight system call.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum InFlightState {
/// Pending
Expand Down Expand Up @@ -223,12 +245,3 @@ pub struct SystemCallResponse {
/// The return value.
pub ret: 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,
}
4 changes: 2 additions & 2 deletions oro-kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ pub struct KernelState<A: Arch> {

/// The system-wide registry, loaded at boot with all of the "static" kernel
/// interfaces.
registry: Arc<ReentrantMutex<RootRegistry>>,
registry: Arc<ReentrantMutex<RootRegistry<A>>>,
}

impl<A: Arch> KernelState<A> {
Expand Down Expand Up @@ -274,7 +274,7 @@ impl<A: Arch> KernelState<A> {

/// Returns a reference to the root registry.
#[inline]
pub fn registry(&self) -> &Arc<ReentrantMutex<RootRegistry>> {
pub fn registry(&self) -> &Arc<ReentrantMutex<RootRegistry<A>>> {
&self.registry
}
}
Expand Down
59 changes: 43 additions & 16 deletions oro-kernel/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use oro_sysabi::{

use crate::{
arch::Arch,
interface::{Interface, SystemCallAction, SystemCallRequest, SystemCallResponse},
interface::{Interface, InterfaceResponse, SystemCallRequest, SystemCallResponse},
table::Table,
thread::Thread,
};
Expand All @@ -35,12 +35,12 @@ use crate::{
/// The lower level entity types (rings, instances, etc.) hold
/// a view into this registry, caching interfaces as needed
/// so as to reduce pressure on the registry's locks.
pub struct RootRegistry {
pub struct RootRegistry<A: Arch> {
/// A map of all registered interfaces.
interface_map: Table<Arc<dyn Interface>>,
interface_map: Table<Arc<dyn Interface<A>>>,
}

impl RootRegistry {
impl<A: Arch> RootRegistry<A> {
/// Creates a new, fully empty registry.
#[must_use]
pub fn new_empty() -> Self {
Expand All @@ -52,26 +52,53 @@ impl RootRegistry {

/// Implements access to a [`RootRegistry`] or a [`RegistryView`]
/// (or some wrapper thereof).
pub trait Registry: Send {
pub trait Registry<A: Arch>: Send {
/// Inserts an interface into the registry and returns its globally unique ID.
///
/// The interface is guaranteed to be unique in the registry, and is registered
/// globally.
fn register_interface(&mut self, interface: Arc<dyn Interface>) -> u64;
fn register_interface(&mut self, interface: Arc<dyn Interface<A>>) -> u64;

/// Looks up an interface by its globally unique ID. If this is a view,
/// it may cache the interface for future lookups.
fn lookup(&mut self, interface_id: u64) -> Option<Arc<dyn Interface>>;
fn lookup(&mut self, interface_id: u64) -> Option<Arc<dyn Interface<A>>>;

/// Handles a system call request to the registry.
fn dispatch(
&mut self,
thread: &Arc<ReentrantMutex<Thread<A>>>,
request: &SystemCallRequest,
) -> InterfaceResponse {
let error = match request.opcode {
Opcode::Get => {
match self.lookup(request.arg1) {
Some(interface) => return interface.get(thread, request.arg2, request.arg3),
None => Error::BadInterface,
}
}
Opcode::Set => {
match self.lookup(request.arg1) {
Some(interface) => {
return interface.set(thread, request.arg2, request.arg3, request.arg4);
}
None => Error::BadInterface,
}
}
_ => Error::BadOpcode,
};

InterfaceResponse::Immediate(SystemCallResponse { error, ret: 0 })
}
}

impl Registry for RootRegistry {
impl<A: Arch> Registry<A> for RootRegistry<A> {
#[inline]
fn register_interface(&mut self, interface: Arc<dyn Interface>) -> u64 {
fn register_interface(&mut self, interface: Arc<dyn Interface<A>>) -> u64 {
self.interface_map.insert_unique(interface)
}

#[inline]
fn lookup(&mut self, interface_id: u64) -> Option<Arc<dyn Interface>> {
fn lookup(&mut self, interface_id: u64) -> Option<Arc<dyn Interface<A>>> {
self.interface_map.get(interface_id).cloned()
}
}
Expand All @@ -80,15 +107,15 @@ impl Registry for RootRegistry {
///
/// Accesses to the registry through this type are cached,
/// reducing contention on the parent registry's locks.
pub struct RegistryView<P: Registry> {
pub struct RegistryView<A: Arch, P: Registry<A>> {
/// The parent registry from which to fetch interfaces.
parent: Arc<ReentrantMutex<P>>,
/// A cache of interfaces.
// TODO(qix-): Use an LFU?
cache: Table<Weak<dyn Interface>>,
cache: Table<Weak<dyn Interface<A>>>,
}

impl<P: Registry> RegistryView<P> {
impl<A: Arch, P: Registry<A>> RegistryView<A, P> {
/// Creates a new registry view into the given parent registry.
pub fn new(parent: Arc<ReentrantMutex<P>>) -> Self {
Self {
Expand All @@ -98,8 +125,8 @@ impl<P: Registry> RegistryView<P> {
}
}

impl<P: Registry> Registry for RegistryView<P> {
fn register_interface(&mut self, interface: Arc<dyn Interface>) -> u64 {
impl<A: Arch, P: Registry<A>> Registry<A> for RegistryView<A, P> {
fn register_interface(&mut self, interface: Arc<dyn Interface<A>>) -> u64 {
let weak = Arc::downgrade(&interface);
let id = self.parent.lock().register_interface(interface);
// SAFETY: We can assume that the interface has not been inserted before, since
Expand All @@ -110,7 +137,7 @@ impl<P: Registry> Registry for RegistryView<P> {
id
}

fn lookup(&mut self, interface_id: u64) -> Option<Arc<dyn Interface>> {
fn lookup(&mut self, interface_id: u64) -> Option<Arc<dyn Interface<A>>> {
self.cache
.get(interface_id)
.and_then(Weak::upgrade)
Expand Down
6 changes: 3 additions & 3 deletions oro-kernel/src/ring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub struct Ring<A: Arch> {
/// The ring's child rings.
children: Vec<Arc<ReentrantMutex<Ring<A>>>>,
/// The ring's registry.
registry: Arc<ReentrantMutex<RegistryView<RootRegistry>>>,
registry: Arc<ReentrantMutex<RegistryView<A, RootRegistry<A>>>>,
}

impl<A: Arch> Ring<A> {
Expand Down Expand Up @@ -97,7 +97,7 @@ impl<A: Arch> Ring<A> {
/// 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(
registry: Arc<ReentrantMutex<RootRegistry>>,
registry: Arc<ReentrantMutex<RootRegistry<A>>>,
) -> Result<Arc<ReentrantMutex<Self>>, MapError> {
// NOTE(qix-): This method CANNOT call `Kernel::<A>::get()` because
// NOTE(qix-): core-local kernels are not guaranteed to be initialized
Expand Down Expand Up @@ -161,7 +161,7 @@ impl<A: Arch> Ring<A> {

/// Returns the ring's registry handle.
#[must_use]
pub fn registry(&self) -> &Arc<ReentrantMutex<RegistryView<RootRegistry>>> {
pub fn registry(&self) -> &Arc<ReentrantMutex<RegistryView<A, RootRegistry<A>>>> {
&self.registry
}
}
38 changes: 22 additions & 16 deletions oro-kernel/src/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use oro_sync::{Lock, ReentrantMutex};
use crate::{
Kernel,
arch::{Arch, CoreHandle},
interface::{SystemCallAction, SystemCallRequest, SystemCallResponse},
interface::{InterfaceResponse, SystemCallRequest, SystemCallResponse},
registry::Registry,
thread::{ScheduleAction, Thread},
};

Expand Down Expand Up @@ -194,34 +195,39 @@ impl<A: Arch> Scheduler<A> {
/// disabled before calling this function.** At no point
/// can other scheduler methods be invoked while this function
/// is running.
///
/// # Panics
/// Will panic if the kernel ever gets into an invalid state
/// (indicating a bug in the scheduler logic / thread state machine).
#[must_use]
pub unsafe fn event_system_call(&mut self, request: &SystemCallRequest) -> Switch<A> {
let coming_from_user = if let Some(thread) = self.current.take() {
let t = thread.lock();
let mut t = thread.lock();

// TODO(qix-): Put back the registry stuff when it's working.
let response = {
// let instance = t.instance();
// let registry = instance.lock().registry();
// let mut registry_lock = registry.lock();
// drop(registry_lock);
// let r = registry_lock.dispatch_system_call(&thread, request);
// r
let _ = request;
SystemCallAction::RespondImmediate(SystemCallResponse {
error: oro_sysabi::syscall::Error::NotImplemented,
ret: 0,
})
if let Some(instance) = t.instance().lock().ring().upgrade() {
let instance_lock = instance.lock();
let registry = instance_lock.registry();
let mut registry_lock = registry.lock();
registry_lock.dispatch(&thread, request)
} else {
// The instance is gone; we can't do anything.
// This is a critical error.
panic!(
"instance is still running but has no ring; kernel is in an invalid state"
);
}
};

match response {
SystemCallAction::RespondImmediate(response) => {
InterfaceResponse::Immediate(response) => {
drop(t);
self.current = Some(thread.clone());
return Switch::UserResume(thread, Some(response));
}
SystemCallAction::Pause => {
InterfaceResponse::Pending(handle) => {
let id = t.id();
t.await_system_call_response(self.kernel.id(), handle);
drop(t);
Some(id)
}
Expand Down
Loading

0 comments on commit a631fd7

Please sign in to comment.