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