lib.rs 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #![no_std]
  2. mod free_area;
  3. mod zone;
  4. use core::sync::atomic::Ordering;
  5. use eonix_mm::{
  6. address::PAddr,
  7. paging::{RawPage, PFN},
  8. };
  9. use intrusive_list::Link;
  10. use zone::Zone;
  11. const MAX_ORDER: u32 = 10;
  12. const ZONE_AREAS: usize = const { MAX_ORDER as usize + 1 };
  13. pub trait BuddyRawPage: RawPage {
  14. /// Get the container raw page struct of the list link.
  15. ///
  16. /// # Safety
  17. /// The caller MUST ensure that the link points to a `RawPage`.
  18. unsafe fn from_link(link: &mut Link) -> Self;
  19. /// Get the list link of the raw page.
  20. ///
  21. /// # Safety
  22. /// The caller MUST ensure that at any time, only one mutable reference
  23. /// to the link exists.
  24. unsafe fn get_link(&self) -> &mut Link;
  25. fn set_order(&self, order: u32);
  26. fn is_buddy(&self) -> bool;
  27. fn is_free(&self) -> bool;
  28. fn set_buddy(&self);
  29. fn set_free(&self);
  30. fn clear_buddy(&self);
  31. fn clear_free(&self);
  32. }
  33. pub struct BuddyAllocator<T>
  34. where
  35. T: BuddyRawPage,
  36. {
  37. zone: Zone<T, ZONE_AREAS>,
  38. }
  39. impl<T> BuddyAllocator<T>
  40. where
  41. T: BuddyRawPage,
  42. {
  43. pub const fn new() -> Self {
  44. Self { zone: Zone::new() }
  45. }
  46. pub fn create_pages(&mut self, start: PAddr, end: PAddr) {
  47. self.zone.create_pages(start, end);
  48. }
  49. pub fn alloc_order(&mut self, order: u32) -> Option<T> {
  50. let pages_ptr = self.zone.get_free_pages(order);
  51. if let Some(pages_ptr) = pages_ptr {
  52. // SAFETY: Memory order here can be Relaxed is for the same reason as that
  53. // in the copy constructor of `std::shared_ptr`.
  54. pages_ptr.refcount().fetch_add(1, Ordering::Relaxed);
  55. pages_ptr.clear_free();
  56. }
  57. pages_ptr
  58. }
  59. pub unsafe fn dealloc(&mut self, page_ptr: T) {
  60. self.zone.free_pages(page_ptr);
  61. }
  62. pub fn has_management_over(page_ptr: T) -> bool {
  63. !page_ptr.is_free() && page_ptr.is_buddy()
  64. }
  65. }
  66. pub(self) trait BuddyPFNOps {
  67. fn buddy_pfn(self, order: u32) -> PFN;
  68. fn combined_pfn(self, buddy_pfn: PFN) -> PFN;
  69. }
  70. impl BuddyPFNOps for PFN {
  71. fn buddy_pfn(self, order: u32) -> PFN {
  72. PFN::from(usize::from(self) ^ (1 << order))
  73. }
  74. fn combined_pfn(self, buddy_pfn: PFN) -> PFN {
  75. PFN::from(usize::from(self) & usize::from(buddy_pfn))
  76. }
  77. }