Skip to main content

ax_cpu/
paging.rs

1//! Page-table metadata for the active architecture.
2
3use ax_memory_addr::VirtAddr;
4use page_table_generic::TableMeta;
5
6bitflags::bitflags! {
7    /// Runtime stage-1 mapping permissions and memory attributes.
8    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
9    pub struct MappingFlags: usize {
10        /// The memory is readable.
11        const READ = 1 << 0;
12        /// The memory is writable.
13        const WRITE = 1 << 1;
14        /// The memory is executable.
15        const EXECUTE = 1 << 2;
16        /// The memory is accessible from a lower-privileged context.
17        const USER = 1 << 3;
18        /// The memory is device memory.
19        const DEVICE = 1 << 4;
20        /// The memory is uncached.
21        const UNCACHED = 1 << 5;
22    }
23}
24
25impl From<crate::trap::PageFaultFlags> for MappingFlags {
26    fn from(fault: crate::trap::PageFaultFlags) -> Self {
27        let mut flags = Self::empty();
28        flags.set(
29            Self::READ,
30            fault.contains(crate::trap::PageFaultFlags::READ),
31        );
32        flags.set(
33            Self::WRITE,
34            fault.contains(crate::trap::PageFaultFlags::WRITE),
35        );
36        flags.set(
37            Self::EXECUTE,
38            fault.contains(crate::trap::PageFaultFlags::EXECUTE),
39        );
40        flags.set(
41            Self::USER,
42            fault.contains(crate::trap::PageFaultFlags::USER),
43        );
44        flags
45    }
46}
47
48cfg_if::cfg_if! {
49    if #[cfg(target_arch = "x86_64")] {
50        use crate::x86_64::paging::{
51            LEVEL_BITS as ARCH_LEVEL_BITS, MAX_BLOCK_LEVEL as ARCH_MAX_BLOCK_LEVEL,
52            PAGE_SIZE as ARCH_PAGE_SIZE, X64Pte as ArchPte,
53        };
54    } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
55        use crate::riscv::paging::{
56            LEVEL_BITS as ARCH_LEVEL_BITS, MAX_BLOCK_LEVEL as ARCH_MAX_BLOCK_LEVEL,
57            PAGE_SIZE as ARCH_PAGE_SIZE, Rv64Pte as ArchPte,
58        };
59    } else if #[cfg(target_arch = "aarch64")] {
60        use crate::aarch64::paging::{
61            A64Pte as ArchPte, LEVEL_BITS as ARCH_LEVEL_BITS,
62            MAX_BLOCK_LEVEL as ARCH_MAX_BLOCK_LEVEL, PAGE_SIZE as ARCH_PAGE_SIZE,
63        };
64    } else if #[cfg(target_arch = "loongarch64")] {
65        use crate::loongarch64::paging::{
66            LEVEL_BITS as ARCH_LEVEL_BITS, La64Pte as ArchPte,
67            MAX_BLOCK_LEVEL as ARCH_MAX_BLOCK_LEVEL, PAGE_SIZE as ARCH_PAGE_SIZE,
68        };
69    }
70}
71
72/// Page-table metadata for the active target architecture.
73#[derive(Clone, Copy)]
74pub struct ArchPagingMeta;
75
76impl TableMeta for ArchPagingMeta {
77    type P = ArchPte;
78
79    const PAGE_SIZE: usize = ARCH_PAGE_SIZE;
80    const LEVEL_BITS: &'static [usize] = ARCH_LEVEL_BITS;
81    const MAX_BLOCK_LEVEL: usize = ARCH_MAX_BLOCK_LEVEL;
82
83    fn canonicalize_vaddr(vaddr: VirtAddr) -> VirtAddr {
84        let address_bits = ARCH_PAGE_SIZE.trailing_zeros() as usize
85            + ARCH_LEVEL_BITS.iter().copied().sum::<usize>();
86        let mask = (1usize << address_bits) - 1;
87        let address = vaddr.as_usize() & mask;
88        if address & (1usize << (address_bits - 1)) == 0 {
89            VirtAddr::from_usize(address)
90        } else {
91            VirtAddr::from_usize(address | !mask)
92        }
93    }
94
95    fn flush(vaddr: Option<VirtAddr>) {
96        crate::asm::flush_tlb(vaddr);
97    }
98}