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