108 lines
2.6 KiB
Rust
Raw Normal View History

2021-10-18 15:06:08 +03:00
//! Thread context
2021-10-15 01:15:19 +03:00
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
/// Thread's translation table physical address with ASID
2021-10-18 12:07:28 +03:00
pub ttbr0: usize, // 0x08
2021-10-15 01:15:19 +03:00
stack_base_phys: usize,
stack_page_count: usize,
}
impl Context {
2021-10-18 15:06:08 +03:00
/// Constructs a new kernel-space thread context
2021-10-15 23:47:53 +03:00
pub fn kernel(entry: usize, arg: usize, ttbr0: usize, ustack: usize) -> Self {
let mut stack = Stack::new(8);
2021-10-15 01:15:19 +03:00
stack.push(entry);
stack.push(arg);
2021-10-15 23:47:53 +03:00
stack.push(ttbr0);
stack.push(ustack);
2021-10-15 01:15:19 +03:00
stack.push(__aa64_ctx_enter_kernel as usize); // x30/lr
2021-10-18 12:07:28 +03:00
stack.push(0); // x29
stack.push(0); // x28
stack.push(0); // x27
stack.push(0); // x26
stack.push(0); // x25
stack.push(0); // x24
stack.push(0); // x23
stack.push(0); // x22
stack.push(0); // x21
stack.push(0); // x20
stack.push(0); // x19
2021-10-15 01:15:19 +03:00
Self {
k_sp: stack.sp,
2021-10-15 23:47:53 +03:00
ttbr0,
2021-10-15 01:15:19 +03:00
stack_base_phys: stack.bp,
2021-10-18 12:07:28 +03:00
stack_page_count: 8,
2021-10-15 01:15:19 +03:00
}
}
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
}
}
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" {
fn __aa64_ctx_enter_kernel();
fn __aa64_ctx_switch(dst: *mut Context, src: *mut Context);
fn __aa64_ctx_switch_to(dst: *mut Context);
}
global_asm!(include_str!("context.S"));