ax_cpu/arch/x86_64/paging/
native.rs1use ax_memory_addr::{PAGE_SIZE_4K, PhysAddr};
4use page_table_generic::PageTableEntry;
5
6use crate::paging::MappingFlags;
7
8pub(crate) const PAGE_SIZE: usize = PAGE_SIZE_4K;
9pub(crate) const LEVEL_BITS: &[usize] = &[9, 9, 9, 9];
10pub(crate) const MAX_BLOCK_LEVEL: usize = 3;
11
12bitflags::bitflags! {
13 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
15 pub struct DescriptorFlags: u64 {
16 const PRESENT = 1 << 0;
18 const WRITABLE = 1 << 1;
20 const USER = 1 << 2;
22 const WRITE_THROUGH = 1 << 3;
24 const NO_CACHE = 1 << 4;
26 const ACCESSED = 1 << 5;
28 const DIRTY = 1 << 6;
30 const HUGE_PAGE = 1 << 7;
32 const GLOBAL = 1 << 8;
34 const NO_EXECUTE = 1 << 63;
36 }
37}
38
39#[derive(Clone, Copy, Default)]
41#[repr(transparent)]
42pub struct X64Pte(u64);
43
44pub type Pte = X64Pte;
46
47impl X64Pte {
48 const PHYS_ADDR_MASK: u64 = 0x000f_ffff_ffff_f000;
49
50 pub const fn from_parts(paddr: PhysAddr, flags: DescriptorFlags) -> Self {
57 Self((paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK) | flags.bits())
58 }
59
60 pub fn flags(self) -> DescriptorFlags {
62 DescriptorFlags::from_bits_truncate(self.0)
63 }
64}
65
66impl PageTableEntry for X64Pte {
67 type PteConfig = MappingFlags;
68
69 fn new_page(paddr: PhysAddr, config: Self::PteConfig, is_huge: bool) -> Self {
70 if config.is_empty() && paddr.as_usize() == 0 {
71 return Self(0);
72 }
73 if config.is_empty() {
74 let huge = if is_huge {
75 DescriptorFlags::HUGE_PAGE.bits()
76 } else {
77 0
78 };
79 return Self((paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK) | huge);
80 }
81
82 let mut flags = DescriptorFlags::PRESENT;
83 if config.contains(MappingFlags::WRITE) {
84 flags |= DescriptorFlags::WRITABLE;
85 }
86 if config.contains(MappingFlags::USER) {
87 flags |= DescriptorFlags::USER;
88 }
89 if config.intersects(MappingFlags::DEVICE | MappingFlags::UNCACHED) {
90 flags |= DescriptorFlags::NO_CACHE | DescriptorFlags::WRITE_THROUGH;
91 }
92 if !config.contains(MappingFlags::EXECUTE) {
93 flags |= DescriptorFlags::NO_EXECUTE;
94 }
95 if is_huge {
96 flags |= DescriptorFlags::HUGE_PAGE;
97 }
98 Self::from_parts(paddr, flags)
99 }
100
101 fn new_table(paddr: PhysAddr) -> Self {
102 Self::from_parts(
103 paddr,
104 DescriptorFlags::PRESENT | DescriptorFlags::WRITABLE | DescriptorFlags::USER,
105 )
106 }
107
108 fn paddr(&self, _is_dir: bool) -> PhysAddr {
109 PhysAddr::from_usize((self.0 & Self::PHYS_ADDR_MASK) as usize)
110 }
111
112 fn config(&self, _is_dir: bool) -> Self::PteConfig {
113 let flags = self.flags();
114 if !flags.contains(DescriptorFlags::PRESENT) {
115 return MappingFlags::empty();
116 }
117 let mut config = MappingFlags::READ;
118 config.set(
119 MappingFlags::WRITE,
120 flags.contains(DescriptorFlags::WRITABLE),
121 );
122 config.set(
123 MappingFlags::EXECUTE,
124 !flags.contains(DescriptorFlags::NO_EXECUTE),
125 );
126 config.set(MappingFlags::USER, flags.contains(DescriptorFlags::USER));
127 config.set(
128 MappingFlags::UNCACHED,
129 flags.contains(DescriptorFlags::NO_CACHE),
130 );
131 config
132 }
133
134 fn present(&self) -> bool {
135 self.flags().contains(DescriptorFlags::PRESENT)
136 }
137
138 fn huge(&self, is_dir: bool) -> bool {
139 is_dir && self.flags().contains(DescriptorFlags::HUGE_PAGE)
140 }
141
142 fn unused(&self) -> bool {
143 self.0 == 0
144 }
145
146 fn clear(&mut self) {
147 self.0 = 0;
148 }
149}
150
151impl core::fmt::Debug for X64Pte {
152 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
153 f.debug_struct("X64Pte")
154 .field("raw", &self.0)
155 .field("config", &self.config(false))
156 .finish()
157 }
158}