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 124 125 126 127 128 129 130 131 132
// SPDX-License-Identifier: MPL-2.0
//! Virtual memory (VM).
/// Virtual addresses.
pub type Vaddr = usize;
/// Physical addresses.
pub type Paddr = usize;
pub(crate) mod dma;
pub mod frame;
pub(crate) mod heap_allocator;
mod io;
pub(crate) mod kspace;
mod offset;
pub(crate) mod page;
pub(crate) mod page_prop;
pub(crate) mod page_table;
mod space;
use alloc::vec::Vec;
use core::{fmt::Debug, ops::Range};
use spin::Once;
pub use self::{
dma::{Daddr, DmaCoherent, DmaDirection, DmaStream, DmaStreamSlice, HasDaddr},
frame::{options::FrameAllocOptions, Frame, FrameVec, FrameVecIter, Segment},
io::{KernelSpace, UserSpace, VmIo, VmReader, VmWriter},
page_prop::{CachePolicy, PageFlags, PageProperty},
space::{VmMapOptions, VmSpace},
};
pub(crate) use self::{
kspace::paddr_to_vaddr, page::meta::init as init_page_meta, page_prop::PrivilegedPageFlags,
page_table::PageTable,
};
use crate::{
arch::mm::PagingConsts,
boot::memory_region::{MemoryRegion, MemoryRegionType},
};
/// 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 + Default + 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;
}
/// 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.
#[allow(dead_code)]
pub(crate) const fn nr_base_per_page<C: PagingConstsTrait>(level: PagingLevel) -> usize {
page_size::<C>(level) / C::BASE_PAGE_SIZE
}
/// The maximum virtual address of user space (non inclusive).
///
/// Typicall 64-bit systems have at least 48-bit virtual address space.
/// A typical way to reserve half of the address space for the kernel is
/// to use the highest 48-bit virtual address space.
///
/// Also, the top page is not regarded as usable since it's a workaround
/// for some x86_64 CPUs' bugs. See
/// <https://github.com/torvalds/linux/blob/480e035fc4c714fb5536e64ab9db04fedc89e910/arch/x86/include/asm/page_64.h#L68-L78>
/// for the rationale.
pub const MAX_USERSPACE_VADDR: Vaddr = 0x0000_8000_0000_0000 - PAGE_SIZE;
/// The kernel address space.
/// There are the high canonical addresses defined in most 48-bit width
/// architectures.
pub(crate) const KERNEL_VADDR_RANGE: Range<Vaddr> = 0xffff_8000_0000_0000..0xffff_ffff_ffff_0000;
/// Gets physical address trait
pub trait HasPaddr {
/// Returns the physical address.
fn paddr(&self) -> Paddr;
}
/// Checks if the given address is page-aligned.
pub const fn is_page_aligned(p: usize) -> bool {
(p & (PAGE_SIZE - 1)) == 0
}
/// Memory regions used for frame buffer.
pub static FRAMEBUFFER_REGIONS: Once<Vec<MemoryRegion>> = Once::new();
pub(crate) fn misc_init() {
dma::init();
let mut framebuffer_regions = Vec::new();
for i in crate::boot::memory_regions() {
if i.typ() == MemoryRegionType::Framebuffer {
framebuffer_regions.push(*i);
}
}
FRAMEBUFFER_REGIONS.call_once(|| framebuffer_regions);
}