x86_64::structures::paging::mapper

Trait Mapper

Source
pub trait Mapper<S: PageSize> {
    // Required methods
    unsafe fn map_to_with_table_flags<A>(
        &mut self,
        page: Page<S>,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        parent_table_flags: PageTableFlags,
        frame_allocator: &mut A,
    ) -> Result<MapperFlush<S>, MapToError<S>>
       where Self: Sized,
             A: FrameAllocator<Size4KiB> + ?Sized;
    fn unmap(
        &mut self,
        page: Page<S>,
    ) -> Result<(PhysFrame<S>, MapperFlush<S>), UnmapError>;
    unsafe fn update_flags(
        &mut self,
        page: Page<S>,
        flags: PageTableFlags,
    ) -> Result<MapperFlush<S>, FlagUpdateError>;
    unsafe fn set_flags_p4_entry(
        &mut self,
        page: Page<S>,
        flags: PageTableFlags,
    ) -> Result<MapperFlushAll, FlagUpdateError>;
    unsafe fn set_flags_p3_entry(
        &mut self,
        page: Page<S>,
        flags: PageTableFlags,
    ) -> Result<MapperFlushAll, FlagUpdateError>;
    unsafe fn set_flags_p2_entry(
        &mut self,
        page: Page<S>,
        flags: PageTableFlags,
    ) -> Result<MapperFlushAll, FlagUpdateError>;
    fn translate_page(
        &self,
        page: Page<S>,
    ) -> Result<PhysFrame<S>, TranslateError>;

    // Provided methods
    unsafe fn map_to<A>(
        &mut self,
        page: Page<S>,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        frame_allocator: &mut A,
    ) -> Result<MapperFlush<S>, MapToError<S>>
       where Self: Sized,
             A: FrameAllocator<Size4KiB> + ?Sized { ... }
    unsafe fn identity_map<A>(
        &mut self,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        frame_allocator: &mut A,
    ) -> Result<MapperFlush<S>, MapToError<S>>
       where Self: Sized + Mapper<S>,
             A: FrameAllocator<Size4KiB> + ?Sized,
             S: PageSize { ... }
}
Expand description

A trait for common page table operations on pages of size S.

Required Methods§

Source

unsafe fn map_to_with_table_flags<A>( &mut self, page: Page<S>, frame: PhysFrame<S>, flags: PageTableFlags, parent_table_flags: PageTableFlags, frame_allocator: &mut A, ) -> Result<MapperFlush<S>, MapToError<S>>
where Self: Sized, A: FrameAllocator<Size4KiB> + ?Sized,

Creates a new mapping in the page table.

This function might need additional physical frames to create new page tables. These frames are allocated from the allocator argument. At most three frames are required.

The flags of the parent table(s) can be explicitly specified. Those flags are used for newly created table entries, and for existing entries the flags are added.

Depending on the used mapper implementation, the PRESENT and WRITABLE flags might be set for parent tables, even if they are not specified in parent_table_flags.

§Safety

Creating page table mappings is a fundamentally unsafe operation because there are various ways to break memory safety through it. For example, re-mapping an in-use page to a different frame changes and invalidates all values stored in that page, resulting in undefined behavior on the next use.

The caller must ensure that no undefined behavior or memory safety violations can occur through the new mapping. Among other things, the caller must prevent the following:

  • Aliasing of &mut references, i.e. two &mut references that point to the same physical address. This is undefined behavior in Rust.
    • This can be ensured by mapping each page to an individual physical frame that is not mapped anywhere else.
  • Creating uninitialized or invalid values: Rust requires that all values have a correct memory layout. For example, a bool must be either a 0 or a 1 in memory, but not a 3 or 4. An exception is the MaybeUninit wrapper type, which abstracts over possibly uninitialized memory.
    • This is only a problem when re-mapping pages to different physical frames. Mapping a page that is not in use yet is fine.

Special care must be taken when sharing pages with other address spaces, e.g. by setting the GLOBAL flag. For example, a global mapping must be the same in all address spaces, otherwise undefined behavior can occur because of TLB races. It’s worth noting that all the above requirements also apply to shared mappings, including the aliasing requirements.

§Examples

Create USER_ACCESSIBLE | NO_EXECUTE | NO_CACHE mapping and update the top hierarchy only with USER_ACCESSIBLE:

        mapper
          .map_to_with_table_flags(
              page,
              frame,
             PageTableFlags::PRESENT
                  | PageTableFlags::WRITABLE
                  | PageTableFlags::USER_ACCESSIBLE
                  | PageTableFlags::NO_EXECUTE
                  | PageTableFlags::NO_CACHE,
             PageTableFlags::USER_ACCESSIBLE,
              frame_allocator,
          )
          .unwrap()
          .flush();
Source

fn unmap( &mut self, page: Page<S>, ) -> Result<(PhysFrame<S>, MapperFlush<S>), UnmapError>

