From 80ffe15e6c2ceb2a586facea56eac3597fddc06a Mon Sep 17 00:00:00 2001 From: janis Date: Tue, 4 Aug 2026 12:35:29 +0200 Subject: [PATCH] kernel: move pmm code around --- kernel/src/memory.rs | 426 +++++++++++++++++++++---------------------- 1 file changed, 213 insertions(+), 213 deletions(-) diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index 73f17a6..8e71ebe 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -368,6 +368,219 @@ unsafe impl Allocator for PanicingAllocator { unsafe fn deallocate(&self, _ptr: NonNull, _layout: core::alloc::Layout) {} } +/// A node for a red-black tree of free physical page chunks. +/// +/// On amd64 platforms, the maximum physical address is 52 bits, the lower +/// 12 of which are zero for page aligned addresses. +/// Our Tree Node entry needs to store 3 page indices (parent, left, right) and a color bit. +struct PhysicalPageNode(Cell); + +impl Debug for PhysicalPageNode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use rbtree::UnsafeNode; + + f.debug_struct("PhysicalPageNode") + .field("parent", &self.parent()) + .field("left", &self.left()) + .field("right", &self.right()) + .field("color", &self.color()) + .finish() + } +} + +impl PhysicalPageNode { + fn phy(&self) -> Option { + PhyAddr::from_hhdm_virt(self) + } + + fn page_index(this: NonNull) -> usize { + let phy = PhyAddr::from_hhdm_virt(VirtAddr::from(this)); + phy.expect("PhysicalPageNode is not in HHDM").page_index() as usize + } + + fn new_from_page_index(page_index: usize) -> NonNull { + let phy = PhyAddr::from_page_index(page_index); + let virt = phy.as_hhdm_virt(); + let ptr = virt.as_mut::(); + + unsafe { + ptr.write(Self::new_red()); + } + + NonNull::new(ptr).unwrap() + } + + fn new_red() -> Self { + PhysicalPageNode(Cell::new(1 << 120)) + } + + fn bits(&self) -> u128 { + self.0.get() + } + + fn parent_bits(&self) -> u64 { + self.bits().get_bits(0..40) as u64 + } + + fn set_parent_bits(&self, parent: u64) { + self.0.update(|mut bits| { + bits.set_bits(0..40, parent as u128); + bits + }); + } + + fn left_bits(&self) -> u64 { + self.bits().get_bits(40..80) as u64 + } + + fn set_left_bits(&self, left: u64) { + self.0.update(|mut bits| { + bits.set_bits(40..80, left as u128); + bits + }); + } + + fn right_bits(&self) -> u64 { + self.bits().get_bits(80..120) as u64 + } + + fn set_right_bits(&self, right: u64) { + self.0.update(|mut bits| { + bits.set_bits(80..120, right as u128); + bits + }); + } + + fn color_bit(&self) -> bool { + self.bits().get_bit(120) + } + + fn set_color_bit(&self, color: bool) { + self.0.update(|mut bits| { + bits.set_bit(120, color); + bits + }); + } +} + +/// A key for a red-black tree of free physical page chunks. +/// The key uses the address of the node as the key, which is unique and means +/// the key does not require any additional bits. +struct PhysicalPageNodeKey; + +impl Debug for PhysicalPageNodeKey { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self.phy()) + } +} + +impl PhysicalPageNodeKey { + fn from_page_index(page_index: usize) -> &'static Self { + let phy = PhyAddr::from_page_index(page_index); + let virt = phy.as_hhdm_virt(); + let ptr = virt.as_ptr::(); + + unsafe { &*ptr } + } + + fn phy(&self) -> Option { + PhyAddr::from_hhdm_virt(self) + } +} + +impl Eq for PhysicalPageNodeKey {} + +impl PartialEq for PhysicalPageNodeKey { + fn eq(&self, _other: &Self) -> bool { + core::ptr::eq(self, _other) + } +} + +impl PartialOrd for PhysicalPageNodeKey { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for PhysicalPageNodeKey { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + (&raw const *self).cmp(&(&raw const *other)) + } +} + +unsafe impl rbtree::UnsafeNode for PhysicalPageNode { + type Key = PhysicalPageNodeKey; + + fn left(&self) -> Option> { + NonZeroUsize::new(self.left_bits() as usize) + .map(|n| PhyAddr::from_page_index(n.get())) + .map(PhyAddr::into_hhdm_virt) + .and_then(VirtAddr::into_nonnull) + } + + fn right(&self) -> Option> { + NonZeroUsize::new(self.right_bits() as usize) + .map(|n| PhyAddr::from_page_index(n.get())) + .map(PhyAddr::into_hhdm_virt) + .and_then(VirtAddr::into_nonnull) + } + + fn parent(&self) -> Option> { + NonZeroUsize::new(self.parent_bits() as usize) + .map(|n| PhyAddr::from_page_index(n.get())) + .map(PhyAddr::into_hhdm_virt) + .and_then(VirtAddr::into_nonnull) + } + + fn key(&self) -> &Self::Key { + assert_eq!( + core::mem::size_of::(), + 0, + "PhysicalPageNodeKey must be zero-sized" + ); + + // SAFETY: The key is a zero-sized type, so we can transmute the + // reference to the node to a reference to the key. + unsafe { core::mem::transmute_copy::<&PhysicalPageNode, &PhysicalPageNodeKey>(&self) } + } + + fn color(&self) -> rbtree::Color { + if self.color_bit() { + rbtree::Color::Red + } else { + rbtree::Color::Black + } + } + + fn set_left(&self, left: Option>) { + self.set_left_bits(left.map_or(0, |ptr| { + PhyAddr::from_hhdm_virt(VirtAddr::from(ptr)) + .expect("PhysicalPageNode left pointer is not in HHDM") + .page_index() + })); + } + + fn set_right(&self, right: Option>) { + self.set_right_bits(right.map_or(0, |ptr| { + PhyAddr::from_hhdm_virt(VirtAddr::from(ptr)) + .expect("PhysicalPageNode right pointer is not in HHDM") + .page_index() + })); + } + + fn set_parent(&self, parent: Option>) { + self.set_parent_bits(parent.map_or(0, |ptr| { + PhyAddr::from_hhdm_virt(VirtAddr::from(ptr)) + .expect("PhysicalPageNode parentpointer is not in HHDM") + .page_index() + })); + } + + fn set_color(&self, color: rbtree::Color) { + self.set_color_bit(color == rbtree::Color::Red); + } +} + pub mod bump { use core::{ alloc::{Allocator, Layout}, @@ -796,216 +1009,3 @@ pub mod bump { assert!(*x == 3); } } - -/// A node for a red-black tree of free physical page chunks. -/// -/// On amd64 platforms, the maximum physical address is 52 bits, the lower -/// 12 of which are zero for page aligned addresses. -/// Our Tree Node entry needs to store 3 page indices (parent, left, right) and a color bit. -struct PhysicalPageNode(Cell); - -impl Debug for PhysicalPageNode { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - use rbtree::UnsafeNode; - - f.debug_struct("PhysicalPageNode") - .field("parent", &self.parent()) - .field("left", &self.left()) - .field("right", &self.right()) - .field("color", &self.color()) - .finish() - } -} - -impl PhysicalPageNode { - fn phy(&self) -> Option { - PhyAddr::from_hhdm_virt(self) - } - - fn page_index(this: NonNull) -> usize { - let phy = PhyAddr::from_hhdm_virt(VirtAddr::from(this)); - phy.expect("PhysicalPageNode is not in HHDM").page_index() as usize - } - - fn new_from_page_index(page_index: usize) -> NonNull { - let phy = PhyAddr::from_page_index(page_index); - let virt = phy.as_hhdm_virt(); - let ptr = virt.as_mut::(); - - unsafe { - ptr.write(Self::new_red()); - } - - NonNull::new(ptr).unwrap() - } - - fn new_red() -> Self { - PhysicalPageNode(Cell::new(1 << 120)) - } - - fn bits(&self) -> u128 { - self.0.get() - } - - fn parent_bits(&self) -> u64 { - self.bits().get_bits(0..40) as u64 - } - - fn set_parent_bits(&self, parent: u64) { - self.0.update(|mut bits| { - bits.set_bits(0..40, parent as u128); - bits - }); - } - - fn left_bits(&self) -> u64 { - self.bits().get_bits(40..80) as u64 - } - - fn set_left_bits(&self, left: u64) { - self.0.update(|mut bits| { - bits.set_bits(40..80, left as u128); - bits - }); - } - - fn right_bits(&self) -> u64 { - self.bits().get_bits(80..120) as u64 - } - - fn set_right_bits(&self, right: u64) { - self.0.update(|mut bits| { - bits.set_bits(80..120, right as u128); - bits - }); - } - - fn color_bit(&self) -> bool { - self.bits().get_bit(120) - } - - fn set_color_bit(&self, color: bool) { - self.0.update(|mut bits| { - bits.set_bit(120, color); - bits - }); - } -} - -/// A key for a red-black tree of free physical page chunks. -/// The key uses the address of the node as the key, which is unique and means -/// the key does not require any additional bits. -struct PhysicalPageNodeKey; - -impl Debug for PhysicalPageNodeKey { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:?}", self.phy()) - } -} - -impl PhysicalPageNodeKey { - fn from_page_index(page_index: usize) -> &'static Self { - let phy = PhyAddr::from_page_index(page_index); - let virt = phy.as_hhdm_virt(); - let ptr = virt.as_ptr::(); - - unsafe { &*ptr } - } - - fn phy(&self) -> Option { - PhyAddr::from_hhdm_virt(self) - } -} - -impl Eq for PhysicalPageNodeKey {} - -impl PartialEq for PhysicalPageNodeKey { - fn eq(&self, _other: &Self) -> bool { - core::ptr::eq(self, _other) - } -} - -impl PartialOrd for PhysicalPageNodeKey { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for PhysicalPageNodeKey { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - (&raw const *self).cmp(&(&raw const *other)) - } -} - -unsafe impl rbtree::UnsafeNode for PhysicalPageNode { - type Key = PhysicalPageNodeKey; - - fn left(&self) -> Option> { - NonZeroUsize::new(self.left_bits() as usize) - .map(|n| PhyAddr::from_page_index(n.get())) - .map(PhyAddr::into_hhdm_virt) - .and_then(VirtAddr::into_nonnull) - } - - fn right(&self) -> Option> { - NonZeroUsize::new(self.right_bits() as usize) - .map(|n| PhyAddr::from_page_index(n.get())) - .map(PhyAddr::into_hhdm_virt) - .and_then(VirtAddr::into_nonnull) - } - - fn parent(&self) -> Option> { - NonZeroUsize::new(self.parent_bits() as usize) - .map(|n| PhyAddr::from_page_index(n.get())) - .map(PhyAddr::into_hhdm_virt) - .and_then(VirtAddr::into_nonnull) - } - - fn key(&self) -> &Self::Key { - assert_eq!( - core::mem::size_of::(), - 0, - "PhysicalPageNodeKey must be zero-sized" - ); - - // SAFETY: The key is a zero-sized type, so we can transmute the - // reference to the node to a reference to the key. - unsafe { core::mem::transmute_copy::<&PhysicalPageNode, &PhysicalPageNodeKey>(&self) } - } - - fn color(&self) -> rbtree::Color { - if self.color_bit() { - rbtree::Color::Red - } else { - rbtree::Color::Black - } - } - - fn set_left(&self, left: Option>) { - self.set_left_bits(left.map_or(0, |ptr| { - PhyAddr::from_hhdm_virt(VirtAddr::from(ptr)) - .expect("PhysicalPageNode left pointer is not in HHDM") - .page_index() - })); - } - - fn set_right(&self, right: Option>) { - self.set_right_bits(right.map_or(0, |ptr| { - PhyAddr::from_hhdm_virt(VirtAddr::from(ptr)) - .expect("PhysicalPageNode right pointer is not in HHDM") - .page_index() - })); - } - - fn set_parent(&self, parent: Option>) { - self.set_parent_bits(parent.map_or(0, |ptr| { - PhyAddr::from_hhdm_virt(VirtAddr::from(ptr)) - .expect("PhysicalPageNode parentpointer is not in HHDM") - .page_index() - })); - } - - fn set_color(&self, color: rbtree::Color) { - self.set_color_bit(color == rbtree::Color::Red); - } -}