diff --git a/Changelog.md b/Changelog.md index 1daa76f8..773a6a19 100644 --- a/Changelog.md +++ b/Changelog.md @@ -13,6 +13,7 @@ - [add `MappedPageTable::display`](https://github.com/rust-osdev/x86_64/pull/574) - The mappings of a `MappedPageTable` can now be displayed. - [Increase the Minimum Supported Rust Version to 1.98](https://github.com/rust-osdev/x86_64/pull/604) +- [make memory encryption bit an upper limit for physical address bits](https://github.com/rust-osdev/x86_64/pull/603) # 0.15.5 – 2026-07-11 diff --git a/src/addr.rs b/src/addr.rs index f5cdada4..78777420 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -9,7 +9,7 @@ use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::sync::atomic::Ordering; #[cfg(feature = "memory_encryption")] -use crate::structures::mem_encrypt::ENC_BIT_MASK; +use crate::structures::mem_encrypt::PHYSICAL_ADDRESS_MASK; use crate::structures::paging::page_table::PageTableLevel; use crate::structures::paging::{PageOffset, PageTableIndex}; @@ -571,14 +571,15 @@ impl PhysAddr { #[cfg(feature = "memory_encryption")] #[inline] pub fn new_truncate(addr: u64) -> PhysAddr { - PhysAddr((addr % (1 << 52)) & !ENC_BIT_MASK.load(Ordering::Relaxed)) + PhysAddr(addr & PHYSICAL_ADDRESS_MASK.load(Ordering::Relaxed)) } /// Creates a new physical address, without any checks. /// /// ## Safety /// - /// You must make sure bits 52..64 are zero. This is not checked. + /// You must make sure bits 52..64 are zero and that no bits at or above + /// the encryption bit (if one is configured) are set. This is not checked. #[inline] pub const unsafe fn new_unsafe(addr: u64) -> PhysAddr { PhysAddr(addr) diff --git a/src/structures/mem_encrypt.rs b/src/structures/mem_encrypt.rs index 16ee9b09..b078ba77 100644 --- a/src/structures/mem_encrypt.rs +++ b/src/structures/mem_encrypt.rs @@ -8,15 +8,21 @@ use core::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use crate::structures::paging::PageTableFlags; -use crate::structures::paging::page_table::PHYSICAL_ADDRESS_MASK; /// Position of the encryption (C/S) bit in the physical address +/// +/// If a memory encryption configuration has been set up, this contains a bit +/// mask with just that bit set. pub(crate) static ENC_BIT_MASK: AtomicU64 = AtomicU64::new(0); /// Is the encryption bit reversed (i.e. its presence denote that the page is _decrypted_ rather /// than encrypted) static ENC_BIT_REVERSED: AtomicBool = AtomicBool::new(false); +/// The mask of valid physical address bits. +#[cfg(feature = "memory_encryption")] +pub(crate) static PHYSICAL_ADDRESS_MASK: AtomicU64 = AtomicU64::new(0x000f_ffff_ffff_ffffu64); + /// Defines the configuration for memory encryption #[derive(Debug)] pub enum MemoryEncryptionConfiguration { @@ -34,22 +40,33 @@ pub enum MemoryEncryptionConfiguration { } /// Enable memory encryption by defining the physical address bit that is used to mark a page -/// encrypted (or shared) in a page table entry +/// encrypted (or shared) in a page table entry. +/// +/// Once memory encryption has been enabled [`PhysAddr::new`](crate::addr::PhysAddr::new) will not +/// allow any bits at or above the encryption bit to be set. /// /// # Safety +/// /// Caller must make sure that any existing page table entry is discarded or adapted to take this /// bit into consideration. +/// +/// The caller must ensure that there are no [`PhysAddr`](crate::addr::PhysAddr) instances that +/// have the encryption bit or any bits above it set. +/// /// The configuration provided by caller must be correct, otherwise physical address bits will /// incorrectly be considered as page table flags. +/// +/// This function may only be called once. pub unsafe fn enable_memory_encryption(configuration: MemoryEncryptionConfiguration) { let (bit_position, reversed) = match configuration { MemoryEncryptionConfiguration::EncryptedBit(pos) => (pos, false), MemoryEncryptionConfiguration::SharedBit(pos) => (pos, true), }; - let c_bit_mask = 1u64 << bit_position; + let addr_mask = u64::MAX << bit_position; + PHYSICAL_ADDRESS_MASK.fetch_and(!addr_mask, Ordering::Relaxed); - PHYSICAL_ADDRESS_MASK.fetch_and(!c_bit_mask, Ordering::Relaxed); + let c_bit_mask = 1u64 << bit_position; ENC_BIT_MASK.store(c_bit_mask, Ordering::Relaxed); ENC_BIT_REVERSED.store(reversed, Ordering::Release); } diff --git a/src/structures/paging/page_table.rs b/src/structures/paging/page_table.rs index 1febcb6b..38bec7b3 100644 --- a/src/structures/paging/page_table.rs +++ b/src/structures/paging/page_table.rs @@ -5,10 +5,12 @@ use core::fmt; use core::iter::Step; use core::ops::{Index, IndexMut}; #[cfg(feature = "memory_encryption")] -use core::sync::atomic::{AtomicU64, Ordering}; +use core::sync::atomic::Ordering; use super::{PageSize, PhysFrame, Size4KiB}; use crate::addr::PhysAddr; +#[cfg(feature = "memory_encryption")] +use crate::structures::mem_encrypt::PHYSICAL_ADDRESS_MASK; use bitflags::bitflags; use dep_const_fn::const_fn; @@ -23,10 +25,6 @@ pub enum FrameError { HugeFrame, } -/// The mask used to remove flags from a page table entry to obtain the physical address -#[cfg(feature = "memory_encryption")] -pub(crate) static PHYSICAL_ADDRESS_MASK: AtomicU64 = AtomicU64::new(0x000f_ffff_ffff_f000u64); - /// A 64-bit page table entry. #[derive(Clone)] #[repr(transparent)] @@ -109,13 +107,13 @@ impl PageTableEntry { #[inline(always)] #[cfg(not(feature = "memory_encryption"))] const fn physical_address_mask() -> u64 { - 0x000f_ffff_ffff_f000u64 + 0x000f_ffff_ffff_f000 } #[inline(always)] #[cfg(feature = "memory_encryption")] fn physical_address_mask() -> u64 { - PHYSICAL_ADDRESS_MASK.load(Ordering::Relaxed) + PHYSICAL_ADDRESS_MASK.load(Ordering::Relaxed) & !0xfff } }