Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

- [add `Mapper::clear` to clear any page table entry regardless of the present flag](https://github.com/rust-osdev/x86_64/pull/484)
- [`Mapper::unmap` now also returns the flags of the page ](https://github.com/rust-osdev/x86_64/pull/484)
- [make `OffsetPageTable` a type alias](https://github.com/rust-osdev/x86_64/pull/576)
- To migrate, replace `OffsetPageTable::new` with `OffsetPageTable::from_phys_offset` or `MappedPageTable::from_phys_offset`.
- `OffsetPageTable`'s `PageTableFrameMapping` implementation is now public as `PhysOffset`.

# 0.15.4 – 2025-11-24

Expand Down
2 changes: 1 addition & 1 deletion src/structures/paging/mapper/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pub use self::mapped_page_table::{MappedPageTable, PageTableFrameMapping};
#[cfg(target_pointer_width = "64")]
pub use self::offset_page_table::OffsetPageTable;
pub use self::offset_page_table::{OffsetPageTable, PhysOffset};
#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
pub use self::recursive_page_table::{InvalidPageTable, RecursivePageTable};

Expand Down
312 changes: 37 additions & 275 deletions src/structures/paging/mapper/offset_page_table.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
#![cfg(target_pointer_width = "64")]

use crate::structures::paging::{mapper::*, page_table::PageTable};
use crate::structures::paging::{mapper::*, PageTable};

/// A Mapper implementation that requires that the complete physical memory is mapped at some
/// offset in the virtual address space.
#[derive(Debug)]
pub struct OffsetPageTable<'a> {
inner: MappedPageTable<'a, PhysOffset>,
}
pub type OffsetPageTable<'a> = MappedPageTable<'a, PhysOffset>;

impl<'a> OffsetPageTable<'a> {
/// Creates a new `OffsetPageTable` that uses the given offset for converting virtual
Expand All @@ -26,291 +23,56 @@ impl<'a> OffsetPageTable<'a> {
/// of a valid page table hierarchy. Otherwise this function might break memory safety, e.g.
/// by writing to an illegal memory location.
#[inline]
pub unsafe fn new(level_4_table: &'a mut PageTable, phys_offset: VirtAddr) -> Self {
let phys_offset = PhysOffset {
offset: phys_offset,
};
Self {
inner: unsafe { MappedPageTable::new(level_4_table, phys_offset) },
}
}

/// Returns an immutable reference to the wrapped level 4 `PageTable` instance.
pub fn level_4_table(&self) -> &PageTable {
self.inner.level_4_table()
}

/// Returns a mutable reference to the wrapped level 4 `PageTable` instance.
pub fn level_4_table_mut(&mut self) -> &mut PageTable {
self.inner.level_4_table_mut()
pub unsafe fn from_phys_offset(
level_4_table: &'a mut PageTable,
phys_offset: VirtAddr,
) -> Self {
let phys_offset = unsafe { PhysOffset::new(phys_offset) };
unsafe { MappedPageTable::new(level_4_table, phys_offset) }
}

/// Returns the offset used for converting virtual to physical addresses.
pub fn phys_offset(&self) -> VirtAddr {
self.inner.page_table_frame_mapping().offset
self.page_table_frame_mapping().phys_offset()
}
}

/// A [`PageTableFrameMapping`] implementation that requires that the complete physical memory is mapped at some
/// offset in the virtual address space.
#[derive(Debug)]
struct PhysOffset {
offset: VirtAddr,
}

unsafe impl PageTableFrameMapping for PhysOffset {
fn frame_to_pointer(&self, frame: PhysFrame) -> *mut PageTable {
let virt = self.offset + frame.start_address().as_u64();
virt.as_mut_ptr()
}
}

// delegate all trait implementations to inner

impl Mapper<Size1GiB> for OffsetPageTable<'_> {
#[inline]
unsafe fn map_to_with_table_flags<A>(
&mut self,
page: Page<Size1GiB>,
frame: PhysFrame<Size1GiB>,
flags: PageTableFlags,
parent_table_flags: PageTableFlags,
allocator: &mut A,
) -> Result<MapperFlush<Size1GiB>, MapToError<Size1GiB>>
where
A: FrameAllocator<Size4KiB> + ?Sized,
{
unsafe {
self.inner
.map_to_with_table_flags(page, frame, flags, parent_table_flags, allocator)
}
}

#[inline]
fn unmap(
&mut self,
page: Page<Size1GiB>,
) -> Result<(PhysFrame<Size1GiB>, PageTableFlags, MapperFlush<Size1GiB>), UnmapError> {
self.inner.unmap(page)
}

#[inline]
fn clear(&mut self, page: Page<Size1GiB>) -> Result<UnmappedFrame<Size1GiB>, UnmapError> {
self.inner.clear(page)
}

#[inline]
unsafe fn update_flags(
&mut self,
page: Page<Size1GiB>,
flags: PageTableFlags,
) -> Result<MapperFlush<Size1GiB>, FlagUpdateError> {
unsafe { self.inner.update_flags(page, flags) }
}

#[inline]
unsafe fn set_flags_p4_entry(
&mut self,
page: Page<Size1GiB>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError> {
unsafe { self.inner.set_flags_p4_entry(page, flags) }
}

#[inline]
unsafe fn set_flags_p3_entry(
&mut self,
page: Page<Size1GiB>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError> {
unsafe { self.inner.set_flags_p3_entry(page, flags) }
}

#[inline]
unsafe fn set_flags_p2_entry(
&mut self,
page: Page<Size1GiB>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError> {
unsafe { self.inner.set_flags_p2_entry(page, flags) }
}

#[inline]
fn translate_page(&self, page: Page<Size1GiB>) -> Result<PhysFrame<Size1GiB>, TranslateError> {
self.inner.translate_page(page)
}
pub struct PhysOffset {
phys_offset: VirtAddr,
}

impl Mapper<Size2MiB> for OffsetPageTable<'_> {
#[inline]
unsafe fn map_to_with_table_flags<A>(
&mut self,
page: Page<Size2MiB>,
frame: PhysFrame<Size2MiB>,
flags: PageTableFlags,
parent_table_flags: PageTableFlags,
allocator: &mut A,
) -> Result<MapperFlush<Size2MiB>, MapToError<Size2MiB>>
where
A: FrameAllocator<Size4KiB> + ?Sized,
{
unsafe {
self.inner
.map_to_with_table_flags(page, frame, flags, parent_table_flags, allocator)
}
}

#[inline]
fn unmap(
&mut self,
page: Page<Size2MiB>,
) -> Result<(PhysFrame<Size2MiB>, PageTableFlags, MapperFlush<Size2MiB>), UnmapError> {
self.inner.unmap(page)
}

#[inline]
fn clear(&mut self, page: Page<Size2MiB>) -> Result<UnmappedFrame<Size2MiB>, UnmapError> {
self.inner.clear(page)
}

#[inline]
unsafe fn update_flags(
&mut self,
page: Page<Size2MiB>,
flags: PageTableFlags,
) -> Result<MapperFlush<Size2MiB>, FlagUpdateError> {
unsafe { self.inner.update_flags(page, flags) }
}

#[inline]
unsafe fn set_flags_p4_entry(
&mut self,
page: Page<Size2MiB>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError> {
unsafe { self.inner.set_flags_p4_entry(page, flags) }
}

#[inline]
unsafe fn set_flags_p3_entry(
&mut self,
page: Page<Size2MiB>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError> {
unsafe { self.inner.set_flags_p3_entry(page, flags) }
}

#[inline]
unsafe fn set_flags_p2_entry(
&mut self,
page: Page<Size2MiB>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError> {
unsafe { self.inner.set_flags_p2_entry(page, flags) }
}

#[inline]
fn translate_page(&self, page: Page<Size2MiB>) -> Result<PhysFrame<Size2MiB>, TranslateError> {
self.inner.translate_page(page)
}
}

impl Mapper<Size4KiB> for OffsetPageTable<'_> {
#[inline]
unsafe fn map_to_with_table_flags<A>(
&mut self,
page: Page<Size4KiB>,
frame: PhysFrame<Size4KiB>,
flags: PageTableFlags,
parent_table_flags: PageTableFlags,
allocator: &mut A,
) -> Result<MapperFlush<Size4KiB>, MapToError<Size4KiB>>
where
A: FrameAllocator<Size4KiB> + ?Sized,
{
unsafe {
self.inner
.map_to_with_table_flags(page, frame, flags, parent_table_flags, allocator)
}
}

#[inline]
fn unmap(
&mut self,
page: Page<Size4KiB>,
) -> Result<(PhysFrame<Size4KiB>, PageTableFlags, MapperFlush<Size4KiB>), UnmapError> {
self.inner.unmap(page)
}

#[inline]
fn clear(&mut self, page: Page<Size4KiB>) -> Result<UnmappedFrame<Size4KiB>, UnmapError> {
self.inner.clear(page)
}

#[inline]
unsafe fn update_flags(
&mut self,
page: Page<Size4KiB>,
flags: PageTableFlags,
) -> Result<MapperFlush<Size4KiB>, FlagUpdateError> {
unsafe { self.inner.update_flags(page, flags) }
}

#[inline]
unsafe fn set_flags_p4_entry(
&mut self,
page: Page<Size4KiB>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError> {
unsafe { self.inner.set_flags_p4_entry(page, flags) }
}

#[inline]
unsafe fn set_flags_p3_entry(
&mut self,
page: Page<Size4KiB>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError> {
unsafe { self.inner.set_flags_p3_entry(page, flags) }
}

#[inline]
unsafe fn set_flags_p2_entry(
&mut self,
page: Page<Size4KiB>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError> {
unsafe { self.inner.set_flags_p2_entry(page, flags) }
}

impl PhysOffset {
/// Creates a new `PhysOffset` that uses the given offset for converting virtual
/// to physical addresses.
///
/// The complete physical memory must be mapped in the virtual address space starting at
/// address `phys_offset`. This means that for example physical address `0x5000` can be
/// accessed through virtual address `phys_offset + 0x5000`. This mapping is required because
/// the mapper needs to access page tables, which are not mapped into the virtual address
/// space by default.
///
/// ## Safety
///
/// This function is unsafe because the caller must guarantee that the passed `phys_offset`
/// is correct. Otherwise this function might break memory safety, e.g. by writing to an
/// illegal memory location.
#[inline]
fn translate_page(&self, page: Page<Size4KiB>) -> Result<PhysFrame<Size4KiB>, TranslateError> {
self.inner.translate_page(page)
pub unsafe fn new(phys_offset: VirtAddr) -> Self {
Self { phys_offset }
}
}

impl Translate for OffsetPageTable<'_> {
#[inline]
fn translate(&self, addr: VirtAddr) -> TranslateResult {
self.inner.translate(addr)
/// Returns the offset used for converting virtual to physical addresses.
pub fn phys_offset(&self) -> VirtAddr {
self.phys_offset
}
}

impl CleanUp for OffsetPageTable<'_> {
#[inline]
unsafe fn clean_up<D>(&mut self, frame_deallocator: &mut D)
where
D: FrameDeallocator<Size4KiB>,
{
unsafe { self.inner.clean_up(frame_deallocator) }
}

#[inline]
unsafe fn clean_up_addr_range<D>(
&mut self,
range: PageRangeInclusive,
frame_deallocator: &mut D,
) where
D: FrameDeallocator<Size4KiB>,
{
unsafe { self.inner.clean_up_addr_range(range, frame_deallocator) }
unsafe impl PageTableFrameMapping for PhysOffset {
fn frame_to_pointer(&self, frame: PhysFrame) -> *mut PageTable {
let virt = self.phys_offset + frame.start_address().as_u64();
virt.as_mut_ptr()
}
}
6 changes: 3 additions & 3 deletions src/structures/paging/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ pub use self::frame::PhysFrame;
pub use self::frame_alloc::{FrameAllocator, FrameDeallocator};
#[doc(no_inline)]
pub use self::mapper::MappedPageTable;
#[cfg(target_pointer_width = "64")]
#[doc(no_inline)]
pub use self::mapper::OffsetPageTable;
#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
#[doc(no_inline)]
pub use self::mapper::RecursivePageTable;
pub use self::mapper::{Mapper, Translate};
#[cfg(target_pointer_width = "64")]
#[doc(no_inline)]
pub use self::mapper::{OffsetPageTable, PhysOffset};
pub use self::page::{Page, PageSize, Size1GiB, Size2MiB, Size4KiB};
pub use self::page_table::{PageOffset, PageTable, PageTableFlags, PageTableIndex};

Expand Down
Loading