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 {}