ostd/mm/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
// SPDX-License-Identifier: MPL-2.0
//! Virtual memory (VM).
#![cfg_attr(
any(target_arch = "riscv64", target_arch = "loongarch64"),
expect(unused_imports)
)]
pub(crate) mod dma;
pub mod frame;
pub mod heap;
pub mod io;
pub mod io_util;
pub(crate) mod kspace;
pub(crate) mod mem_obj;
pub(crate) mod page_prop;
pub(crate) mod page_table;
pub mod tlb;
pub mod vm_space;
#[cfg(ktest)]
mod test;
use core::fmt::Debug;
pub use self::{
dma::{DmaCoherent, DmaDirection, DmaStream},
frame::{
allocator::FrameAllocOptions,
segment::{Segment, USegment},
unique::UniqueFrame,
untyped::{AnyUFrameMeta, UFrame},
Frame,
},
io::{
Fallible, FallibleVmRead, FallibleVmWrite, Infallible, PodAtomic, PodOnce, VmIo, VmIoFill,
VmIoOnce, VmReader, VmWriter,
},
kspace::{KERNEL_VADDR_RANGE, MAX_USERSPACE_VADDR},
mem_obj::{HasDaddr, HasPaddr, HasPaddrRange, HasSize},
page_prop::{CachePolicy, PageFlags, PageProperty},
vm_space::VmSpace,
};
pub(crate) use self::{
kspace::paddr_to_vaddr, page_prop::PrivilegedPageFlags, page_table::PageTable,
};
use crate::arch::mm::PagingConsts;
/// Virtual addresses.
pub type Vaddr = usize;
/// Physical addresses.
pub type Paddr = usize;
/// Device addresses.
pub type Daddr = usize;
/// The level of a page table node or a frame.
pub type PagingLevel = u8;
/// A minimal set of constants that determines the paging system.
/// This provides an abstraction over most paging modes in common architectures.
pub(crate) trait PagingConstsTrait: Clone + Debug + Send + Sync + 'static {
/// The smallest page size.
/// This is also the page size at level 1 page tables.
const BASE_PAGE_SIZE: usize;
/// The number of levels in the page table.
/// The numbering of levels goes from deepest node to the root node. For example,
/// the level 1 to 5 on AMD64 corresponds to Page Tables, Page Directory Tables,
/// Page Directory Pointer Tables, Page-Map Level-4 Table, and Page-Map Level-5
/// Table, respectively.
const NR_LEVELS: PagingLevel;
/// The highest level that a PTE can be directly used to translate a VA.
/// This affects the the largest page size supported by the page table.
const HIGHEST_TRANSLATION_LEVEL: PagingLevel;
/// The size of a PTE.
const PTE_SIZE: usize;
/// The address width may be BASE_PAGE_SIZE.ilog2() + NR_LEVELS * IN_FRAME_INDEX_BITS.
/// If it is shorter than that, the higher bits in the highest level are ignored.
const ADDRESS_WIDTH: usize;
/// Whether virtual addresses are sign-extended.
///
/// The sign bit of a [`Vaddr`] is the bit at index [`PagingConstsTrait::ADDRESS_WIDTH`] - 1.
/// If this constant is `true`, bits in [`Vaddr`] that are higher than the sign bit must be
/// equal to the sign bit. If an address violates this rule, both the hardware and OSTD
/// should reject it.
///
/// Otherwise, if this constant is `false`, higher bits must be zero.
///
/// Regardless of sign extension, [`Vaddr`] is always not signed upon calculation.
/// That means, `0xffff_ffff_ffff_0000 < 0xffff_ffff_ffff_0001` is `true`.
const VA_SIGN_EXT: bool;
}
/// The page size
pub const PAGE_SIZE: usize = page_size::<PagingConsts>(1);
/// The page size at a given level.
pub(crate) const fn page_size<C: PagingConstsTrait>(level: PagingLevel) -> usize {
C::BASE_PAGE_SIZE << (nr_subpage_per_huge::<C>().ilog2() as usize * (level as usize - 1))
}
/// The number of sub pages in a huge page.
pub(crate) const fn nr_subpage_per_huge<C: PagingConstsTrait>() -> usize {
C::BASE_PAGE_SIZE / C::PTE_SIZE
}
/// The number of base pages in a huge page at a given level.
#[expect(dead_code)]
pub(crate) const fn nr_base_per_page<C: PagingConstsTrait>(level: PagingLevel) -> usize {
page_size::<C>(level) / C::BASE_PAGE_SIZE
}
/// Checks if the given address is page-aligned.
pub const fn is_page_aligned(p: usize) -> bool {
(p & (PAGE_SIZE - 1)) == 0
}