Skip to content

Commit

Permalink
Merge #83
Browse files Browse the repository at this point in the history
83: Add a new `OffsetPageTable` mapper type r=phil-opp a=phil-opp

The type wraps a `MappedPageTable` instance with a simpler interface. It uses a simple phys-to-virt offset instead of being generic over a phys-to-virt closure, which makes it easier to e.g. store the type in a `static`.

TODO:

- [x] Make `phys_offset` a `VirtAddr` instead of an `u64` 

Fixes #81 

Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
  • Loading branch information
bors[bot] and phil-opp committed Jul 17, 2019
2 parents 663b344 + cdde870 commit fdc88ab
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 42 deletions.
2 changes: 2 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
- Add a new `OffsetPageTable` mapper type ([#83](https://github.com/rust-osdev/x86_64/pull/83))

# 0.7.2

- Add `instructions::bochs_breakpoint` and `registers::read_rip` functions ([#79](https://github.com/rust-osdev/x86_64/pull/79))
Expand Down
70 changes: 32 additions & 38 deletions src/structures/paging/mapper/mapped_page_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,20 @@ use crate::structures::paging::{
/// memory are possible too, as long as they can be calculated as an `PhysAddr` to
/// `VirtAddr` closure.
#[derive(Debug)]
pub struct MappedPageTable<'a, PhysToVirt>
where
PhysToVirt: Fn(PhysFrame) -> *mut PageTable,
{
page_table_walker: PageTableWalker<PhysToVirt>,
pub struct MappedPageTable<'a, P: PhysToVirt> {
page_table_walker: PageTableWalker<P>,
level_4_table: &'a mut PageTable,
}

impl<'a, PhysToVirt> MappedPageTable<'a, PhysToVirt>
where
PhysToVirt: Fn(PhysFrame) -> *mut PageTable,
{
impl<'a, P: PhysToVirt> MappedPageTable<'a, P> {
/// Creates a new `MappedPageTable` that uses the passed closure for converting virtual
/// to physical addresses.
///
/// This function is unsafe because the caller must guarantee that the passed `phys_to_virt`
/// closure is correct. Also, the passed `level_4_table` must point to the level 4 page table
/// of a valid page table hierarchy. Otherwise this function might break memory safety, e.g.
/// by writing to an illegal memory location.
pub unsafe fn new(level_4_table: &'a mut PageTable, phys_to_virt: PhysToVirt) -> Self {
pub unsafe fn new(level_4_table: &'a mut PageTable, phys_to_virt: P) -> Self {
Self {
level_4_table,
page_table_walker: PageTableWalker::new(phys_to_virt),
Expand Down Expand Up @@ -125,10 +119,7 @@ where
}
}

impl<'a, PhysToVirt> Mapper<Size1GiB> for MappedPageTable<'a, PhysToVirt>
where
PhysToVirt: Fn(PhysFrame) -> *mut PageTable,
{
impl<'a, P: PhysToVirt> Mapper<Size1GiB> for MappedPageTable<'a, P> {
unsafe fn map_to<A>(
&mut self,
page: Page<Size1GiB>,
Expand Down Expand Up @@ -201,10 +192,7 @@ where
}
}

impl<'a, PhysToVirt> Mapper<Size2MiB> for MappedPageTable<'a, PhysToVirt>
where
PhysToVirt: Fn(PhysFrame) -> *mut PageTable,
{
impl<'a, P: PhysToVirt> Mapper<Size2MiB> for MappedPageTable<'a, P> {
unsafe fn map_to<A>(
&mut self,
page: Page<Size2MiB>,
Expand Down Expand Up @@ -285,10 +273,7 @@ where
}
}

impl<'a, PhysToVirt> Mapper<Size4KiB> for MappedPageTable<'a, PhysToVirt>
where
PhysToVirt: Fn(PhysFrame) -> *mut PageTable,
{
impl<'a, P: PhysToVirt> Mapper<Size4KiB> for MappedPageTable<'a, P> {
unsafe fn map_to<A>(
&mut self,
page: Page<Size4KiB>,
Expand Down Expand Up @@ -370,10 +355,7 @@ where
}
}

impl<'a, PhysToVirt> MapperAllSizes for MappedPageTable<'a, PhysToVirt>
where
PhysToVirt: Fn(PhysFrame) -> *mut PageTable,
{
impl<'a, P: PhysToVirt> MapperAllSizes for MappedPageTable<'a, P> {
fn translate(&self, addr: VirtAddr) -> TranslateResult {
let p4 = &self.level_4_table;
let p3 = match self.page_table_walker.next_table(&p4[addr.p4_index()]) {
Expand Down Expand Up @@ -418,18 +400,12 @@ where
}

#[derive(Debug)]
struct PageTableWalker<PhysToVirt>
where
PhysToVirt: Fn(PhysFrame) -> *mut PageTable,
{
phys_to_virt: PhysToVirt,
struct PageTableWalker<P: PhysToVirt> {
phys_to_virt: P,
}

impl<PhysToVirt> PageTableWalker<PhysToVirt>
where
PhysToVirt: Fn(PhysFrame) -> *mut PageTable,
{
pub unsafe fn new(phys_to_virt: PhysToVirt) -> Self {
impl<P: PhysToVirt> PageTableWalker<P> {
pub unsafe fn new(phys_to_virt: P) -> Self {
Self { phys_to_virt }
}

Expand All @@ -442,7 +418,7 @@ where
&self,
entry: &'b PageTableEntry,
) -> Result<&'b PageTable, PageTableWalkError> {
let page_table_ptr = (self.phys_to_virt)(entry.frame()?);
let page_table_ptr = self.phys_to_virt.phys_to_virt(entry.frame()?);
let page_table: &PageTable = unsafe { &*page_table_ptr };

Ok(page_table)
Expand All @@ -457,7 +433,7 @@ where
&self,
entry: &'b mut PageTableEntry,
) -> Result<&'b mut PageTable, PageTableWalkError> {
let page_table_ptr = (self.phys_to_virt)(entry.frame()?);
let page_table_ptr = self.phys_to_virt.phys_to_virt(entry.frame()?);
let page_table: &mut PageTable = unsafe { &mut *page_table_ptr };

Ok(page_table)
Expand Down Expand Up @@ -564,3 +540,21 @@ impl From<PageTableWalkError> for TranslateError {
}
}
}

/// Trait for converting a physical address to a virtual one.
///
/// This only works if the physical address space is somehow mapped to the virtual
/// address space, e.g. at an offset.
pub trait PhysToVirt {
/// Translate the given physical frame to a virtual page table pointer.
fn phys_to_virt(&self, phys_frame: PhysFrame) -> *mut PageTable;
}

impl<T> PhysToVirt for T
where
T: Fn(PhysFrame) -> *mut PageTable,
{
fn phys_to_virt(&self, phys_frame: PhysFrame) -> *mut PageTable {
self(phys_frame)
}
}
5 changes: 3 additions & 2 deletions src/structures/paging/mapper/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Abstractions for reading and modifying the mapping of pages.
pub use self::mapped_page_table::MappedPageTable;
pub use self::mapped_page_table::{MappedPageTable, PhysToVirt};
#[cfg(target_arch = "x86_64")]
pub use self::recursive_page_table::RecursivePageTable;
pub use self::{offset_page_table::OffsetPageTable, recursive_page_table::RecursivePageTable};

use crate::structures::paging::{
frame_alloc::FrameAllocator, page_table::PageTableFlags, Page, PageSize, PhysFrame, Size1GiB,
Expand All @@ -11,6 +11,7 @@ use crate::structures::paging::{
use crate::{PhysAddr, VirtAddr};

mod mapped_page_table;
mod offset_page_table;
mod recursive_page_table;

/// This trait defines page table operations that work for all page sizes of the x86_64
Expand Down
157 changes: 157 additions & 0 deletions src/structures/paging/mapper/offset_page_table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#![cfg(target_arch = "x86_64")]

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

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

impl<'a> OffsetPageTable<'a> {
/// Creates a new `OffsetPageTable` 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.
///
/// This function is unsafe because the caller must guarantee that the passed `phys_offset`
/// is correct. Also, the passed `level_4_table` must point to the level 4 page table
/// of a valid page table hierarchy. Otherwise this function might break memory safety, e.g.
/// by writing to an illegal memory location.
pub unsafe fn new(level_4_table: &'a mut PageTable, phys_offset: VirtAddr) -> Self {
let phys_offset = PhysOffset {
offset: phys_offset,
};
Self {
inner: MappedPageTable::new(level_4_table, phys_offset),
}
}
}

#[derive(Debug)]
struct PhysOffset {
offset: VirtAddr,
}

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

// delegate all trait implementations to inner

impl<'a> Mapper<Size1GiB> for OffsetPageTable<'a> {
unsafe fn map_to<A>(
&mut self,
page: Page<Size1GiB>,
frame: PhysFrame<Size1GiB>,
flags: PageTableFlags,
allocator: &mut A,
) -> Result<MapperFlush<Size1GiB>, MapToError>
where
A: FrameAllocator<Size4KiB>,
{
self.inner.map_to(page, frame, flags, allocator)
}

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

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

fn translate_page(&self, page: Page<Size1GiB>) -> Result<PhysFrame<Size1GiB>, TranslateError> {
self.inner.translate_page(page)
}
}

impl<'a> Mapper<Size2MiB> for OffsetPageTable<'a> {
unsafe fn map_to<A>(
&mut self,
page: Page<Size2MiB>,
frame: PhysFrame<Size2MiB>,
flags: PageTableFlags,
allocator: &mut A,
) -> Result<MapperFlush<Size2MiB>, MapToError>
where
A: FrameAllocator<Size4KiB>,
{
self.inner.map_to(page, frame, flags, allocator)
}

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

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

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

impl<'a> Mapper<Size4KiB> for OffsetPageTable<'a> {
unsafe fn map_to<A>(
&mut self,
page: Page<Size4KiB>,
frame: PhysFrame<Size4KiB>,
flags: PageTableFlags,
allocator: &mut A,
) -> Result<MapperFlush<Size4KiB>, MapToError>
where
A: FrameAllocator<Size4KiB>,
{
self.inner.map_to(page, frame, flags, allocator)
}

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

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

fn translate_page(&self, page: Page<Size4KiB>) -> Result<PhysFrame<Size4KiB>, TranslateError> {
self.inner.translate_page(page)
}
}

impl<'a> MapperAllSizes for OffsetPageTable<'a> {
fn translate(&self, addr: VirtAddr) -> TranslateResult {
self.inner.translate(addr)
}
}
4 changes: 2 additions & 2 deletions src/structures/paging/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ pub use self::frame::PhysFrame;
pub use self::frame_alloc::{FrameAllocator, FrameDeallocator};
#[doc(no_inline)]
pub use self::mapper::MappedPageTable;
pub use self::mapper::{Mapper, MapperAllSizes};
#[cfg(target_arch = "x86_64")]
#[doc(no_inline)]
pub use self::mapper::RecursivePageTable;
pub use self::mapper::{Mapper, MapperAllSizes};
pub use self::mapper::{OffsetPageTable, RecursivePageTable};
pub use self::page::{Page, PageSize, Size1GiB, Size2MiB, Size4KiB};
pub use self::page_table::{PageTable, PageTableFlags};

Expand Down

0 comments on commit fdc88ab

Please sign in to comment.