xref: /DragonOS/kernel/src/mm/allocator/buddy.rs (revision 46795849a29eef77fd6f7af548d05ee6e654c5bb)
1 /// @Author: longjin@dragonos.org
2 /// @Author: kongweichao@dragonos.org
3 /// @Date: 2023-03-28 16:03:47
4 /// @FilePath: /DragonOS/kernel/src/mm/allocator/buddy.rs
5 /// @Description: 伙伴分配器
6 use crate::arch::MMArch;
7 use crate::mm::allocator::bump::BumpAllocator;
8 use crate::mm::allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage};
9 use crate::mm::{MemoryManagementArch, PhysAddr, VirtAddr};
10 use crate::{kdebug, kwarn};
11 use core::cmp::{max, min};
12 use core::fmt::Debug;
13 use core::intrinsics::{likely, unlikely};
14 
15 use core::{marker::PhantomData, mem};
16 
17 // 一个全局变量MAX_ORDER,用来表示buddy算法的最大阶数 [MIN_ORDER, MAX_ORDER)左闭右开区间
18 const MAX_ORDER: usize = 31;
19 // 4KB
20 const MIN_ORDER: usize = 12;
21 
22 /// 保存buddy算法中每一页存放的BuddyEntry的信息,占据每个页的起始位置
23 #[derive(Debug)]
24 pub struct PageList<A> {
25     // 页存放entry的数量
26     entry_num: usize,
27     // 下一个页面的地址
28     next_page: PhysAddr,
29     phantom: PhantomData<A>,
30 }
31 
32 impl<A> Clone for PageList<A> {
33     fn clone(&self) -> Self {
34         Self {
35             entry_num: self.entry_num,
36             next_page: self.next_page,
37             phantom: PhantomData,
38         }
39     }
40 }
41 
42 impl<A> PageList<A> {
43     #[allow(dead_code)]
44     fn empty() -> Self {
45         Self {
46             entry_num: 0,
47             next_page: PhysAddr::new(0),
48             phantom: PhantomData,
49         }
50     }
51     fn new(entry_num: usize, next_page: PhysAddr) -> Self {
52         Self {
53             entry_num,
54             next_page,
55             phantom: PhantomData,
56         }
57     }
58 }
59 
60 /// @brief: 用来表示 buddy 算法中的一个 buddy 块,整体存放在area的头部
61 // 这种方式会出现对齐问题
62 // #[repr(packed)]
63 #[repr(C)]
64 #[derive(Debug)]
65 pub struct BuddyAllocator<A> {
66     // 存放每个阶的空闲“链表”的头部地址
67     free_area: [PhysAddr; (MAX_ORDER - MIN_ORDER) as usize],
68     /// 总页数
69     total: PageFrameCount,
70     phantom: PhantomData<A>,
71 }
72 
73 impl<A: MemoryManagementArch> BuddyAllocator<A> {
74     const BUDDY_ENTRIES: usize =
75         // 定义一个变量记录buddy表的大小
76         (A::PAGE_SIZE - mem::size_of::<PageList<A>>()) / mem::size_of::<PhysAddr>();
77 
78     pub unsafe fn new(mut bump_allocator: BumpAllocator<A>) -> Option<Self> {
79         let initial_free_pages = bump_allocator.usage().free();
80         kdebug!("Free pages before init buddy: {:?}", initial_free_pages);
81         kdebug!("Buddy entries: {}", Self::BUDDY_ENTRIES);
82         // 最高阶的链表页数
83         let max_order_linked_list_page_num = max(
84             1,
85             (((initial_free_pages.data() * A::PAGE_SIZE) >> (MAX_ORDER - 1)) + Self::BUDDY_ENTRIES
86                 - 1)
87                 / Self::BUDDY_ENTRIES,
88         );
89 
90         let mut free_area: [PhysAddr; (MAX_ORDER - MIN_ORDER) as usize] =
91             [PhysAddr::new(0); (MAX_ORDER - MIN_ORDER) as usize];
92 
93         // Buddy初始占用的空间从bump分配
94         for f in free_area.iter_mut() {
95             let curr_page = bump_allocator.allocate_one();
96             // 保存每个阶的空闲链表的头部地址
97             *f = curr_page.unwrap();
98             // 清空当前页
99             core::ptr::write_bytes(MMArch::phys_2_virt(*f)?.data() as *mut u8, 0, A::PAGE_SIZE);
100 
101             let page_list: PageList<A> = PageList::new(0, PhysAddr::new(0));
102             Self::write_page(*f, page_list);
103         }
104 
105         // 分配最高阶的链表页
106         for _ in 1..max_order_linked_list_page_num {
107             let curr_page = bump_allocator.allocate_one().unwrap();
108             // 清空当前页
109             core::ptr::write_bytes(
110                 MMArch::phys_2_virt(curr_page)?.data() as *mut u8,
111                 0,
112                 A::PAGE_SIZE,
113             );
114 
115             let page_list: PageList<A> =
116                 PageList::new(0, free_area[Self::order2index((MAX_ORDER - 1) as u8)]);
117             Self::write_page(curr_page, page_list);
118             free_area[Self::order2index((MAX_ORDER - 1) as u8)] = curr_page;
119         }
120 
121         let initial_bump_offset = bump_allocator.offset();
122         let pages_to_buddy = bump_allocator.usage().free();
123         kdebug!("pages_to_buddy {:?}", pages_to_buddy);
124         // kdebug!("initial_bump_offset {:#x}", initial_bump_offset);
125         let mut paddr = initial_bump_offset;
126         let mut remain_pages = pages_to_buddy;
127         // 设置entry,这里假设了bump_allocator当前offset之后,所有的area的地址是连续的.
128         // TODO: 这里需要修改,按照area来处理
129         for i in MIN_ORDER..MAX_ORDER {
130             // kdebug!("i {i}, remain pages={}", remain_pages.data());
131             if remain_pages.data() < (1 << (i - MIN_ORDER)) {
132                 break;
133             }
134 
135             assert!(paddr & ((1 << i) - 1) == 0);
136 
137             if likely(i != MAX_ORDER - 1) {
138                 // 要填写entry
139                 if paddr & (1 << i) != 0 {
140                     let page_list_paddr: PhysAddr = free_area[Self::order2index(i as u8)];
141                     let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
142 
143                     A::write(
144                         Self::entry_virt_addr(page_list_paddr, page_list.entry_num),
145                         paddr,
146                     );
147                     page_list.entry_num += 1;
148                     Self::write_page(page_list_paddr, page_list);
149 
150                     paddr += 1 << i;
151                     remain_pages -= 1 << (i - MIN_ORDER);
152                 };
153             } else {
154                 // 往最大的阶数的链表中添加entry(注意要考虑到最大阶数的链表可能有多页)
155                 // 断言剩余页面数量是MAX_ORDER-1阶的整数倍
156 
157                 let mut entries = (remain_pages.data() * A::PAGE_SIZE) >> i;
158                 let mut page_list_paddr: PhysAddr = free_area[Self::order2index(i as u8)];
159                 let block_size = 1usize << i;
160 
161                 if entries > Self::BUDDY_ENTRIES {
162                     // 在第一页填写一些entries
163                     let num = entries % Self::BUDDY_ENTRIES;
164                     entries -= num;
165 
166                     let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
167                     for _j in 0..num {
168                         A::write(
169                             Self::entry_virt_addr(page_list_paddr, page_list.entry_num),
170                             paddr,
171                         );
172                         page_list.entry_num += 1;
173                         paddr += block_size;
174                         remain_pages -= 1 << (i - MIN_ORDER);
175                     }
176                     page_list_paddr = page_list.next_page;
177                     Self::write_page(page_list_paddr, page_list);
178                     assert!(!page_list_paddr.is_null());
179                 }
180 
181                 while entries > 0 {
182                     let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
183 
184                     for _ in 0..Self::BUDDY_ENTRIES {
185                         A::write(
186                             Self::entry_virt_addr(page_list_paddr, page_list.entry_num),
187                             paddr,
188                         );
189                         page_list.entry_num += 1;
190                         paddr += block_size;
191                         remain_pages -= 1 << (i - MIN_ORDER);
192                         entries -= 1;
193                         if entries == 0 {
194                             break;
195                         }
196                     }
197                     page_list_paddr = page_list.next_page;
198                     Self::write_page(page_list_paddr, page_list);
199 
200                     if likely(entries > 0) {
201                         assert!(!page_list_paddr.is_null());
202                     }
203                 }
204             }
205         }
206 
207         let mut remain_bytes = remain_pages.data() * A::PAGE_SIZE;
208 
209         assert!(remain_bytes < (1 << MAX_ORDER - 1));
210 
211         for i in (MIN_ORDER..MAX_ORDER).rev() {
212             if remain_bytes >= (1 << i) {
213                 assert!(paddr & ((1 << i) - 1) == 0);
214                 let page_list_paddr: PhysAddr = free_area[Self::order2index(i as u8)];
215                 let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
216 
217                 A::write(
218                     Self::entry_virt_addr(page_list_paddr, page_list.entry_num),
219                     paddr,
220                 );
221                 page_list.entry_num += 1;
222                 Self::write_page(page_list_paddr, page_list);
223 
224                 paddr += 1 << i;
225                 remain_bytes -= 1 << i;
226             }
227         }
228 
229         assert!(remain_bytes == 0);
230         assert!(paddr == initial_bump_offset + pages_to_buddy.data() * A::PAGE_SIZE);
231 
232         let allocator = Self {
233             free_area,
234             total: pages_to_buddy,
235             phantom: PhantomData,
236         };
237 
238         Some(allocator)
239     }
240     /// 获取第j个entry的虚拟地址,
241     /// j从0开始计数
242     pub fn entry_virt_addr(base_addr: PhysAddr, j: usize) -> VirtAddr {
243         let entry_virt_addr = unsafe { A::phys_2_virt(Self::entry_addr(base_addr, j)) };
244         return entry_virt_addr.unwrap();
245     }
246     pub fn entry_addr(base_addr: PhysAddr, j: usize) -> PhysAddr {
247         let entry_addr = base_addr + mem::size_of::<PageList<A>>() + j * mem::size_of::<PhysAddr>();
248         return entry_addr;
249     }
250     pub fn read_page<T>(addr: PhysAddr) -> T {
251         let page_list = unsafe { A::read(A::phys_2_virt(addr).unwrap()) };
252         return page_list;
253     }
254 
255     pub fn write_page(curr_page: PhysAddr, page_list: PageList<A>) {
256         // 把物理地址转换为虚拟地址
257         let virt_addr = unsafe { A::phys_2_virt(curr_page) };
258         let virt_addr = virt_addr.unwrap();
259         unsafe { A::write(virt_addr, page_list) };
260     }
261 
262     /// 从order转换为free_area的下标
263     ///
264     /// # 参数
265     ///
266     /// - `order` - order
267     ///
268     /// # 返回值
269     ///
270     /// free_area的下标
271     #[inline]
272     fn order2index(order: u8) -> usize {
273         (order as usize - MIN_ORDER) as usize
274     }
275 
276     /// 从空闲链表的开头,取出1个指定阶数的伙伴块,如果没有,则返回None
277     ///
278     /// ## 参数
279     ///
280     /// - `order` - 伙伴块的阶数
281     fn pop_front(&mut self, order: u8) -> Option<PhysAddr> {
282         let mut alloc_in_specific_order = |spec_order: u8| {
283             // 先尝试在order阶的“空闲链表”的开头位置分配一个伙伴块
284             let mut page_list_addr = self.free_area[Self::order2index(spec_order)];
285             let mut page_list: PageList<A> = Self::read_page(page_list_addr);
286 
287             // 循环删除头部的空闲链表页
288             while page_list.entry_num == 0 {
289                 let next_page_list_addr = page_list.next_page;
290                 // 找完了,都是空的
291                 if next_page_list_addr.is_null() {
292                     return None;
293                 }
294 
295                 if !next_page_list_addr.is_null() {
296                     // 此时page_list已经没有空闲伙伴块了,又因为非唯一页,需要删除该page_list
297                     self.free_area[Self::order2index(spec_order)] = next_page_list_addr;
298                     drop(page_list);
299                     // kdebug!("FREE: page_list_addr={:b}", page_list_addr.data());
300                     unsafe {
301                         self.buddy_free(page_list_addr, MMArch::PAGE_SHIFT as u8);
302                     }
303                 }
304                 // 由于buddy_free可能导致首部的链表页发生变化,因此需要重新读取
305                 let next_page_list_addr = self.free_area[Self::order2index(spec_order)];
306                 assert!(!next_page_list_addr.is_null());
307                 page_list = Self::read_page(next_page_list_addr);
308                 page_list_addr = next_page_list_addr;
309             }
310 
311             // 有空闲页面,直接分配
312             if page_list.entry_num > 0 {
313                 let entry: PhysAddr = unsafe {
314                     A::read(Self::entry_virt_addr(
315                         page_list_addr,
316                         page_list.entry_num - 1,
317                     ))
318                 };
319                 // 清除该entry
320                 unsafe {
321                     A::write(
322                         Self::entry_virt_addr(page_list_addr, page_list.entry_num - 1),
323                         PhysAddr::new(0),
324                     )
325                 };
326                 if entry.is_null() {
327                     panic!(
328                         "entry is null, entry={:?}, order={}, entry_num = {}",
329                         entry,
330                         spec_order,
331                         page_list.entry_num - 1
332                     );
333                 }
334                 // kdebug!("entry={entry:?}");
335 
336                 // 更新page_list的entry_num
337                 page_list.entry_num -= 1;
338                 let tmp_current_entry_num = page_list.entry_num;
339                 if page_list.entry_num == 0 {
340                     if !page_list.next_page.is_null() {
341                         // 此时page_list已经没有空闲伙伴块了,又因为非唯一页,需要删除该page_list
342                         self.free_area[Self::order2index(spec_order)] = page_list.next_page;
343                         drop(page_list);
344                         unsafe { self.buddy_free(page_list_addr, MMArch::PAGE_SHIFT as u8) };
345                     } else {
346                         Self::write_page(page_list_addr, page_list);
347                     }
348                 } else {
349                     // 若entry_num不为0,说明该page_list还有空闲伙伴块,需要更新该page_list
350                     // 把更新后的page_list写回
351                     Self::write_page(page_list_addr, page_list.clone());
352                 }
353 
354                 // 检测entry 是否对齐
355                 if !entry.check_aligned(1 << spec_order) {
356                     panic!("entry={:?} is not aligned, spec_order={spec_order}, page_list.entry_num={}", entry, tmp_current_entry_num);
357                 }
358                 return Some(entry);
359             }
360             return None;
361         };
362         let result: Option<PhysAddr> = alloc_in_specific_order(order as u8);
363         // kdebug!("result={:?}", result);
364         if result.is_some() {
365             return result;
366         }
367         // 尝试从更大的链表中分裂
368 
369         let mut current_order = (order + 1) as usize;
370         let mut x: Option<PhysAddr> = None;
371         while current_order < MAX_ORDER {
372             x = alloc_in_specific_order(current_order as u8);
373             // kdebug!("current_order={:?}", current_order);
374             if x.is_some() {
375                 break;
376             }
377             current_order += 1;
378         }
379 
380         // kdebug!("x={:?}", x);
381         // 如果找到一个大的块,就进行分裂
382         if x.is_some() {
383             // 分裂到order阶
384             while current_order > order as usize {
385                 current_order -= 1;
386                 // 把后面那半块放回空闲链表
387 
388                 let buddy = *x.as_ref().unwrap() + (1 << current_order);
389                 // kdebug!("x={:?}, buddy={:?}", x, buddy);
390                 // kdebug!("current_order={:?}, buddy={:?}", current_order, buddy);
391                 unsafe { self.buddy_free(buddy, current_order as u8) };
392             }
393             return x;
394         }
395 
396         return None;
397     }
398 
399     /// 从伙伴系统中分配count个页面
400     ///
401     /// ## 参数
402     ///
403     /// - `count`:需要分配的页面数
404     ///
405     /// ## 返回值
406     ///
407     /// 返回分配的页面的物理地址和页面数
408     fn buddy_alloc(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
409         assert!(count.data().is_power_of_two());
410         // 计算需要分配的阶数
411         let mut order = log2(count.data() as usize);
412         if count.data() & ((1 << order) - 1) != 0 {
413             order += 1;
414         }
415         let order = (order + MIN_ORDER) as u8;
416         if order as usize >= MAX_ORDER {
417             return None;
418         }
419 
420         // kdebug!("buddy_alloc: order = {}", order);
421         // 获取该阶数的一个空闲页面
422         let free_addr = self.pop_front(order);
423         // kdebug!(
424         //     "buddy_alloc: order = {}, free_addr = {:?}",
425         //     order,
426         //     free_addr
427         // );
428         return free_addr
429             .map(|addr| (addr, PageFrameCount::new(1 << (order as usize - MIN_ORDER))));
430     }
431 
432     /// 释放一个块
433     ///
434     /// ## 参数
435     ///
436     /// - `base` - 块的起始地址
437     /// - `order` - 块的阶数
438     unsafe fn buddy_free(&mut self, mut base: PhysAddr, order: u8) {
439         // kdebug!("buddy_free: base = {:?}, order = {}", base, order);
440         let mut order = order as usize;
441 
442         while order < MAX_ORDER {
443             // 检测地址是否合法
444             if base.data() & ((1 << (order)) - 1) != 0 {
445                 panic!(
446                     "buddy_free: base is not aligned, base = {:#x}, order = {}",
447                     base.data(),
448                     order
449                 );
450             }
451 
452             // 在链表中寻找伙伴块
453             // 伙伴块的地址是base ^ (1 << order)
454             let buddy_addr = PhysAddr::new(base.data() ^ (1 << order));
455 
456             let first_page_list_paddr = self.free_area[Self::order2index(order as u8)];
457             let mut page_list_paddr = first_page_list_paddr;
458             let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
459             let first_page_list = page_list.clone();
460 
461             let mut buddy_entry_virt_vaddr = None;
462             let mut buddy_entry_page_list_paddr = None;
463             // 除非order是最大的,否则尝试查找伙伴块
464             if likely(order != MAX_ORDER - 1) {
465                 'outer: loop {
466                     for i in 0..page_list.entry_num {
467                         let entry_virt_addr = Self::entry_virt_addr(page_list_paddr, i);
468                         let entry: PhysAddr = unsafe { A::read(entry_virt_addr) };
469                         if entry == buddy_addr {
470                             // 找到了伙伴块,记录该entry相关信息,然后退出查找
471                             buddy_entry_virt_vaddr = Some(entry_virt_addr);
472                             buddy_entry_page_list_paddr = Some(page_list_paddr);
473                             break 'outer;
474                         }
475                     }
476                     if page_list.next_page.is_null() {
477                         break;
478                     }
479                     page_list_paddr = page_list.next_page;
480                     page_list = Self::read_page(page_list_paddr);
481                 }
482             }
483 
484             // 如果没有找到伙伴块
485             if buddy_entry_virt_vaddr.is_none() {
486                 assert!(
487                     page_list.entry_num <= Self::BUDDY_ENTRIES,
488                     "buddy_free: page_list.entry_num > Self::BUDDY_ENTRIES"
489                 );
490 
491                 // 当前第一个page_list没有空间了
492                 if first_page_list.entry_num == Self::BUDDY_ENTRIES {
493                     // 如果当前order是最小的,那么就把这个块当作新的page_list使用
494                     let new_page_list_addr = if order == MIN_ORDER {
495                         base
496                     } else {
497                         // 否则分配新的page_list
498                         // 请注意,分配之后,有可能当前的entry_num会减1(伙伴块分裂),造成出现整个链表为null的entry数量为Self::BUDDY_ENTRIES+1的情况
499                         // 但是不影响,我们在后面插入链表项的时候,会处理这种情况,检查链表中的第2个页是否有空位
500                         self.buddy_alloc(PageFrameCount::new(1))
501                             .expect("buddy_alloc failed: no enough memory")
502                             .0
503                     };
504 
505                     // 清空这个页面
506                     core::ptr::write_bytes(
507                         A::phys_2_virt(new_page_list_addr)
508                             .expect(
509                                 "Buddy free: failed to get virt address of [new_page_list_addr]",
510                             )
511                             .as_ptr::<u8>(),
512                         0,
513                         1 << order,
514                     );
515                     assert!(
516                         first_page_list_paddr == self.free_area[Self::order2index(order as u8)]
517                     );
518                     // 初始化新的page_list
519                     let new_page_list = PageList::new(0, first_page_list_paddr);
520                     Self::write_page(new_page_list_addr, new_page_list);
521                     self.free_area[Self::order2index(order as u8)] = new_page_list_addr;
522                 }
523 
524                 // 由于上面可能更新了第一个链表页,因此需要重新获取这个值
525                 let first_page_list_paddr = self.free_area[Self::order2index(order as u8)];
526                 let first_page_list: PageList<A> = Self::read_page(first_page_list_paddr);
527 
528                 // 检查第二个page_list是否有空位
529                 let second_page_list = if first_page_list.next_page.is_null() {
530                     None
531                 } else {
532                     Some(Self::read_page::<PageList<A>>(first_page_list.next_page))
533                 };
534 
535                 let (paddr, mut page_list) = if let Some(second) = second_page_list {
536                     // 第二个page_list有空位
537                     // 应当符合之前的假设:还有1个空位
538                     assert!(second.entry_num == Self::BUDDY_ENTRIES - 1);
539 
540                     (first_page_list.next_page, second)
541                 } else {
542                     // 在第一个page list中分配
543                     (first_page_list_paddr, first_page_list)
544                 };
545 
546                 // kdebug!("to write entry, page_list_base={paddr:?}, page_list.entry_num={}, value={base:?}", page_list.entry_num);
547                 assert!(page_list.entry_num < Self::BUDDY_ENTRIES);
548                 // 把要归还的块,写入到链表项中
549                 unsafe { A::write(Self::entry_virt_addr(paddr, page_list.entry_num), base) }
550                 page_list.entry_num += 1;
551                 Self::write_page(paddr, page_list);
552                 return;
553             } else {
554                 // 如果找到了伙伴块,合并,向上递归
555 
556                 // 伙伴块所在的表项的虚拟地址
557                 let buddy_entry_virt_addr = buddy_entry_virt_vaddr.unwrap();
558                 // 伙伴块所在的page_list的物理地址
559                 let buddy_entry_page_list_paddr = buddy_entry_page_list_paddr.unwrap();
560 
561                 let mut page_list_paddr = self.free_area[Self::order2index(order as u8)];
562                 let mut page_list = Self::read_page::<PageList<A>>(page_list_paddr);
563                 // 找第一个有空闲块的链表页。跳过空闲链表页。不进行回收的原因是担心出现死循环
564                 while page_list.entry_num == 0 {
565                     if page_list.next_page.is_null() {
566                         panic!(
567                             "buddy_free: page_list.entry_num == 0 && page_list.next_page.is_null()"
568                         );
569                     }
570                     page_list_paddr = page_list.next_page;
571                     page_list = Self::read_page(page_list_paddr);
572                 }
573 
574                 // 如果伙伴块不在第一个链表页,则把第一个链表中的某个空闲块替换到伙伴块的位置
575                 if page_list_paddr != buddy_entry_page_list_paddr {
576                     let entry: PhysAddr = unsafe {
577                         A::read(Self::entry_virt_addr(
578                             page_list_paddr,
579                             page_list.entry_num - 1,
580                         ))
581                     };
582                     // 把这个空闲块写入到伙伴块的位置
583                     unsafe {
584                         A::write(buddy_entry_virt_addr, entry);
585                     }
586                     // 设置刚才那个entry为空
587                     unsafe {
588                         A::write(
589                             Self::entry_virt_addr(page_list_paddr, page_list.entry_num - 1),
590                             PhysAddr::new(0),
591                         );
592                     }
593                     // 更新当前链表页的统计数据
594                     page_list.entry_num -= 1;
595                     Self::write_page(page_list_paddr, page_list);
596                 } else {
597                     // 伙伴块所在的链表页就是第一个链表页
598                     let last_entry: PhysAddr = unsafe {
599                         A::read(Self::entry_virt_addr(
600                             page_list_paddr,
601                             page_list.entry_num - 1,
602                         ))
603                     };
604 
605                     // 如果最后一个空闲块不是伙伴块,则把最后一个空闲块移动到伙伴块的位置
606                     // 否则后面的操作也将删除这个伙伴块
607                     if last_entry != buddy_addr {
608                         unsafe {
609                             A::write(buddy_entry_virt_addr, last_entry);
610                             A::write(
611                                 Self::entry_virt_addr(page_list_paddr, page_list.entry_num - 1),
612                                 PhysAddr::new(0),
613                             );
614                         }
615                     } else {
616                         unsafe {
617                             A::write(
618                                 Self::entry_virt_addr(page_list_paddr, page_list.entry_num - 1),
619                                 PhysAddr::new(0),
620                             );
621                         }
622                     }
623                     // 更新当前链表页的统计数据
624                     page_list.entry_num -= 1;
625                     Self::write_page(page_list_paddr, page_list);
626                 }
627             }
628             base = min(base, buddy_addr);
629             order += 1;
630         }
631         // 走到这一步,order应该为MAX_ORDER-1
632         assert!(order == MAX_ORDER - 1);
633     }
634 }
635 
636 impl<A: MemoryManagementArch> FrameAllocator for BuddyAllocator<A> {
637     unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
638         return self.buddy_alloc(count);
639     }
640 
641     /// 释放一个块
642     ///
643     /// ## 参数
644     ///
645     /// - `base` - 块的起始地址
646     /// - `count` - 块的页数(必须是2的幂)
647     ///
648     /// ## Panic
649     ///
650     /// 如果count不是2的幂,会panic
651     unsafe fn free(&mut self, base: PhysAddr, count: PageFrameCount) {
652         // 要求count是2的幂
653         if unlikely(!count.data().is_power_of_two()) {
654             kwarn!("buddy free: count is not power of two");
655         }
656         let mut order = log2(count.data() as usize);
657         if count.data() & ((1 << order) - 1) != 0 {
658             order += 1;
659         }
660         let order = (order + MIN_ORDER) as u8;
661         // kdebug!("free: base={:?}, count={:?}", base, count);
662         self.buddy_free(base, order);
663     }
664 
665     unsafe fn usage(&self) -> PageFrameUsage {
666         let mut free_page_num: usize = 0;
667         for index in 0..(MAX_ORDER - MIN_ORDER) {
668             let mut pagelist: PageList<A> = Self::read_page(self.free_area[index]);
669             loop {
670                 free_page_num += pagelist.entry_num << index;
671                 if pagelist.next_page.is_null() {
672                     break;
673                 }
674                 pagelist = Self::read_page(pagelist.next_page);
675             }
676         }
677         let free = PageFrameCount::new(free_page_num);
678         PageFrameUsage::new(self.total - free, self.total)
679     }
680 }
681 
682 /// 一个用于计算整数的对数的函数,会向下取整。(由于内核不能进行浮点运算,因此需要这个函数)
683 fn log2(x: usize) -> usize {
684     let leading_zeros = x.leading_zeros() as usize;
685     let log2x = 63 - leading_zeros;
686     return log2x;
687 }
688