From 25ff43aeecac52dbf546488569e99f3526d0a31a Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Sat, 4 Jul 2026 13:51:24 +0800 Subject: [PATCH 01/11] fix: :ambulance: Fixed the `Star` register's selector checking - Change `cs_sysret - 16` as `cs_sysret` #592 --- 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 a694615d..73982603 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -464,7 +464,7 @@ mod x86_64 { ss_syscall: SegmentSelector, ) -> Result<(), InvalidStarSegmentSelectors> { // Convert to i32 to prevent underflows. - let cs_sysret_cmp = i32::from(cs_sysret.0) - 16; + let cs_sysret_cmp = i32::from(cs_sysret.0); let ss_sysret_cmp = i32::from(ss_sysret.0) - 8; let cs_syscall_cmp = i32::from(cs_syscall.0); let ss_syscall_cmp = i32::from(ss_syscall.0) - 8; From 8cedd1ad43d7f1f282b6670713b4257951fe5041 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Sat, 4 Jul 2026 13:53:35 +0800 Subject: [PATCH 02/11] feat: :sparkles: Added a function called `from_pfn` - Added a fn in `PhysFrame` so that we can create a frame easily (instead of converting) --- src/structures/paging/frame.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index 95015969..753d9d83 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -46,6 +46,24 @@ impl PhysFrame { } } + /// Returns the frame by a physical frame number. + #[inline] + pub fn from_pfn(pfn: u64) -> Self { + // Let's see the size of this frame... + // XXX: We have to hard-code it, as it only supports number, not expr. + let addr = match S::SIZE { + 4096 => PhysAddr::new(pfn >> 12), // Size4KiB + 2097152 => PhysAddr::new(pfn >> 21), // Size2MiB + 1073741824 => PhysAddr::new(pfn >> 30), // Size1GiB + _ => panic!("Invalid frame size: {}", S::SIZE), // Wth??? + }; + + PhysFrame { + start_address: addr, // Already aligned upthere + size: PhantomData, + } + } + /// Returns the frame that contains the given physical address. #[inline] #[rustversion::attr(since(1.61), const)] From bbb17769309057ab0590178ed07a85ac476f1a06 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Wed, 8 Jul 2026 09:23:52 +0800 Subject: [PATCH 03/11] feat(paging): :sparkles: Added `from_pfn_unchecked`, `try_from_pfn`, `pfn` functions to implement more about it --- src/registers/model_specific.rs | 5 ++++ src/structures/paging/frame.rs | 46 ++++++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/registers/model_specific.rs b/src/registers/model_specific.rs index 73982603..3968a2ac 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -451,11 +451,16 @@ mod x86_64 { } /// Write the Ring 0 and Ring 3 segment bases. + /// /// The remaining fields are ignored because they are /// not valid for long mode. + /// /// This function will fail if the segment selectors are /// not in the correct offset of each other or if the /// segment selectors do not have correct privileges. + /// + /// Also, if you want to return from syscall, you + /// shall use "sysretq" (64) instead of "sysret" (32). #[inline] pub fn write( cs_sysret: SegmentSelector, diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index 753d9d83..b6efb723 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -1,6 +1,7 @@ //! Abstractions for default-sized and huge physical memory frames. use super::page::AddressNotAligned; +use crate::addr::PhysAddrNotValid; use crate::structures::paging::page::{PageSize, Size4KiB}; use crate::PhysAddr; use core::convert::TryFrom; @@ -47,19 +48,39 @@ impl PhysFrame { } /// Returns the frame by a physical frame number. + /// + /// ## Panics + /// Will panic if the after-converted address's 52..64 bits is not empty. #[inline] pub fn from_pfn(pfn: u64) -> Self { - // Let's see the size of this frame... - // XXX: We have to hard-code it, as it only supports number, not expr. - let addr = match S::SIZE { - 4096 => PhysAddr::new(pfn >> 12), // Size4KiB - 2097152 => PhysAddr::new(pfn >> 21), // Size2MiB - 1073741824 => PhysAddr::new(pfn >> 30), // Size1GiB - _ => panic!("Invalid frame size: {}", S::SIZE), // Wth??? - }; + match Self::try_from_pfn(pfn) { + Ok(frame) => frame, + Err(_) => panic!("The PFN \"{}\"is not valid", pfn), + } + } + + /// Try to convert a physical frame number to a frame. + /// + /// ## Error + /// Will return error if the after-converted address's 52..64 bits is not empty. + #[inline] + pub fn try_from_pfn(pfn: u64) -> Result { + let addr = PhysAddr::try_new(pfn * S::SIZE)?; + Ok(PhysFrame { + start_address: addr, + size: PhantomData, + }) + } + /// Returns the frame by a physical frame number without checking. + /// + /// # Safety + /// The PFN must be valid (The after-converted address's 52..64 bits must be empty). + #[inline] + #[rustversion::attr(since(1.61), const)] + pub unsafe fn from_pfn_unchecked(pfn: u64) -> Self { PhysFrame { - start_address: addr, // Already aligned upthere + start_address: unsafe { PhysAddr::new_unsafe(pfn * S::SIZE) }, size: PhantomData, } } @@ -88,6 +109,13 @@ impl PhysFrame { S::SIZE } + /// Returns the PFN of the current frame. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn pfn(self) -> u64 { + self.start_address.as_u64() / S::SIZE + } + /// Returns a range of frames, exclusive `end`. #[inline] #[rustversion::attr(since(1.61), const)] From 0f6126dc171b917786df96c0bb18491df27cf359 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Wed, 8 Jul 2026 09:30:46 +0800 Subject: [PATCH 04/11] docs([aging): :memo: Updated docs --- src/structures/paging/frame.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index b6efb723..e644debe 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -48,6 +48,9 @@ impl PhysFrame { } /// Returns the frame by a physical frame number. + /// + /// This function will automatically time the size of the frame to get its + /// physical address /// /// ## Panics /// Will panic if the after-converted address's 52..64 bits is not empty. From 6810ebb229dda3076e1c678771894853c2d106df Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Wed, 8 Jul 2026 14:03:47 +0800 Subject: [PATCH 05/11] revert(syscall): :bug: Revert to previous star writer --- 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 3968a2ac..1e4ad194 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -469,7 +469,7 @@ mod x86_64 { ss_syscall: SegmentSelector, ) -> Result<(), InvalidStarSegmentSelectors> { // Convert to i32 to prevent underflows. - let cs_sysret_cmp = i32::from(cs_sysret.0); + let cs_sysret_cmp = i32::from(cs_sysret.0) - 16; let ss_sysret_cmp = i32::from(ss_sysret.0) - 8; let cs_syscall_cmp = i32::from(cs_syscall.0); let ss_syscall_cmp = i32::from(ss_syscall.0) - 8; From 4a52e0eac45d66a0a58082b9b26a3c03d9d35c36 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Thu, 9 Jul 2026 21:24:48 +0800 Subject: [PATCH 06/11] fix(paging): :bug: Fixed that the mul might cause overflow / panic - Use `checked_mul` to ensure that the mul operation won't cause panick - Updated docs about `PhysAddrNotValid` to make it much clear #523 --- src/addr.rs | 5 ++++- src/structures/paging/frame.rs | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index d9cc4fcf..f6139e9f 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -11,6 +11,8 @@ use core::sync::atomic::Ordering; #[cfg(feature = "memory_encryption")] use crate::structures::mem_encrypt::ENC_BIT_MASK; use crate::structures::paging::page_table::PageTableLevel; +#[cfg(doc)] +use crate::structures::paging::PhysFrame; use crate::structures::paging::{PageOffset, PageTableIndex}; use bit_field::BitField; @@ -522,7 +524,8 @@ impl kani::Arbitrary for VirtAddr { /// /// This means that bits 52 to 64 were not all null. /// -/// Contains the invalid address. +/// Contains the invalid address in common situation, or the PFN number +/// if use [`PhysFrame::try_from_pfn`] / [`PhysFrame::from_pfn`]. pub struct PhysAddrNotValid(pub u64); impl core::fmt::Debug for PhysAddrNotValid { diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index e644debe..b01ff42e 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -48,8 +48,8 @@ impl PhysFrame { } /// Returns the frame by a physical frame number. - /// - /// This function will automatically time the size of the frame to get its + /// + /// This function will automatically time the size of the frame to get its /// physical address /// /// ## Panics @@ -68,7 +68,8 @@ impl PhysFrame { /// Will return error if the after-converted address's 52..64 bits is not empty. #[inline] pub fn try_from_pfn(pfn: u64) -> Result { - let addr = PhysAddr::try_new(pfn * S::SIZE)?; + let addr_raw = pfn.checked_mul(S::SIZE).ok_or(PhysAddrNotValid(pfn))?; // XXX: The phys addr that the PFN ref is invalid. + let addr = PhysAddr::try_new(addr_raw)?; Ok(PhysFrame { start_address: addr, size: PhantomData, From 3a5107f150714b539a7c6968c4fb18a4a03779d4 Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Fri, 10 Jul 2026 07:42:58 +0800 Subject: [PATCH 07/11] feat(paging): :sparkles: Added new error type about invalid pfn --- src/structures/paging/frame.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index b01ff42e..d322f726 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -1,7 +1,6 @@ //! Abstractions for default-sized and huge physical memory frames. use super::page::AddressNotAligned; -use crate::addr::PhysAddrNotValid; use crate::structures::paging::page::{PageSize, Size4KiB}; use crate::PhysAddr; use core::convert::TryFrom; @@ -9,6 +8,26 @@ use core::fmt; use core::marker::PhantomData; use core::ops::{Add, AddAssign, Sub, SubAssign}; +/// A passed `u64` was not a valid physical address. +/// +/// This means address which PFN refer to is: +/// - Overflowed the `u64`; +/// - The address's 52..64 is not empty. +/// +/// Contains the invalid PFN number if use [`PhysFrame::try_from_pfn`] / [`PhysFrame::from_pfn`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] +pub struct InvalidPfn(pub u64); + +// Implementation of display +impl fmt::Display for InvalidPfn { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("PhysAddrNotValid") + .field(&format_args!("{:#x}", self.0)) + .finish() + } +} + /// A physical memory frame. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] @@ -67,9 +86,9 @@ impl PhysFrame { /// ## Error /// Will return error if the after-converted address's 52..64 bits is not empty. #[inline] - pub fn try_from_pfn(pfn: u64) -> Result { - let addr_raw = pfn.checked_mul(S::SIZE).ok_or(PhysAddrNotValid(pfn))?; // XXX: The phys addr that the PFN ref is invalid. - let addr = PhysAddr::try_new(addr_raw)?; + pub fn try_from_pfn(pfn: u64) -> Result { + let addr_raw = pfn.checked_mul(S::SIZE).ok_or(InvalidPfn(pfn))?; // XXX: The phys addr that the PFN ref is invalid. + let addr = PhysAddr::try_new(addr_raw).map_err(|_| InvalidPfn(pfn))?; Ok(PhysFrame { start_address: addr, size: PhantomData, From b94acdc9ead8d3f4dff4e051c66eb03615672f2e Mon Sep 17 00:00:00 2001 From: zhangxuan2011 Date: Fri, 10 Jul 2026 13:25:17 +0800 Subject: [PATCH 08/11] perf(addr): :fire: Removed unnessary docs and code --- src/addr.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index f6139e9f..d9cc4fcf 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -11,8 +11,6 @@ use core::sync::atomic::Ordering; #[cfg(feature = "memory_encryption")] use crate::structures::mem_encrypt::ENC_BIT_MASK; use crate::structures::paging::page_table::PageTableLevel; -#[cfg(doc)] -use crate::structures::paging::PhysFrame; use crate::structures::paging::{PageOffset, PageTableIndex}; use bit_field::BitField; @@ -524,8 +522,7 @@ impl kani::Arbitrary for VirtAddr { /// /// This means that bits 52 to 64 were not all null. /// -/// Contains the invalid address in common situation, or the PFN number -/// if use [`PhysFrame::try_from_pfn`] / [`PhysFrame::from_pfn`]. +/// Contains the invalid address. pub struct PhysAddrNotValid(pub u64); impl core::fmt::Debug for PhysAddrNotValid { From 8f2866a6cbfd7448fa83c80da14361b0d7946198 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 10 Jul 2026 18:53:47 +0200 Subject: [PATCH 09/11] improve documentation - Slightly reword things - Add more examples --- src/addr.rs | 5 ++-- src/registers/model_specific.rs | 13 +++++---- src/structures/paging/frame.rs | 50 ++++++++++++++++++++++++--------- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index d9cc4fcf..e3645034 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -539,8 +539,9 @@ impl PhysAddr { /// ## Panics /// /// This function panics if a bit in the range 52 to 64 is set. - // If the `memory_encryption` feature has been enabled and an encryption bit has been - // configured, this also panics if the encryption bit is manually set in the address. + /// + /// If the `memory_encryption` feature has been enabled and an encryption bit has been + /// configured, this also panics if the encryption bit is manually set in the address. #[inline] #[const_fn(cfg(not(feature = "memory_encryption")))] pub const fn new(addr: u64) -> Self { diff --git a/src/registers/model_specific.rs b/src/registers/model_specific.rs index 1e4ad194..79340959 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -428,9 +428,12 @@ mod x86_64 { /// not valid for long mode. /// /// # Parameters - /// - sysret: The CS selector is set to this field + 16. SS.Sel is set to - /// this field + 8. Because SYSRET always returns to CPL 3, the - /// RPL bits 1:0 should be initialized to 11b. + /// + /// - sysret: For SYSRETQ (64-bit), the CS selector is set to this + /// field + 16. For SYSRET (32-bit), the CS selector is set to this + /// field. SS.Sel is set to this field + 8. Because SYSRETQ/SYSRET + /// always returns to CPL 3, the RPL bits 1:0 should be initialized + /// to 11b. /// - syscall: This field is copied directly into CS.Sel. SS.Sel is set to /// this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits /// 33:32 should be initialized to 00b. @@ -459,8 +462,8 @@ mod x86_64 { /// not in the correct offset of each other or if the /// segment selectors do not have correct privileges. /// - /// Also, if you want to return from syscall, you - /// shall use "sysretq" (64) instead of "sysret" (32). + /// Note that `cs_sysret` should contain the segment to be used for + /// SYSRETQ (64-bit), not SYSRET (32-bit). #[inline] pub fn write( cs_sysret: SegmentSelector, diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index d322f726..2d9d1b4f 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -10,11 +10,9 @@ use core::ops::{Add, AddAssign, Sub, SubAssign}; /// A passed `u64` was not a valid physical address. /// -/// This means address which PFN refer to is: -/// - Overflowed the `u64`; -/// - The address's 52..64 is not empty. +/// This means that bits 40 to 64 were not all null. /// -/// Contains the invalid PFN number if use [`PhysFrame::try_from_pfn`] / [`PhysFrame::from_pfn`]. +/// Contains the invalid PFN. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(transparent)] pub struct InvalidPfn(pub u64); @@ -68,11 +66,15 @@ impl PhysFrame { /// Returns the frame by a physical frame number. /// - /// This function will automatically time the size of the frame to get its - /// physical address + /// ``` + /// use x86_64::{PhysAddr, structures::paging::{PhysFrame, Size4KiB}}; /// - /// ## Panics - /// Will panic if the after-converted address's 52..64 bits is not empty. + /// assert_eq!(PhysFrame::::from_pfn(0x123), PhysFrame::::containing_address(PhysAddr::new(0x123000))); + /// ``` + /// + /// # Panics + /// + /// This function will panic if the resulting address is not valid. #[inline] pub fn from_pfn(pfn: u64) -> Self { match Self::try_from_pfn(pfn) { @@ -81,10 +83,17 @@ impl PhysFrame { } } - /// Try to convert a physical frame number to a frame. + /// Returns the frame by a physical frame number. + /// + /// ``` + /// use x86_64::{PhysAddr, structures::paging::{PhysFrame, Size4KiB}}; + /// + /// assert_eq!(PhysFrame::::try_from_pfn(0x123), Ok(PhysFrame::::containing_address(PhysAddr::new(0x123000)))); + /// ``` + /// + /// # Error /// - /// ## Error - /// Will return error if the after-converted address's 52..64 bits is not empty. + /// This function will return an error if the resulting address is not valid. #[inline] pub fn try_from_pfn(pfn: u64) -> Result { let addr_raw = pfn.checked_mul(S::SIZE).ok_or(InvalidPfn(pfn))?; // XXX: The phys addr that the PFN ref is invalid. @@ -95,10 +104,11 @@ impl PhysFrame { }) } - /// Returns the frame by a physical frame number without checking. + /// Returns the frame by a physical frame number. /// /// # Safety - /// The PFN must be valid (The after-converted address's 52..64 bits must be empty). + /// + /// The resulting address must be valid. #[inline] #[rustversion::attr(since(1.61), const)] pub unsafe fn from_pfn_unchecked(pfn: u64) -> Self { @@ -133,6 +143,20 @@ impl PhysFrame { } /// Returns the PFN of the current frame. + /// + /// The PFN is defined to be the address divided by the page size. + /// + /// ``` + /// use x86_64::{PhysAddr, structures::paging::{PhysFrame, Size1GiB, Size2MiB, Size4KiB}}; + /// + /// assert_eq!(PhysFrame::::containing_address(PhysAddr::new(0x123000)).pfn(), 0x123); + /// + /// // Note that this means that the PFN for the same address will be + /// // different for different page sizes. + /// assert_eq!(PhysFrame::::containing_address(PhysAddr::new(0xC000_0000)).pfn(), 0xC0000); + /// assert_eq!(PhysFrame::::containing_address(PhysAddr::new(0xC000_0000)).pfn(), 0x600); + /// assert_eq!(PhysFrame::::containing_address(PhysAddr::new(0xC000_0000)).pfn(), 0x3); + /// ``` #[inline] #[rustversion::attr(since(1.61), const)] pub fn pfn(self) -> u64 { From 8cc3adb02422109b74498160ecca51dd905a6d20 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 10 Jul 2026 18:55:34 +0200 Subject: [PATCH 10/11] rename InvalidPfn to PfnNotValid InvalidPfn is more in line with the existing error names (VirtAddrNotValid, PhysAddrNotValid). Also move it down in the file. `PhysFrame` is arguably more important, so let's make sure it's at the top of the file. --- src/structures/paging/frame.rs | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index 2d9d1b4f..f3c2d7a1 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -8,24 +8,6 @@ use core::fmt; use core::marker::PhantomData; use core::ops::{Add, AddAssign, Sub, SubAssign}; -/// A passed `u64` was not a valid physical address. -/// -/// This means that bits 40 to 64 were not all null. -/// -/// Contains the invalid PFN. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(transparent)] -pub struct InvalidPfn(pub u64); - -// Implementation of display -impl fmt::Display for InvalidPfn { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("PhysAddrNotValid") - .field(&format_args!("{:#x}", self.0)) - .finish() - } -} - /// A physical memory frame. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] @@ -95,9 +77,9 @@ impl PhysFrame { /// /// This function will return an error if the resulting address is not valid. #[inline] - pub fn try_from_pfn(pfn: u64) -> Result { - let addr_raw = pfn.checked_mul(S::SIZE).ok_or(InvalidPfn(pfn))?; // XXX: The phys addr that the PFN ref is invalid. - let addr = PhysAddr::try_new(addr_raw).map_err(|_| InvalidPfn(pfn))?; + pub fn try_from_pfn(pfn: u64) -> Result { + let addr_raw = pfn.checked_mul(S::SIZE).ok_or(PfnNotValid(pfn))?; // XXX: The phys addr that the PFN ref is invalid. + let addr = PhysAddr::try_new(addr_raw).map_err(|_| PfnNotValid(pfn))?; Ok(PhysFrame { start_address: addr, size: PhantomData, @@ -349,6 +331,24 @@ impl fmt::Debug for PhysFrameRange { } } +/// A passed `u64` was not a valid physical address. +/// +/// This means that bits 40 to 64 were not all null. +/// +/// Contains the invalid PFN. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] +pub struct PfnNotValid(pub u64); + +// Implementation of display +impl fmt::Display for PfnNotValid { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("PhysAddrNotValid") + .field(&format_args!("{:#x}", self.0)) + .finish() + } +} + /// An range of physical memory frames, inclusive the upper bound. #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[repr(C)] From 4c759257c297ed29e61e9321c153d3aa0a2132e7 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 10 Jul 2026 18:59:10 +0200 Subject: [PATCH 11/11] constify PhysFrame::from_pfn and PhysFrame::try_from_pfn --- src/structures/paging/frame.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index f3c2d7a1..7ad1a717 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -58,10 +58,14 @@ impl PhysFrame { /// /// This function will panic if the resulting address is not valid. #[inline] + #[rustversion::attr( + since(1.61), + dep_const_fn::const_fn(cfg(not(feature = "memory_encryption"))) + )] pub fn from_pfn(pfn: u64) -> Self { match Self::try_from_pfn(pfn) { Ok(frame) => frame, - Err(_) => panic!("The PFN \"{}\"is not valid", pfn), + Err(_) => panic!("PFNs must not have any bits in the range 40 to 64 set"), } } @@ -77,9 +81,21 @@ impl PhysFrame { /// /// This function will return an error if the resulting address is not valid. #[inline] + #[rustversion::attr( + since(1.61), + dep_const_fn::const_fn(cfg(not(feature = "memory_encryption"))) + )] pub fn try_from_pfn(pfn: u64) -> Result { - let addr_raw = pfn.checked_mul(S::SIZE).ok_or(PfnNotValid(pfn))?; // XXX: The phys addr that the PFN ref is invalid. - let addr = PhysAddr::try_new(addr_raw).map_err(|_| PfnNotValid(pfn))?; + let addr_raw = if let Some(addr_raw) = pfn.checked_mul(S::SIZE) { + addr_raw + } else { + return Err(PfnNotValid(pfn)); + }; + let addr = if let Ok(addr) = PhysAddr::try_new(addr_raw) { + addr + } else { + return Err(PfnNotValid(pfn)); + }; Ok(PhysFrame { start_address: addr, size: PhantomData,