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