2021-10-18 15:06:08 +03:00
|
|
|
//! Thread context
|
2021-10-15 01:15:19 +03:00
|
|
|
|
2021-11-05 14:06:38 +02:00
|
|
|
use crate::arch::aarch64::exception::ExceptionFrame;
|
2021-10-18 12:07:28 +03:00
|
|
|
use crate::mem::{
|
|
|
|
self,
|
|
|
|
phys::{self, PageUsage},
|
|
|
|
};
|
2021-10-15 01:15:19 +03:00
|
|
|
use core::mem::size_of;
|
|
|
|
|
|
|
|
struct Stack {
|
|
|
|
bp: usize,
|
|
|
|
sp: usize,
|
|
|
|
}
|
|
|
|
|
2021-10-18 15:06:08 +03:00
|
|
|
/// Structure representing thread context
|
2021-10-15 01:15:19 +03:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct Context {
|
2021-10-18 15:06:08 +03:00
|
|
|
/// Thread's kernel stack pointer
|
|
|
|
pub k_sp: usize, // 0x00
|
2021-10-15 01:15:19 +03:00
|
|
|
|
2021-11-11 13:46:36 +02:00
|
|
|
stack_base: usize,
|
2021-10-15 01:15:19 +03:00
|
|
|
stack_page_count: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Context {
|
2021-10-18 15:06:08 +03:00
|
|
|
/// Constructs a new kernel-space thread context
|
2021-10-20 11:41:47 +03:00
|
|
|
pub fn kernel(entry: usize, arg: usize) -> Self {
|
|
|
|
let mut stack = Stack::new(8);
|
|
|
|
|
|
|
|
stack.push(entry);
|
|
|
|
stack.push(arg);
|
|
|
|
|
2021-11-02 15:36:34 +02:00
|
|
|
stack.setup_common(__aa64_ctx_enter_kernel as usize, 0);
|
2021-10-20 11:41:47 +03:00
|
|
|
|
|
|
|
Self {
|
|
|
|
k_sp: stack.sp,
|
|
|
|
|
2021-11-11 13:46:36 +02:00
|
|
|
stack_base: stack.bp,
|
2021-10-20 11:41:47 +03:00
|
|
|
stack_page_count: 8,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-04 13:29:27 +02:00
|
|
|
/// Clones a process context from given `frame`
|
2021-11-04 11:26:15 +02:00
|
|
|
pub fn fork(frame: &ExceptionFrame, ttbr0: usize) -> Self {
|
|
|
|
let mut stack = Stack::new(8);
|
|
|
|
|
|
|
|
stack.push(frame.x[18]);
|
|
|
|
stack.push(frame.x[17]);
|
|
|
|
stack.push(frame.x[16]);
|
|
|
|
stack.push(frame.x[15]);
|
|
|
|
stack.push(frame.x[14]);
|
|
|
|
stack.push(frame.x[13]);
|
|
|
|
stack.push(frame.x[12]);
|
|
|
|
stack.push(frame.x[11]);
|
|
|
|
stack.push(frame.x[10]);
|
|
|
|
stack.push(frame.x[9]);
|
|
|
|
stack.push(frame.x[8]);
|
|
|
|
stack.push(frame.x[7]);
|
|
|
|
stack.push(frame.x[6]);
|
|
|
|
stack.push(frame.x[5]);
|
|
|
|
stack.push(frame.x[4]);
|
|
|
|
stack.push(frame.x[3]);
|
|
|
|
stack.push(frame.x[2]);
|
|
|
|
stack.push(frame.x[1]);
|
|
|
|
|
|
|
|
stack.push(frame.elr_el1 as usize);
|
|
|
|
stack.push(frame.sp_el0 as usize);
|
|
|
|
|
|
|
|
// Setup common
|
2021-11-20 15:46:38 +02:00
|
|
|
stack.push(0); // tpidr_el0
|
2021-11-04 11:26:15 +02:00
|
|
|
stack.push(ttbr0);
|
|
|
|
stack.push(__aa64_ctx_enter_from_fork as usize); // x30/lr
|
|
|
|
stack.push(frame.x[29]); // x29
|
|
|
|
stack.push(frame.x[28]); // x28
|
|
|
|
stack.push(frame.x[27]); // x27
|
|
|
|
stack.push(frame.x[26]); // x26
|
|
|
|
stack.push(frame.x[25]); // x25
|
|
|
|
stack.push(frame.x[24]); // x24
|
|
|
|
stack.push(frame.x[23]); // x23
|
|
|
|
stack.push(frame.x[22]); // x22
|
|
|
|
stack.push(frame.x[21]); // x21
|
|
|
|
stack.push(frame.x[20]); // x20
|
|
|
|
stack.push(frame.x[19]); // x19
|
|
|
|
|
|
|
|
Self {
|
|
|
|
k_sp: stack.sp,
|
|
|
|
|
2021-11-11 13:46:36 +02:00
|
|
|
stack_base: stack.bp,
|
2021-11-05 14:06:38 +02:00
|
|
|
stack_page_count: 8,
|
2021-11-04 11:26:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-20 11:41:47 +03:00
|
|
|
/// Constructs a new user-space thread context
|
|
|
|
pub fn user(entry: usize, arg: usize, ttbr0: usize, ustack: usize) -> Self {
|
2021-10-15 23:47:53 +03:00
|
|
|
let mut stack = Stack::new(8);
|
|
|
|
|
2021-10-15 01:15:19 +03:00
|
|
|
stack.push(entry);
|
|
|
|
stack.push(arg);
|
2021-11-20 15:46:38 +02:00
|
|
|
stack.push(0);
|
2021-10-15 23:47:53 +03:00
|
|
|
stack.push(ustack);
|
2021-10-15 01:15:19 +03:00
|
|
|
|
2021-11-02 15:36:34 +02:00
|
|
|
stack.setup_common(__aa64_ctx_enter_user as usize, ttbr0);
|
2021-10-15 01:15:19 +03:00
|
|
|
|
|
|
|
Self {
|
|
|
|
k_sp: stack.sp,
|
|
|
|
|
2021-11-11 13:46:36 +02:00
|
|
|
stack_base: stack.bp,
|
2021-10-18 12:07:28 +03:00
|
|
|
stack_page_count: 8,
|
2021-10-15 01:15:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-12 10:26:58 +02:00
|
|
|
/// Constructs an uninitialized thread context
|
|
|
|
pub fn empty() -> Self {
|
|
|
|
let stack = Stack::new(8);
|
2021-11-11 13:46:36 +02:00
|
|
|
Self {
|
|
|
|
k_sp: stack.sp,
|
|
|
|
stack_base: stack.bp,
|
|
|
|
stack_page_count: 8
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-12 10:26:58 +02:00
|
|
|
/// Sets up a context for signal entry
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// Unsafe: may clobber an already active context
|
2021-11-11 13:46:36 +02:00
|
|
|
pub unsafe fn setup_signal_entry(&mut self, entry: usize, arg: usize, ttbr0: usize, ustack: usize) {
|
|
|
|
let mut stack = Stack::from_base_size(self.stack_base, self.stack_page_count);
|
|
|
|
|
|
|
|
stack.push(entry);
|
|
|
|
stack.push(arg);
|
|
|
|
stack.push(0);
|
|
|
|
stack.push(ustack);
|
|
|
|
|
|
|
|
stack.setup_common(__aa64_ctx_enter_user as usize, ttbr0);
|
|
|
|
|
|
|
|
self.k_sp = stack.sp;
|
|
|
|
}
|
|
|
|
|
2021-10-18 15:06:08 +03:00
|
|
|
/// Performs initial thread entry
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// Unsafe: does not check if any context has already been activated
|
|
|
|
/// before, so must only be called once.
|
2021-10-15 23:47:53 +03:00
|
|
|
pub unsafe extern "C" fn enter(&mut self) -> ! {
|
2021-10-15 01:15:19 +03:00
|
|
|
__aa64_ctx_switch_to(self);
|
|
|
|
panic!("This code should not run");
|
|
|
|
}
|
|
|
|
|
2021-10-18 15:06:08 +03:00
|
|
|
/// Performs context switch from `self` to `to`.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// Unsafe: does not check if `self` is actually an active context.
|
2021-10-15 23:47:53 +03:00
|
|
|
pub unsafe extern "C" fn switch(&mut self, to: &mut Context) {
|
2021-10-15 01:15:19 +03:00
|
|
|
__aa64_ctx_switch(to, self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Stack {
|
|
|
|
pub fn new(page_count: usize) -> Stack {
|
|
|
|
let phys = phys::alloc_contiguous_pages(PageUsage::Kernel, page_count).unwrap();
|
|
|
|
let bp = mem::virtualize(phys);
|
|
|
|
Stack {
|
|
|
|
bp,
|
2021-10-18 12:07:28 +03:00
|
|
|
sp: bp + page_count * mem::PAGE_SIZE,
|
2021-10-15 01:15:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-11 13:46:36 +02:00
|
|
|
pub unsafe fn from_base_size(bp: usize, page_count: usize) -> Stack {
|
|
|
|
Stack {
|
|
|
|
bp,
|
|
|
|
sp: bp + page_count * mem::PAGE_SIZE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-02 15:36:34 +02:00
|
|
|
pub fn setup_common(&mut self, entry: usize, ttbr: usize) {
|
2021-11-20 15:46:38 +02:00
|
|
|
self.push(0); // tpidr_el0
|
2021-11-02 15:36:34 +02:00
|
|
|
self.push(ttbr);
|
2021-11-20 15:46:38 +02:00
|
|
|
self.push(entry); // x30/lr
|
|
|
|
self.push(0); // x29
|
|
|
|
self.push(0); // x28
|
|
|
|
self.push(0); // x27
|
|
|
|
self.push(0); // x26
|
|
|
|
self.push(0); // x25
|
|
|
|
self.push(0); // x24
|
|
|
|
self.push(0); // x23
|
|
|
|
self.push(0); // x22
|
|
|
|
self.push(0); // x21
|
|
|
|
self.push(0); // x20
|
|
|
|
self.push(0); // x19
|
2021-10-20 11:41:47 +03:00
|
|
|
}
|
|
|
|
|
2021-10-15 01:15:19 +03:00
|
|
|
pub fn push(&mut self, value: usize) {
|
|
|
|
if self.bp == self.sp {
|
|
|
|
panic!("Stack overflow");
|
|
|
|
}
|
|
|
|
|
|
|
|
self.sp -= size_of::<usize>();
|
|
|
|
unsafe {
|
|
|
|
*(self.sp as *mut usize) = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" {
|
2021-11-04 11:26:15 +02:00
|
|
|
fn __aa64_ctx_enter_from_fork();
|
2021-10-15 01:15:19 +03:00
|
|
|
fn __aa64_ctx_enter_kernel();
|
2021-10-20 11:41:47 +03:00
|
|
|
fn __aa64_ctx_enter_user();
|
2021-10-15 01:15:19 +03:00
|
|
|
fn __aa64_ctx_switch(dst: *mut Context, src: *mut Context);
|
|
|
|
fn __aa64_ctx_switch_to(dst: *mut Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
global_asm!(include_str!("context.S"));
|