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§
Sourceunsafe 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>>
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>>
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 theMaybeUninit
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();
Sourcefn unmap(
&mut self,
page: Page<S>,
) -> Result<(PhysFrame<S>, MapperFlush<S>), UnmapError>
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.
Sourceunsafe fn update_flags(
&mut self,
page: Page<S>,
flags: PageTableFlags,
) -> Result<MapperFlush<S>, FlagUpdateError>
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.
Sourceunsafe fn set_flags_p4_entry(
&mut self,
page: Page<S>,
flags: PageTableFlags,
) -> Result<MapperFlushAll, FlagUpdateError>
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.
Sourceunsafe fn set_flags_p3_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>
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.
Sourceunsafe fn set_flags_p2_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>
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.
Sourcefn translate_page(&self, page: Page<S>) -> Result<PhysFrame<S>, TranslateError>
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§
Sourceunsafe fn map_to<A>(
&mut self,
page: Page<S>,
frame: PhysFrame<S>,
flags: PageTableFlags,
frame_allocator: &mut A,
) -> Result<MapperFlush<S>, MapToError<S>>
unsafe fn map_to<A>( &mut self, page: Page<S>, frame: PhysFrame<S>, flags: PageTableFlags, frame_allocator: &mut A, ) -> Result<MapperFlush<S>, MapToError<S>>
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 theMaybeUninit
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();
Sourceunsafe fn identity_map<A>(
&mut self,
frame: PhysFrame<S>,
flags: PageTableFlags,
frame_allocator: &mut A,
) -> Result<MapperFlush<S>, MapToError<S>>
unsafe fn identity_map<A>( &mut self, frame: PhysFrame<S>, flags: PageTableFlags, frame_allocator: &mut A, ) -> Result<MapperFlush<S>, MapToError<S>>
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.