diff --git a/src/context/arch/x86_64.rs b/src/context/arch/x86_64.rs index 6462c39c22..64cf84cd00 100644 --- a/src/context/arch/x86_64.rs +++ b/src/context/arch/x86_64.rs @@ -148,7 +148,7 @@ pub unsafe fn switch_to(prev: &mut super::Context, next: &mut super::Context) { let pcr = crate::gdt::pcr(); if let Some(ref stack) = next.kstack { - crate::gdt::set_tss_stack(pcr, stack.as_ptr() as usize + stack.len()); + crate::gdt::set_tss_stack(pcr, stack.initial_top() as usize); } crate::gdt::set_userspace_io_allowed(pcr, next.arch.userspace_io_allowed); diff --git a/src/context/context.rs b/src/context/context.rs index 8be7efaf94..d167f68094 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -1,10 +1,10 @@ use alloc::{borrow::Cow, sync::Arc, vec::Vec}; use syscall::{SIGKILL, SIGSTOP}; -use core::{cmp::Ordering, mem, num::NonZeroUsize}; +use core::{cmp::Ordering, mem::{self, size_of}, num::NonZeroUsize}; use spin::RwLock; use crate::{ - arch::{interrupt::InterruptStack, paging::PAGE_SIZE}, common::aligned_box::AlignedBox, context::{self, arch, file::FileDescriptor, memory::AddrSpace}, cpu_set::{LogicalCpuId, LogicalCpuSet}, ipi::{ipi, IpiKind, IpiTarget}, memory::{Frame, RaiiFrame}, paging::{RmmA, RmmArch}, percpu::PercpuBlock, scheme::{CallerCtx, FileHandle, SchemeNamespace}, sync::WaitMap, + arch::{interrupt::InterruptStack, paging::PAGE_SIZE}, common::aligned_box::AlignedBox, context::{self, arch, file::FileDescriptor, memory::AddrSpace}, cpu_set::{LogicalCpuId, LogicalCpuSet}, ipi::{ipi, IpiKind, IpiTarget}, memory::{allocate_p2frame, deallocate_p2frame, Enomem, Frame, RaiiFrame}, paging::{RmmA, RmmArch}, percpu::PercpuBlock, scheme::{CallerCtx, FileHandle, SchemeNamespace}, sync::WaitMap, }; use crate::syscall::{ @@ -180,7 +180,7 @@ pub struct Context { /// Kernel FX - used to store SIMD and FPU registers on context switch pub kfx: AlignedBox<[u8], { arch::KFX_ALIGN }>, /// Kernel stack, if located on the heap. - pub kstack: Option>, + pub kstack: Option, /// Address space containing a page table lock, and grants. Normally this will have a value, /// but can be None while the context is being reaped or when a new context is created but has /// not yet had its address space changed. Note that these are only for user mappings; kernel @@ -460,8 +460,7 @@ impl Context { let Some(ref kstack) = self.kstack else { return None; }; - let range = kstack.len().checked_sub(mem::size_of::())?..; - Some(unsafe { &*kstack.get(range)?.as_ptr().cast() }) + Some(unsafe { &*kstack.initial_top().sub(size_of::()).cast() }) } pub fn regs_mut(&mut self) -> Option<&mut InterruptStack> { if !self.can_access_regs() { @@ -470,8 +469,7 @@ impl Context { let Some(ref mut kstack) = self.kstack else { return None; }; - let range = kstack.len().checked_sub(mem::size_of::())?..; - Some(unsafe { &mut *kstack.get_mut(range)?.as_mut_ptr().cast() }) + Some(unsafe { &mut *kstack.initial_top().sub(size_of::()).cast() }) } } @@ -581,3 +579,45 @@ impl Drop for BorrowedHtBuf { } } } + +pub struct Kstack { + /// naturally aligned, order 4 + base: Frame, +} +impl Kstack { + pub fn new() -> Result { + Ok(Self { + base: allocate_p2frame(4).ok_or(Enomem)?, + }) + } + pub fn initial_top(&self) -> *mut u8 { + unsafe { + (RmmA::phys_to_virt(self.base.start_address()).data() as *mut u8).add(PAGE_SIZE << 4) + } + } + pub fn len(&self) -> usize { + PAGE_SIZE << 4 + } +} + +const _: () = { + if PAGE_SIZE << 4 != arch::KSTACK_SIZE { + panic!(); + } + if arch::KSTACK_ALIGN > (PAGE_SIZE << 4) { + panic!(); + } +}; + +impl Drop for Kstack { + fn drop(&mut self) { + unsafe { + deallocate_p2frame(self.base, 4) + } + } +} +impl core::fmt::Debug for Kstack { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "[kstack at {:?}]", self.base) + } +} diff --git a/src/context/list.rs b/src/context/list.rs index e0e6cb3375..0061fdd629 100644 --- a/src/context/list.rs +++ b/src/context/list.rs @@ -3,10 +3,8 @@ use core::iter; use spinning_top::RwSpinlock; -use super::arch::KSTACK_SIZE; -use super::context::{Context, ContextId}; +use super::context::{Context, ContextId, Kstack}; use super::memory::AddrSpaceWrapper; -use crate::common::aligned_box::AlignedBox; use crate::interrupt::InterruptStack; use crate::syscall::error::{Error, Result, EAGAIN}; @@ -108,14 +106,14 @@ impl ContextList { /// Spawn a context from a function. pub fn spawn(&mut self, userspace_allowed: bool, func: extern "C" fn()) -> Result<&Arc>> { - let mut stack = AlignedBox::<[u8; crate::context::arch::KSTACK_SIZE], {crate::context::arch::KSTACK_ALIGN}>::try_zeroed()?; + let mut stack = Kstack::new()?; let context_lock = self.new_context()?; { let mut context = context_lock.write(); let _ = context.set_addr_space(Some(AddrSpaceWrapper::new()?)); - let mut stack_top = unsafe { stack.as_mut_ptr().add(KSTACK_SIZE) }; + let mut stack_top = stack.initial_top(); const INT_REGS_SIZE: usize = core::mem::size_of::();