tartan_arch/x86_common/paging.rs
1//! Support for virtual memory paging.
2
3use crate::simple_register_access;
4use tartan_bitfield::{bitfield, bitfield_accessors, Bitfield};
5
6#[cfg(doc)]
7use super::features::BasicFeatures;
8#[cfg(doc)]
9use super::ControlRegister4;
10#[cfg(doc)]
11use crate::x86_64::ExtendedFeatureEnableRegister;
12
13
14bitfield! {
15 /// `CR2`: Contains the address that triggered a page fault.
16 pub struct ControlRegister2(usize) {}
17}
18
19simple_register_access!(ControlRegister2, "cr2");
20
21
22bitfield! {
23 /// `CR3`: System control register that contains the top-level page table address
24 /// and two associated caching flags.
25 ///
26 /// Getters and setters for this structure only access a value in memory, not the
27 /// register itself. Use the [`get`](Self::get) and [`set`](Self::set) methods to work
28 /// with the actual register.
29 pub struct ControlRegister3(usize) {
30 /// `CR3.PWT`: Enables write-through caching for the top-level page table.
31 ///
32 /// Does not apply when [`ControlRegister4::process_context_ids`] or
33 /// [`ControlRegister4::physical_address_extension`] is enabled.
34 [3] pub write_through,
35
36 /// `CR3.PCD`: Disables caching for the top-level page table.
37 ///
38 /// Does not apply when [`ControlRegister4::process_context_ids`] or
39 /// [`ControlRegister4::physical_address_extension`] is enabled.
40 [4] pub cache_disabled,
41
42 /// `CR4.PCIDE`: The process-context identifier (PCID) associated with this
43 /// series of page tables.
44 ///
45 /// Requires 64-bit mode and [`ControlRegister4::process_context_ids`].
46 #[cfg(any(target_arch = "x86_64", doc))]
47 #[doc(cfg(target_arch = "x86_64"))]
48 [0..11] pub process_context_id: u16,
49 }
50}
51
52simple_register_access!(ControlRegister3, "cr3");
53
54impl ControlRegister3 {
55 const ADDRESS_MASK: usize = !0xfff;
56
57 /// Get the address of the top-level page table.
58 pub fn address(self) -> usize {
59 self.0 & Self::ADDRESS_MASK
60 }
61
62 /// Set the address of the top-level page table.
63 ///
64 /// # Panics
65 /// Panics if the new address is not 4K-aligned.
66 pub fn set_address(&mut self, value: usize) {
67 assert!(
68 value & Self::ADDRESS_MASK == 0,
69 "Invalid page table address {value:#x}. Must be 4K aligned."
70 );
71 self.0 &= !Self::ADDRESS_MASK;
72 self.0 |= value;
73 }
74}
75
76
77/// An entry in a page table at any level.
78pub trait GenericPageTableEntry: Bitfield<usize> {
79 bitfield_accessors! {
80 /// `P`: Indicates that this entry is mapped. Otherwise the whole entry is
81 /// ignored.
82 [0] present,
83
84 /// `R/W`: Allows writes to this memory region.
85 [1] writable,
86
87 /// `U/S`: Allows access to this memory region from permission level 3. Otherwise,
88 /// it is only accessible from levels 0–2.
89 [2] user,
90
91 /// `PWT`: Enables write-through caching for this memory region.
92 [3] write_through,
93
94 /// `PCD`: Disables caching for this memory region.
95 [4] cache_disabled,
96
97 /// `A`: Set by the processor when an instruction accesses the memory region.
98 [5] accessed,
99
100 /// `XD`/`NX`: Prevent the processor from executing any instructions in this
101 /// memory region.
102 ///
103 /// Requires [`ExtendedFeatureEnableRegister::no_execute`].
104 #[cfg(any(target_arch = "x86_64", doc))]
105 #[doc(cfg(target_arch = "x86_64"))]
106 [63] no_execute,
107 }
108}
109
110
111/// An page table entry (any level) that directly maps a page.
112pub trait DirectPageTableEntry: GenericPageTableEntry {
113 bitfield_accessors! {
114 /// `D`: Set by the processor when an instruction modifies the memory region.
115 [6] dirty,
116
117 /// `PAT`: Used to associate this page with a page attribute table.
118 ///
119 /// In 32-bit mode, requires [`BasicFeatures::page_attribute_table`]. Always
120 /// applicable in 64-bit mode.
121 //
122 // NOTE: This bit is remapped for implementations of `HybridPageTableEntry`.
123 [7] attribute_table,
124
125 /// `G`: Indicates that this is a global page shared by all task contexts.
126 ///
127 /// Requires [`ControlRegister4::global_pages`].
128 [8] global,
129
130 /// The protection key that applies to this memory region.
131 ///
132 /// Requires [`ControlRegister4::user_protection_keys`] or
133 /// [`ControlRegister4::supervisor_protection_keys`].
134 #[cfg(any(target_arch = "x86_64", doc))]
135 #[doc(cfg(target_arch = "x86_64"))]
136 [59..63] protection_key: u8,
137 }
138}
139
140
141/// A page table entry (any level) that either directly maps a page or points to another
142/// page table.
143///
144/// This trait provides an implementation for [`DirectPageTableEntry`], but its methods
145/// are only applicable if [`is_page`](Self::is_page) is true.
146pub trait HybridPageTableEntry: GenericPageTableEntry {
147 bitfield_accessors! {
148 /// `PS`: Indicates that this entry directly maps a page. Otherwise, this
149 /// is a pointer to a lower-level page table.
150 ///
151 /// In 32-bit mode, requires [`ControlRegister4::page_size_extensions`]. Always
152 /// applicable in 64-bit mode.
153 [7] is_page,
154 }
155}
156
157impl<T> DirectPageTableEntry for T
158where
159 T: HybridPageTableEntry,
160{
161 bitfield_accessors! {
162 // This field is moved in hybrid page tables, because it conflicts with `is_page`.
163 [12] attribute_table,
164 }
165}
166
167
168bitfield! {
169 /// Second-level page table (page directory) entry that either points to a
170 /// bottom-level page table or directly maps a 2MB/4MB page.
171 pub struct Level2PageTableEntry(usize) {}
172}
173
174impl GenericPageTableEntry for Level2PageTableEntry {}
175impl HybridPageTableEntry for Level2PageTableEntry {}
176
177
178bitfield! {
179 /// Bottom-level page table entry that maps a single 4KB page.
180 pub struct Level1PageTableEntry(usize) {}
181}
182
183impl GenericPageTableEntry for Level1PageTableEntry {}
184impl DirectPageTableEntry for Level1PageTableEntry {}