From 7c82b6cbe3ad250e88316b84c87d7fdd3bec733f Mon Sep 17 00:00:00 2001 From: Alison Davis Date: Sat, 18 Jan 2025 19:32:30 -0600 Subject: [PATCH 1/4] Add page attribute table support --- src/registers/model_specific.rs | 106 ++++++++++++++++++ .../paging/mapper/mapped_page_table.rs | 8 +- .../paging/mapper/recursive_page_table.rs | 43 ++++--- src/structures/paging/page_table.rs | 30 +++-- 4 files changed, 153 insertions(+), 34 deletions(-) diff --git a/src/registers/model_specific.rs b/src/registers/model_specific.rs index cf2dd34b..cfe324b1 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -67,6 +67,10 @@ pub struct UCet; #[derive(Debug)] pub struct SCet; +/// IA32_PAT: Page Attribute Table. +#[derive(Debug)] +pub struct Pat; + impl Efer { /// The underlying model specific register. pub const MSR: Msr = Msr(0xC000_0080); @@ -112,6 +116,22 @@ impl SCet { pub const MSR: Msr = Msr(0x6A2); } +impl Pat { + /// The underlying model specific register. + pub const MSR: Msr = Msr(0x277); + /// The default PAT configuration following a power up or reset of the processor. + pub const DEFAULT: [PatFlags; 8] = [ + PatFlags::WRITE_BACK, + PatFlags::WRITE_THROUGH, + PatFlags::UNCACHED, + PatFlags::UNCACHEABLE, + PatFlags::WRITE_BACK, + PatFlags::WRITE_THROUGH, + PatFlags::UNCACHED, + PatFlags::UNCACHEABLE, + ]; +} + bitflags! { /// Flags of the Extended Feature Enable Register. #[repr(transparent)] @@ -161,6 +181,52 @@ bitflags! { } } +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] +/// Flags for the [PAT](Pat). +pub struct PatFlags(u8); +impl PatFlags { + /// Disables caching. + pub const UNCACHEABLE: Self = Self(0x00); + /// Uses a write combining cache policy. + pub const WRITE_COMBINING: Self = Self(0x01); + /// Uses a write through cache policy. + pub const WRITE_THROUGH: Self = Self(0x04); + /// Uses a write protected cache policy. + pub const WRITE_PROTECTED: Self = Self(0x05); + /// Uses a write back cache policy. + pub const WRITE_BACK: Self = Self(0x06); + /// Same as uncacheable, but can be overridden by MTRRs. + pub const UNCACHED: Self = Self(0x07); + + /// Converts from bits, returning `None` if the value is invalid. + pub const fn from_bits(bits: u8) -> Option { + match Self(bits) { + Self::UNCACHEABLE + | Self::WRITE_COMBINING + | Self::WRITE_THROUGH + | Self::WRITE_PROTECTED + | Self::WRITE_BACK + | Self::UNCACHED => Some(Self(bits)), + _ => None, + } + } + + /// Converts from bits without checking if the value is valid. + /// + /// # Safety + /// + /// `bits` must correspond to a valid memory type, otherwise a general protection exception will + /// occur if it is written to the PAT. + pub const unsafe fn from_bits_unchecked(bits: u8) -> Self { + Self(bits) + } + + /// Gets the underlying bits. + pub const fn bits(self) -> u8 { + self.0 + } +} + #[cfg(all(feature = "instructions", target_arch = "x86_64"))] mod x86_64 { use super::*; @@ -636,4 +702,44 @@ mod x86_64 { Self::write(flags, legacy_bitmap); } } + + impl Pat { + /// Reads IA32_PAT. + /// + /// # Safety + /// + /// The PAT must be supported on the CPU, otherwise a general protection exception will + /// occur. Support can be detected using the `cpuid` instruction. + #[inline] + pub unsafe fn read() -> [PatFlags; 8] { + let bits = unsafe { Self::MSR.read() }; + let mut flags = [PatFlags::UNCACHEABLE; 8]; + for (i, flag) in flags.iter_mut().enumerate() { + *flag = PatFlags((bits >> (8 * i)) as u8); + } + flags + } + + /// Writes IA32_PAT. + /// + /// # Safety + /// + /// All affected pages must be flushed from the TLB. Processor caches may also need to be + /// flushed. Additionally, all pages that map to a given frame must have the same memory + /// type. + /// + /// The PAT must be supported on the CPU, otherwise a general protection exception will + /// occur. Support can be detected using the `cpuid` instruction. + #[inline] + pub unsafe fn write(flags: [PatFlags; 8]) { + let mut bits = 0u64; + for (i, flag) in flags.iter().enumerate() { + bits |= (flag.bits() as u64) << (8 * i); + } + let mut msr = Self::MSR; + unsafe { + msr.write(bits); + } + } + } } diff --git a/src/structures/paging/mapper/mapped_page_table.rs b/src/structures/paging/mapper/mapped_page_table.rs index b50f072e..56c38155 100644 --- a/src/structures/paging/mapper/mapped_page_table.rs +++ b/src/structures/paging/mapper/mapped_page_table.rs @@ -421,7 +421,6 @@ impl Mapper for MappedPageTable<'_, P> { let frame = p1_entry.frame().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, })?; p1_entry.set_unused(); @@ -711,6 +710,9 @@ impl PageTableWalker

