1*2eab6dd7S曾俊 use log::{debug, warn};
2*2eab6dd7S曾俊
340fe15e0SLoGin /// @Author: longjin@dragonos.org
440fe15e0SLoGin /// @Author: kongweichao@dragonos.org
540fe15e0SLoGin /// @Date: 2023-03-28 16:03:47
640fe15e0SLoGin /// @FilePath: /DragonOS/kernel/src/mm/allocator/buddy.rs
740fe15e0SLoGin /// @Description: 伙伴分配器
840fe15e0SLoGin use crate::arch::MMArch;
940fe15e0SLoGin use crate::mm::allocator::bump::BumpAllocator;
1040fe15e0SLoGin use crate::mm::allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage};
1199dbf38dSLoGin use crate::mm::{MemoryManagementArch, PhysAddr, PhysMemoryArea, VirtAddr};
12*2eab6dd7S曾俊
1399dbf38dSLoGin use core::cmp::min;
1440fe15e0SLoGin use core::fmt::Debug;
1540fe15e0SLoGin use core::intrinsics::{likely, unlikely};
1640fe15e0SLoGin
1740fe15e0SLoGin use core::{marker::PhantomData, mem};
1840fe15e0SLoGin
1940fe15e0SLoGin // 一个全局变量MAX_ORDER,用来表示buddy算法的最大阶数 [MIN_ORDER, MAX_ORDER)左闭右开区间
2040fe15e0SLoGin const MAX_ORDER: usize = 31;
2140fe15e0SLoGin // 4KB
2240fe15e0SLoGin const MIN_ORDER: usize = 12;
2340fe15e0SLoGin
2440fe15e0SLoGin /// 保存buddy算法中每一页存放的BuddyEntry的信息,占据每个页的起始位置
2540fe15e0SLoGin #[derive(Debug)]
2640fe15e0SLoGin pub struct PageList<A> {
2740fe15e0SLoGin // 页存放entry的数量
2840fe15e0SLoGin entry_num: usize,
2940fe15e0SLoGin // 下一个页面的地址
3040fe15e0SLoGin next_page: PhysAddr,
3140fe15e0SLoGin phantom: PhantomData<A>,
3240fe15e0SLoGin }
3340fe15e0SLoGin
3440fe15e0SLoGin impl<A> Clone for PageList<A> {
clone(&self) -> Self3540fe15e0SLoGin fn clone(&self) -> Self {
3640fe15e0SLoGin Self {
3740fe15e0SLoGin entry_num: self.entry_num,
3840fe15e0SLoGin next_page: self.next_page,
3940fe15e0SLoGin phantom: PhantomData,
4040fe15e0SLoGin }
4140fe15e0SLoGin }
4240fe15e0SLoGin }
4340fe15e0SLoGin
4440fe15e0SLoGin impl<A> PageList<A> {
4540fe15e0SLoGin #[allow(dead_code)]
empty() -> Self4640fe15e0SLoGin fn empty() -> Self {
4740fe15e0SLoGin Self {
4840fe15e0SLoGin entry_num: 0,
4940fe15e0SLoGin next_page: PhysAddr::new(0),
5040fe15e0SLoGin phantom: PhantomData,
5140fe15e0SLoGin }
5240fe15e0SLoGin }
new(entry_num: usize, next_page: PhysAddr) -> Self5340fe15e0SLoGin fn new(entry_num: usize, next_page: PhysAddr) -> Self {
5440fe15e0SLoGin Self {
5540fe15e0SLoGin entry_num,
5640fe15e0SLoGin next_page,
5740fe15e0SLoGin phantom: PhantomData,
5840fe15e0SLoGin }
5940fe15e0SLoGin }
6040fe15e0SLoGin }
6140fe15e0SLoGin
6240fe15e0SLoGin /// @brief: 用来表示 buddy 算法中的一个 buddy 块,整体存放在area的头部
6340fe15e0SLoGin // 这种方式会出现对齐问题
6440fe15e0SLoGin // #[repr(packed)]
6540fe15e0SLoGin #[repr(C)]
6640fe15e0SLoGin #[derive(Debug)]
6740fe15e0SLoGin pub struct BuddyAllocator<A> {
6840fe15e0SLoGin // 存放每个阶的空闲“链表”的头部地址
69b5b571e0SLoGin free_area: [PhysAddr; MAX_ORDER - MIN_ORDER],
7034e6d6c8Syuyi2439 /// 总页数
7134e6d6c8Syuyi2439 total: PageFrameCount,
7240fe15e0SLoGin phantom: PhantomData<A>,
7340fe15e0SLoGin }
7440fe15e0SLoGin
7540fe15e0SLoGin impl<A: MemoryManagementArch> BuddyAllocator<A> {
7640fe15e0SLoGin const BUDDY_ENTRIES: usize =
7740fe15e0SLoGin // 定义一个变量记录buddy表的大小
7840fe15e0SLoGin (A::PAGE_SIZE - mem::size_of::<PageList<A>>()) / mem::size_of::<PhysAddr>();
7940fe15e0SLoGin
new(mut bump_allocator: BumpAllocator<A>) -> Option<Self>8040fe15e0SLoGin pub unsafe fn new(mut bump_allocator: BumpAllocator<A>) -> Option<Self> {
8140fe15e0SLoGin let initial_free_pages = bump_allocator.usage().free();
8299dbf38dSLoGin let total_memory = bump_allocator.usage().total();
83*2eab6dd7S曾俊 debug!("Free pages before init buddy: {:?}", initial_free_pages);
84*2eab6dd7S曾俊 debug!("Buddy entries: {}", Self::BUDDY_ENTRIES);
8540fe15e0SLoGin
86b5b571e0SLoGin let mut free_area: [PhysAddr; MAX_ORDER - MIN_ORDER] =
87b5b571e0SLoGin [PhysAddr::new(0); MAX_ORDER - MIN_ORDER];
8840fe15e0SLoGin
8940fe15e0SLoGin // Buddy初始占用的空间从bump分配
9040fe15e0SLoGin for f in free_area.iter_mut() {
9140fe15e0SLoGin let curr_page = bump_allocator.allocate_one();
9240fe15e0SLoGin // 保存每个阶的空闲链表的头部地址
9340fe15e0SLoGin *f = curr_page.unwrap();
9440fe15e0SLoGin // 清空当前页
9540fe15e0SLoGin core::ptr::write_bytes(MMArch::phys_2_virt(*f)?.data() as *mut u8, 0, A::PAGE_SIZE);
9640fe15e0SLoGin
9740fe15e0SLoGin let page_list: PageList<A> = PageList::new(0, PhysAddr::new(0));
9840fe15e0SLoGin Self::write_page(*f, page_list);
9940fe15e0SLoGin }
10040fe15e0SLoGin
10199dbf38dSLoGin let mut allocator = Self {
10299dbf38dSLoGin free_area,
10399dbf38dSLoGin total: PageFrameCount::new(0),
10499dbf38dSLoGin phantom: PhantomData,
10599dbf38dSLoGin };
10640fe15e0SLoGin
10799dbf38dSLoGin let mut total_pages_to_buddy = PageFrameCount::new(0);
10899dbf38dSLoGin let mut res_areas = [PhysMemoryArea::default(); 128];
10999dbf38dSLoGin let mut offset_in_remain_area = bump_allocator
11099dbf38dSLoGin .remain_areas(&mut res_areas)
11199dbf38dSLoGin .expect("BuddyAllocator: failed to get remain areas from bump allocator");
11299dbf38dSLoGin
11399dbf38dSLoGin let remain_areas = &res_areas[0..];
11499dbf38dSLoGin
11599dbf38dSLoGin for area in remain_areas {
11699dbf38dSLoGin let mut paddr = (area.area_base_aligned() + offset_in_remain_area).data();
11799dbf38dSLoGin let mut remain_pages =
11899dbf38dSLoGin PageFrameCount::from_bytes(area.area_end_aligned().data() - paddr).unwrap();
119453452ccSLoGin
120453452ccSLoGin if remain_pages.data() == 0 {
121453452ccSLoGin continue;
122453452ccSLoGin }
123*2eab6dd7S曾俊 debug!("area: {area:?}, paddr: {paddr:#x}, remain_pages: {remain_pages:?}");
124453452ccSLoGin
12599dbf38dSLoGin total_pages_to_buddy += remain_pages;
12699dbf38dSLoGin
12799dbf38dSLoGin if offset_in_remain_area != 0 {
12899dbf38dSLoGin offset_in_remain_area = 0;
12940fe15e0SLoGin }
13040fe15e0SLoGin
13199dbf38dSLoGin // 先从低阶开始,尽可能地填满空闲链表
13240fe15e0SLoGin for i in MIN_ORDER..MAX_ORDER {
133*2eab6dd7S曾俊 // debug!("i {i}, remain pages={}", remain_pages.data());
13440fe15e0SLoGin if remain_pages.data() < (1 << (i - MIN_ORDER)) {
13540fe15e0SLoGin break;
13640fe15e0SLoGin }
13740fe15e0SLoGin
13840fe15e0SLoGin assert!(paddr & ((1 << i) - 1) == 0);
13940fe15e0SLoGin
14040fe15e0SLoGin if likely(i != MAX_ORDER - 1) {
14140fe15e0SLoGin // 要填写entry
14240fe15e0SLoGin if paddr & (1 << i) != 0 {
14399dbf38dSLoGin allocator.buddy_free(PhysAddr::new(paddr), i as u8);
14440fe15e0SLoGin
14540fe15e0SLoGin paddr += 1 << i;
14640fe15e0SLoGin remain_pages -= 1 << (i - MIN_ORDER);
14740fe15e0SLoGin };
14840fe15e0SLoGin } else {
14940fe15e0SLoGin // 往最大的阶数的链表中添加entry(注意要考虑到最大阶数的链表可能有多页)
15040fe15e0SLoGin // 断言剩余页面数量是MAX_ORDER-1阶的整数倍
15140fe15e0SLoGin
15240fe15e0SLoGin let mut entries = (remain_pages.data() * A::PAGE_SIZE) >> i;
15340fe15e0SLoGin while entries > 0 {
15499dbf38dSLoGin allocator.buddy_free(PhysAddr::new(paddr), i as u8);
15599dbf38dSLoGin paddr += 1 << i;
15640fe15e0SLoGin remain_pages -= 1 << (i - MIN_ORDER);
15799dbf38dSLoGin
15840fe15e0SLoGin entries -= 1;
15940fe15e0SLoGin }
16040fe15e0SLoGin }
16140fe15e0SLoGin }
16299dbf38dSLoGin // 然后从高往低,把剩余的页面加入链表
16340fe15e0SLoGin let mut remain_bytes = remain_pages.data() * A::PAGE_SIZE;
16440fe15e0SLoGin
165b5b571e0SLoGin assert!(remain_bytes < (1 << MAX_ORDER) - 1);
16640fe15e0SLoGin
16740fe15e0SLoGin for i in (MIN_ORDER..MAX_ORDER).rev() {
16826887c63SLoGin if remain_bytes >= (1 << i) {
16926887c63SLoGin assert!(paddr & ((1 << i) - 1) == 0);
17099dbf38dSLoGin allocator.buddy_free(PhysAddr::new(paddr), i as u8);
17140fe15e0SLoGin
17240fe15e0SLoGin paddr += 1 << i;
17340fe15e0SLoGin remain_bytes -= 1 << i;
17440fe15e0SLoGin }
17540fe15e0SLoGin }
17640fe15e0SLoGin
17740fe15e0SLoGin assert!(remain_bytes == 0);
17899dbf38dSLoGin }
17940fe15e0SLoGin
180*2eab6dd7S曾俊 debug!("Total pages to buddy: {:?}", total_pages_to_buddy);
18199dbf38dSLoGin allocator.total = total_memory;
18240fe15e0SLoGin
18340fe15e0SLoGin Some(allocator)
18440fe15e0SLoGin }
18540fe15e0SLoGin /// 获取第j个entry的虚拟地址,
18640fe15e0SLoGin /// j从0开始计数
entry_virt_addr(base_addr: PhysAddr, j: usize) -> VirtAddr18740fe15e0SLoGin pub fn entry_virt_addr(base_addr: PhysAddr, j: usize) -> VirtAddr {
18840fe15e0SLoGin let entry_virt_addr = unsafe { A::phys_2_virt(Self::entry_addr(base_addr, j)) };
18940fe15e0SLoGin return entry_virt_addr.unwrap();
19040fe15e0SLoGin }
entry_addr(base_addr: PhysAddr, j: usize) -> PhysAddr19140fe15e0SLoGin pub fn entry_addr(base_addr: PhysAddr, j: usize) -> PhysAddr {
19240fe15e0SLoGin let entry_addr = base_addr + mem::size_of::<PageList<A>>() + j * mem::size_of::<PhysAddr>();
19340fe15e0SLoGin return entry_addr;
19440fe15e0SLoGin }
read_page<T>(addr: PhysAddr) -> T19540fe15e0SLoGin pub fn read_page<T>(addr: PhysAddr) -> T {
19640fe15e0SLoGin let page_list = unsafe { A::read(A::phys_2_virt(addr).unwrap()) };
19740fe15e0SLoGin return page_list;
19840fe15e0SLoGin }
19940fe15e0SLoGin
write_page(curr_page: PhysAddr, page_list: PageList<A>)20040fe15e0SLoGin pub fn write_page(curr_page: PhysAddr, page_list: PageList<A>) {
20140fe15e0SLoGin // 把物理地址转换为虚拟地址
20240fe15e0SLoGin let virt_addr = unsafe { A::phys_2_virt(curr_page) };
20340fe15e0SLoGin let virt_addr = virt_addr.unwrap();
20440fe15e0SLoGin unsafe { A::write(virt_addr, page_list) };
20540fe15e0SLoGin }
20640fe15e0SLoGin
20740fe15e0SLoGin /// 从order转换为free_area的下标
20840fe15e0SLoGin ///
20940fe15e0SLoGin /// # 参数
21040fe15e0SLoGin ///
21140fe15e0SLoGin /// - `order` - order
21240fe15e0SLoGin ///
21340fe15e0SLoGin /// # 返回值
21440fe15e0SLoGin ///
21540fe15e0SLoGin /// free_area的下标
21640fe15e0SLoGin #[inline]
order2index(order: u8) -> usize21740fe15e0SLoGin fn order2index(order: u8) -> usize {
218b5b571e0SLoGin order as usize - MIN_ORDER
21940fe15e0SLoGin }
22040fe15e0SLoGin
22140fe15e0SLoGin /// 从空闲链表的开头,取出1个指定阶数的伙伴块,如果没有,则返回None
22240fe15e0SLoGin ///
22340fe15e0SLoGin /// ## 参数
22440fe15e0SLoGin ///
22540fe15e0SLoGin /// - `order` - 伙伴块的阶数
pop_front(&mut self, order: u8) -> Option<PhysAddr>22640fe15e0SLoGin fn pop_front(&mut self, order: u8) -> Option<PhysAddr> {
22740fe15e0SLoGin let mut alloc_in_specific_order = |spec_order: u8| {
22840fe15e0SLoGin // 先尝试在order阶的“空闲链表”的开头位置分配一个伙伴块
22940fe15e0SLoGin let mut page_list_addr = self.free_area[Self::order2index(spec_order)];
23040fe15e0SLoGin let mut page_list: PageList<A> = Self::read_page(page_list_addr);
23140fe15e0SLoGin
23240fe15e0SLoGin // 循环删除头部的空闲链表页
23340fe15e0SLoGin while page_list.entry_num == 0 {
23440fe15e0SLoGin let next_page_list_addr = page_list.next_page;
23540fe15e0SLoGin // 找完了,都是空的
23640fe15e0SLoGin if next_page_list_addr.is_null() {
23740fe15e0SLoGin return None;
23840fe15e0SLoGin }
23940fe15e0SLoGin
24040fe15e0SLoGin if !next_page_list_addr.is_null() {
24140fe15e0SLoGin // 此时page_list已经没有空闲伙伴块了,又因为非唯一页,需要删除该page_list
24240fe15e0SLoGin self.free_area[Self::order2index(spec_order)] = next_page_list_addr;
243*2eab6dd7S曾俊 // debug!("FREE: page_list_addr={:b}", page_list_addr.data());
24440fe15e0SLoGin unsafe {
24540fe15e0SLoGin self.buddy_free(page_list_addr, MMArch::PAGE_SHIFT as u8);
24640fe15e0SLoGin }
24740fe15e0SLoGin }
24840fe15e0SLoGin // 由于buddy_free可能导致首部的链表页发生变化,因此需要重新读取
24940fe15e0SLoGin let next_page_list_addr = self.free_area[Self::order2index(spec_order)];
25040fe15e0SLoGin assert!(!next_page_list_addr.is_null());
25140fe15e0SLoGin page_list = Self::read_page(next_page_list_addr);
25240fe15e0SLoGin page_list_addr = next_page_list_addr;
25340fe15e0SLoGin }
25440fe15e0SLoGin
25540fe15e0SLoGin // 有空闲页面,直接分配
25640fe15e0SLoGin if page_list.entry_num > 0 {
25740fe15e0SLoGin let entry: PhysAddr = unsafe {
25840fe15e0SLoGin A::read(Self::entry_virt_addr(
25940fe15e0SLoGin page_list_addr,
26040fe15e0SLoGin page_list.entry_num - 1,
26140fe15e0SLoGin ))
26240fe15e0SLoGin };
26326887c63SLoGin // 清除该entry
26426887c63SLoGin unsafe {
26526887c63SLoGin A::write(
26626887c63SLoGin Self::entry_virt_addr(page_list_addr, page_list.entry_num - 1),
26726887c63SLoGin PhysAddr::new(0),
26826887c63SLoGin )
26926887c63SLoGin };
27040fe15e0SLoGin if entry.is_null() {
27126887c63SLoGin panic!(
27240fe15e0SLoGin "entry is null, entry={:?}, order={}, entry_num = {}",
27340fe15e0SLoGin entry,
27440fe15e0SLoGin spec_order,
27540fe15e0SLoGin page_list.entry_num - 1
27640fe15e0SLoGin );
27740fe15e0SLoGin }
278*2eab6dd7S曾俊 // debug!("entry={entry:?}");
27926887c63SLoGin
28040fe15e0SLoGin // 更新page_list的entry_num
28140fe15e0SLoGin page_list.entry_num -= 1;
28240fe15e0SLoGin let tmp_current_entry_num = page_list.entry_num;
28340fe15e0SLoGin if page_list.entry_num == 0 {
28440fe15e0SLoGin if !page_list.next_page.is_null() {
28540fe15e0SLoGin // 此时page_list已经没有空闲伙伴块了,又因为非唯一页,需要删除该page_list
28640fe15e0SLoGin self.free_area[Self::order2index(spec_order)] = page_list.next_page;
287b5b571e0SLoGin let _ = page_list;
28840fe15e0SLoGin unsafe { self.buddy_free(page_list_addr, MMArch::PAGE_SHIFT as u8) };
28940fe15e0SLoGin } else {
29040fe15e0SLoGin Self::write_page(page_list_addr, page_list);
29140fe15e0SLoGin }
29240fe15e0SLoGin } else {
29340fe15e0SLoGin // 若entry_num不为0,说明该page_list还有空闲伙伴块,需要更新该page_list
29440fe15e0SLoGin // 把更新后的page_list写回
29540fe15e0SLoGin Self::write_page(page_list_addr, page_list.clone());
29640fe15e0SLoGin }
29740fe15e0SLoGin
29840fe15e0SLoGin // 检测entry 是否对齐
29940fe15e0SLoGin if !entry.check_aligned(1 << spec_order) {
30040fe15e0SLoGin panic!("entry={:?} is not aligned, spec_order={spec_order}, page_list.entry_num={}", entry, tmp_current_entry_num);
30140fe15e0SLoGin }
30240fe15e0SLoGin return Some(entry);
30340fe15e0SLoGin }
30440fe15e0SLoGin return None;
30540fe15e0SLoGin };
306b5b571e0SLoGin let result: Option<PhysAddr> = alloc_in_specific_order(order);
307*2eab6dd7S曾俊 // debug!("result={:?}", result);
30840fe15e0SLoGin if result.is_some() {
30940fe15e0SLoGin return result;
31040fe15e0SLoGin }
31140fe15e0SLoGin // 尝试从更大的链表中分裂
31240fe15e0SLoGin
31340fe15e0SLoGin let mut current_order = (order + 1) as usize;
31440fe15e0SLoGin let mut x: Option<PhysAddr> = None;
31540fe15e0SLoGin while current_order < MAX_ORDER {
31640fe15e0SLoGin x = alloc_in_specific_order(current_order as u8);
317*2eab6dd7S曾俊 // debug!("current_order={:?}", current_order);
31840fe15e0SLoGin if x.is_some() {
31940fe15e0SLoGin break;
32040fe15e0SLoGin }
32140fe15e0SLoGin current_order += 1;
32240fe15e0SLoGin }
32340fe15e0SLoGin
324*2eab6dd7S曾俊 // debug!("x={:?}", x);
32540fe15e0SLoGin // 如果找到一个大的块,就进行分裂
32640fe15e0SLoGin if x.is_some() {
32740fe15e0SLoGin // 分裂到order阶
32840fe15e0SLoGin while current_order > order as usize {
32940fe15e0SLoGin current_order -= 1;
33040fe15e0SLoGin // 把后面那半块放回空闲链表
33140fe15e0SLoGin
33240fe15e0SLoGin let buddy = *x.as_ref().unwrap() + (1 << current_order);
333*2eab6dd7S曾俊 // debug!("x={:?}, buddy={:?}", x, buddy);
334*2eab6dd7S曾俊 // debug!("current_order={:?}, buddy={:?}", current_order, buddy);
33540fe15e0SLoGin unsafe { self.buddy_free(buddy, current_order as u8) };
33640fe15e0SLoGin }
33740fe15e0SLoGin return x;
33840fe15e0SLoGin }
33940fe15e0SLoGin
34040fe15e0SLoGin return None;
34140fe15e0SLoGin }
34240fe15e0SLoGin
34340fe15e0SLoGin /// 从伙伴系统中分配count个页面
34440fe15e0SLoGin ///
34540fe15e0SLoGin /// ## 参数
34640fe15e0SLoGin ///
34740fe15e0SLoGin /// - `count`:需要分配的页面数
34840fe15e0SLoGin ///
34940fe15e0SLoGin /// ## 返回值
35040fe15e0SLoGin ///
35140fe15e0SLoGin /// 返回分配的页面的物理地址和页面数
buddy_alloc(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)>35240fe15e0SLoGin fn buddy_alloc(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
35340fe15e0SLoGin assert!(count.data().is_power_of_two());
35440fe15e0SLoGin // 计算需要分配的阶数
355b5b571e0SLoGin let mut order = log2(count.data());
35640fe15e0SLoGin if count.data() & ((1 << order) - 1) != 0 {
35740fe15e0SLoGin order += 1;
35840fe15e0SLoGin }
35940fe15e0SLoGin let order = (order + MIN_ORDER) as u8;
36040fe15e0SLoGin if order as usize >= MAX_ORDER {
36140fe15e0SLoGin return None;
36240fe15e0SLoGin }
36340fe15e0SLoGin
364*2eab6dd7S曾俊 // debug!("buddy_alloc: order = {}", order);
36540fe15e0SLoGin // 获取该阶数的一个空闲页面
36640fe15e0SLoGin let free_addr = self.pop_front(order);
367*2eab6dd7S曾俊 // debug!(
36840fe15e0SLoGin // "buddy_alloc: order = {}, free_addr = {:?}",
36940fe15e0SLoGin // order,
37040fe15e0SLoGin // free_addr
37140fe15e0SLoGin // );
37240fe15e0SLoGin return free_addr
37340fe15e0SLoGin .map(|addr| (addr, PageFrameCount::new(1 << (order as usize - MIN_ORDER))));
37440fe15e0SLoGin }
37540fe15e0SLoGin
37640fe15e0SLoGin /// 释放一个块
37740fe15e0SLoGin ///
37840fe15e0SLoGin /// ## 参数
37940fe15e0SLoGin ///
38040fe15e0SLoGin /// - `base` - 块的起始地址
38140fe15e0SLoGin /// - `order` - 块的阶数
buddy_free(&mut self, mut base: PhysAddr, order: u8)38240fe15e0SLoGin unsafe fn buddy_free(&mut self, mut base: PhysAddr, order: u8) {
383*2eab6dd7S曾俊 // debug!("buddy_free: base = {:?}, order = {}", base, order);
38440fe15e0SLoGin let mut order = order as usize;
38540fe15e0SLoGin
38640fe15e0SLoGin while order < MAX_ORDER {
38740fe15e0SLoGin // 检测地址是否合法
38840fe15e0SLoGin if base.data() & ((1 << (order)) - 1) != 0 {
38940fe15e0SLoGin panic!(
39040fe15e0SLoGin "buddy_free: base is not aligned, base = {:#x}, order = {}",
39140fe15e0SLoGin base.data(),
39240fe15e0SLoGin order
39340fe15e0SLoGin );
39440fe15e0SLoGin }
39540fe15e0SLoGin
39640fe15e0SLoGin // 在链表中寻找伙伴块
39740fe15e0SLoGin // 伙伴块的地址是base ^ (1 << order)
39840fe15e0SLoGin let buddy_addr = PhysAddr::new(base.data() ^ (1 << order));
39940fe15e0SLoGin
40040fe15e0SLoGin let first_page_list_paddr = self.free_area[Self::order2index(order as u8)];
40140fe15e0SLoGin let mut page_list_paddr = first_page_list_paddr;
40240fe15e0SLoGin let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
40340fe15e0SLoGin let first_page_list = page_list.clone();
40440fe15e0SLoGin
40540fe15e0SLoGin let mut buddy_entry_virt_vaddr = None;
40640fe15e0SLoGin let mut buddy_entry_page_list_paddr = None;
40740fe15e0SLoGin // 除非order是最大的,否则尝试查找伙伴块
40840fe15e0SLoGin if likely(order != MAX_ORDER - 1) {
40940fe15e0SLoGin 'outer: loop {
41040fe15e0SLoGin for i in 0..page_list.entry_num {
41140fe15e0SLoGin let entry_virt_addr = Self::entry_virt_addr(page_list_paddr, i);
41240fe15e0SLoGin let entry: PhysAddr = unsafe { A::read(entry_virt_addr) };
41340fe15e0SLoGin if entry == buddy_addr {
41440fe15e0SLoGin // 找到了伙伴块,记录该entry相关信息,然后退出查找
41540fe15e0SLoGin buddy_entry_virt_vaddr = Some(entry_virt_addr);
41640fe15e0SLoGin buddy_entry_page_list_paddr = Some(page_list_paddr);
41740fe15e0SLoGin break 'outer;
41840fe15e0SLoGin }
41940fe15e0SLoGin }
42040fe15e0SLoGin if page_list.next_page.is_null() {
42140fe15e0SLoGin break;
42240fe15e0SLoGin }
42340fe15e0SLoGin page_list_paddr = page_list.next_page;
42440fe15e0SLoGin page_list = Self::read_page(page_list_paddr);
42540fe15e0SLoGin }
42640fe15e0SLoGin }
42740fe15e0SLoGin
42840fe15e0SLoGin // 如果没有找到伙伴块
429b5b571e0SLoGin if let Some(buddy_entry_virt_addr) = buddy_entry_virt_vaddr {
43040fe15e0SLoGin // 如果找到了伙伴块,合并,向上递归
43140fe15e0SLoGin
43240fe15e0SLoGin // 伙伴块所在的page_list的物理地址
43340fe15e0SLoGin let buddy_entry_page_list_paddr = buddy_entry_page_list_paddr.unwrap();
43440fe15e0SLoGin
43540fe15e0SLoGin let mut page_list_paddr = self.free_area[Self::order2index(order as u8)];
43640fe15e0SLoGin let mut page_list = Self::read_page::<PageList<A>>(page_list_paddr);
43740fe15e0SLoGin // 找第一个有空闲块的链表页。跳过空闲链表页。不进行回收的原因是担心出现死循环
43840fe15e0SLoGin while page_list.entry_num == 0 {
43940fe15e0SLoGin if page_list.next_page.is_null() {
44040fe15e0SLoGin panic!(
44140fe15e0SLoGin "buddy_free: page_list.entry_num == 0 && page_list.next_page.is_null()"
44240fe15e0SLoGin );
44340fe15e0SLoGin }
44440fe15e0SLoGin page_list_paddr = page_list.next_page;
44540fe15e0SLoGin page_list = Self::read_page(page_list_paddr);
44640fe15e0SLoGin }
44740fe15e0SLoGin
44840fe15e0SLoGin // 如果伙伴块不在第一个链表页,则把第一个链表中的某个空闲块替换到伙伴块的位置
44940fe15e0SLoGin if page_list_paddr != buddy_entry_page_list_paddr {
45040fe15e0SLoGin let entry: PhysAddr = unsafe {
45140fe15e0SLoGin A::read(Self::entry_virt_addr(
45240fe15e0SLoGin page_list_paddr,
45340fe15e0SLoGin page_list.entry_num - 1,
45440fe15e0SLoGin ))
45540fe15e0SLoGin };
45640fe15e0SLoGin // 把这个空闲块写入到伙伴块的位置
45740fe15e0SLoGin unsafe {
45840fe15e0SLoGin A::write(buddy_entry_virt_addr, entry);
45940fe15e0SLoGin }
46040fe15e0SLoGin // 设置刚才那个entry为空
46140fe15e0SLoGin unsafe {
46240fe15e0SLoGin A::write(
46340fe15e0SLoGin Self::entry_virt_addr(page_list_paddr, page_list.entry_num - 1),
46440fe15e0SLoGin PhysAddr::new(0),
46540fe15e0SLoGin );
46640fe15e0SLoGin }
46740fe15e0SLoGin // 更新当前链表页的统计数据
46840fe15e0SLoGin page_list.entry_num -= 1;
46940fe15e0SLoGin Self::write_page(page_list_paddr, page_list);
47040fe15e0SLoGin } else {
47140fe15e0SLoGin // 伙伴块所在的链表页就是第一个链表页
47240fe15e0SLoGin let last_entry: PhysAddr = unsafe {
47340fe15e0SLoGin A::read(Self::entry_virt_addr(
47440fe15e0SLoGin page_list_paddr,
47540fe15e0SLoGin page_list.entry_num - 1,
47640fe15e0SLoGin ))
47740fe15e0SLoGin };
47840fe15e0SLoGin
47940fe15e0SLoGin // 如果最后一个空闲块不是伙伴块,则把最后一个空闲块移动到伙伴块的位置
48040fe15e0SLoGin // 否则后面的操作也将删除这个伙伴块
48140fe15e0SLoGin if last_entry != buddy_addr {
48240fe15e0SLoGin unsafe {
48340fe15e0SLoGin A::write(buddy_entry_virt_addr, last_entry);
48440fe15e0SLoGin A::write(
48540fe15e0SLoGin Self::entry_virt_addr(page_list_paddr, page_list.entry_num - 1),
48640fe15e0SLoGin PhysAddr::new(0),
48740fe15e0SLoGin );
48840fe15e0SLoGin }
48940fe15e0SLoGin } else {
49040fe15e0SLoGin unsafe {
49140fe15e0SLoGin A::write(
49240fe15e0SLoGin Self::entry_virt_addr(page_list_paddr, page_list.entry_num - 1),
49340fe15e0SLoGin PhysAddr::new(0),
49440fe15e0SLoGin );
49540fe15e0SLoGin }
49640fe15e0SLoGin }
49740fe15e0SLoGin // 更新当前链表页的统计数据
49840fe15e0SLoGin page_list.entry_num -= 1;
49940fe15e0SLoGin Self::write_page(page_list_paddr, page_list);
50040fe15e0SLoGin }
501b5b571e0SLoGin } else {
502b5b571e0SLoGin assert!(
503b5b571e0SLoGin page_list.entry_num <= Self::BUDDY_ENTRIES,
504b5b571e0SLoGin "buddy_free: page_list.entry_num > Self::BUDDY_ENTRIES"
505b5b571e0SLoGin );
506b5b571e0SLoGin
507b5b571e0SLoGin // 当前第一个page_list没有空间了
508b5b571e0SLoGin if first_page_list.entry_num == Self::BUDDY_ENTRIES {
509b5b571e0SLoGin // 如果当前order是最小的,那么就把这个块当作新的page_list使用
510b5b571e0SLoGin let new_page_list_addr = if order == MIN_ORDER {
511b5b571e0SLoGin base
512b5b571e0SLoGin } else {
513b5b571e0SLoGin // 否则分配新的page_list
514b5b571e0SLoGin // 请注意,分配之后,有可能当前的entry_num会减1(伙伴块分裂),造成出现整个链表为null的entry数量为Self::BUDDY_ENTRIES+1的情况
515b5b571e0SLoGin // 但是不影响,我们在后面插入链表项的时候,会处理这种情况,检查链表中的第2个页是否有空位
516b5b571e0SLoGin self.buddy_alloc(PageFrameCount::new(1))
517b5b571e0SLoGin .expect("buddy_alloc failed: no enough memory")
518b5b571e0SLoGin .0
519b5b571e0SLoGin };
520b5b571e0SLoGin
521b5b571e0SLoGin // 清空这个页面
522b5b571e0SLoGin core::ptr::write_bytes(
523b5b571e0SLoGin A::phys_2_virt(new_page_list_addr)
524b5b571e0SLoGin .expect(
525b5b571e0SLoGin "Buddy free: failed to get virt address of [new_page_list_addr]",
526b5b571e0SLoGin )
527b5b571e0SLoGin .as_ptr::<u8>(),
528b5b571e0SLoGin 0,
529b5b571e0SLoGin 1 << order,
530b5b571e0SLoGin );
531b5b571e0SLoGin assert!(
532b5b571e0SLoGin first_page_list_paddr == self.free_area[Self::order2index(order as u8)]
533b5b571e0SLoGin );
534b5b571e0SLoGin // 初始化新的page_list
535b5b571e0SLoGin let new_page_list = PageList::new(0, first_page_list_paddr);
536b5b571e0SLoGin Self::write_page(new_page_list_addr, new_page_list);
537b5b571e0SLoGin self.free_area[Self::order2index(order as u8)] = new_page_list_addr;
538b5b571e0SLoGin }
539b5b571e0SLoGin
540b5b571e0SLoGin // 由于上面可能更新了第一个链表页,因此需要重新获取这个值
541b5b571e0SLoGin let first_page_list_paddr = self.free_area[Self::order2index(order as u8)];
542b5b571e0SLoGin let first_page_list: PageList<A> = Self::read_page(first_page_list_paddr);
543b5b571e0SLoGin
544b5b571e0SLoGin // 检查第二个page_list是否有空位
545b5b571e0SLoGin let second_page_list = if first_page_list.next_page.is_null() {
546b5b571e0SLoGin None
547b5b571e0SLoGin } else {
548b5b571e0SLoGin Some(Self::read_page::<PageList<A>>(first_page_list.next_page))
549b5b571e0SLoGin };
550b5b571e0SLoGin
551b5b571e0SLoGin let (paddr, mut page_list) = if let Some(second) = second_page_list {
552b5b571e0SLoGin // 第二个page_list有空位
553b5b571e0SLoGin // 应当符合之前的假设:还有1个空位
554b5b571e0SLoGin assert!(second.entry_num == Self::BUDDY_ENTRIES - 1);
555b5b571e0SLoGin
556b5b571e0SLoGin (first_page_list.next_page, second)
557b5b571e0SLoGin } else {
558b5b571e0SLoGin // 在第一个page list中分配
559b5b571e0SLoGin (first_page_list_paddr, first_page_list)
560b5b571e0SLoGin };
561b5b571e0SLoGin
562*2eab6dd7S曾俊 // debug!("to write entry, page_list_base={paddr:?}, page_list.entry_num={}, value={base:?}", page_list.entry_num);
563b5b571e0SLoGin assert!(page_list.entry_num < Self::BUDDY_ENTRIES);
564b5b571e0SLoGin // 把要归还的块,写入到链表项中
565b5b571e0SLoGin unsafe { A::write(Self::entry_virt_addr(paddr, page_list.entry_num), base) }
566b5b571e0SLoGin page_list.entry_num += 1;
567b5b571e0SLoGin Self::write_page(paddr, page_list);
568b5b571e0SLoGin return;
56940fe15e0SLoGin }
57040fe15e0SLoGin base = min(base, buddy_addr);
57140fe15e0SLoGin order += 1;
57240fe15e0SLoGin }
57340fe15e0SLoGin // 走到这一步,order应该为MAX_ORDER-1
57440fe15e0SLoGin assert!(order == MAX_ORDER - 1);
57540fe15e0SLoGin }
57640fe15e0SLoGin }
57740fe15e0SLoGin
57840fe15e0SLoGin impl<A: MemoryManagementArch> FrameAllocator for BuddyAllocator<A> {
allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)>57940fe15e0SLoGin unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
58040fe15e0SLoGin return self.buddy_alloc(count);
58140fe15e0SLoGin }
58240fe15e0SLoGin
58340fe15e0SLoGin /// 释放一个块
58440fe15e0SLoGin ///
58540fe15e0SLoGin /// ## 参数
58640fe15e0SLoGin ///
58740fe15e0SLoGin /// - `base` - 块的起始地址
58840fe15e0SLoGin /// - `count` - 块的页数(必须是2的幂)
58940fe15e0SLoGin ///
59040fe15e0SLoGin /// ## Panic
59140fe15e0SLoGin ///
59240fe15e0SLoGin /// 如果count不是2的幂,会panic
free(&mut self, base: PhysAddr, count: PageFrameCount)59340fe15e0SLoGin unsafe fn free(&mut self, base: PhysAddr, count: PageFrameCount) {
59440fe15e0SLoGin // 要求count是2的幂
59540fe15e0SLoGin if unlikely(!count.data().is_power_of_two()) {
596*2eab6dd7S曾俊 warn!("buddy free: count is not power of two");
59740fe15e0SLoGin }
598b5b571e0SLoGin let mut order = log2(count.data());
59940fe15e0SLoGin if count.data() & ((1 << order) - 1) != 0 {
60040fe15e0SLoGin order += 1;
60140fe15e0SLoGin }
60240fe15e0SLoGin let order = (order + MIN_ORDER) as u8;
603*2eab6dd7S曾俊 // debug!("free: base={:?}, count={:?}", base, count);
60440fe15e0SLoGin self.buddy_free(base, order);
60540fe15e0SLoGin }
60640fe15e0SLoGin
usage(&self) -> PageFrameUsage60740fe15e0SLoGin unsafe fn usage(&self) -> PageFrameUsage {
60834e6d6c8Syuyi2439 let mut free_page_num: usize = 0;
60934e6d6c8Syuyi2439 for index in 0..(MAX_ORDER - MIN_ORDER) {
61034e6d6c8Syuyi2439 let mut pagelist: PageList<A> = Self::read_page(self.free_area[index]);
61134e6d6c8Syuyi2439 loop {
61234e6d6c8Syuyi2439 free_page_num += pagelist.entry_num << index;
61334e6d6c8Syuyi2439 if pagelist.next_page.is_null() {
61434e6d6c8Syuyi2439 break;
61534e6d6c8Syuyi2439 }
61634e6d6c8Syuyi2439 pagelist = Self::read_page(pagelist.next_page);
61734e6d6c8Syuyi2439 }
61834e6d6c8Syuyi2439 }
61934e6d6c8Syuyi2439 let free = PageFrameCount::new(free_page_num);
62034e6d6c8Syuyi2439 PageFrameUsage::new(self.total - free, self.total)
62140fe15e0SLoGin }
62240fe15e0SLoGin }
62340fe15e0SLoGin
62440fe15e0SLoGin /// 一个用于计算整数的对数的函数,会向下取整。(由于内核不能进行浮点运算,因此需要这个函数)
log2(x: usize) -> usize62540fe15e0SLoGin fn log2(x: usize) -> usize {
62640fe15e0SLoGin let leading_zeros = x.leading_zeros() as usize;
62740fe15e0SLoGin let log2x = 63 - leading_zeros;
62840fe15e0SLoGin return log2x;
62940fe15e0SLoGin }
630