From 54f2d683b8ca85bd95e10a6b645aabe78248cdba Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Tue, 16 Dec 2025 19:53:39 +0000 Subject: [PATCH] libkernel: move `ClaimedPage` into libkernel crate By moving `ClaimedPage` into libkernel we can utilise it in arch-agonstic ode. --- libkernel/src/memory/address.rs | 2 +- libkernel/src/memory/page.rs | 109 ++++++++++++++++++++++++++++- libkernel/src/memory/page_alloc.rs | 6 +- libkernel/src/memory/pg_offset.rs | 3 + src/memory/page.rs | 100 +++----------------------- 5 files changed, 125 insertions(+), 95 deletions(-) diff --git a/libkernel/src/memory/address.rs b/libkernel/src/memory/address.rs index 4ad5396..828ecf1 100644 --- a/libkernel/src/memory/address.rs +++ b/libkernel/src/memory/address.rs @@ -297,7 +297,7 @@ impl PA { } /// Trait for translating between physical and virtual addresses. -pub trait AddressTranslator { +pub trait AddressTranslator: 'static + Send + Sync { fn virt_to_phys(va: TVA) -> TPA; fn phys_to_virt(pa: TPA) -> TVA; } diff --git a/libkernel/src/memory/page.rs b/libkernel/src/memory/page.rs index 26d462e..9e2298f 100644 --- a/libkernel/src/memory/page.rs +++ b/libkernel/src/memory/page.rs @@ -1,6 +1,18 @@ +use super::{ + PAGE_SHIFT, address::AddressTranslator, page_alloc::PageAllocGetter, region::PhysMemoryRegion, +}; +use crate::{ + CpuOps, + error::Result, + memory::{ + PAGE_SIZE, + address::{PA, VA}, + page_alloc::PageAllocation, + }, +}; +use alloc::slice; use core::fmt::Display; - -use super::{PAGE_SHIFT, PAGE_SIZE, address::PA, region::PhysMemoryRegion}; +use core::marker::PhantomData; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct PageFrame { @@ -36,3 +48,96 @@ impl PageFrame { } } } + +/// A conveniance wrapper for dealing with single-page allocaitons. +pub struct ClaimedPage, T: AddressTranslator<()>>( + PageAllocation<'static, A>, + PhantomData, + PhantomData, +); + +impl, T: AddressTranslator<()>> Display for ClaimedPage { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.0.region().start_address().to_pfn()) + } +} + +impl, T: AddressTranslator<()>> ClaimedPage { + /// Allocates a single physical page. The contents of the page are + /// undefined. + fn alloc() -> Result { + let frame = G::global_page_alloc().get().unwrap().alloc_frames(0)?; + Ok(Self(frame, PhantomData, PhantomData)) + } + + /// Allocates a single physical page and zeroes its contents. + pub fn alloc_zeroed() -> Result { + let mut page = Self::alloc()?; + page.as_slice_mut().fill(0); + Ok(page) + } + + /// Takes ownership of the page at pfn. + /// + /// SAFETY: Ensure that the calling context does indeed own this page. + /// Otherwise, the page may be free'd when it's owned by another context. + pub unsafe fn from_pfn(pfn: PageFrame) -> Self { + Self( + unsafe { + G::global_page_alloc() + .get() + .unwrap() + .alloc_from_region(pfn.as_phys_range()) + }, + PhantomData, + PhantomData, + ) + } + + #[inline(always)] + pub fn pa(&self) -> PA { + self.0.region().start_address() + } + + /// Returns the kernel virtual address where this page is mapped. + #[inline(always)] + pub fn va(&self) -> VA { + self.pa().to_va::() + } + + /// Returns a raw pointer to the page's content. + #[inline(always)] + pub fn as_ptr(&self) -> *const u8 { + self.va().as_ptr() as *const _ + } + + /// Returns a mutable raw pointer to the page's content. + #[inline(always)] + pub fn as_ptr_mut(&self) -> *mut u8 { + self.va().as_ptr_mut() as *mut _ + } + + /// Returns a slice representing the page's content. + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + // This is safe because: + // 1. We have a reference `&self`, guaranteeing safe access. + // 2. The pointer is valid and aligned. + // 3. The lifetime of the slice is tied to `&self` by the compiler. + unsafe { slice::from_raw_parts(self.as_ptr(), PAGE_SIZE) } + } + + /// Returns a mutable slice representing the page's content. + #[inline(always)] + pub fn as_slice_mut(&mut self) -> &mut [u8] { + // This is safe because: + // 1. We have a mutable reference `&mut self`, guaranteeing exclusive access. + // 2. The pointer is valid and aligned. + // 3. The lifetime of the slice is tied to `&mut self` by the compiler. + unsafe { slice::from_raw_parts_mut(self.as_ptr_mut(), PAGE_SIZE) } + } + + pub fn leak(self) -> PageFrame { + self.0.leak().start_address().to_pfn() + } +} diff --git a/libkernel/src/memory/page_alloc.rs b/libkernel/src/memory/page_alloc.rs index 4767e63..0f8a067 100644 --- a/libkernel/src/memory/page_alloc.rs +++ b/libkernel/src/memory/page_alloc.rs @@ -2,7 +2,7 @@ use crate::{ CpuOps, error::{KernelError, Result}, memory::{PAGE_SHIFT, address::AddressTranslator, page::PageFrame, smalloc::Smalloc}, - sync::spinlock::SpinLockIrq, + sync::{once_lock::OnceLock, spinlock::SpinLockIrq}, }; use core::{ cmp::min, @@ -422,6 +422,10 @@ impl FrameAllocator { } } +pub trait PageAllocGetter: Send + Sync + 'static { + fn global_page_alloc() -> &'static OnceLock, C>; +} + #[cfg(test)] mod tests { use super::*; diff --git a/libkernel/src/memory/pg_offset.rs b/libkernel/src/memory/pg_offset.rs index 362e28c..486f8c0 100644 --- a/libkernel/src/memory/pg_offset.rs +++ b/libkernel/src/memory/pg_offset.rs @@ -6,6 +6,9 @@ pub struct PageOffsetTranslator { _phantom: PhantomData, } +unsafe impl Send for PageOffsetTranslator {} +unsafe impl Sync for PageOffsetTranslator {} + impl AddressTranslator for PageOffsetTranslator { fn virt_to_phys(va: TVA) -> TPA { let mut v = va.value(); diff --git a/src/memory/page.rs b/src/memory/page.rs index a797589..1455c1b 100644 --- a/src/memory/page.rs +++ b/src/memory/page.rs @@ -1,98 +1,16 @@ use super::{PAGE_ALLOC, PageOffsetTranslator}; use crate::arch::ArchImpl; -use alloc::slice; -use core::fmt::Display; -use libkernel::{ - error::Result, - memory::{ - PAGE_SIZE, - address::{PA, VA}, - page::PageFrame, - page_alloc::PageAllocation, - }, -}; +use libkernel::memory::page_alloc::PageAllocGetter; -/// An conveniance wrapper for dealing with single-page allocaitons. -pub struct ClaimedPage(PageAllocation<'static, ArchImpl>); +pub struct PgAllocGetter {} -impl Display for ClaimedPage { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.0.region().start_address().to_pfn()) +impl PageAllocGetter for PgAllocGetter { + fn global_page_alloc() -> &'static libkernel::sync::once_lock::OnceLock< + libkernel::memory::page_alloc::FrameAllocator, + ArchImpl, + > { + &PAGE_ALLOC } } -impl ClaimedPage { - /// Allocates a single physical page. The contents of the page are - /// undefined. - fn alloc() -> Result { - let frame = PAGE_ALLOC.get().unwrap().alloc_frames(0)?; - Ok(Self(frame)) - } - - /// Allocates a single physical page and zeroes its contents. - pub fn alloc_zeroed() -> Result { - let mut page = Self::alloc()?; - page.as_slice_mut().fill(0); - Ok(page) - } - - /// Takes ownership of the page at pfn. - /// - /// SAFETY: Ensure that the calling context does indeed own this page. - /// Otherwise, the page may be free'd when it's owned by another context. - pub unsafe fn from_pfn(pfn: PageFrame) -> Self { - Self(unsafe { - PAGE_ALLOC - .get() - .unwrap() - .alloc_from_region(pfn.as_phys_range()) - }) - } - - #[inline(always)] - pub fn pa(&self) -> PA { - self.0.region().start_address() - } - - /// Returns the kernel virtual address where this page is mapped. - #[inline(always)] - pub fn va(&self) -> VA { - self.pa().to_va::() - } - - /// Returns a raw pointer to the page's content. - #[inline(always)] - pub fn as_ptr(&self) -> *const u8 { - self.va().as_ptr() as *const _ - } - - /// Returns a mutable raw pointer to the page's content. - #[inline(always)] - pub fn as_ptr_mut(&self) -> *mut u8 { - self.va().as_ptr_mut() as *mut _ - } - - /// Returns a slice representing the page's content. - #[inline(always)] - pub fn as_slice(&self) -> &[u8] { - // This is safe because: - // 1. We have a reference `&self`, guaranteeing safe access. - // 2. The pointer is valid and aligned. - // 3. The lifetime of the slice is tied to `&self` by the compiler. - unsafe { slice::from_raw_parts(self.as_ptr(), PAGE_SIZE) } - } - - /// Returns a mutable slice representing the page's content. - #[inline(always)] - pub fn as_slice_mut(&mut self) -> &mut [u8] { - // This is safe because: - // 1. We have a mutable reference `&mut self`, guaranteeing exclusive access. - // 2. The pointer is valid and aligned. - // 3. The lifetime of the slice is tied to `&mut self` by the compiler. - unsafe { slice::from_raw_parts_mut(self.as_ptr_mut(), PAGE_SIZE) } - } - - pub fn leak(self) -> PageFrame { - self.0.leak().start_address().to_pfn() - } -} +pub type ClaimedPage = libkernel::memory::page::ClaimedPage;