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