Skip to main content

proka_kernel/memory/
protection.rs

1//! Page protection flags and utilities
2//! Copyright (C) RainSTR Studio 2025, All Rights Reserved.
3//!
4//! This module provides page protection bit definitions and utilities
5//! for managing memory access permissions.
6
7use x86_64::structures::paging::PageTableFlags;
8
9/// Page protection flags with human-readable descriptions
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum Protection {
12    /// Read-only, executable
13    ReadExecute,
14    /// Read-only, non-executable
15    Read,
16    /// Read-write, executable
17    ReadWriteExecute,
18    /// Read-write, non-executable
19    ReadWrite,
20    /// No access (page not present)
21    None,
22}
23
24impl Protection {
25    /// Convert protection to x86_64 page table flags
26    pub fn to_flags(self) -> PageTableFlags {
27        match self {
28            Protection::ReadExecute => PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE,
29            Protection::Read => {
30                PageTableFlags::PRESENT
31                    | PageTableFlags::USER_ACCESSIBLE
32                    | PageTableFlags::NO_EXECUTE
33            }
34            Protection::ReadWriteExecute => {
35                PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE
36            }
37            Protection::ReadWrite => {
38                PageTableFlags::PRESENT
39                    | PageTableFlags::WRITABLE
40                    | PageTableFlags::USER_ACCESSIBLE
41                    | PageTableFlags::NO_EXECUTE
42            }
43            Protection::None => PageTableFlags::empty(),
44        }
45    }
46
47    /// Check if protection allows reading
48    pub fn can_read(self) -> bool {
49        matches!(
50            self,
51            Protection::Read
52                | Protection::ReadWrite
53                | Protection::ReadExecute
54                | Protection::ReadWriteExecute
55        )
56    }
57
58    /// Check if protection allows writing
59    pub fn can_write(self) -> bool {
60        matches!(self, Protection::ReadWrite | Protection::ReadWriteExecute)
61    }
62
63    /// Check if protection allows execution
64    pub fn can_execute(self) -> bool {
65        matches!(self, Protection::ReadExecute | Protection::ReadWriteExecute)
66    }
67
68    /// Get protection description
69    pub fn description(self) -> &'static str {
70        match self {
71            Protection::ReadExecute => "read+execute",
72            Protection::Read => "read-only",
73            Protection::ReadWriteExecute => "read+write+execute",
74            Protection::ReadWrite => "read+write",
75            Protection::None => "no access",
76        }
77    }
78}
79
80impl From<PageTableFlags> for Protection {
81    fn from(flags: PageTableFlags) -> Self {
82        if !flags.contains(PageTableFlags::PRESENT) {
83            return Protection::None;
84        }
85
86        let writable = flags.contains(PageTableFlags::WRITABLE);
87        let no_execute = flags.contains(PageTableFlags::NO_EXECUTE);
88
89        match (writable, no_execute) {
90            (false, false) => Protection::ReadExecute,
91            (false, true) => Protection::Read,
92            (true, false) => Protection::ReadWriteExecute,
93            (true, true) => Protection::ReadWrite,
94        }
95    }
96}
97
98/// Create kernel page flags (always executable, can be read-write or read-only)
99pub fn kernel_flags(writable: bool) -> PageTableFlags {
100    let mut flags = PageTableFlags::PRESENT;
101    if writable {
102        flags |= PageTableFlags::WRITABLE;
103    }
104    flags
105}
106
107/// Create user page flags with specified protection
108pub fn user_flags(protection: Protection) -> PageTableFlags {
109    protection.to_flags()
110}
111
112/// Create read-only page flags (for both kernel and user)
113pub fn read_only_flags() -> PageTableFlags {
114    PageTableFlags::PRESENT | PageTableFlags::NO_EXECUTE
115}
116
117/// Create writable page flags (for both kernel and user)
118pub fn writable_flags() -> PageTableFlags {
119    PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE
120}
121
122/// Create executable page flags
123pub fn executable_flags() -> PageTableFlags {
124    PageTableFlags::PRESENT
125}
126
127/// Create read-write-executable page flags
128pub fn read_write_execute_flags() -> PageTableFlags {
129    PageTableFlags::PRESENT | PageTableFlags::WRITABLE
130}
131
132/// Check if page table flags allow read access
133pub fn flags_can_read(flags: PageTableFlags) -> bool {
134    flags.contains(PageTableFlags::PRESENT)
135}
136
137/// Check if page table flags allow write access
138pub fn flags_can_write(flags: PageTableFlags) -> bool {
139    flags.contains(PageTableFlags::PRESENT) && flags.contains(PageTableFlags::WRITABLE)
140}
141
142/// Check if page table flags allow execute access
143pub fn flags_can_execute(flags: PageTableFlags) -> bool {
144    flags.contains(PageTableFlags::PRESENT) && !flags.contains(PageTableFlags::NO_EXECUTE)
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test_case]
152    fn test_protection_to_flags() {
153        let flags = Protection::Read.to_flags();
154        assert!(flags.contains(PageTableFlags::PRESENT));
155        assert!(flags.contains(PageTableFlags::USER_ACCESSIBLE));
156        assert!(flags.contains(PageTableFlags::NO_EXECUTE));
157        assert!(!flags.contains(PageTableFlags::WRITABLE));
158
159        let flags = Protection::ReadWrite.to_flags();
160        assert!(flags.contains(PageTableFlags::PRESENT));
161        assert!(flags.contains(PageTableFlags::USER_ACCESSIBLE));
162        assert!(flags.contains(PageTableFlags::NO_EXECUTE));
163        assert!(flags.contains(PageTableFlags::WRITABLE));
164
165        let flags = Protection::ReadExecute.to_flags();
166        assert!(flags.contains(PageTableFlags::PRESENT));
167        assert!(flags.contains(PageTableFlags::USER_ACCESSIBLE));
168        assert!(!flags.contains(PageTableFlags::NO_EXECUTE));
169        assert!(!flags.contains(PageTableFlags::WRITABLE));
170
171        let flags = Protection::ReadWriteExecute.to_flags();
172        assert!(flags.contains(PageTableFlags::PRESENT));
173        assert!(flags.contains(PageTableFlags::USER_ACCESSIBLE));
174        assert!(!flags.contains(PageTableFlags::NO_EXECUTE));
175        assert!(flags.contains(PageTableFlags::WRITABLE));
176
177        let flags = Protection::None.to_flags();
178        assert!(!flags.contains(PageTableFlags::PRESENT));
179    }
180
181    #[test_case]
182    fn test_protection_from_flags() {
183        let flags =
184            PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | PageTableFlags::NO_EXECUTE;
185        assert_eq!(Protection::from(flags), Protection::Read);
186
187        let flags = PageTableFlags::PRESENT
188            | PageTableFlags::USER_ACCESSIBLE
189            | PageTableFlags::NO_EXECUTE
190            | PageTableFlags::WRITABLE;
191        assert_eq!(Protection::from(flags), Protection::ReadWrite);
192
193        let flags = PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE;
194        assert_eq!(Protection::from(flags), Protection::ReadExecute);
195
196        let flags =
197            PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | PageTableFlags::WRITABLE;
198        assert_eq!(Protection::from(flags), Protection::ReadWriteExecute);
199
200        let flags = PageTableFlags::empty();
201        assert_eq!(Protection::from(flags), Protection::None);
202    }
203
204    #[test_case]
205    fn test_kernel_flags() {
206        let flags = kernel_flags(false);
207        assert!(flags.contains(PageTableFlags::PRESENT));
208        assert!(!flags.contains(PageTableFlags::WRITABLE));
209        assert!(!flags.contains(PageTableFlags::USER_ACCESSIBLE));
210
211        let flags = kernel_flags(true);
212        assert!(flags.contains(PageTableFlags::PRESENT));
213        assert!(flags.contains(PageTableFlags::WRITABLE));
214        assert!(!flags.contains(PageTableFlags::USER_ACCESSIBLE));
215    }
216
217    #[test_case]
218    fn test_user_flags() {
219        let flags = user_flags(Protection::Read);
220        assert_eq!(flags, Protection::Read.to_flags());
221
222        let flags = user_flags(Protection::ReadWrite);
223        assert_eq!(flags, Protection::ReadWrite.to_flags());
224
225        let flags = user_flags(Protection::ReadExecute);
226        assert_eq!(flags, Protection::ReadExecute.to_flags());
227
228        let flags = user_flags(Protection::ReadWriteExecute);
229        assert_eq!(flags, Protection::ReadWriteExecute.to_flags());
230    }
231
232    #[test_case]
233    fn test_read_only_flags() {
234        let flags = read_only_flags();
235        assert!(flags.contains(PageTableFlags::PRESENT));
236        assert!(flags.contains(PageTableFlags::NO_EXECUTE));
237        assert!(!flags.contains(PageTableFlags::WRITABLE));
238        assert!(!flags.contains(PageTableFlags::USER_ACCESSIBLE));
239    }
240
241    #[test_case]
242    fn test_writable_flags() {
243        let flags = writable_flags();
244        assert!(flags.contains(PageTableFlags::PRESENT));
245        assert!(flags.contains(PageTableFlags::NO_EXECUTE));
246        assert!(flags.contains(PageTableFlags::WRITABLE));
247        assert!(!flags.contains(PageTableFlags::USER_ACCESSIBLE));
248    }
249
250    #[test_case]
251    fn test_executable_flags() {
252        let flags = executable_flags();
253        assert!(flags.contains(PageTableFlags::PRESENT));
254        assert!(!flags.contains(PageTableFlags::NO_EXECUTE));
255        assert!(!flags.contains(PageTableFlags::WRITABLE));
256        assert!(!flags.contains(PageTableFlags::USER_ACCESSIBLE));
257    }
258
259    #[test_case]
260    fn test_read_write_execute_flags() {
261        let flags = read_write_execute_flags();
262        assert!(flags.contains(PageTableFlags::PRESENT));
263        assert!(!flags.contains(PageTableFlags::NO_EXECUTE));
264        assert!(flags.contains(PageTableFlags::WRITABLE));
265        assert!(!flags.contains(PageTableFlags::USER_ACCESSIBLE));
266    }
267
268    #[test_case]
269    fn test_flags_can_read() {
270        let flags = PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE;
271        assert!(flags_can_read(flags));
272
273        let flags = PageTableFlags::empty();
274        assert!(!flags_can_read(flags));
275    }
276
277    #[test_case]
278    fn test_flags_can_write() {
279        let flags =
280            PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE;
281        assert!(flags_can_write(flags));
282
283        let flags = PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE;
284        assert!(!flags_can_write(flags));
285
286        let flags = PageTableFlags::empty();
287        assert!(!flags_can_write(flags));
288    }
289
290    #[test_case]
291    fn test_flags_can_execute() {
292        let flags = PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE;
293        assert!(flags_can_execute(flags));
294
295        let flags =
296            PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | PageTableFlags::NO_EXECUTE;
297        assert!(!flags_can_execute(flags));
298
299        let flags = PageTableFlags::empty();
300        assert!(!flags_can_execute(flags));
301    }
302}