101 lines
3.2 KiB
Rust
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)
|
|
}
|
|
}
|