yggdrasil/src/task/context.rs

101 lines
3.2 KiB
Rust

//! Platform-specific task context manipulation interfaces
use abi::{arch::SavedFrame, error::Error};
use alloc::boxed::Box;
use cfg_if::cfg_if;
use kernel_util::thread::Termination;
use crate::task::thread::Thread;
// use crate::task::process::Process;
cfg_if! {
if #[cfg(target_arch = "aarch64")] {
pub use crate::arch::aarch64::{context::TaskContext, cpu::Cpu};
} else if #[cfg(target_arch = "x86_64")] {
pub use crate::arch::x86_64::{context::TaskContext, cpu::Cpu};
}
}
/// Interface for task state save/restore mechanisms
pub trait TaskFrame {
/// Creates a "snapshot" of a exception/syscall frame
fn store(&self) -> SavedFrame;
/// Restores the exception/syscall frame from its saved state
fn restore(&mut self, saved: &SavedFrame);
/// Replaces the return value in the frame (or does nothing, if the frame is not a part of a
/// syscall signal handler)
fn set_return_value(&mut self, value: u64);
/// Replaces the userspace stack pointer in the frame
fn set_user_sp(&mut self, value: usize);
/// Replaces the userspace instruction pointer in the frame
fn set_user_ip(&mut self, value: usize);
/// Replaces the argument in the frame
fn set_argument(&mut self, value: u64);
/// Returns the argument (if any) of the frame being processed
fn argument(&self) -> u64;
/// Returns the userspace stack pointer
fn user_sp(&self) -> usize;
/// Returns the userspace instruction pointer
fn user_ip(&self) -> usize;
}
/// Platform-specific task context implementation
pub trait TaskContextImpl: Sized {
/// Number of bytes to offset the signal stack pointer by
const SIGNAL_STACK_EXTRA_ALIGN: usize;
/// Number of bytes to offset the user stack pointer by
const USER_STACK_EXTRA_ALIGN: usize;
/// Constructs a kernel-space task context
fn kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result<Self, Error>;
/// Constructs a user thread context. The caller is responsible for allocating the userspace
/// stack and setting up a valid address space for the context.
fn user(
entry: usize,
arg: usize,
cr3: u64,
user_stack_sp: usize,
tls_address: usize,
) -> Result<Self, Error>;
/// Performs an entry into a context.
///
/// # Safety
///
/// Only meant to be called from the scheduler code.
unsafe fn enter(&self) -> !;
/// Performs a context switch between two contexts.
///
/// # Safety
///
/// Only meant to be called from the scheduler code.
unsafe fn switch(&self, from: &Self);
/// Constructs a safe wrapper process to execute a kernel-space closure
fn kernel_closure<T: Termination, F: FnOnce() -> T + Send + 'static>(
f: F,
) -> Result<Self, Error> {
extern "C" fn closure_wrapper<T: Termination, F: FnOnce() -> T + Send + 'static>(
closure_addr: usize,
) -> ! {
let closure = unsafe { Box::from_raw(closure_addr as *mut F) };
let result = closure();
Thread::current().exit(result.into_exit_code())
}
let closure = Box::new(f);
debugln!("closure: {:p}", closure);
Self::kernel(closure_wrapper::<T, F>, Box::into_raw(closure) as usize)
}
}