Removes a mapping from the page table and returns the frame that used to be mapped.

Note that no page tables or pages are deallocated.

Source

unsafe fn update_flags( &mut self, page: Page<S>, flags: PageTableFlags, ) -> Result<MapperFlush<S>, FlagUpdateError>

Updates the flags of an existing mapping.

To read the current flags of a mapped page, use the Translate::translate method.

§Safety

This method is unsafe because changing the flags of a mapping might result in undefined behavior. For example, setting the GLOBAL and WRITABLE flags for a page might result in the corruption of values stored in that page from processes running in other address spaces.

Source

unsafe fn set_flags_p4_entry( &mut self, page: Page<S>, flags: PageTableFlags, ) -> Result<MapperFlushAll, FlagUpdateError>

Set the flags of an existing page level 4 table entry

§Safety

This method is unsafe because changing the flags of a mapping might result in undefined behavior. For example, setting the GLOBAL and WRITABLE flags for a page might result in the corruption of values stored in that page from processes running in other address spaces.

Source

unsafe fn set_flags_p3_entry( &mut self, page: Page<S>, flags: PageTableFlags, ) -> Result<MapperFlushAll, FlagUpdateError>

Set the flags of an existing page table level 3 entry

§Safety

This method is unsafe because changing the flags of a mapping might result in undefined behavior. For example, setting the GLOBAL and WRITABLE flags for a page might result in the corruption of values stored in that page from processes running in other address spaces.

Source

unsafe fn set_flags_p2_entry( &mut self, page: Page<S>, flags: PageTableFlags, ) -> Result<MapperFlushAll, FlagUpdateError>

Set the flags of an existing page table level 2 entry

§Safety

This method is unsafe because changing the flags of a mapping might result in undefined behavior. For example, setting the GLOBAL and WRITABLE flags for a page might result in the corruption of values stored in that page from processes running in other address spaces.

Source

fn translate_page(&self, page: Page<S>) -> Result<PhysFrame<S>, TranslateError>

Return the frame that the specified page is mapped to.

This function assumes that the page is mapped to a frame of size S and returns an error otherwise.

Provided Methods§

Source

unsafe fn map_to<A>( &mut self, page: Page<S>, frame: PhysFrame<S>, flags: PageTableFlags, frame_allocator: &mut A, ) -> Result<MapperFlush<S>, MapToError<S>>
where Self: Sized, A: FrameAllocator<Size4KiB> + ?Sized,

Creates a new mapping in the page table.

This function might need additional physical frames to create new page tables. These frames are allocated from the allocator argument. At most three frames are required.

Parent page table entries are automatically updated with PRESENT | WRITABLE | USER_ACCESSIBLE if present in the PageTableFlags. Depending on the used mapper implementation the PRESENT and WRITABLE flags might be set for parent tables, even if they are not set in PageTableFlags.

The map_to_with_table_flags method gives explicit control over the parent page table flags.

§Safety

Creating page table mappings is a fundamentally unsafe operation because there are various ways to break memory safety through it. For example, re-mapping an in-use page to a different frame changes and invalidates all values stored in that page, resulting in undefined behavior on the next use.

The caller must ensure that no undefined behavior or memory safety violations can occur through the new mapping. Among other things, the caller must prevent the following:

  • Aliasing of &mut references, i.e. two &mut references that point to the same physical address. This is undefined behavior in Rust.
    • This can be ensured by mapping each page to an individual physical frame that is not mapped anywhere else.
  • Creating uninitialized or invalid values: Rust requires that all values have a correct memory layout. For example, a bool must be either a 0 or a 1 in memory, but not a 3 or 4. An exception is the MaybeUninit wrapper type, which abstracts over possibly uninitialized memory.
    • This is only a problem when re-mapping pages to different physical frames. Mapping a page that is not in use yet is fine.

Special care must be taken when sharing pages with other address spaces, e.g. by setting the GLOBAL flag. For example, a global mapping must be the same in all address spaces, otherwise undefined behavior can occur because of TLB races. It’s worth noting that all the above requirements also apply to shared mappings, including the aliasing requirements.

§Examples

Create a USER_ACCESSIBLE mapping:

        mapper
          .map_to(
              page,
              frame,
             PageTableFlags::PRESENT
                  | PageTableFlags::WRITABLE
                  | PageTableFlags::USER_ACCESSIBLE,
              frame_allocator,
          )
          .unwrap()
          .flush();
Source

unsafe fn identity_map<A>( &mut self, frame: PhysFrame<S>, flags: PageTableFlags, frame_allocator: &mut A, ) -> Result<MapperFlush<S>, MapToError<S>>
where Self: Sized + Mapper<S>, A: FrameAllocator<Size4KiB> + ?Sized, S: PageSize,

Maps the given frame to the virtual page with the same address.

§Safety

This is a convencience function that invokes Mapper::map_to internally, so all safety requirements of it also apply for this function.

Implementors§