use crate::{
mm::{kspace::KERNEL_PAGE_TABLE, FrameAllocOptions, Paddr, PageFlags, Segment, PAGE_SIZE},
prelude::*,
};
pub static STACK_SIZE_IN_PAGES: u32 = parse_u32_or_default(
option_env!("OSTD_TASK_STACK_SIZE_IN_PAGES"),
DEFAULT_STACK_SIZE_IN_PAGES,
);
pub const DEFAULT_STACK_SIZE_IN_PAGES: u32 = 128;
#[derive(Debug)]
pub struct KernelStack {
segment: Segment,
has_guard_page: bool,
}
impl KernelStack {
pub fn new() -> Result<Self> {
Ok(Self {
segment: FrameAllocOptions::new(STACK_SIZE_IN_PAGES as usize).alloc_contiguous()?,
has_guard_page: false,
})
}
pub fn new_with_guard_page() -> Result<Self> {
let stack_segment =
FrameAllocOptions::new(STACK_SIZE_IN_PAGES as usize + 1).alloc_contiguous()?;
let page_table = KERNEL_PAGE_TABLE.get().unwrap();
let guard_page_vaddr = {
let guard_page_paddr = stack_segment.start_paddr();
crate::mm::paddr_to_vaddr(guard_page_paddr)
};
unsafe {
let vaddr_range = guard_page_vaddr..guard_page_vaddr + PAGE_SIZE;
page_table
.protect_flush_tlb(&vaddr_range, |p| p.flags -= PageFlags::RW)
.unwrap();
}
Ok(Self {
segment: stack_segment,
has_guard_page: true,
})
}
pub fn end_paddr(&self) -> Paddr {
self.segment.end_paddr()
}
}
impl Drop for KernelStack {
fn drop(&mut self) {
if self.has_guard_page {
let page_table = KERNEL_PAGE_TABLE.get().unwrap();
let guard_page_vaddr = {
let guard_page_paddr = self.segment.start_paddr();
crate::mm::paddr_to_vaddr(guard_page_paddr)
};
unsafe {
let vaddr_range = guard_page_vaddr..guard_page_vaddr + PAGE_SIZE;
page_table
.protect_flush_tlb(&vaddr_range, |p| p.flags |= PageFlags::RW)
.unwrap();
}
}
}
}
const fn parse_u32_or_default(size: Option<&str>, default: u32) -> u32 {
match size {
Some(value) => parse_u32(value),
None => default,
}
}
const fn parse_u32(input: &str) -> u32 {
let mut output: u32 = 0;
let bytes = input.as_bytes();
let mut i = 0;
while i < bytes.len() {
let digit = (bytes[i] - b'0') as u32;
output = output * 10 + digit;
i += 1;
}
output
}