1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//! Support for virtual memory paging.

use crate::simple_register_access;
use tartan_bitfield::{bitfield, bitfield_accessors, Bitfield};

#[cfg(doc)]
use super::features::BasicFeatures;
#[cfg(doc)]
use super::ControlRegister4;
#[cfg(doc)]
use crate::x86_64::ExtendedFeatureEnableRegister;


bitfield! {
    /// `CR2`: Contains the address that triggered a page fault.
    pub struct ControlRegister2(usize) {}
}

simple_register_access!(ControlRegister2, "cr2");


bitfield! {
    /// `CR3`: System control register that contains the top-level page table address
    /// and two associated caching flags.
    ///
    /// Getters and setters for this structure only access a value in memory, not the
    /// register itself. Use the [`get`](Self::get) and [`set`](Self::set) methods to work
    /// with the actual register.
    pub struct ControlRegister3(usize) {
        /// `CR3.PWT`: Enables write-through caching for the top-level page table.
        ///
        /// Does not apply when [`ControlRegister4::process_context_ids`] or
        /// [`ControlRegister4::physical_address_extension`] is enabled.
        [3] pub write_through,

        /// `CR3.PCD`: Disables caching for the top-level page table.
        ///
        /// Does not apply when [`ControlRegister4::process_context_ids`] or
        /// [`ControlRegister4::physical_address_extension`] is enabled.
        [4] pub cache_disabled,

        /// `CR4.PCIDE`: The process-context identifier (PCID) associated with this
        /// series of page tables.
        ///
        /// Requires 64-bit mode and [`ControlRegister4::process_context_ids`].
        #[cfg(any(target_arch = "x86_64", doc))]
        #[doc(cfg(target_arch = "x86_64"))]
        [0..11] pub process_context_id: u16,
    }
}

simple_register_access!(ControlRegister3, "cr3");

impl ControlRegister3 {
    const ADDRESS_MASK: usize = !0xfff;

    /// Get the address of the top-level page table.
    pub fn address(self) -> usize {
        self.0 & Self::ADDRESS_MASK
    }

    /// Set the address of the top-level page table.
    ///
    /// # Panics
    /// Panics if the new address is not 4K-aligned.
    pub fn set_address(&mut self, value: usize) {
        assert!(
            value & Self::ADDRESS_MASK == 0,
            "Invalid page table address {value:#x}. Must be 4K aligned."
        );
        self.0 &= !Self::ADDRESS_MASK;
        self.0 |= value;
    }
}


/// An entry in a page table at any level.
pub trait GenericPageTableEntry: Bitfield<usize> {
    bitfield_accessors! {
        /// `P`: Indicates that this entry is mapped. Otherwise the whole entry is
        /// ignored.
        [0] present,

        /// `R/W`: Allows writes to this memory region.
        [1] writable,

        /// `U/S`: Allows access to this memory region from permission level 3. Otherwise,
        /// it is only accessible from levels 0–2.
        [2] user,

        /// `PWT`: Enables write-through caching for this memory region.
        [3] write_through,

        /// `PCD`: Disables caching for this memory region.
        [4] cache_disabled,

        /// `A`: Set by the processor when an instruction accesses the memory region.
        [5] accessed,

        /// `XD`/`NX`: Prevent the processor from executing any instructions in this
        /// memory region.
        ///
        /// Requires [`ExtendedFeatureEnableRegister::no_execute`].
        #[cfg(any(target_arch = "x86_64", doc))]
        #[doc(cfg(target_arch = "x86_64"))]
        [63] no_execute,
    }
}


/// An page table entry (any level) that directly maps a page.
pub trait DirectPageTableEntry: GenericPageTableEntry {
    bitfield_accessors! {
        /// `D`: Set by the processor when an instruction modifies the memory region.
        [6] dirty,

        /// `PAT`: Used to associate this page with a page attribute table.
        ///
        /// In 32-bit mode, requires [`BasicFeatures::page_attribute_table`]. Always
        /// applicable in 64-bit mode.
        //
        // NOTE: This bit is remapped for implementations of `HybridPageTableEntry`.
        [7] attribute_table,

        /// `G`: Indicates that this is a global page shared by all task contexts.
        ///
        /// Requires [`ControlRegister4::global_pages`].
        [8] global,

        /// The protection key that applies to this memory region.
        ///
        /// Requires [`ControlRegister4::user_protection_keys`] or
        /// [`ControlRegister4::supervisor_protection_keys`].
        #[cfg(any(target_arch = "x86_64", doc))]
        #[doc(cfg(target_arch = "x86_64"))]
        [59..63] protection_key: u8,
    }
}


/// A page table entry (any level) that either directly maps a page or points to another
/// page table.
///
/// This trait provides an implementation for [`DirectPageTableEntry`], but its methods
/// are only applicable if [`is_page`](Self::is_page) is true.
pub trait HybridPageTableEntry: GenericPageTableEntry {
    bitfield_accessors! {
        /// `PS`: Indicates that this entry directly maps a page. Otherwise, this
        /// is a pointer to a lower-level page table.
        ///
        /// In 32-bit mode, requires [`ControlRegister4::page_size_extensions`]. Always
        /// applicable in 64-bit mode.
        [7] is_page,
    }
}

impl<T> DirectPageTableEntry for T
where
    T: HybridPageTableEntry,
{
    bitfield_accessors! {
        // This field is moved in hybrid page tables, because it conflicts with `is_page`.
        [12] attribute_table,
    }
}


bitfield! {
    /// Second-level page table (page directory) entry that either points to a
    /// bottom-level page table or directly maps a 2MB/4MB page.
    pub struct Level2PageTableEntry(usize) {}
}

impl GenericPageTableEntry for Level2PageTableEntry {}
impl HybridPageTableEntry for Level2PageTableEntry {}


bitfield! {
    /// Bottom-level page table entry that maps a single 4KB page.
    pub struct Level1PageTableEntry(usize) {}
}

impl GenericPageTableEntry for Level1PageTableEntry {}
impl DirectPageTableEntry for Level1PageTableEntry {}