ax_cpu/arch/x86_64/paging/
ept.rs1use crate::{PhysAddr, paging::PageTableEntry};
5
6bitflags::bitflags! {
7 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
9 pub struct EptFlags: u64 {
10 const READ = 1 << 0;
12 const WRITE = 1 << 1;
14 const EXECUTE = 1 << 2;
16 const MEM_TYPE_MASK = 7 << 3;
18 const IGNORE_PAT = 1 << 6;
20 const HUGE_PAGE = 1 << 7;
22 const ACCESSED = 1 << 8;
24 const DIRTY = 1 << 9;
26 const EXECUTE_FOR_USER = 1 << 10;
28 }
29}
30
31#[repr(u8)]
33#[derive(Clone, Copy, Debug, Eq, PartialEq)]
34pub enum EptMemoryType {
35 Uncached = 0,
37 WriteCombining = 1,
39 WriteThrough = 4,
41 WriteProtected = 5,
43 WriteBack = 6,
45}
46
47impl EptFlags {
48 pub const fn with_memory_type(self, memory_type: EptMemoryType) -> Self {
50 Self::from_bits_retain(
51 (self.bits() & !Self::MEM_TYPE_MASK.bits()) | ((memory_type as u64) << 3),
52 )
53 }
54
55 pub const fn memory_type(self) -> Option<EptMemoryType> {
57 match (self.bits() & Self::MEM_TYPE_MASK.bits()) >> 3 {
58 0 => Some(EptMemoryType::Uncached),
59 1 => Some(EptMemoryType::WriteCombining),
60 4 => Some(EptMemoryType::WriteThrough),
61 5 => Some(EptMemoryType::WriteProtected),
62 6 => Some(EptMemoryType::WriteBack),
63 _ => None,
64 }
65 }
66}
67
68#[repr(transparent)]
70#[derive(Clone, Copy, Default)]
71pub struct EptEntry(u64);
72
73impl EptEntry {
74 const PHYS_ADDR_MASK: u64 = 0x000f_ffff_ffff_f000;
75
76 pub const fn from_parts(paddr: PhysAddr, flags: EptFlags) -> Self {
82 Self((paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK) | flags.bits())
83 }
84
85 pub fn flags(self) -> EptFlags {
87 EptFlags::from_bits_truncate(self.0)
88 }
89}
90
91impl PageTableEntry for EptEntry {
92 type PteConfig = EptFlags;
93
94 fn new_page(paddr: PhysAddr, mut flags: EptFlags, is_huge: bool) -> Self {
95 flags.set(EptFlags::HUGE_PAGE, is_huge);
96 Self::from_parts(paddr, flags)
97 }
98
99 fn new_table(paddr: PhysAddr) -> Self {
100 Self::from_parts(paddr, EptFlags::READ | EptFlags::WRITE | EptFlags::EXECUTE)
101 }
102
103 fn paddr(&self, _is_dir: bool) -> PhysAddr {
104 PhysAddr::from_usize((self.0 & Self::PHYS_ADDR_MASK) as usize)
105 }
106
107 fn config(&self, _is_dir: bool) -> EptFlags {
108 self.flags()
109 }
110
111 fn present(&self) -> bool {
112 self.flags()
113 .intersects(EptFlags::READ | EptFlags::WRITE | EptFlags::EXECUTE)
114 }
115
116 fn huge(&self, is_dir: bool) -> bool {
117 is_dir && self.flags().contains(EptFlags::HUGE_PAGE)
118 }
119
120 fn unused(&self) -> bool {
121 self.0 == 0
122 }
123
124 fn clear(&mut self) {
125 self.0 = 0;
126 }
127}
128
129impl core::fmt::Debug for EptEntry {
130 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
131 f.debug_struct("EptEntry")
132 .field("raw", &self.0)
133 .field("paddr", &self.paddr(false))
134 .field("flags", &self.flags())
135 .field("memory_type", &self.flags().memory_type())
136 .finish()
137 }
138}