{ &self, entry: &'b PageTableEntry, ) -> Result<&'b PageTable, PageTableWalkError> { + if entry.flags().contains(PageTableFlags::HUGE_PAGE) { + return Err(PageTableWalkError::MappedToHugePage); + } let page_table_ptr = self .page_table_frame_mapping .frame_to_pointer(entry.frame()?); @@ -729,6 +731,9 @@ impl PageTableWalker

{ &self, entry: &'b mut PageTableEntry, ) -> Result<&'b mut PageTable, PageTableWalkError> { + if entry.flags().contains(PageTableFlags::HUGE_PAGE) { + return Err(PageTableWalkError::MappedToHugePage); + } let page_table_ptr = self .page_table_frame_mapping .frame_to_pointer(entry.frame()?); @@ -832,7 +837,6 @@ impl From for PageTableWalkError { #[inline] fn from(err: FrameError) -> Self { match err { - FrameError::HugeFrame => PageTableWalkError::MappedToHugePage, FrameError::FrameNotPresent => PageTableWalkError::NotMapped, } } diff --git a/src/structures/paging/mapper/recursive_page_table.rs b/src/structures/paging/mapper/recursive_page_table.rs index ff427ffa..e57ddcb9 100644 --- a/src/structures/paging/mapper/recursive_page_table.rs +++ b/src/structures/paging/mapper/recursive_page_table.rs @@ -322,9 +322,11 @@ impl Mapper for RecursivePageTable<'_> { let p4 = &mut self.p4; let p4_entry = &p4[page.p4_index()]; - p4_entry.frame().map_err(|err| match err { + if p4_entry.flags().contains(PageTableFlags::HUGE_PAGE) { + return Err(UnmapError::ParentEntryHugePage); + } + p4_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, })?; let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; @@ -441,16 +443,20 @@ impl Mapper for RecursivePageTable<'_> { ) -> Result<(PhysFrame, MapperFlush), UnmapError> { let p4 = &mut self.p4; let p4_entry = &p4[page.p4_index()]; - p4_entry.frame().map_err(|err| match err { + if p4_entry.flags().contains(PageTableFlags::HUGE_PAGE) { + return Err(UnmapError::ParentEntryHugePage); + } + p4_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, })?; let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; let p3_entry = &p3[page.p3_index()]; - p3_entry.frame().map_err(|err| match err { + if p3_entry.flags().contains(PageTableFlags::HUGE_PAGE) { + return Err(UnmapError::ParentEntryHugePage); + } + p3_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, })?; let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; @@ -596,23 +602,29 @@ impl Mapper for RecursivePageTable<'_> { ) -> Result<(PhysFrame, MapperFlush), UnmapError> { let p4 = &mut self.p4; let p4_entry = &p4[page.p4_index()]; - p4_entry.frame().map_err(|err| match err { + if p4_entry.flags().contains(PageTableFlags::HUGE_PAGE) { + return Err(UnmapError::ParentEntryHugePage); + } + p4_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, })?; let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; let p3_entry = &p3[page.p3_index()]; - p3_entry.frame().map_err(|err| match err { + if p3_entry.flags().contains(PageTableFlags::HUGE_PAGE) { + return Err(UnmapError::ParentEntryHugePage); + } + p3_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, })?; let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; let p2_entry = &p2[page.p2_index()]; - p2_entry.frame().map_err(|err| match err { + if p2_entry.flags().contains(PageTableFlags::HUGE_PAGE) { + return Err(UnmapError::ParentEntryHugePage); + } + p2_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, })?; let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) }; @@ -620,7 +632,6 @@ impl Mapper for RecursivePageTable<'_> { let frame = p1_entry.frame().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, })?; p1_entry.set_unused(); @@ -818,9 +829,6 @@ impl Translate for RecursivePageTable<'_> { if p1_entry.is_unused() { return TranslateResult::NotMapped; } - if p1_entry.flags().contains(PageTableFlags::HUGE_PAGE) { - panic!("level 1 entry has huge page bit set") - } let frame = match PhysFrame::from_start_address(p1_entry.addr()) { Ok(frame) => frame, @@ -890,6 +898,9 @@ impl CleanUp for RecursivePageTable<'_> { !(level == PageTableLevel::Four && *i == recursive_index.into()) }) { + if entry.flags().contains(PageTableFlags::HUGE_PAGE) { + continue; + } if let Ok(frame) = entry.frame() { let start = VirtAddr::forward_checked_impl( table_addr, diff --git a/src/structures/paging/page_table.rs b/src/structures/paging/page_table.rs index e9069bcc..65a656b4 100644 --- a/src/structures/paging/page_table.rs +++ b/src/structures/paging/page_table.rs @@ -15,9 +15,6 @@ use bitflags::bitflags; pub enum FrameError { /// The entry does not have the `PRESENT` flag set, so it isn't currently mapped to a frame. FrameNotPresent, - /// The entry does have the `HUGE_PAGE` flag set. The `frame` method has a standard 4KiB frame - /// as return type, so a huge frame can't be returned. - HugeFrame, } /// A 64-bit page table entry. @@ -63,16 +60,12 @@ impl PageTableEntry { /// Returns the following errors: /// /// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set. - /// - `FrameError::HugeFrame` if the entry has the `HUGE_PAGE` flag set (for huge pages the - /// `addr` function must be used) #[inline] - pub fn frame(&self) -> Result { - if !self.flags().contains(PageTableFlags::PRESENT) { - Err(FrameError::FrameNotPresent) - } else if self.flags().contains(PageTableFlags::HUGE_PAGE) { - Err(FrameError::HugeFrame) - } else { + pub fn frame(&self) -> Result, FrameError> { + if self.flags().contains(PageTableFlags::PRESENT) { Ok(PhysFrame::containing_address(self.addr())) + } else { + Err(FrameError::FrameNotPresent) } } @@ -86,7 +79,6 @@ impl PageTableEntry { /// Map the entry to the specified physical frame with the specified flags. #[inline] pub fn set_frame(&mut self, frame: PhysFrame, flags: PageTableFlags) { - assert!(!flags.contains(PageTableFlags::HUGE_PAGE)); self.set_addr(frame.start_address(), flags) } @@ -128,17 +120,21 @@ bitflags! { /// Controls whether accesses from userspace (i.e. ring 3) are permitted. const USER_ACCESSIBLE = 1 << 2; /// If this bit is set, a “write-through” policy is used for the cache, else a “write-back” - /// policy is used. + /// policy is used. This referred to as the page-level write-through (PWT) bit. const WRITE_THROUGH = 1 << 3; - /// Disables caching for the pointed entry is cacheable. + /// Disables caching for the pointed entry if it is cacheable. This referred to as the + /// page-level cache disable (PCD) bit. const NO_CACHE = 1 << 4; /// Set by the CPU when the mapped frame or page table is accessed. const ACCESSED = 1 << 5; /// Set by the CPU on a write to the mapped frame. const DIRTY = 1 << 6; - /// Specifies that the entry maps a huge frame instead of a page table. Only allowed in - /// P2 or P3 tables. + /// Specifies that the entry maps a huge frame instead of a page table. This is the same bit + /// as `PAT_4KIB_PAGE`. const HUGE_PAGE = 1 << 7; + /// This is the PAT bit for page table entries that point to 4KiB pages. This is the same + /// bit as `HUGE_PAGE`. + const PAT_4KIB_PAGE = 1 << 7; /// Indicates that the mapping is present in all address spaces, so it isn't flushed from /// the TLB on an address space switch. const GLOBAL = 1 << 8; @@ -148,6 +144,8 @@ bitflags! { const BIT_10 = 1 << 10; /// Available to the OS, can be used to store additional data, e.g. custom flags. const BIT_11 = 1 << 11; + /// This is the PAT bit for page table entries that point to huge pages. + const PAT_HUGE_PAGE = 1 << 12; /// Available to the OS, can be used to store additional data, e.g. custom flags. const BIT_52 = 1 << 52; /// Available to the OS, can be used to store additional data, e.g. custom flags. From e396fefb3fda7b026fe2a14326ebd94947e838ad Mon Sep 17 00:00:00 2001 From: Alison Davis Date: Sat, 18 Jan 2025 23:24:13 -0600 Subject: [PATCH 2/4] Formatting --- src/registers/model_specific.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registers/model_specific.rs b/src/registers/model_specific.rs index cfe324b1..54a3ff18 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -727,7 +727,7 @@ mod x86_64 { /// All affected pages must be flushed from the TLB. Processor caches may also need to be /// flushed. Additionally, all pages that map to a given frame must have the same memory /// type. - /// + /// /// The PAT must be supported on the CPU, otherwise a general protection exception will /// occur. Support can be detected using the `cpuid` instruction. #[inline] From 0ba90da5ddd7d69bc451ff8e5a650d13b83e9bf2 Mon Sep 17 00:00:00 2001 From: Alison Davis Date: Sun, 19 Jan 2025 15:04:32 -0600 Subject: [PATCH 3/4] Apply suggestions --- src/registers/model_specific.rs | 83 ++++++++----------- .../paging/mapper/mapped_page_table.rs | 4 + .../paging/mapper/recursive_page_table.rs | 14 ++++ src/structures/paging/page_table.rs | 3 + 4 files changed, 57 insertions(+), 47 deletions(-) diff --git a/src/registers/model_specific.rs b/src/registers/model_specific.rs index 54a3ff18..2260743a 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -120,15 +120,15 @@ impl Pat { /// The underlying model specific register. pub const MSR: Msr = Msr(0x277); /// The default PAT configuration following a power up or reset of the processor. - pub const DEFAULT: [PatFlags; 8] = [ - PatFlags::WRITE_BACK, - PatFlags::WRITE_THROUGH, - PatFlags::UNCACHED, - PatFlags::UNCACHEABLE, - PatFlags::WRITE_BACK, - PatFlags::WRITE_THROUGH, - PatFlags::UNCACHED, - PatFlags::UNCACHEABLE, + pub const DEFAULT: [PatMemoryType; 8] = [ + PatMemoryType::WriteBack, + PatMemoryType::WriteThrough, + PatMemoryType::Uncached, + PatMemoryType::Uncacheable, + PatMemoryType::WriteBack, + PatMemoryType::WriteThrough, + PatMemoryType::Uncached, + PatMemoryType::Uncacheable, ]; } @@ -182,48 +182,39 @@ bitflags! { } #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)] -/// Flags for the [PAT](Pat). -pub struct PatFlags(u8); -impl PatFlags { +/// Memory types used in the [PAT](Pat). +#[repr(u8)] +pub enum PatMemoryType { /// Disables caching. - pub const UNCACHEABLE: Self = Self(0x00); + Uncacheable = 0x00, /// Uses a write combining cache policy. - pub const WRITE_COMBINING: Self = Self(0x01); + WriteCombining = 0x01, /// Uses a write through cache policy. - pub const WRITE_THROUGH: Self = Self(0x04); + WriteThrough = 0x04, /// Uses a write protected cache policy. - pub const WRITE_PROTECTED: Self = Self(0x05); + WriteProtected = 0x05, /// Uses a write back cache policy. - pub const WRITE_BACK: Self = Self(0x06); + WriteBack = 0x06, /// Same as uncacheable, but can be overridden by MTRRs. - pub const UNCACHED: Self = Self(0x07); - + Uncached = 0x07, +} +impl PatMemoryType { /// Converts from bits, returning `None` if the value is invalid. pub const fn from_bits(bits: u8) -> Option { - match Self(bits) { - Self::UNCACHEABLE - | Self::WRITE_COMBINING - | Self::WRITE_THROUGH - | Self::WRITE_PROTECTED - | Self::WRITE_BACK - | Self::UNCACHED => Some(Self(bits)), + match bits { + 0x00 => Some(Self::Uncacheable), + 0x01 => Some(Self::WriteCombining), + 0x04 => Some(Self::WriteThrough), + 0x05 => Some(Self::WriteProtected), + 0x06 => Some(Self::WriteBack), + 0x07 => Some(Self::Uncached), _ => None, } } - /// Converts from bits without checking if the value is valid. - /// - /// # Safety - /// - /// `bits` must correspond to a valid memory type, otherwise a general protection exception will - /// occur if it is written to the PAT. - pub const unsafe fn from_bits_unchecked(bits: u8) -> Self { - Self(bits) - } - /// Gets the underlying bits. pub const fn bits(self) -> u8 { - self.0 + self as u8 } } @@ -706,34 +697,32 @@ mod x86_64 { impl Pat { /// Reads IA32_PAT. /// - /// # Safety - /// /// The PAT must be supported on the CPU, otherwise a general protection exception will /// occur. Support can be detected using the `cpuid` instruction. #[inline] - pub unsafe fn read() -> [PatFlags; 8] { + pub fn read() -> [PatMemoryType; 8] { let bits = unsafe { Self::MSR.read() }; - let mut flags = [PatFlags::UNCACHEABLE; 8]; + let mut flags = [PatMemoryType::Uncacheable; 8]; for (i, flag) in flags.iter_mut().enumerate() { - *flag = PatFlags((bits >> (8 * i)) as u8); + *flag = PatMemoryType::from_bits((bits >> (8 * i)) as u8).unwrap(); } flags } /// Writes IA32_PAT. /// + /// The PAT must be supported on the CPU, otherwise a general protection exception will + /// occur. Support can be detected using the `cpuid` instruction. + /// /// # Safety /// /// All affected pages must be flushed from the TLB. Processor caches may also need to be /// flushed. Additionally, all pages that map to a given frame must have the same memory /// type. - /// - /// The PAT must be supported on the CPU, otherwise a general protection exception will - /// occur. Support can be detected using the `cpuid` instruction. #[inline] - pub unsafe fn write(flags: [PatFlags; 8]) { + pub unsafe fn write(table: [PatMemoryType; 8]) { let mut bits = 0u64; - for (i, flag) in flags.iter().enumerate() { + for (i, flag) in table.iter().enumerate() { bits |= (flag.bits() as u64) << (8 * i); } let mut msr = Self::MSR; diff --git a/src/structures/paging/mapper/mapped_page_table.rs b/src/structures/paging/mapper/mapped_page_table.rs index 56c38155..dfa3602e 100644 --- a/src/structures/paging/mapper/mapped_page_table.rs +++ b/src/structures/paging/mapper/mapped_page_table.rs @@ -421,6 +421,8 @@ impl Mapper for MappedPageTable<'_, P> { let frame = p1_entry.frame().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, + #[allow(deprecated)] + FrameError::HugeFrame => unreachable!(), })?; p1_entry.set_unused(); @@ -837,6 +839,8 @@ impl From for PageTableWalkError { #[inline] fn from(err: FrameError) -> Self { match err { + #[allow(deprecated)] + FrameError::HugeFrame => unreachable!(), FrameError::FrameNotPresent => PageTableWalkError::NotMapped, } } diff --git a/src/structures/paging/mapper/recursive_page_table.rs b/src/structures/paging/mapper/recursive_page_table.rs index e57ddcb9..65785ad2 100644 --- a/src/structures/paging/mapper/recursive_page_table.rs +++ b/src/structures/paging/mapper/recursive_page_table.rs @@ -327,6 +327,8 @@ impl Mapper for RecursivePageTable<'_> { } p4_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, + #[allow(deprecated)] + FrameError::HugeFrame => unreachable!(), })?; let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; @@ -448,6 +450,8 @@ impl Mapper for RecursivePageTable<'_> { } p4_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, + #[allow(deprecated)] + FrameError::HugeFrame => unreachable!(), })?; let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; @@ -457,6 +461,8 @@ impl Mapper for RecursivePageTable<'_> { } p3_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, + #[allow(deprecated)] + FrameError::HugeFrame => unreachable!(), })?; let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; @@ -607,6 +613,8 @@ impl Mapper for RecursivePageTable<'_> { } p4_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, + #[allow(deprecated)] + FrameError::HugeFrame => unreachable!(), })?; let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) }; @@ -616,6 +624,8 @@ impl Mapper for RecursivePageTable<'_> { } p3_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, + #[allow(deprecated)] + FrameError::HugeFrame => unreachable!(), })?; let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) }; @@ -625,6 +635,8 @@ impl Mapper for RecursivePageTable<'_> { } p2_entry.frame::().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, + #[allow(deprecated)] + FrameError::HugeFrame => unreachable!(), })?; let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) }; @@ -632,6 +644,8 @@ impl Mapper for RecursivePageTable<'_> { let frame = p1_entry.frame().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, + #[allow(deprecated)] + FrameError::HugeFrame => unreachable!(), })?; p1_entry.set_unused(); diff --git a/src/structures/paging/page_table.rs b/src/structures/paging/page_table.rs index 65a656b4..330be709 100644 --- a/src/structures/paging/page_table.rs +++ b/src/structures/paging/page_table.rs @@ -15,6 +15,9 @@ use bitflags::bitflags; pub enum FrameError { /// The entry does not have the `PRESENT` flag set, so it isn't currently mapped to a frame. FrameNotPresent, + #[deprecated = "`HugeFrame` is no longer returned by the `frame` method, as it can now return huge pages"] + /// The entry does have the `HUGE_PAGE` flag set. + HugeFrame, } /// A 64-bit page table entry. From 2486164b5cfbfcecc08ad8a762bb6b88072c20ed Mon Sep 17 00:00:00 2001 From: Alison Davis Date: Sun, 26 Jan 2025 22:52:24 -0600 Subject: [PATCH 4/4] Fixes --- src/registers/model_specific.rs | 38 ++++++++----------- .../paging/mapper/recursive_page_table.rs | 12 +++--- src/structures/paging/page_table.rs | 4 +- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/registers/model_specific.rs b/src/registers/model_specific.rs index 2260743a..fa1902c9 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -123,12 +123,12 @@ impl Pat { pub const DEFAULT: [PatMemoryType; 8] = [ PatMemoryType::WriteBack, PatMemoryType::WriteThrough, - PatMemoryType::Uncached, PatMemoryType::Uncacheable, + PatMemoryType::StrongUncacheable, PatMemoryType::WriteBack, PatMemoryType::WriteThrough, - PatMemoryType::Uncached, PatMemoryType::Uncacheable, + PatMemoryType::StrongUncacheable, ]; } @@ -185,29 +185,29 @@ bitflags! { /// Memory types used in the [PAT](Pat). #[repr(u8)] pub enum PatMemoryType { - /// Disables caching. - Uncacheable = 0x00, - /// Uses a write combining cache policy. + /// Uncacheable (UC). + StrongUncacheable = 0x00, + /// Uses a write combining (WC) cache policy. WriteCombining = 0x01, - /// Uses a write through cache policy. + /// Uses a write through (WT) cache policy. WriteThrough = 0x04, - /// Uses a write protected cache policy. + /// Uses a write protected (WP) cache policy. WriteProtected = 0x05, - /// Uses a write back cache policy. + /// Uses a write back (WB) cache policy. WriteBack = 0x06, - /// Same as uncacheable, but can be overridden by MTRRs. - Uncached = 0x07, + /// Same as strong uncacheable, but can be overridden to be write combining by MTRRs (UC-). + Uncacheable = 0x07, } impl PatMemoryType { /// Converts from bits, returning `None` if the value is invalid. pub const fn from_bits(bits: u8) -> Option { match bits { - 0x00 => Some(Self::Uncacheable), + 0x00 => Some(Self::StrongUncacheable), 0x01 => Some(Self::WriteCombining), 0x04 => Some(Self::WriteThrough), 0x05 => Some(Self::WriteProtected), 0x06 => Some(Self::WriteBack), - 0x07 => Some(Self::Uncached), + 0x07 => Some(Self::Uncacheable), _ => None, } } @@ -701,12 +701,9 @@ mod x86_64 { /// occur. Support can be detected using the `cpuid` instruction. #[inline] pub fn read() -> [PatMemoryType; 8] { - let bits = unsafe { Self::MSR.read() }; - let mut flags = [PatMemoryType::Uncacheable; 8]; - for (i, flag) in flags.iter_mut().enumerate() { - *flag = PatMemoryType::from_bits((bits >> (8 * i)) as u8).unwrap(); - } - flags + unsafe { Self::MSR.read() } + .to_ne_bytes() + .map(|bits| PatMemoryType::from_bits(bits).unwrap()) } /// Writes IA32_PAT. @@ -721,10 +718,7 @@ mod x86_64 { /// type. #[inline] pub unsafe fn write(table: [PatMemoryType; 8]) { - let mut bits = 0u64; - for (i, flag) in table.iter().enumerate() { - bits |= (flag.bits() as u64) << (8 * i); - } + let bits = u64::from_ne_bytes(table.map(PatMemoryType::bits)); let mut msr = Self::MSR; unsafe { msr.write(bits); diff --git a/src/structures/paging/mapper/recursive_page_table.rs b/src/structures/paging/mapper/recursive_page_table.rs index 65785ad2..3906a1a5 100644 --- a/src/structures/paging/mapper/recursive_page_table.rs +++ b/src/structures/paging/mapper/recursive_page_table.rs @@ -325,7 +325,7 @@ impl Mapper for RecursivePageTable<'_> { if p4_entry.flags().contains(PageTableFlags::HUGE_PAGE) { return Err(UnmapError::ParentEntryHugePage); } - p4_entry.frame::().map_err(|err| match err { + p4_entry.frame().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, #[allow(deprecated)] FrameError::HugeFrame => unreachable!(), @@ -448,7 +448,7 @@ impl Mapper for RecursivePageTable<'_> { if p4_entry.flags().contains(PageTableFlags::HUGE_PAGE) { return Err(UnmapError::ParentEntryHugePage); } - p4_entry.frame::().map_err(|err| match err { + p4_entry.frame().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, #[allow(deprecated)] FrameError::HugeFrame => unreachable!(), @@ -459,7 +459,7 @@ impl Mapper for RecursivePageTable<'_> { if p3_entry.flags().contains(PageTableFlags::HUGE_PAGE) { return Err(UnmapError::ParentEntryHugePage); } - p3_entry.frame::().map_err(|err| match err { + p3_entry.frame().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, #[allow(deprecated)] FrameError::HugeFrame => unreachable!(), @@ -611,7 +611,7 @@ impl Mapper for RecursivePageTable<'_> { if p4_entry.flags().contains(PageTableFlags::HUGE_PAGE) { return Err(UnmapError::ParentEntryHugePage); } - p4_entry.frame::().map_err(|err| match err { + p4_entry.frame().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, #[allow(deprecated)] FrameError::HugeFrame => unreachable!(), @@ -622,7 +622,7 @@ impl Mapper for RecursivePageTable<'_> { if p3_entry.flags().contains(PageTableFlags::HUGE_PAGE) { return Err(UnmapError::ParentEntryHugePage); } - p3_entry.frame::().map_err(|err| match err { + p3_entry.frame().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, #[allow(deprecated)] FrameError::HugeFrame => unreachable!(), @@ -633,7 +633,7 @@ impl Mapper for RecursivePageTable<'_> { if p2_entry.flags().contains(PageTableFlags::HUGE_PAGE) { return Err(UnmapError::ParentEntryHugePage); } - p2_entry.frame::().map_err(|err| match err { + p2_entry.frame().map_err(|err| match err { FrameError::FrameNotPresent => UnmapError::PageNotMapped, #[allow(deprecated)] FrameError::HugeFrame => unreachable!(), diff --git a/src/structures/paging/page_table.rs b/src/structures/paging/page_table.rs index 330be709..6ee1a8dc 100644 --- a/src/structures/paging/page_table.rs +++ b/src/structures/paging/page_table.rs @@ -15,7 +15,7 @@ use bitflags::bitflags; pub enum FrameError { /// The entry does not have the `PRESENT` flag set, so it isn't currently mapped to a frame. FrameNotPresent, - #[deprecated = "`HugeFrame` is no longer returned by the `frame` method, as it can now return huge pages"] + #[deprecated = "`HugeFrame` is no longer returned by the `frame` method"] /// The entry does have the `HUGE_PAGE` flag set. HugeFrame, } @@ -64,7 +64,7 @@ impl PageTableEntry { /// /// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set. #[inline] - pub fn frame(&self) -> Result, FrameError> { + pub fn frame(&self) -> Result { if self.flags().contains(PageTableFlags::PRESENT) { Ok(PhysFrame::containing_address(self.addr())) } else {