Skip to content

Commit 8468914

Browse files
authored
Merge pull request #484 from Wasabi375/page_not_present
add Mapper::clear to clear any page table entry regardless of present flag
2 parents f53cbec + ec292d1 commit 8468914

File tree

5 files changed

+289
-17
lines changed

5 files changed

+289
-17
lines changed

Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Unreleased
22

3+
## Breaking changes
4+
5+
- [add `Mapper::clear` to clear any page table entry regardless of the present flag](https://github.com/rust-osdev/x86_64/pull/484)
6+
- [`Mapper::unmap` now also returns the flags of the page ](https://github.com/rust-osdev/x86_64/pull/484)
7+
38
# 0.15.1 – 2024-03-19
49

510
## New Features

src/structures/paging/mapper/mapped_page_table.rs

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ impl<'a, P: PageTableFrameMapping> Mapper<Size1GiB> for MappedPageTable<'a, P> {
169169
fn unmap(
170170
&mut self,
171171
page: Page<Size1GiB>,
172-
) -> Result<(PhysFrame<Size1GiB>, MapperFlush<Size1GiB>), UnmapError> {
172+
) -> Result<(PhysFrame<Size1GiB>, PageTableFlags, MapperFlush<Size1GiB>), UnmapError> {
173173
let p4 = &mut self.level_4_table;
174174
let p3 = self
175175
.page_table_walker
@@ -189,7 +189,39 @@ impl<'a, P: PageTableFrameMapping> Mapper<Size1GiB> for MappedPageTable<'a, P> {
189189
.map_err(|AddressNotAligned| UnmapError::InvalidFrameAddress(p3_entry.addr()))?;
190190

191191
p3_entry.set_unused();
192-
Ok((frame, MapperFlush::new(page)))
192+
Ok((frame, flags, MapperFlush::new(page)))
193+
}
194+
195+
fn clear(&mut self, page: Page<Size1GiB>) -> Result<UnmappedFrame<Size1GiB>, UnmapError> {
196+
let p4 = &mut self.level_4_table;
197+
let p3 = self
198+
.page_table_walker
199+
.next_table_mut(&mut p4[page.p4_index()])?;
200+
201+
let p3_entry = &mut p3[page.p3_index()];
202+
let flags = p3_entry.flags();
203+
204+
if !flags.contains(PageTableFlags::HUGE_PAGE) {
205+
return Err(UnmapError::ParentEntryHugePage);
206+
}
207+
208+
if !flags.contains(PageTableFlags::PRESENT) {
209+
let cloned = p3_entry.clone();
210+
p3_entry.set_unused();
211+
return Ok(UnmappedFrame::NotPresent { entry: cloned });
212+
}
213+
214+
let frame = PhysFrame::from_start_address(p3_entry.addr())
215+
.map_err(|AddressNotAligned| UnmapError::InvalidFrameAddress(p3_entry.addr()))?;
216+
let flags = p3_entry.flags();
217+
218+
p3_entry.set_unused();
219+
220+
Ok(UnmappedFrame::Present {
221+
frame,
222+
flags,
223+
flush: MapperFlush::new(page),
224+
})
193225
}
194226

195227
unsafe fn update_flags(
@@ -277,7 +309,7 @@ impl<'a, P: PageTableFrameMapping> Mapper<Size2MiB> for MappedPageTable<'a, P> {
277309
fn unmap(
278310
&mut self,
279311
page: Page<Size2MiB>,
280-
) -> Result<(PhysFrame<Size2MiB>, MapperFlush<Size2MiB>), UnmapError> {
312+
) -> Result<(PhysFrame<Size2MiB>, PageTableFlags, MapperFlush<Size2MiB>), UnmapError> {
281313
let p4 = &mut self.level_4_table;
282314
let p3 = self
283315
.page_table_walker
@@ -300,7 +332,40 @@ impl<'a, P: PageTableFrameMapping> Mapper<Size2MiB> for MappedPageTable<'a, P> {
300332
.map_err(|AddressNotAligned| UnmapError::InvalidFrameAddress(p2_entry.addr()))?;
301333

302334
p2_entry.set_unused();
303-
Ok((frame, MapperFlush::new(page)))
335+
Ok((frame, flags, MapperFlush::new(page)))
336+
}
337+
338+
fn clear(&mut self, page: Page<Size2MiB>) -> Result<UnmappedFrame<Size2MiB>, UnmapError> {
339+
let p4 = &mut self.level_4_table;
340+
let p3 = self
341+
.page_table_walker
342+
.next_table_mut(&mut p4[page.p4_index()])?;
343+
let p2 = self
344+
.page_table_walker
345+
.next_table_mut(&mut p3[page.p3_index()])?;
346+
347+
let p2_entry = &mut p2[page.p2_index()];
348+
let flags = p2_entry.flags();
349+
350+
if !flags.contains(PageTableFlags::HUGE_PAGE) {
351+
return Err(UnmapError::ParentEntryHugePage);
352+
}
353+
354+
if !flags.contains(PageTableFlags::PRESENT) {
355+
let cloned = p2_entry.clone();
356+
p2_entry.set_unused();
357+
return Ok(UnmappedFrame::NotPresent { entry: cloned });
358+
}
359+
let frame = PhysFrame::from_start_address(p2_entry.addr())
360+
.map_err(|AddressNotAligned| UnmapError::InvalidFrameAddress(p2_entry.addr()))?;
361+
let flags = p2_entry.flags();
362+
363+
p2_entry.set_unused();
364+
Ok(UnmappedFrame::Present {
365+
frame,
366+
flags,
367+
flush: MapperFlush::new(page),
368+
})
304369
}
305370

306371
unsafe fn update_flags(
@@ -405,7 +470,7 @@ impl<'a, P: PageTableFrameMapping> Mapper<Size4KiB> for MappedPageTable<'a, P> {
405470
fn unmap(
406471
&mut self,
407472
page: Page<Size4KiB>,
408-
) -> Result<(PhysFrame<Size4KiB>, MapperFlush<Size4KiB>), UnmapError> {
473+
) -> Result<(PhysFrame<Size4KiB>, PageTableFlags, MapperFlush<Size4KiB>), UnmapError> {
409474
let p4 = &mut self.level_4_table;
410475
let p3 = self
411476
.page_table_walker
@@ -423,9 +488,43 @@ impl<'a, P: PageTableFrameMapping> Mapper<Size4KiB> for MappedPageTable<'a, P> {
423488
FrameError::FrameNotPresent => UnmapError::PageNotMapped,
424489
FrameError::HugeFrame => UnmapError::ParentEntryHugePage,
425490
})?;
491+
let flags = p1_entry.flags();
492+
493+
p1_entry.set_unused();
494+
Ok((frame, flags, MapperFlush::new(page)))
495+
}
496+
497+
fn clear(&mut self, page: Page<Size4KiB>) -> Result<UnmappedFrame<Size4KiB>, UnmapError> {
498+
let p4 = &mut self.level_4_table;
499+
let p3 = self
500+
.page_table_walker
501+
.next_table_mut(&mut p4[page.p4_index()])?;
502+
let p2 = self
503+
.page_table_walker
504+
.next_table_mut(&mut p3[page.p3_index()])?;
505+
let p1 = self
506+
.page_table_walker
507+
.next_table_mut(&mut p2[page.p2_index()])?;
508+
509+
let p1_entry = &mut p1[page.p1_index()];
510+
511+
let frame = match p1_entry.frame() {
512+
Ok(frame) => frame,
513+
Err(FrameError::HugeFrame) => return Err(UnmapError::ParentEntryHugePage),
514+
Err(FrameError::FrameNotPresent) => {
515+
let cloned = p1_entry.clone();
516+
p1_entry.set_unused();
517+
return Ok(UnmappedFrame::NotPresent { entry: cloned });
518+
}
519+
};
520+
let flags = p1_entry.flags();
426521

427522
p1_entry.set_unused();
428-
Ok((frame, MapperFlush::new(page)))
523+
Ok(UnmappedFrame::Present {
524+
frame,
525+
flags,
526+
flush: MapperFlush::new(page),
527+
})
429528
}
430529

431530
unsafe fn update_flags(

src/structures/paging/mapper/mod.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub use self::recursive_page_table::{InvalidPageTable, RecursivePageTable};
99
use crate::structures::paging::{
1010
frame_alloc::{FrameAllocator, FrameDeallocator},
1111
page::PageRangeInclusive,
12-
page_table::PageTableFlags,
12+
page_table::{PageTableEntry, PageTableFlags},
1313
Page, PageSize, PhysFrame, Size1GiB, Size2MiB, Size4KiB,
1414
};
1515
use crate::{PhysAddr, VirtAddr};
@@ -282,7 +282,18 @@ pub trait Mapper<S: PageSize> {
282282
/// Removes a mapping from the page table and returns the frame that used to be mapped.
283283
///
284284
/// Note that no page tables or pages are deallocated.
285-
fn unmap(&mut self, page: Page<S>) -> Result<(PhysFrame<S>, MapperFlush<S>), UnmapError>;
285+
fn unmap(
286+
&mut self,
287+
page: Page<S>,
288+
) -> Result<(PhysFrame<S>, PageTableFlags, MapperFlush<S>), UnmapError>;
289+
290+
/// Clears a mapping from the page table and returns the frame that used to be mapped.
291+
///
292+
/// Unlike [`Mapper::unmap`] this will ignore the present flag of the page and will successfully
293+
/// clear the table entry for any valid page.
294+
///
295+
/// Note that no page tables or pages are deallocated.
296+
fn clear(&mut self, page: Page<S>) -> Result<UnmappedFrame<S>, UnmapError>;
286297

287298
/// Updates the flags of an existing mapping.
288299
///
@@ -376,6 +387,27 @@ pub trait Mapper<S: PageSize> {
376387
}
377388
}
378389

390+
/// The result of [`Mapper::clear`], representing either
391+
/// the unmapped frame or the entry data if the frame is not marked as present.
392+
#[derive(Debug)]
393+
#[must_use = "Page table changes must be flushed or ignored if the page is present."]
394+
pub enum UnmappedFrame<S: PageSize> {
395+
/// The frame was present before the [`Mapper::clear`] call
396+
Present {
397+
/// The physical frame that was unmapped
398+
frame: PhysFrame<S>,
399+
/// The flags of the frame that was unmapped
400+
flags: PageTableFlags,
401+
/// The changed page, to flush the TLB
402+
flush: MapperFlush<S>,
403+
},
404+
/// The frame was not present before the [`Mapper::clear`] call
405+
NotPresent {
406+
/// The page table entry
407+
entry: PageTableEntry,
408+
},
409+
}
410+
379411
/// This type represents a page whose mapping has changed in the page table.
380412
///
381413
/// The old mapping might be still cached in the translation lookaside buffer (TLB), so it needs

src/structures/paging/mapper/offset_page_table.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,15 @@ impl<'a> Mapper<Size1GiB> for OffsetPageTable<'a> {
8888
fn unmap(
8989
&mut self,
9090
page: Page<Size1GiB>,
91-
) -> Result<(PhysFrame<Size1GiB>, MapperFlush<Size1GiB>), UnmapError> {
91+
) -> Result<(PhysFrame<Size1GiB>, PageTableFlags, MapperFlush<Size1GiB>), UnmapError> {
9292
self.inner.unmap(page)
9393
}
9494

95+
#[inline]
96+
fn clear(&mut self, page: Page<Size1GiB>) -> Result<UnmappedFrame<Size1GiB>, UnmapError> {
97+
self.inner.clear(page)
98+
}
99+
95100
#[inline]
96101
unsafe fn update_flags(
97102
&mut self,
@@ -157,10 +162,15 @@ impl<'a> Mapper<Size2MiB> for OffsetPageTable<'a> {
157162
fn unmap(
158163
&mut self,
159164
page: Page<Size2MiB>,
160-
) -> Result<(PhysFrame<Size2MiB>, MapperFlush<Size2MiB>), UnmapError> {
165+
) -> Result<(PhysFrame<Size2MiB>, PageTableFlags, MapperFlush<Size2MiB>), UnmapError> {
161166
self.inner.unmap(page)
162167
}
163168

169+
#[inline]
170+
fn clear(&mut self, page: Page<Size2MiB>) -> Result<UnmappedFrame<Size2MiB>, UnmapError> {
171+
self.inner.clear(page)
172+
}
173+
164174
#[inline]
165175
unsafe fn update_flags(
166176
&mut self,
@@ -226,10 +236,15 @@ impl<'a> Mapper<Size4KiB> for OffsetPageTable<'a> {
226236
fn unmap(
227237
&mut self,
228238
page: Page<Size4KiB>,
229-
) -> Result<(PhysFrame<Size4KiB>, MapperFlush<Size4KiB>), UnmapError> {
239+
) -> Result<(PhysFrame<Size4KiB>, PageTableFlags, MapperFlush<Size4KiB>), UnmapError> {
230240
self.inner.unmap(page)
231241
}
232242

243+
#[inline]
244+
fn clear(&mut self, page: Page<Size4KiB>) -> Result<UnmappedFrame<Size4KiB>, UnmapError> {
245+
self.inner.clear(page)
246+
}
247+
233248
#[inline]
234249
unsafe fn update_flags(
235250
&mut self,

0 commit comments

Comments
 (0)