mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2025-12-23 22:47:55 -05:00
libkernel: move ClaimedPage into libkernel crate
By moving `ClaimedPage` into libkernel we can utilise it in arch-agonstic ode.
This commit is contained in:
committed by
Ashwin Naren
parent
c1bea5ecbb
commit
54f2d683b8
@@ -297,7 +297,7 @@ impl PA {
|
||||
}
|
||||
|
||||
/// Trait for translating between physical and virtual addresses.
|
||||
pub trait AddressTranslator<T> {
|
||||
pub trait AddressTranslator<T>: 'static + Send + Sync {
|
||||
fn virt_to_phys(va: TVA<T>) -> TPA<T>;
|
||||
fn phys_to_virt(pa: TPA<T>) -> TVA<T>;
|
||||
}
|
||||
|
||||
@@ -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<A: CpuOps, G: PageAllocGetter<A>, T: AddressTranslator<()>>(
|
||||
PageAllocation<'static, A>,
|
||||
PhantomData<G>,
|
||||
PhantomData<T>,
|
||||
);
|
||||
|
||||
impl<A: CpuOps, G: PageAllocGetter<A>, T: AddressTranslator<()>> Display for ClaimedPage<A, G, T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{}", self.0.region().start_address().to_pfn())
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: CpuOps, G: PageAllocGetter<A>, T: AddressTranslator<()>> ClaimedPage<A, G, T> {
|
||||
/// Allocates a single physical page. The contents of the page are
|
||||
/// undefined.
|
||||
fn alloc() -> Result<Self> {
|
||||
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<Self> {
|
||||
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::<T>()
|
||||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<CPU: CpuOps> FrameAllocator<CPU> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PageAllocGetter<C: CpuOps>: Send + Sync + 'static {
|
||||
fn global_page_alloc() -> &'static OnceLock<FrameAllocator<C>, C>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -6,6 +6,9 @@ pub struct PageOffsetTranslator<VM: VirtualMemory> {
|
||||
_phantom: PhantomData<VM>,
|
||||
}
|
||||
|
||||
unsafe impl<VM: VirtualMemory> Send for PageOffsetTranslator<VM> {}
|
||||
unsafe impl<VM: VirtualMemory> Sync for PageOffsetTranslator<VM> {}
|
||||
|
||||
impl<T, VM: VirtualMemory> AddressTranslator<T> for PageOffsetTranslator<VM> {
|
||||
fn virt_to_phys(va: TVA<T>) -> TPA<T> {
|
||||
let mut v = va.value();
|
||||
|
||||
@@ -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<ArchImpl> for PgAllocGetter {
|
||||
fn global_page_alloc() -> &'static libkernel::sync::once_lock::OnceLock<
|
||||
libkernel::memory::page_alloc::FrameAllocator<ArchImpl>,
|
||||
ArchImpl,
|
||||
> {
|
||||
&PAGE_ALLOC
|
||||
}
|
||||
}
|
||||
|
||||
impl ClaimedPage {
|
||||
/// Allocates a single physical page. The contents of the page are
|
||||
/// undefined.
|
||||
fn alloc() -> Result<Self> {
|
||||
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<Self> {
|
||||
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::<PageOffsetTranslator>()
|
||||
}
|
||||
|
||||
/// 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<ArchImpl, PgAllocGetter, PageOffsetTranslator>;
|
||||
|
||||
Reference in New Issue
Block a user