mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 00:43:24 +00:00
Use pointer metadata for page metadata
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
cd22854f59
commit
60365a818a
@ -11,8 +11,9 @@ use crate::{
|
|||||||
arch::boot::smp::{bringup_all_aps, get_num_processors},
|
arch::boot::smp::{bringup_all_aps, get_num_processors},
|
||||||
cpu,
|
cpu,
|
||||||
mm::{
|
mm::{
|
||||||
|
kspace::KernelMeta,
|
||||||
paddr_to_vaddr,
|
paddr_to_vaddr,
|
||||||
page::{self, meta::KernelMeta, ContPages},
|
page::{self, ContPages},
|
||||||
PAGE_SIZE,
|
PAGE_SIZE,
|
||||||
},
|
},
|
||||||
task::Task,
|
task::Task,
|
||||||
|
@ -44,8 +44,9 @@ use spin::Once;
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch,
|
arch,
|
||||||
mm::{
|
mm::{
|
||||||
|
kspace::KernelMeta,
|
||||||
paddr_to_vaddr,
|
paddr_to_vaddr,
|
||||||
page::{self, meta::KernelMeta, ContPages},
|
page::{self, ContPages},
|
||||||
PAGE_SIZE,
|
PAGE_SIZE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -15,8 +15,10 @@
|
|||||||
#![feature(linkage)]
|
#![feature(linkage)]
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
#![feature(negative_impls)]
|
#![feature(negative_impls)]
|
||||||
|
#![feature(ptr_metadata)]
|
||||||
#![feature(ptr_sub_ptr)]
|
#![feature(ptr_sub_ptr)]
|
||||||
#![feature(sync_unsafe_cell)]
|
#![feature(sync_unsafe_cell)]
|
||||||
|
#![feature(trait_upcasting)]
|
||||||
// The `generic_const_exprs` feature is incomplete however required for the page table
|
// The `generic_const_exprs` feature is incomplete however required for the page table
|
||||||
// const generic implementation. We are using this feature in a conservative manner.
|
// const generic implementation. We are using this feature in a conservative manner.
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
@ -15,14 +15,17 @@ use core::mem::ManuallyDrop;
|
|||||||
|
|
||||||
pub use segment::Segment;
|
pub use segment::Segment;
|
||||||
|
|
||||||
use super::page::{
|
use super::{
|
||||||
meta::{FrameMeta, MetaSlot, PageMeta, PageUsage},
|
page::{
|
||||||
DynPage, Page,
|
meta::{impl_page_meta, MetaSlot},
|
||||||
|
DynPage, Page,
|
||||||
|
},
|
||||||
|
Infallible,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
mm::{
|
mm::{
|
||||||
io::{FallibleVmRead, FallibleVmWrite, VmIo, VmReader, VmWriter},
|
io::{FallibleVmRead, FallibleVmWrite, VmIo, VmReader, VmWriter},
|
||||||
paddr_to_vaddr, HasPaddr, Infallible, Paddr, PAGE_SIZE,
|
paddr_to_vaddr, HasPaddr, Paddr, PAGE_SIZE,
|
||||||
},
|
},
|
||||||
Error, Result,
|
Error, Result,
|
||||||
};
|
};
|
||||||
@ -178,14 +181,11 @@ impl VmIo for Frame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageMeta for FrameMeta {
|
/// Metadata for a frame.
|
||||||
const USAGE: PageUsage = PageUsage::Frame;
|
#[derive(Debug, Default)]
|
||||||
|
pub struct FrameMeta {}
|
||||||
|
|
||||||
fn on_drop(_page: &mut Page<Self>) {
|
impl_page_meta!(FrameMeta);
|
||||||
// Nothing should be done so far since dropping the page would
|
|
||||||
// have all taken care of.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here are implementations for `xarray`.
|
// Here are implementations for `xarray`.
|
||||||
|
|
||||||
|
@ -4,10 +4,7 @@
|
|||||||
|
|
||||||
use super::{Frame, Segment};
|
use super::{Frame, Segment};
|
||||||
use crate::{
|
use crate::{
|
||||||
mm::{
|
mm::{frame::FrameMeta, page, PAGE_SIZE},
|
||||||
page::{self, meta::FrameMeta},
|
|
||||||
PAGE_SIZE,
|
|
||||||
},
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
@ -6,8 +6,9 @@ use core::ops::Range;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mm::{
|
mm::{
|
||||||
|
frame::FrameMeta,
|
||||||
io::{FallibleVmRead, FallibleVmWrite},
|
io::{FallibleVmRead, FallibleVmWrite},
|
||||||
page::{meta::FrameMeta, ContPages},
|
page::ContPages,
|
||||||
Frame, HasPaddr, Infallible, Paddr, VmIo, VmReader, VmWriter,
|
Frame, HasPaddr, Infallible, Paddr, VmIo, VmReader, VmWriter,
|
||||||
},
|
},
|
||||||
Error, Result,
|
Error, Result,
|
||||||
|
@ -50,7 +50,7 @@ use spin::Once;
|
|||||||
use super::{
|
use super::{
|
||||||
nr_subpage_per_huge,
|
nr_subpage_per_huge,
|
||||||
page::{
|
page::{
|
||||||
meta::{mapping, KernelMeta, MetaPageMeta},
|
meta::{impl_page_meta, mapping, MetaPageMeta},
|
||||||
Page,
|
Page,
|
||||||
},
|
},
|
||||||
page_prop::{CachePolicy, PageFlags, PageProperty, PrivilegedPageFlags},
|
page_prop::{CachePolicy, PageFlags, PageProperty, PrivilegedPageFlags},
|
||||||
@ -247,3 +247,9 @@ pub unsafe fn activate_kernel_page_table() {
|
|||||||
crate::mm::page_table::boot_pt::dismiss();
|
crate::mm::page_table::boot_pt::dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The metadata of pages that contains the kernel itself.
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct KernelMeta {}
|
||||||
|
|
||||||
|
impl_page_meta!(KernelMeta);
|
||||||
|
@ -44,7 +44,7 @@ pub type PagingLevel = u8;
|
|||||||
|
|
||||||
/// A minimal set of constants that determines the paging system.
|
/// A minimal set of constants that determines the paging system.
|
||||||
/// This provides an abstraction over most paging modes in common architectures.
|
/// This provides an abstraction over most paging modes in common architectures.
|
||||||
pub(crate) trait PagingConstsTrait: Clone + Debug + Default + Sync + 'static {
|
pub(crate) trait PagingConstsTrait: Clone + Debug + Default + Send + Sync + 'static {
|
||||||
/// The smallest page size.
|
/// The smallest page size.
|
||||||
/// This is also the page size at level 1 page tables.
|
/// This is also the page size at level 1 page tables.
|
||||||
const BASE_PAGE_SIZE: usize;
|
const BASE_PAGE_SIZE: usize;
|
||||||
|
@ -37,53 +37,31 @@ pub mod mapping {
|
|||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::{
|
use core::{
|
||||||
|
any::Any,
|
||||||
cell::UnsafeCell,
|
cell::UnsafeCell,
|
||||||
marker::PhantomData,
|
mem::size_of,
|
||||||
mem::{size_of, ManuallyDrop},
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
panic,
|
|
||||||
sync::atomic::{AtomicU32, AtomicU8, Ordering},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use num_derive::FromPrimitive;
|
|
||||||
use static_assertions::const_assert_eq;
|
use static_assertions::const_assert_eq;
|
||||||
|
|
||||||
use super::{allocator, Page};
|
use super::{allocator, Page};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::mm::{PageTableEntry, PagingConsts},
|
arch::mm::PagingConsts,
|
||||||
mm::{
|
mm::{
|
||||||
paddr_to_vaddr, page_size,
|
paddr_to_vaddr, page_size, page_table::boot_pt, CachePolicy, Paddr, PageFlags,
|
||||||
page_table::{boot_pt, PageTableEntryTrait},
|
PageProperty, PrivilegedPageFlags, Vaddr, PAGE_SIZE,
|
||||||
CachePolicy, Paddr, PageFlags, PageProperty, PagingConstsTrait, PagingLevel,
|
|
||||||
PrivilegedPageFlags, Vaddr, PAGE_SIZE,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents the usage of a page.
|
/// The maximum number of bytes of the metadata of a page.
|
||||||
#[repr(u8)]
|
pub const PAGE_METADATA_MAX_SIZE: usize =
|
||||||
#[derive(Debug, FromPrimitive, PartialEq)]
|
META_SLOT_SIZE - size_of::<AtomicU32>() - size_of::<PageMetaVtablePtr>();
|
||||||
pub enum PageUsage {
|
/// The maximum alignment in bytes of the metadata of a page.
|
||||||
// The zero variant is reserved for the unused type. Only an unused page
|
pub const PAGE_METADATA_MAX_ALIGN: usize = align_of::<MetaSlot>();
|
||||||
// can be designated for one of the other purposes.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
Unused = 0,
|
|
||||||
/// The page is reserved or unusable. The kernel should not touch it.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
Reserved = 1,
|
|
||||||
|
|
||||||
/// The page is used as a frame, i.e., a page of untyped memory.
|
const META_SLOT_SIZE: usize = 64;
|
||||||
Frame = 32,
|
|
||||||
|
|
||||||
/// The page is used by a page table.
|
|
||||||
PageTable = 64,
|
|
||||||
/// The page stores metadata of other pages.
|
|
||||||
Meta = 65,
|
|
||||||
/// The page stores the kernel such as kernel code, data, etc.
|
|
||||||
Kernel = 66,
|
|
||||||
|
|
||||||
/// The page stores data for kernel stack.
|
|
||||||
KernelStack = 67,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub(in crate::mm) struct MetaSlot {
|
pub(in crate::mm) struct MetaSlot {
|
||||||
@ -92,41 +70,58 @@ pub(in crate::mm) struct MetaSlot {
|
|||||||
/// It is placed at the beginning of a slot because:
|
/// It is placed at the beginning of a slot because:
|
||||||
/// - the implementation can simply cast a `*const MetaSlot`
|
/// - the implementation can simply cast a `*const MetaSlot`
|
||||||
/// to a `*const PageMeta` for manipulation;
|
/// to a `*const PageMeta` for manipulation;
|
||||||
/// - the subsequent fields can utilize the end padding of the
|
/// - if the metadata need special alignment, we can provide
|
||||||
/// the inner union to save space.
|
/// at most `PAGE_METADATA_ALIGN` bytes of alignment;
|
||||||
_inner: MetaSlotInner,
|
/// - the subsequent fields can utilize the padding of the
|
||||||
/// To store [`PageUsage`].
|
/// reference count to save space.
|
||||||
pub(super) usage: AtomicU8,
|
storage: UnsafeCell<[u8; PAGE_METADATA_MAX_SIZE]>,
|
||||||
|
/// The reference count of the page.
|
||||||
pub(super) ref_count: AtomicU32,
|
pub(super) ref_count: AtomicU32,
|
||||||
|
/// The virtual table that indicates the type of the metadata.
|
||||||
|
pub(super) vtable_ptr: UnsafeCell<PageMetaVtablePtr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) union MetaSlotInner {
|
type PageMetaVtablePtr = core::ptr::DynMetadata<dyn PageMeta>;
|
||||||
_frame: ManuallyDrop<FrameMeta>,
|
|
||||||
_pt: ManuallyDrop<PageTablePageMeta>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Currently the sizes of the `MetaSlotInner` union variants are no larger
|
const_assert_eq!(PAGE_SIZE % META_SLOT_SIZE, 0);
|
||||||
// than 8 bytes and aligned to 8 bytes. So the size of `MetaSlot` is 16 bytes.
|
const_assert_eq!(size_of::<MetaSlot>(), META_SLOT_SIZE);
|
||||||
//
|
|
||||||
// Note that the size of `MetaSlot` should be a multiple of 8 bytes to prevent
|
|
||||||
// cross-page accesses.
|
|
||||||
const_assert_eq!(size_of::<MetaSlot>(), 16);
|
|
||||||
|
|
||||||
/// All page metadata types must implemented this sealed trait,
|
/// All page metadata types must implement this trait.
|
||||||
/// which ensures that each fields of `PageUsage` has one and only
|
|
||||||
/// one metadata type corresponding to the usage purpose. Any user
|
|
||||||
/// outside this module won't be able to add more metadata types
|
|
||||||
/// and break assumptions made by this module.
|
|
||||||
///
|
///
|
||||||
/// If a page type needs specific drop behavior, it should specify
|
/// If a page type needs specific drop behavior, it should specify
|
||||||
/// when implementing this trait. When we drop the last handle to
|
/// when implementing this trait. When we drop the last handle to
|
||||||
/// this page, the `on_drop` method will be called.
|
/// this page, the `on_drop` method will be called. The `on_drop`
|
||||||
pub trait PageMeta: Sync + private::Sealed + Sized {
|
/// method is called with the physical address of the page.
|
||||||
const USAGE: PageUsage;
|
///
|
||||||
|
/// # Safety
|
||||||
fn on_drop(page: &mut Page<Self>);
|
///
|
||||||
|
/// The implemented structure must have a size less than or equal to
|
||||||
|
/// [`PAGE_METADATA_MAX_SIZE`] and an alignment less than or equal to
|
||||||
|
/// [`PAGE_METADATA_MAX_ALIGN`].
|
||||||
|
pub unsafe trait PageMeta: Any + Send + Sync + 'static {
|
||||||
|
fn on_drop(&mut self, _paddr: Paddr) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a structure usable as a page metadata.
|
||||||
|
///
|
||||||
|
/// Directly implementing [`PageMeta`] is not safe since the size and alignment
|
||||||
|
/// must be checked. This macro provides a safe way to implement the trait with
|
||||||
|
/// compile-time checks.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! impl_page_meta {
|
||||||
|
($($t:ty),*) => {
|
||||||
|
$(
|
||||||
|
use static_assertions::const_assert;
|
||||||
|
const_assert!(size_of::<$t>() <= $crate::mm::page::meta::PAGE_METADATA_MAX_SIZE);
|
||||||
|
const_assert!(align_of::<$t>() <= $crate::mm::page::meta::PAGE_METADATA_MAX_ALIGN);
|
||||||
|
// SAFETY: The size and alignment of the structure are checked.
|
||||||
|
unsafe impl $crate::mm::page::meta::PageMeta for $t {}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use impl_page_meta;
|
||||||
|
|
||||||
/// An internal routine in dropping implementations.
|
/// An internal routine in dropping implementations.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -134,154 +129,35 @@ pub trait PageMeta: Sync + private::Sealed + Sized {
|
|||||||
/// The caller should ensure that the pointer points to a page's metadata slot. The
|
/// The caller should ensure that the pointer points to a page's metadata slot. The
|
||||||
/// page should have a last handle to the page, and the page is about to be dropped,
|
/// page should have a last handle to the page, and the page is about to be dropped,
|
||||||
/// as the metadata slot after this operation becomes uninitialized.
|
/// as the metadata slot after this operation becomes uninitialized.
|
||||||
pub(super) unsafe fn drop_as_last<M: PageMeta>(ptr: *const MetaSlot) {
|
pub(super) unsafe fn drop_last_in_place(ptr: *mut MetaSlot) {
|
||||||
// This would be guaranteed as a safety requirement.
|
// This would be guaranteed as a safety requirement.
|
||||||
debug_assert_eq!((*ptr).ref_count.load(Ordering::Relaxed), 0);
|
debug_assert_eq!((*ptr).ref_count.load(Ordering::Relaxed), 0);
|
||||||
|
|
||||||
|
let paddr = mapping::meta_to_page::<PagingConsts>(ptr as Vaddr);
|
||||||
|
|
||||||
|
let meta_ptr: *mut dyn PageMeta = core::ptr::from_raw_parts_mut(ptr, *(*ptr).vtable_ptr.get());
|
||||||
|
|
||||||
// Let the custom dropper handle the drop.
|
// Let the custom dropper handle the drop.
|
||||||
let mut page = Page::<M> {
|
(*meta_ptr).on_drop(paddr);
|
||||||
ptr,
|
|
||||||
_marker: PhantomData,
|
|
||||||
};
|
|
||||||
M::on_drop(&mut page);
|
|
||||||
let _ = ManuallyDrop::new(page);
|
|
||||||
// Drop the metadata.
|
// Drop the metadata.
|
||||||
core::ptr::drop_in_place(ptr as *mut M);
|
core::ptr::drop_in_place(meta_ptr);
|
||||||
// No handles means no usage. This also releases the page as unused for further
|
|
||||||
// calls to `Page::from_unused`.
|
|
||||||
(*ptr).usage.store(0, Ordering::Release);
|
|
||||||
// Deallocate the page.
|
// Deallocate the page.
|
||||||
// It would return the page to the allocator for further use. This would be done
|
// It would return the page to the allocator for further use. This would be done
|
||||||
// after the release of the metadata to avoid re-allocation before the metadata
|
// after the release of the metadata to avoid re-allocation before the metadata
|
||||||
// is reset.
|
// is reset.
|
||||||
allocator::PAGE_ALLOCATOR.get().unwrap().lock().dealloc(
|
allocator::PAGE_ALLOCATOR
|
||||||
mapping::meta_to_page::<PagingConsts>(ptr as Vaddr) / PAGE_SIZE,
|
.get()
|
||||||
1,
|
.unwrap()
|
||||||
);
|
.lock()
|
||||||
|
.dealloc(paddr / PAGE_SIZE, 1);
|
||||||
}
|
}
|
||||||
|
/// The metadata of pages that holds metadata of pages.
|
||||||
mod private {
|
|
||||||
pub trait Sealed {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======= Start of all the specific metadata structures definitions ==========
|
|
||||||
|
|
||||||
use private::Sealed;
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
#[repr(C)]
|
|
||||||
pub struct FrameMeta {
|
|
||||||
// If not doing so, the page table metadata would fit
|
|
||||||
// in the front padding of meta slot and make it 12 bytes.
|
|
||||||
// We make it 16 bytes. Further usage of frame metadata
|
|
||||||
// is welcome to exploit this space.
|
|
||||||
_unused_for_layout_padding: [u8; 8],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sealed for FrameMeta {}
|
|
||||||
|
|
||||||
/// The metadata of any kinds of page table pages.
|
|
||||||
/// Make sure the the generic parameters don't effect the memory layout.
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub(in crate::mm) struct PageTablePageMeta<
|
|
||||||
E: PageTableEntryTrait = PageTableEntry,
|
|
||||||
C: PagingConstsTrait = PagingConsts,
|
|
||||||
> where
|
|
||||||
[(); C::NR_LEVELS as usize]:,
|
|
||||||
{
|
|
||||||
/// The number of valid PTEs. It is mutable if the lock is held.
|
|
||||||
pub nr_children: UnsafeCell<u16>,
|
|
||||||
/// The level of the page table page. A page table page cannot be
|
|
||||||
/// referenced by page tables of different levels.
|
|
||||||
pub level: PagingLevel,
|
|
||||||
/// Whether the pages mapped by the node is tracked.
|
|
||||||
pub is_tracked: MapTrackingStatus,
|
|
||||||
/// The lock for the page table page.
|
|
||||||
pub lock: AtomicU8,
|
|
||||||
_phantom: core::marker::PhantomData<(E, C)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Describe if the physical address recorded in this page table refers to a
|
|
||||||
/// page tracked by metadata.
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub(in crate::mm) enum MapTrackingStatus {
|
|
||||||
/// The page table node cannot contain references to any pages. It can only
|
|
||||||
/// contain references to child page table nodes.
|
|
||||||
NotApplicable,
|
|
||||||
/// The mapped pages are not tracked by metadata. If any child page table
|
|
||||||
/// nodes exist, they should also be tracked.
|
|
||||||
Untracked,
|
|
||||||
/// The mapped pages are tracked by metadata. If any child page table nodes
|
|
||||||
/// exist, they should also be tracked.
|
|
||||||
Tracked,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: PageTableEntryTrait, C: PagingConstsTrait> PageTablePageMeta<E, C>
|
|
||||||
where
|
|
||||||
[(); C::NR_LEVELS as usize]:,
|
|
||||||
{
|
|
||||||
pub fn new_locked(level: PagingLevel, is_tracked: MapTrackingStatus) -> Self {
|
|
||||||
Self {
|
|
||||||
nr_children: UnsafeCell::new(0),
|
|
||||||
level,
|
|
||||||
is_tracked,
|
|
||||||
lock: AtomicU8::new(1),
|
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: PageTableEntryTrait, C: PagingConstsTrait> Sealed for PageTablePageMeta<E, C> where
|
|
||||||
[(); C::NR_LEVELS as usize]:
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<E: PageTableEntryTrait, C: PagingConstsTrait> Send for PageTablePageMeta<E, C> where
|
|
||||||
[(); C::NR_LEVELS as usize]:
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<E: PageTableEntryTrait, C: PagingConstsTrait> Sync for PageTablePageMeta<E, C> where
|
|
||||||
[(); C::NR_LEVELS as usize]:
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct MetaPageMeta {}
|
pub struct MetaPageMeta {}
|
||||||
|
|
||||||
impl Sealed for MetaPageMeta {}
|
impl_page_meta!(MetaPageMeta);
|
||||||
impl PageMeta for MetaPageMeta {
|
|
||||||
const USAGE: PageUsage = PageUsage::Meta;
|
|
||||||
fn on_drop(_page: &mut Page<Self>) {
|
|
||||||
panic!("Meta pages are currently not allowed to be dropped");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct KernelMeta {}
|
|
||||||
|
|
||||||
impl Sealed for KernelMeta {}
|
|
||||||
impl PageMeta for KernelMeta {
|
|
||||||
const USAGE: PageUsage = PageUsage::Kernel;
|
|
||||||
fn on_drop(_page: &mut Page<Self>) {
|
|
||||||
panic!("Kernel pages are not allowed to be dropped");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct KernelStackMeta {}
|
|
||||||
|
|
||||||
impl Sealed for KernelStackMeta {}
|
|
||||||
impl PageMeta for KernelStackMeta {
|
|
||||||
const USAGE: PageUsage = PageUsage::KernelStack;
|
|
||||||
fn on_drop(_page: &mut Page<Self>) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======== End of all the specific metadata structures definitions ===========
|
|
||||||
|
|
||||||
/// Initializes the metadata of all physical pages.
|
/// Initializes the metadata of all physical pages.
|
||||||
///
|
///
|
||||||
|
@ -19,16 +19,16 @@ mod cont_pages;
|
|||||||
pub mod meta;
|
pub mod meta;
|
||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
|
any::Any,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem::ManuallyDrop,
|
mem::ManuallyDrop,
|
||||||
panic,
|
|
||||||
sync::atomic::{AtomicU32, AtomicUsize, Ordering},
|
sync::atomic::{AtomicU32, AtomicUsize, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use cont_pages::ContPages;
|
pub use cont_pages::ContPages;
|
||||||
use meta::{mapping, FrameMeta, MetaSlot, PageMeta, PageUsage};
|
use meta::{mapping, MetaSlot, PageMeta, PAGE_METADATA_MAX_ALIGN, PAGE_METADATA_MAX_SIZE};
|
||||||
|
|
||||||
use super::{Frame, PagingLevel, PAGE_SIZE};
|
use super::{frame::FrameMeta, Frame, PagingLevel, PAGE_SIZE};
|
||||||
use crate::mm::{Paddr, PagingConsts, Vaddr};
|
use crate::mm::{Paddr, PagingConsts, Vaddr};
|
||||||
|
|
||||||
static MAX_PADDR: AtomicUsize = AtomicUsize::new(0);
|
static MAX_PADDR: AtomicUsize = AtomicUsize::new(0);
|
||||||
@ -41,6 +41,7 @@ pub struct Page<M: PageMeta> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<M: PageMeta> Send for Page<M> {}
|
unsafe impl<M: PageMeta> Send for Page<M> {}
|
||||||
|
|
||||||
unsafe impl<M: PageMeta> Sync for Page<M> {}
|
unsafe impl<M: PageMeta> Sync for Page<M> {}
|
||||||
|
|
||||||
impl<M: PageMeta> Page<M> {
|
impl<M: PageMeta> Page<M> {
|
||||||
@ -56,20 +57,26 @@ impl<M: PageMeta> Page<M> {
|
|||||||
pub fn from_unused(paddr: Paddr, metadata: M) -> Self {
|
pub fn from_unused(paddr: Paddr, metadata: M) -> Self {
|
||||||
assert!(paddr % PAGE_SIZE == 0);
|
assert!(paddr % PAGE_SIZE == 0);
|
||||||
assert!(paddr < MAX_PADDR.load(Ordering::Relaxed) as Paddr);
|
assert!(paddr < MAX_PADDR.load(Ordering::Relaxed) as Paddr);
|
||||||
|
|
||||||
|
// Checking unsafe preconditions of the `PageMeta` trait.
|
||||||
|
debug_assert!(size_of::<M>() <= PAGE_METADATA_MAX_SIZE);
|
||||||
|
debug_assert!(align_of::<M>() <= PAGE_METADATA_MAX_ALIGN);
|
||||||
|
|
||||||
let vaddr = mapping::page_to_meta::<PagingConsts>(paddr);
|
let vaddr = mapping::page_to_meta::<PagingConsts>(paddr);
|
||||||
let ptr = vaddr as *const MetaSlot;
|
let ptr = vaddr as *const MetaSlot;
|
||||||
|
|
||||||
// SAFETY: The aligned pointer points to an initialized `MetaSlot`.
|
// SAFETY: The aligned pointer points to a initialized `MetaSlot`.
|
||||||
let usage = unsafe { &(*ptr).usage };
|
|
||||||
// SAFETY: The aligned pointer points to an initialized `MetaSlot`.
|
|
||||||
let ref_count = unsafe { &(*ptr).ref_count };
|
let ref_count = unsafe { &(*ptr).ref_count };
|
||||||
|
|
||||||
usage
|
ref_count
|
||||||
.compare_exchange(0, M::USAGE as u8, Ordering::SeqCst, Ordering::Relaxed)
|
.compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed)
|
||||||
.expect("page already in use when trying to get a new handle");
|
.expect("Page already in use when trying to get a new handle");
|
||||||
|
|
||||||
let old_ref_count = ref_count.fetch_add(1, Ordering::Relaxed);
|
// SAFETY: The aligned pointer points to a initialized `MetaSlot`.
|
||||||
debug_assert_eq!(old_ref_count, 0);
|
let vtable_ptr = unsafe { (*ptr).vtable_ptr.get() };
|
||||||
|
|
||||||
|
// SAFETY: The pointer is valid and we have the exclusive access.
|
||||||
|
unsafe { vtable_ptr.write(core::ptr::metadata(&metadata as &dyn PageMeta)) };
|
||||||
|
|
||||||
// Initialize the metadata
|
// Initialize the metadata
|
||||||
// SAFETY: The pointer points to the first byte of the `MetaSlot`
|
// SAFETY: The pointer points to the first byte of the `MetaSlot`
|
||||||
@ -183,9 +190,10 @@ impl<M: PageMeta> Drop for Page<M> {
|
|||||||
// A fence is needed here with the same reasons stated in the implementation of
|
// A fence is needed here with the same reasons stated in the implementation of
|
||||||
// `Arc::drop`: <https://doc.rust-lang.org/std/sync/struct.Arc.html#method.drop>.
|
// `Arc::drop`: <https://doc.rust-lang.org/std/sync/struct.Arc.html#method.drop>.
|
||||||
core::sync::atomic::fence(Ordering::Acquire);
|
core::sync::atomic::fence(Ordering::Acquire);
|
||||||
|
|
||||||
// SAFETY: this is the last reference and is about to be dropped.
|
// SAFETY: this is the last reference and is about to be dropped.
|
||||||
unsafe {
|
unsafe {
|
||||||
meta::drop_as_last::<M>(self.ptr);
|
meta::drop_last_in_place(self.ptr as *mut MetaSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,6 +237,18 @@ impl DynPage {
|
|||||||
Self { ptr }
|
Self { ptr }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the metadata of this page.
|
||||||
|
pub fn meta(&self) -> &dyn Any {
|
||||||
|
// SAFETY: The pointer is valid and no other writes will be done to it.
|
||||||
|
let vtable_ptr = unsafe { *(*self.ptr).vtable_ptr.get() };
|
||||||
|
|
||||||
|
let meta_ptr: *const dyn PageMeta = core::ptr::from_raw_parts(self.ptr, vtable_ptr);
|
||||||
|
|
||||||
|
// SAFETY: The pointer is valid and the type is correct for the stored
|
||||||
|
// metadata.
|
||||||
|
(unsafe { &*meta_ptr }) as &dyn Any
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the physical address of the start of the page
|
/// Get the physical address of the start of the page
|
||||||
pub fn paddr(&self) -> Paddr {
|
pub fn paddr(&self) -> Paddr {
|
||||||
mapping::meta_to_page::<PagingConsts>(self.ptr as Vaddr)
|
mapping::meta_to_page::<PagingConsts>(self.ptr as Vaddr)
|
||||||
@ -244,14 +264,6 @@ impl DynPage {
|
|||||||
PAGE_SIZE
|
PAGE_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the usage of the page.
|
|
||||||
pub fn usage(&self) -> PageUsage {
|
|
||||||
// SAFETY: structure is safely created with a pointer that points
|
|
||||||
// to initialized [`MetaSlot`] memory.
|
|
||||||
let usage_raw = unsafe { (*self.ptr).usage.load(Ordering::Relaxed) };
|
|
||||||
num::FromPrimitive::from_u8(usage_raw).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ref_count(&self) -> &AtomicU32 {
|
fn ref_count(&self) -> &AtomicU32 {
|
||||||
unsafe { &(*self.ptr).ref_count }
|
unsafe { &(*self.ptr).ref_count }
|
||||||
}
|
}
|
||||||
@ -265,7 +277,7 @@ impl<M: PageMeta> TryFrom<DynPage> for Page<M> {
|
|||||||
/// If the usage of the page is not the same as the expected usage, it will
|
/// If the usage of the page is not the same as the expected usage, it will
|
||||||
/// return the dynamic page itself as is.
|
/// return the dynamic page itself as is.
|
||||||
fn try_from(dyn_page: DynPage) -> Result<Self, Self::Error> {
|
fn try_from(dyn_page: DynPage) -> Result<Self, Self::Error> {
|
||||||
if dyn_page.usage() == M::USAGE {
|
if dyn_page.meta().is::<M>() {
|
||||||
let result = Page {
|
let result = Page {
|
||||||
ptr: dyn_page.ptr,
|
ptr: dyn_page.ptr,
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
@ -307,28 +319,10 @@ impl Drop for DynPage {
|
|||||||
// A fence is needed here with the same reasons stated in the implementation of
|
// A fence is needed here with the same reasons stated in the implementation of
|
||||||
// `Arc::drop`: <https://doc.rust-lang.org/std/sync/struct.Arc.html#method.drop>.
|
// `Arc::drop`: <https://doc.rust-lang.org/std/sync/struct.Arc.html#method.drop>.
|
||||||
core::sync::atomic::fence(Ordering::Acquire);
|
core::sync::atomic::fence(Ordering::Acquire);
|
||||||
// Drop the page and its metadata according to its usage.
|
|
||||||
// SAFETY: all `drop_as_last` calls in match arms operates on a last, about to be
|
// SAFETY: this is the last reference and is about to be dropped.
|
||||||
// dropped page reference.
|
|
||||||
unsafe {
|
unsafe {
|
||||||
match self.usage() {
|
meta::drop_last_in_place(self.ptr as *mut MetaSlot);
|
||||||
PageUsage::Frame => {
|
|
||||||
meta::drop_as_last::<meta::FrameMeta>(self.ptr);
|
|
||||||
}
|
|
||||||
PageUsage::PageTable => {
|
|
||||||
meta::drop_as_last::<meta::PageTablePageMeta>(self.ptr);
|
|
||||||
}
|
|
||||||
PageUsage::KernelStack => {
|
|
||||||
meta::drop_as_last::<meta::KernelStackMeta>(self.ptr);
|
|
||||||
}
|
|
||||||
// The following pages don't have metadata and can't be dropped.
|
|
||||||
PageUsage::Unused
|
|
||||||
| PageUsage::Reserved
|
|
||||||
| PageUsage::Kernel
|
|
||||||
| PageUsage::Meta => {
|
|
||||||
panic!("dropping a dynamic page with usage {:?}", self.usage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,15 +70,13 @@ use core::{any::TypeId, marker::PhantomData, mem::ManuallyDrop, ops::Range};
|
|||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
page_size, pte_index, Child, Entry, KernelMode, PageTable, PageTableEntryTrait, PageTableError,
|
page_size, pte_index, Child, Entry, KernelMode, MapTrackingStatus, PageTable,
|
||||||
PageTableMode, PageTableNode, PagingConstsTrait, PagingLevel, RawPageTableNode, UserMode,
|
PageTableEntryTrait, PageTableError, PageTableMode, PageTableNode, PagingConstsTrait,
|
||||||
|
PagingLevel, RawPageTableNode, UserMode,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
mm::{
|
mm::{
|
||||||
kspace::should_map_as_tracked,
|
kspace::should_map_as_tracked, paddr_to_vaddr, page::DynPage, Paddr, PageProperty, Vaddr,
|
||||||
paddr_to_vaddr,
|
|
||||||
page::{meta::MapTrackingStatus, DynPage},
|
|
||||||
Paddr, PageProperty, Vaddr,
|
|
||||||
},
|
},
|
||||||
task::{disable_preempt, DisabledPreemptGuard},
|
task::{disable_preempt, DisabledPreemptGuard},
|
||||||
};
|
};
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
use core::{fmt::Debug, marker::PhantomData, ops::Range};
|
use core::{fmt::Debug, marker::PhantomData, ops::Range};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
nr_subpage_per_huge, page::meta::MapTrackingStatus, page_prop::PageProperty, page_size, Paddr,
|
nr_subpage_per_huge, page_prop::PageProperty, page_size, Paddr, PagingConstsTrait, PagingLevel,
|
||||||
PagingConstsTrait, PagingLevel, Vaddr,
|
Vaddr,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::mm::{PageTableEntry, PagingConsts},
|
arch::mm::{PageTableEntry, PagingConsts},
|
||||||
@ -338,7 +338,9 @@ pub(super) unsafe fn page_walk<E: PageTableEntryTrait, C: PagingConstsTrait>(
|
|||||||
/// The interface for defining architecture-specific page table entries.
|
/// The interface for defining architecture-specific page table entries.
|
||||||
///
|
///
|
||||||
/// Note that a default PTE should be a PTE that points to nothing.
|
/// Note that a default PTE should be a PTE that points to nothing.
|
||||||
pub trait PageTableEntryTrait: Clone + Copy + Debug + Default + Pod + Sized + Sync {
|
pub trait PageTableEntryTrait:
|
||||||
|
Clone + Copy + Debug + Default + Pod + Sized + Send + Sync + 'static
|
||||||
|
{
|
||||||
/// Create a set of new invalid page table flags that indicates an absent page.
|
/// Create a set of new invalid page table flags that indicates an absent page.
|
||||||
///
|
///
|
||||||
/// Note that currently the implementation requires an all zero PTE to be an absent PTE.
|
/// Note that currently the implementation requires an all zero PTE to be an absent PTE.
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
|
|
||||||
use core::{mem::ManuallyDrop, panic};
|
use core::{mem::ManuallyDrop, panic};
|
||||||
|
|
||||||
use super::{PageTableEntryTrait, RawPageTableNode};
|
use super::{MapTrackingStatus, PageTableEntryTrait, RawPageTableNode};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::mm::{PageTableEntry, PagingConsts},
|
arch::mm::{PageTableEntry, PagingConsts},
|
||||||
mm::{
|
mm::{
|
||||||
page::{inc_page_ref_count, meta::MapTrackingStatus, DynPage},
|
page::{inc_page_ref_count, DynPage},
|
||||||
page_prop::PageProperty,
|
page_prop::PageProperty,
|
||||||
Paddr, PagingConstsTrait, PagingLevel,
|
Paddr, PagingConstsTrait, PagingLevel,
|
||||||
},
|
},
|
||||||
|
@ -2,11 +2,8 @@
|
|||||||
|
|
||||||
//! This module provides accessors to the page table entries in a node.
|
//! This module provides accessors to the page table entries in a node.
|
||||||
|
|
||||||
use super::{Child, PageTableEntryTrait, PageTableNode};
|
use super::{Child, MapTrackingStatus, PageTableEntryTrait, PageTableNode};
|
||||||
use crate::mm::{
|
use crate::mm::{nr_subpage_per_huge, page_prop::PageProperty, page_size, PagingConstsTrait};
|
||||||
nr_subpage_per_huge, page::meta::MapTrackingStatus, page_prop::PageProperty, page_size,
|
|
||||||
PagingConstsTrait,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A view of an entry in a page table node.
|
/// A view of an entry in a page table node.
|
||||||
///
|
///
|
||||||
|
@ -28,7 +28,12 @@
|
|||||||
mod child;
|
mod child;
|
||||||
mod entry;
|
mod entry;
|
||||||
|
|
||||||
use core::{marker::PhantomData, mem::ManuallyDrop, sync::atomic::Ordering};
|
use core::{
|
||||||
|
cell::SyncUnsafeCell,
|
||||||
|
marker::PhantomData,
|
||||||
|
mem::ManuallyDrop,
|
||||||
|
sync::atomic::{AtomicU8, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
pub(in crate::mm) use self::{child::Child, entry::Entry};
|
pub(in crate::mm) use self::{child::Child, entry::Entry};
|
||||||
use super::{nr_subpage_per_huge, PageTableEntryTrait};
|
use super::{nr_subpage_per_huge, PageTableEntryTrait};
|
||||||
@ -36,11 +41,7 @@ use crate::{
|
|||||||
arch::mm::{PageTableEntry, PagingConsts},
|
arch::mm::{PageTableEntry, PagingConsts},
|
||||||
mm::{
|
mm::{
|
||||||
paddr_to_vaddr,
|
paddr_to_vaddr,
|
||||||
page::{
|
page::{self, inc_page_ref_count, meta::PageMeta, DynPage, Page},
|
||||||
self, inc_page_ref_count,
|
|
||||||
meta::{MapTrackingStatus, PageMeta, PageTablePageMeta, PageUsage},
|
|
||||||
DynPage, Page,
|
|
||||||
},
|
|
||||||
Paddr, PagingConstsTrait, PagingLevel, PAGE_SIZE,
|
Paddr, PagingConstsTrait, PagingLevel, PAGE_SIZE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -352,23 +353,73 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: PageTableEntryTrait, C: PagingConstsTrait> PageMeta for PageTablePageMeta<E, C>
|
/// The metadata of any kinds of page table pages.
|
||||||
|
/// Make sure the the generic parameters don't effect the memory layout.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(in crate::mm) struct PageTablePageMeta<
|
||||||
|
E: PageTableEntryTrait = PageTableEntry,
|
||||||
|
C: PagingConstsTrait = PagingConsts,
|
||||||
|
> where
|
||||||
|
[(); C::NR_LEVELS as usize]:,
|
||||||
|
{
|
||||||
|
/// The number of valid PTEs. It is mutable if the lock is held.
|
||||||
|
pub nr_children: SyncUnsafeCell<u16>,
|
||||||
|
/// The level of the page table page. A page table page cannot be
|
||||||
|
/// referenced by page tables of different levels.
|
||||||
|
pub level: PagingLevel,
|
||||||
|
/// The lock for the page table page.
|
||||||
|
pub lock: AtomicU8,
|
||||||
|
/// Whether the pages mapped by the node is tracked.
|
||||||
|
pub is_tracked: MapTrackingStatus,
|
||||||
|
_phantom: core::marker::PhantomData<(E, C)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Describe if the physical address recorded in this page table refers to a
|
||||||
|
/// page tracked by metadata.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub(in crate::mm) enum MapTrackingStatus {
|
||||||
|
/// The page table node cannot contain references to any pages. It can only
|
||||||
|
/// contain references to child page table nodes.
|
||||||
|
NotApplicable,
|
||||||
|
/// The mapped pages are not tracked by metadata. If any child page table
|
||||||
|
/// nodes exist, they should also be tracked.
|
||||||
|
Untracked,
|
||||||
|
/// The mapped pages are tracked by metadata. If any child page table nodes
|
||||||
|
/// exist, they should also be tracked.
|
||||||
|
Tracked,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: PageTableEntryTrait, C: PagingConstsTrait> PageTablePageMeta<E, C>
|
||||||
where
|
where
|
||||||
[(); C::NR_LEVELS as usize]:,
|
[(); C::NR_LEVELS as usize]:,
|
||||||
{
|
{
|
||||||
const USAGE: PageUsage = PageUsage::PageTable;
|
pub fn new_locked(level: PagingLevel, is_tracked: MapTrackingStatus) -> Self {
|
||||||
|
Self {
|
||||||
|
nr_children: SyncUnsafeCell::new(0),
|
||||||
|
level,
|
||||||
|
lock: AtomicU8::new(1),
|
||||||
|
is_tracked,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn on_drop(page: &mut Page<Self>) {
|
// SAFETY: The layout of the `PageTablePageMeta` is ensured to be the same for
|
||||||
// SAFETY: This is the last reference so we have an exclusive access.
|
// all possible generic parameters. And the layout fits the requirements.
|
||||||
let nr_children = unsafe { *page.meta().nr_children.get() };
|
unsafe impl<E: PageTableEntryTrait, C: PagingConstsTrait> PageMeta for PageTablePageMeta<E, C>
|
||||||
|
where
|
||||||
|
[(); C::NR_LEVELS as usize]:,
|
||||||
|
{
|
||||||
|
fn on_drop(&mut self, paddr: Paddr) {
|
||||||
|
let nr_children = self.nr_children.get_mut();
|
||||||
|
|
||||||
if nr_children == 0 {
|
if *nr_children == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let paddr = page.paddr();
|
let level = self.level;
|
||||||
let level = page.meta().level;
|
let is_tracked = self.is_tracked;
|
||||||
let is_tracked = page.meta().is_tracked;
|
|
||||||
|
|
||||||
// Drop the children.
|
// Drop the children.
|
||||||
for i in 0..nr_subpage_per_huge::<C>() {
|
for i in 0..nr_subpage_per_huge::<C>() {
|
||||||
|
@ -5,8 +5,9 @@ use core::mem::ManuallyDrop;
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
mm::{
|
mm::{
|
||||||
|
frame::FrameMeta,
|
||||||
kspace::LINEAR_MAPPING_BASE_VADDR,
|
kspace::LINEAR_MAPPING_BASE_VADDR,
|
||||||
page::{allocator, meta::FrameMeta},
|
page::allocator,
|
||||||
page_prop::{CachePolicy, PageFlags},
|
page_prop::{CachePolicy, PageFlags},
|
||||||
MAX_USERSPACE_VADDR,
|
MAX_USERSPACE_VADDR,
|
||||||
},
|
},
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
impl_page_meta,
|
||||||
mm::{
|
mm::{
|
||||||
kspace::kvirt_area::{KVirtArea, Tracked},
|
kspace::kvirt_area::{KVirtArea, Tracked},
|
||||||
page::{allocator, meta::KernelStackMeta},
|
page::allocator,
|
||||||
page_prop::{CachePolicy, PageFlags, PageProperty, PrivilegedPageFlags},
|
page_prop::{CachePolicy, PageFlags, PageProperty, PrivilegedPageFlags},
|
||||||
PAGE_SIZE,
|
PAGE_SIZE,
|
||||||
},
|
},
|
||||||
@ -34,6 +35,11 @@ pub struct KernelStack {
|
|||||||
has_guard_page: bool,
|
has_guard_page: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct KernelStackMeta {}
|
||||||
|
|
||||||
|
impl_page_meta!(KernelStackMeta);
|
||||||
|
|
||||||
impl KernelStack {
|
impl KernelStack {
|
||||||
/// Generates a kernel stack with guard pages.
|
/// Generates a kernel stack with guard pages.
|
||||||
/// 4 additional pages are allocated and regarded as guard pages, which should not be accessed.
|
/// 4 additional pages are allocated and regarded as guard pages, which should not be accessed.
|
||||||
|
Reference in New Issue
Block a user