diff --git a/src/structures/paging/mapper/mapped_page_table.rs b/src/structures/paging/mapper/mapped_page_table.rs index d4c7053a8..0b4b4fe8c 100644 --- a/src/structures/paging/mapper/mapped_page_table.rs +++ b/src/structures/paging/mapper/mapped_page_table.rs @@ -44,15 +44,18 @@ impl<'a, P: PhysToVirt> MappedPageTable<'a, P> { page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .create_next_table(&mut p4[page.p4_index()], allocator)?; + let p3 = self.page_table_walker.create_next_table( + &mut p4[page.p4_index()], + parent_table_flags, + allocator, + )?; if !p3[page.p3_index()].is_unused() { return Err(MapToError::PageAlreadyMapped(frame)); @@ -69,18 +72,23 @@ impl<'a, P: PhysToVirt> MappedPageTable<'a, P> { page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .create_next_table(&mut p4[page.p4_index()], allocator)?; - let p2 = self - .page_table_walker - .create_next_table(&mut p3[page.p3_index()], allocator)?; + let p3 = self.page_table_walker.create_next_table( + &mut p4[page.p4_index()], + parent_table_flags, + allocator, + )?; + let p2 = self.page_table_walker.create_next_table( + &mut p3[page.p3_index()], + parent_table_flags, + allocator, + )?; if !p2[page.p2_index()].is_unused() { return Err(MapToError::PageAlreadyMapped(frame)); @@ -97,21 +105,28 @@ impl<'a, P: PhysToVirt> MappedPageTable<'a, P> { page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { let p4 = &mut self.level_4_table; - let p3 = self - .page_table_walker - .create_next_table(&mut p4[page.p4_index()], allocator)?; - let p2 = self - .page_table_walker - .create_next_table(&mut p3[page.p3_index()], allocator)?; - let p1 = self - .page_table_walker - .create_next_table(&mut p2[page.p2_index()], allocator)?; + let p3 = self.page_table_walker.create_next_table( + &mut p4[page.p4_index()], + parent_table_flags, + allocator, + )?; + let p2 = self.page_table_walker.create_next_table( + &mut p3[page.p3_index()], + parent_table_flags, + allocator, + )?; + let p1 = self.page_table_walker.create_next_table( + &mut p2[page.p2_index()], + parent_table_flags, + allocator, + )?; if !p1[page.p1_index()].is_unused() { return Err(MapToError::PageAlreadyMapped(frame)); @@ -124,17 +139,18 @@ impl<'a, P: PhysToVirt> MappedPageTable<'a, P> { impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { #[inline] - unsafe fn map_to( + unsafe fn map_to_with_table_flags( &mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { - self.map_to_1gib(page, frame, flags, allocator) + self.map_to_1gib(page, frame, flags, parent_table_flags, allocator) } fn unmap( @@ -181,6 +197,39 @@ impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { Ok(MapperFlush::new(page)) } + unsafe fn set_flags_p4_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.level_4_table; + let p4_entry = &mut p4[page.p4_index()]; + + if p4_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p4_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + + unsafe fn set_flags_p3_entry( + &mut self, + _page: Page, + _flags: PageTableFlags, + ) -> Result { + Err(FlagUpdateError::ParentEntryHugePage) + } + + unsafe fn set_flags_p2_entry( + &mut self, + _page: Page, + _flags: PageTableFlags, + ) -> Result { + Err(FlagUpdateError::ParentEntryHugePage) + } + fn translate_page(&self, page: Page) -> Result, TranslateError> { let p4 = &self.level_4_table; let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; @@ -198,17 +247,18 @@ impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { #[inline] - unsafe fn map_to( + unsafe fn map_to_with_table_flags( &mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { - self.map_to_2mib(page, frame, flags, allocator) + self.map_to_2mib(page, frame, flags, parent_table_flags, allocator) } fn unmap( @@ -262,6 +312,51 @@ impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { Ok(MapperFlush::new(page)) } + unsafe fn set_flags_p4_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.level_4_table; + let p4_entry = &mut p4[page.p4_index()]; + + if p4_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p4_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + + unsafe fn set_flags_p3_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.level_4_table; + let p3 = self + .page_table_walker + .next_table_mut(&mut p4[page.p4_index()])?; + let p3_entry = &mut p3[page.p3_index()]; + + if p3_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p3_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + + unsafe fn set_flags_p2_entry( + &mut self, + _page: Page, + _flags: PageTableFlags, + ) -> Result { + Err(FlagUpdateError::ParentEntryHugePage) + } + fn translate_page(&self, page: Page) -> Result, TranslateError> { let p4 = &self.level_4_table; let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; @@ -280,17 +375,18 @@ impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { #[inline] - unsafe fn map_to( + unsafe fn map_to_with_table_flags( &mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { - self.map_to_4kib(page, frame, flags, allocator) + self.map_to_4kib(page, frame, flags, parent_table_flags, allocator) } fn unmap( @@ -344,6 +440,66 @@ impl<'a, P: PhysToVirt> Mapper for MappedPageTable<'a, P> { Ok(MapperFlush::new(page)) } + unsafe fn set_flags_p4_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.level_4_table; + let p4_entry = &mut p4[page.p4_index()]; + + if p4_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p4_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + + unsafe fn set_flags_p3_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.level_4_table; + let p3 = self + .page_table_walker + .next_table_mut(&mut p4[page.p4_index()])?; + let p3_entry = &mut p3[page.p3_index()]; + + if p3_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p3_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + + unsafe fn set_flags_p2_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.level_4_table; + let p3 = self + .page_table_walker + .next_table_mut(&mut p4[page.p4_index()])?; + let p2 = self + .page_table_walker + .next_table_mut(&mut p3[page.p3_index()])?; + let p2_entry = &mut p2[page.p2_index()]; + + if p2_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p2_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + fn translate_page(&self, page: Page) -> Result, TranslateError> { let p4 = &self.level_4_table; let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; @@ -461,6 +617,7 @@ impl PageTableWalker

{ fn create_next_table<'b, A>( &self, entry: &'b mut PageTableEntry, + insert_flags: PageTableFlags, allocator: &mut A, ) -> Result<&'b mut PageTable, PageTableCreateError> where @@ -470,12 +627,15 @@ impl PageTableWalker

{ if entry.is_unused() { if let Some(frame) = allocator.allocate_frame() { - entry.set_frame(frame, PageTableFlags::PRESENT | PageTableFlags::WRITABLE); + entry.set_frame(frame, insert_flags); created = true; } else { return Err(PageTableCreateError::FrameAllocationFailed); } } else { + if !insert_flags.is_empty() && !entry.flags().contains(insert_flags) { + entry.set_flags(entry.flags() | insert_flags); + } created = false; } diff --git a/src/structures/paging/mapper/mod.rs b/src/structures/paging/mapper/mod.rs index 70a874d08..44dc0d4b7 100644 --- a/src/structures/paging/mapper/mod.rs +++ b/src/structures/paging/mapper/mod.rs @@ -83,6 +83,13 @@ pub trait Mapper { /// 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 @@ -111,6 +118,32 @@ pub trait Mapper { /// 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: + /// + /// ``` + /// # use x86_64::structures::paging::{ + /// # Mapper, Page, PhysFrame, FrameAllocator, + /// # Size4KiB, OffsetPageTable, page_table::PageTableFlags + /// # }; + /// # unsafe fn test(mapper: &mut OffsetPageTable, frame_allocator: &mut impl FrameAllocator, + /// # page: Page, frame: PhysFrame) { + /// mapper + /// .map_to( + /// page, + /// frame, + /// PageTableFlags::PRESENT + /// | PageTableFlags::WRITABLE + /// | PageTableFlags::USER_ACCESSIBLE, + /// frame_allocator, + /// ) + /// .unwrap() + /// .flush(); + /// # } + /// ``` + #[inline] unsafe fn map_to( &mut self, page: Page, @@ -118,6 +151,94 @@ pub trait Mapper { flags: PageTableFlags, frame_allocator: &mut A, ) -> Result, MapToError> + where + Self: Sized, + A: FrameAllocator, + { + let parent_table_flags = flags + & (PageTableFlags::PRESENT + | PageTableFlags::WRITABLE + | PageTableFlags::USER_ACCESSIBLE); + + self.map_to_with_table_flags(page, frame, flags, parent_table_flags, frame_allocator) + } + + /// 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 uninitalized 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: + /// + /// ``` + /// # use x86_64::structures::paging::{ + /// # Mapper, PhysFrame, Page, FrameAllocator, + /// # Size4KiB, OffsetPageTable, page_table::PageTableFlags + /// # }; + /// # unsafe fn test(mapper: &mut OffsetPageTable, frame_allocator: &mut impl FrameAllocator, + /// # page: Page, frame: PhysFrame) { + /// 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(); + /// # } + /// ``` + unsafe fn map_to_with_table_flags( + &mut self, + page: Page, + frame: PhysFrame, + flags: PageTableFlags, + parent_table_flags: PageTableFlags, + frame_allocator: &mut A, + ) -> Result, MapToError> where Self: Sized, A: FrameAllocator; @@ -142,6 +263,51 @@ pub trait Mapper { flags: PageTableFlags, ) -> Result, 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. + unsafe fn set_flags_p4_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result; + + /// 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. + unsafe fn set_flags_p3_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result; + + /// 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. + unsafe fn set_flags_p2_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result; + /// 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 @@ -200,6 +366,34 @@ impl MapperFlush { pub fn ignore(self) {} } +/// This type represents a change of a page table requiring a complete TLB flush +/// +/// The old mapping might be still cached in the translation lookaside buffer (TLB), so it needs +/// to be flushed from the TLB before it's accessed. This type is returned from a function that +/// made the change to ensure that the TLB flush is not forgotten. +#[derive(Debug)] +#[must_use = "Page Table changes must be flushed or ignored."] +pub struct MapperFlushAll(()); + +impl MapperFlushAll { + /// Create a new flush promise + #[inline] + fn new() -> Self { + MapperFlushAll(()) + } + + /// Flush all pages from the TLB to ensure that the newest mapping is used. + #[cfg(target_arch = "x86_64")] + #[inline] + pub fn flush_all(self) { + crate::instructions::tlb::flush_all() + } + + /// Don't flush the TLB and silence the “must be used” warning. + #[inline] + pub fn ignore(self) {} +} + /// This error is returned from `map_to` and similar methods. #[derive(Debug)] pub enum MapToError { diff --git a/src/structures/paging/mapper/offset_page_table.rs b/src/structures/paging/mapper/offset_page_table.rs index 4e5a07375..76287e672 100644 --- a/src/structures/paging/mapper/offset_page_table.rs +++ b/src/structures/paging/mapper/offset_page_table.rs @@ -1,6 +1,8 @@ #![cfg(target_arch = "x86_64")] -use crate::structures::paging::{frame::PhysFrame, mapper::*, page_table::PageTable}; +use crate::structures::paging::{ + frame::PhysFrame, mapper::*, page_table::PageTable, Page, PageTableFlags, +}; /// A Mapper implementation that requires that the complete physically memory is mapped at some /// offset in the virtual address space. @@ -54,17 +56,19 @@ impl PhysToVirt for PhysOffset { impl<'a> Mapper for OffsetPageTable<'a> { #[inline] - unsafe fn map_to( + unsafe fn map_to_with_table_flags( &mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { - self.inner.map_to(page, frame, flags, allocator) + self.inner + .map_to_with_table_flags(page, frame, flags, parent_table_flags, allocator) } #[inline] @@ -84,6 +88,33 @@ impl<'a> Mapper for OffsetPageTable<'a> { self.inner.update_flags(page, flags) } + #[inline] + unsafe fn set_flags_p4_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + self.inner.set_flags_p4_entry(page, flags) + } + + #[inline] + unsafe fn set_flags_p3_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + self.inner.set_flags_p3_entry(page, flags) + } + + #[inline] + unsafe fn set_flags_p2_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + self.inner.set_flags_p2_entry(page, flags) + } + #[inline] fn translate_page(&self, page: Page) -> Result, TranslateError> { self.inner.translate_page(page) @@ -92,17 +123,19 @@ impl<'a> Mapper for OffsetPageTable<'a> { impl<'a> Mapper for OffsetPageTable<'a> { #[inline] - unsafe fn map_to( + unsafe fn map_to_with_table_flags( &mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { - self.inner.map_to(page, frame, flags, allocator) + self.inner + .map_to_with_table_flags(page, frame, flags, parent_table_flags, allocator) } #[inline] @@ -122,6 +155,33 @@ impl<'a> Mapper for OffsetPageTable<'a> { self.inner.update_flags(page, flags) } + #[inline] + unsafe fn set_flags_p4_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + self.inner.set_flags_p4_entry(page, flags) + } + + #[inline] + unsafe fn set_flags_p3_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + self.inner.set_flags_p3_entry(page, flags) + } + + #[inline] + unsafe fn set_flags_p2_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + self.inner.set_flags_p2_entry(page, flags) + } + #[inline] fn translate_page(&self, page: Page) -> Result, TranslateError> { self.inner.translate_page(page) @@ -130,17 +190,19 @@ impl<'a> Mapper for OffsetPageTable<'a> { impl<'a> Mapper for OffsetPageTable<'a> { #[inline] - unsafe fn map_to( + unsafe fn map_to_with_table_flags( &mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { - self.inner.map_to(page, frame, flags, allocator) + self.inner + .map_to_with_table_flags(page, frame, flags, parent_table_flags, allocator) } #[inline] @@ -160,6 +222,33 @@ impl<'a> Mapper for OffsetPageTable<'a> { self.inner.update_flags(page, flags) } + #[inline] + unsafe fn set_flags_p4_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + self.inner.set_flags_p4_entry(page, flags) + } + + #[inline] + unsafe fn set_flags_p3_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + self.inner.set_flags_p3_entry(page, flags) + } + + #[inline] + unsafe fn set_flags_p2_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + self.inner.set_flags_p2_entry(page, flags) + } + #[inline] fn translate_page(&self, page: Page) -> Result, TranslateError> { self.inner.translate_page(page) diff --git a/src/structures/paging/mapper/recursive_page_table.rs b/src/structures/paging/mapper/recursive_page_table.rs index 7215e5de5..14cba0b31 100644 --- a/src/structures/paging/mapper/recursive_page_table.rs +++ b/src/structures/paging/mapper/recursive_page_table.rs @@ -26,6 +26,9 @@ use crate::VirtAddr; /// level 3 index, then the level 2 index. /// /// This struct implements the `Mapper` trait. +/// +/// The page table flags `PRESENT` and `WRITABLE` are always set for higher level page table +/// entries, even if not specified, because the design of the recursive page table requires it. #[derive(Debug)] pub struct RecursivePageTable<'a> { p4: &'a mut PageTable, @@ -84,6 +87,10 @@ impl<'a> RecursivePageTable<'a> { /// and the entry is updated to that address. If the passed entry is already mapped, the next /// table is returned directly. /// + /// The page table flags `PRESENT` and `WRITABLE` are always set for higher level page table + /// entries, even if not specified in the `insert_flags`, because the design of the + /// recursive page table requires it. + /// /// The `next_page_table` page must be the page of the next page table in the hierarchy. /// /// Returns `MapToError::FrameAllocationFailed` if the entry is unused and the allocator @@ -92,6 +99,7 @@ impl<'a> RecursivePageTable<'a> { unsafe fn create_next_table<'b, A, S: PageSize>( entry: &'b mut PageTableEntry, next_table_page: Page, + insert_flags: PageTableFlags, allocator: &mut A, ) -> Result<&'b mut PageTable, MapToError> where @@ -103,6 +111,7 @@ impl<'a> RecursivePageTable<'a> { fn inner<'b, A, S: PageSize>( entry: &'b mut PageTableEntry, next_table_page: Page, + insert_flags: PageTableFlags, allocator: &mut A, ) -> Result<&'b mut PageTable, MapToError> where @@ -114,12 +123,15 @@ impl<'a> RecursivePageTable<'a> { if entry.is_unused() { if let Some(frame) = allocator.allocate_frame() { - entry.set_frame(frame, Flags::PRESENT | Flags::WRITABLE); + entry.set_frame(frame, Flags::PRESENT | Flags::WRITABLE | insert_flags); created = true; } else { return Err(MapToError::FrameAllocationFailed); } } else { + if !insert_flags.is_empty() && !entry.flags().contains(insert_flags) { + entry.set_flags(entry.flags() | insert_flags); + } created = false; } if entry.flags().contains(Flags::HUGE_PAGE) { @@ -134,7 +146,7 @@ impl<'a> RecursivePageTable<'a> { Ok(page_table) } - inner(entry, next_table_page, allocator) + inner(entry, next_table_page, insert_flags, allocator) } /// Helper function for implementing Mapper. Safe to limit the scope of unsafe, see @@ -144,6 +156,7 @@ impl<'a> RecursivePageTable<'a> { page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where @@ -153,7 +166,14 @@ impl<'a> RecursivePageTable<'a> { let p4 = &mut self.p4; let p3_page = p3_page(page, self.recursive_index); - let p3 = unsafe { Self::create_next_table(&mut p4[page.p4_index()], p3_page, allocator)? }; + let p3 = unsafe { + Self::create_next_table( + &mut p4[page.p4_index()], + p3_page, + parent_table_flags, + allocator, + )? + }; if !p3[page.p3_index()].is_unused() { return Err(MapToError::PageAlreadyMapped(frame)); @@ -170,6 +190,7 @@ impl<'a> RecursivePageTable<'a> { page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where @@ -179,10 +200,24 @@ impl<'a> RecursivePageTable<'a> { let p4 = &mut self.p4; let p3_page = p3_page(page, self.recursive_index); - let p3 = unsafe { Self::create_next_table(&mut p4[page.p4_index()], p3_page, allocator)? }; + let p3 = unsafe { + Self::create_next_table( + &mut p4[page.p4_index()], + p3_page, + parent_table_flags, + allocator, + )? + }; let p2_page = p2_page(page, self.recursive_index); - let p2 = unsafe { Self::create_next_table(&mut p3[page.p3_index()], p2_page, allocator)? }; + let p2 = unsafe { + Self::create_next_table( + &mut p3[page.p3_index()], + p2_page, + parent_table_flags, + allocator, + )? + }; if !p2[page.p2_index()].is_unused() { return Err(MapToError::PageAlreadyMapped(frame)); @@ -199,6 +234,7 @@ impl<'a> RecursivePageTable<'a> { page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where @@ -207,13 +243,34 @@ impl<'a> RecursivePageTable<'a> { let p4 = &mut self.p4; let p3_page = p3_page(page, self.recursive_index); - let p3 = unsafe { Self::create_next_table(&mut p4[page.p4_index()], p3_page, allocator)? }; + let p3 = unsafe { + Self::create_next_table( + &mut p4[page.p4_index()], + p3_page, + parent_table_flags, + allocator, + )? + }; let p2_page = p2_page(page, self.recursive_index); - let p2 = unsafe { Self::create_next_table(&mut p3[page.p3_index()], p2_page, allocator)? }; + let p2 = unsafe { + Self::create_next_table( + &mut p3[page.p3_index()], + p2_page, + parent_table_flags, + allocator, + )? + }; let p1_page = p1_page(page, self.recursive_index); - let p1 = unsafe { Self::create_next_table(&mut p2[page.p2_index()], p1_page, allocator)? }; + let p1 = unsafe { + Self::create_next_table( + &mut p2[page.p2_index()], + p1_page, + parent_table_flags, + allocator, + )? + }; if !p1[page.p1_index()].is_unused() { return Err(MapToError::PageAlreadyMapped(frame)); @@ -226,17 +283,18 @@ impl<'a> RecursivePageTable<'a> { impl<'a> Mapper for RecursivePageTable<'a> { #[inline] - unsafe fn map_to( + unsafe fn map_to_with_table_flags( &mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { - self.map_to_1gib(page, frame, flags, allocator) + self.map_to_1gib(page, frame, flags, parent_table_flags, allocator) } fn unmap( @@ -293,6 +351,39 @@ impl<'a> Mapper for RecursivePageTable<'a> { Ok(MapperFlush::new(page)) } + unsafe fn set_flags_p4_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.p4; + let p4_entry = &mut p4[page.p4_index()]; + + if p4_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p4_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + + unsafe fn set_flags_p3_entry( + &mut self, + _page: Page, + _flags: PageTableFlags, + ) -> Result { + Err(FlagUpdateError::ParentEntryHugePage) + } + + unsafe fn set_flags_p2_entry( + &mut self, + _page: Page, + _flags: PageTableFlags, + ) -> Result { + Err(FlagUpdateError::ParentEntryHugePage) + } + fn translate_page(&self, page: Page) -> Result, TranslateError> { let p4 = &self.p4; @@ -314,17 +405,18 @@ impl<'a> Mapper for RecursivePageTable<'a> { impl<'a> Mapper for RecursivePageTable<'a> { #[inline] - unsafe fn map_to( + unsafe fn map_to_with_table_flags( &mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { - self.map_to_2mib(page, frame, flags, allocator) + self.map_to_2mib(page, frame, flags, parent_table_flags, allocator) } fn unmap( @@ -394,6 +486,54 @@ impl<'a> Mapper for RecursivePageTable<'a> { Ok(MapperFlush::new(page)) } + unsafe fn set_flags_p4_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.p4; + let p4_entry = &mut p4[page.p4_index()]; + + if p4_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p4_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + + unsafe fn set_flags_p3_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.p4; + + if p4[page.p4_index()].is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + let p3 = &mut *(p3_ptr(page, self.recursive_index)); + let p3_entry = &mut p3[page.p3_index()]; + + if p3_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p3_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + + unsafe fn set_flags_p2_entry( + &mut self, + _page: Page, + _flags: PageTableFlags, + ) -> Result { + Err(FlagUpdateError::ParentEntryHugePage) + } + fn translate_page(&self, page: Page) -> Result, TranslateError> { let p4 = &self.p4; @@ -422,17 +562,18 @@ impl<'a> Mapper for RecursivePageTable<'a> { impl<'a> Mapper for RecursivePageTable<'a> { #[inline] - unsafe fn map_to( + unsafe fn map_to_with_table_flags( &mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, + parent_table_flags: PageTableFlags, allocator: &mut A, ) -> Result, MapToError> where A: FrameAllocator, { - self.map_to_4kib(page, frame, flags, allocator) + self.map_to_4kib(page, frame, flags, parent_table_flags, allocator) } fn unmap( @@ -508,6 +649,75 @@ impl<'a> Mapper for RecursivePageTable<'a> { Ok(MapperFlush::new(page)) } + unsafe fn set_flags_p4_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.p4; + let p4_entry = &mut p4[page.p4_index()]; + + if p4_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p4_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + + unsafe fn set_flags_p3_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.p4; + + if p4[page.p4_index()].is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + let p3 = &mut *(p3_ptr(page, self.recursive_index)); + let p3_entry = &mut p3[page.p3_index()]; + + if p3_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p3_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + + unsafe fn set_flags_p2_entry( + &mut self, + page: Page, + flags: PageTableFlags, + ) -> Result { + let p4 = &mut self.p4; + + if p4[page.p4_index()].is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + let p3 = &mut *(p3_ptr(page, self.recursive_index)); + + if p3[page.p3_index()].is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + let p2 = &mut *(p2_ptr(page, self.recursive_index)); + let p2_entry = &mut p2[page.p2_index()]; + + if p2_entry.is_unused() { + return Err(FlagUpdateError::PageNotMapped); + } + + p2_entry.set_flags(flags); + + Ok(MapperFlushAll::new()) + } + fn translate_page(&self, page: Page) -> Result, TranslateError> { let p4 = &self.p4;