proka_kernel/memory/
protection.rs1use x86_64::structures::paging::PageTableFlags;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum Protection {
12 ReadExecute,
14 Read,
16 ReadWriteExecute,
18 ReadWrite,
20 None,
22}
23
24impl Protection {
25 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 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 pub fn can_write(self) -> bool {
60 matches!(self, Protection::ReadWrite | Protection::ReadWriteExecute)
61 }
62
63 pub fn can_execute(self) -> bool {
65 matches!(self, Protection::ReadExecute | Protection::ReadWriteExecute)
66 }
67
68 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
98pub fn kernel_flags(writable: bool) -> PageTableFlags {
100 let mut flags = PageTableFlags::PRESENT;
101 if writable {
102 flags |= PageTableFlags::WRITABLE;
103 }
104 flags
105}
106
107pub fn user_flags(protection: Protection) -> PageTableFlags {
109 protection.to_flags()
110}
111
112pub fn read_only_flags() -> PageTableFlags {
114 PageTableFlags::PRESENT | PageTableFlags::NO_EXECUTE
115}
116
117pub fn writable_flags() -> PageTableFlags {
119 PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE
120}
121
122pub fn executable_flags() -> PageTableFlags {
124 PageTableFlags::PRESENT
125}
126
127pub fn read_write_execute_flags() -> PageTableFlags {
129 PageTableFlags::PRESENT | PageTableFlags::WRITABLE
130}
131
132pub fn flags_can_read(flags: PageTableFlags) -> bool {
134 flags.contains(PageTableFlags::PRESENT)
135}
136
137pub fn flags_can_write(flags: PageTableFlags) -> bool {
139 flags.contains(PageTableFlags::PRESENT) && flags.contains(PageTableFlags::WRITABLE)
140}
141
142pub 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}