@@ -68,6 +68,64 @@ static PMM: SpinMutex<Pmm> = SpinMutex::new(Pmm {
6868 pages : & mut [ ] ,
6969} ) ;
7070
71+ impl Pmm {
72+ fn free_region ( & mut self , idx : usize , pages : usize ) {
73+ debug_assert ! ( pages > 0 ) ;
74+ debug_assert ! ( self . pages[ idx] . count == 0 ) ;
75+
76+ let mut prev: Option < usize > = None ;
77+ let mut cur = self . head ;
78+ while cur != NO_PAGE && cur < idx {
79+ prev = Some ( cur) ;
80+ cur = self . pages [ cur] . next ;
81+ }
82+ let next = if cur == NO_PAGE { None } else { Some ( cur) } ;
83+ debug_assert ! ( next != Some ( idx) ) ;
84+
85+ // The previous region ends exactly where this one starts.
86+ if let Some ( p) = prev
87+ && p + self . pages [ p] . count == idx
88+ {
89+ self . pages [ p] . count += pages;
90+ self . pages [ idx] . next = NO_PAGE ;
91+
92+ // Having grown `p`, it may now also be adjacent to `next`.
93+ if let Some ( n) = next
94+ && p + self . pages [ p] . count == n
95+ {
96+ self . pages [ p] . count += self . pages [ n] . count ;
97+ self . pages [ p] . next = self . pages [ n] . next ;
98+ self . pages [ n] . count = 0 ;
99+ self . pages [ n] . next = NO_PAGE ;
100+ }
101+ return ;
102+ }
103+
104+ if let Some ( n) = next
105+ && idx + pages == n
106+ {
107+ let n_count = self . pages [ n] . count ;
108+ let n_next = self . pages [ n] . next ;
109+ self . pages [ idx] . count = pages + n_count;
110+ self . pages [ idx] . next = n_next;
111+ self . pages [ n] . count = 0 ;
112+ self . pages [ n] . next = NO_PAGE ;
113+ match prev {
114+ Some ( p) => self . pages [ p] . next = idx,
115+ None => self . head = idx,
116+ }
117+ return ;
118+ }
119+
120+ self . pages [ idx] . count = pages;
121+ self . pages [ idx] . next = next. unwrap_or ( NO_PAGE ) ;
122+ match prev {
123+ Some ( p) => self . pages [ p] . next = idx,
124+ None => self . head = idx,
125+ }
126+ }
127+ }
128+
71129pub struct KernelAlloc ;
72130impl KernelAlloc {
73131 fn dealloc_inner ( addr : PhysAddr , pages : usize ) {
@@ -78,15 +136,11 @@ impl KernelAlloc {
78136
79137 let mut pmm = PMM . lock ( ) ;
80138 let idx = Page :: idx_from_addr ( addr) ;
81- let old_head = pmm. head ;
82- let page = pmm. pages . get_mut ( idx) . unwrap ( ) ;
83139
84- debug_assert ! ( page . count == 0 ) ;
85- debug_assert ! ( page . next == NO_PAGE ) ;
140+ debug_assert ! ( pmm . pages [ idx ] . count == 0 ) ;
141+ debug_assert ! ( pmm . pages [ idx ] . next == NO_PAGE ) ;
86142
87- page. count = pages;
88- page. next = old_head;
89- pmm. head = idx;
143+ pmm. free_region ( idx, pages) ;
90144 }
91145}
92146
@@ -141,7 +195,6 @@ impl PageAllocator for KernelAlloc {
141195 break ;
142196 }
143197
144- // TODO: Merge adjacent regions if we didn't find anything.
145198 debug_assert ! ( addr. is_some( ) ) ;
146199
147200 match addr {
@@ -201,11 +254,8 @@ pub fn init(memory_map: &[PhysMemory], pages: &'static mut [Page]) {
201254 }
202255
203256 let idx = Page :: idx_from_addr ( entry. address ) ;
204- let old_head = pmm. head ;
205- let page = pmm. pages . get_mut ( idx) . unwrap ( ) ;
206- page. count = entry. length / arch:: virt:: get_page_size ( ) ;
207- page. next = old_head;
208- pmm. head = idx;
257+ let count = entry. length / arch:: virt:: get_page_size ( ) ;
258+ pmm. free_region ( idx, count) ;
209259
210260 total_memory += entry. length ;
211261 }
0 commit comments