1a7eb62a4Shoumkh use crate::libs::spinlock::{SpinLock, SpinLockGuard}; 2c2481452Shoumkh use crate::{ 3c2481452Shoumkh arch::asm::current::current_pcb, 4c2481452Shoumkh include::bindings::bindings::{ 5c2481452Shoumkh initial_mm, mm_create_vma, mm_unmap, vm_area_del, vm_area_free, vm_area_struct, vm_flags_t, 6c2481452Shoumkh vma_find, EINVAL, ENOMEM, EPERM, MMIO_BASE, MMIO_TOP, PAGE_1G_SHIFT, PAGE_1G_SIZE, 7c2481452Shoumkh PAGE_2M_SIZE, PAGE_4K_SHIFT, PAGE_4K_SIZE, VM_DONTCOPY, VM_IO, 8c2481452Shoumkh }, 9c2481452Shoumkh kdebug, kerror, 10c2481452Shoumkh }; 11c2481452Shoumkh use alloc::{boxed::Box, collections::LinkedList, vec::Vec}; 12c2481452Shoumkh use core::{mem, ptr::null_mut}; 13c2481452Shoumkh 14c2481452Shoumkh // 最大的伙伴块的幂 15c2481452Shoumkh const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT; 16c2481452Shoumkh // 最小的伙伴块的幂 17c2481452Shoumkh const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT; 18c2481452Shoumkh // 内存池数组的范围 19c2481452Shoumkh const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1; 20c2481452Shoumkh 21c2481452Shoumkh lazy_static! { 22c2481452Shoumkh pub static ref MMIO_POOL: MmioBuddyMemPool = MmioBuddyMemPool::new(); 23c2481452Shoumkh } 24c2481452Shoumkh 25c2481452Shoumkh pub enum MmioResult { 26c2481452Shoumkh SUCCESS, 27c2481452Shoumkh EINVAL, 28c2481452Shoumkh ENOFOUND, 29c2481452Shoumkh WRONGEXP, 30c2481452Shoumkh ISEMPTY, 31c2481452Shoumkh } 32c2481452Shoumkh 33c2481452Shoumkh /// @brief buddy内存池 34c2481452Shoumkh pub struct MmioBuddyMemPool { 35c2481452Shoumkh pool_start_addr: u64, 36c2481452Shoumkh pool_size: u64, 37c2481452Shoumkh free_regions: [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize], 38c2481452Shoumkh } 39c2481452Shoumkh impl Default for MmioBuddyMemPool { 40c2481452Shoumkh fn default() -> Self { 41c2481452Shoumkh MmioBuddyMemPool { 42c2481452Shoumkh pool_start_addr: MMIO_BASE as u64, 43c2481452Shoumkh pool_size: (MMIO_TOP - MMIO_BASE) as u64, 44c2481452Shoumkh free_regions: unsafe { mem::zeroed() }, 45c2481452Shoumkh } 46c2481452Shoumkh } 47c2481452Shoumkh } 48c2481452Shoumkh impl MmioBuddyMemPool { 49c2481452Shoumkh fn new() -> Self { 50c2481452Shoumkh return MmioBuddyMemPool { 51c2481452Shoumkh ..Default::default() 52c2481452Shoumkh }; 53c2481452Shoumkh } 54c2481452Shoumkh 55c2481452Shoumkh /// @brief 创建新的地址区域结构体 56c2481452Shoumkh /// 57c2481452Shoumkh /// @param vaddr 虚拟地址 58c2481452Shoumkh /// 59c2481452Shoumkh /// @return 创建好的地址区域结构体 60a7eb62a4Shoumkh fn create_region(&self, vaddr: u64) -> Box<MmioBuddyAddrRegion> { 61c2481452Shoumkh let mut region: Box<MmioBuddyAddrRegion> = Box::new(MmioBuddyAddrRegion::new()); 62c2481452Shoumkh region.vaddr = vaddr; 63c2481452Shoumkh return region; 64c2481452Shoumkh } 65c2481452Shoumkh 66c2481452Shoumkh /// @brief 将内存块归还给buddy 67c2481452Shoumkh /// 68c2481452Shoumkh /// @param vaddr 虚拟地址 69c2481452Shoumkh /// 70c2481452Shoumkh /// @param exp 内存空间的大小(2^exp) 71c2481452Shoumkh /// 72c2481452Shoumkh /// @param list_guard 【exp】对应的链表 73c2481452Shoumkh /// 74c2481452Shoumkh /// @return Ok(i32) 返回0 75c2481452Shoumkh /// 76c2481452Shoumkh /// @return Err(i32) 返回错误码 77a7eb62a4Shoumkh fn give_back_block(&self, vaddr: u64, exp: u32) -> Result<i32, i32> { 78c2481452Shoumkh // 确保内存对齐,低位都要为0 79c2481452Shoumkh if (vaddr & ((1 << exp) - 1)) != 0 { 80c2481452Shoumkh return Err(-(EINVAL as i32)); 81c2481452Shoumkh } 82a7eb62a4Shoumkh let region: Box<MmioBuddyAddrRegion> = self.create_region(vaddr); 83c2481452Shoumkh // 加入buddy 84c2481452Shoumkh let list_guard: &mut SpinLockGuard<MmioFreeRegionList> = 85a7eb62a4Shoumkh &mut self.free_regions[exp2index(exp)].lock(); 86a7eb62a4Shoumkh self.push_block(region, list_guard); 87c2481452Shoumkh return Ok(0); 88c2481452Shoumkh } 89c2481452Shoumkh 90c2481452Shoumkh /// @brief 将给定大小为2^{exp}的内存块一分为二,并插入内存块大小为2^{exp-1}的链表中 91c2481452Shoumkh /// 92c2481452Shoumkh /// @param region 要被分割的地址区域结构体(保证其已经从链表中取出) 93c2481452Shoumkh /// 94c2481452Shoumkh /// @param exp 要被分割的地址区域的大小的幂 95c2481452Shoumkh /// 96c2481452Shoumkh /// @param list_guard 【exp-1】对应的链表 97a7eb62a4Shoumkh fn split_block( 98c2481452Shoumkh &self, 99c2481452Shoumkh region: Box<MmioBuddyAddrRegion>, 100c2481452Shoumkh exp: u32, 101c2481452Shoumkh low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 102c2481452Shoumkh ) { 103a7eb62a4Shoumkh let vaddr: u64 = self.calculate_block_vaddr(region.vaddr, exp - 1); 104a7eb62a4Shoumkh let new_region: Box<MmioBuddyAddrRegion> = self.create_region(vaddr); 105a7eb62a4Shoumkh self.push_block(region, low_list_guard); 106a7eb62a4Shoumkh self.push_block(new_region, low_list_guard); 107c2481452Shoumkh } 108c2481452Shoumkh 109c2481452Shoumkh /// @brief 从buddy中申请一块指定大小的内存区域 110c2481452Shoumkh /// 111c2481452Shoumkh /// @param exp 要申请的内存块的大小的幂(2^exp) 112c2481452Shoumkh /// 113c2481452Shoumkh /// @param list_guard exp对应的链表 114c2481452Shoumkh /// 115c2481452Shoumkh /// @return Ok(Box<MmioBuddyAddrRegion>) 符合要求的内存区域。 116c2481452Shoumkh /// 117c2481452Shoumkh /// @return Err(MmioResult) 118c2481452Shoumkh /// - 没有满足要求的内存块时,返回ENOFOUND 119c2481452Shoumkh /// - 申请的内存块大小超过合法范围,返回WRONGEXP 120c2481452Shoumkh /// - 调用函数出错时,返回出错函数对应错误码 121a7eb62a4Shoumkh fn query_addr_region( 122c2481452Shoumkh &self, 123c2481452Shoumkh exp: u32, 124c2481452Shoumkh list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 125c2481452Shoumkh ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> { 126c2481452Shoumkh // 申请范围错误 127c2481452Shoumkh if exp < MMIO_BUDDY_MIN_EXP || exp > MMIO_BUDDY_MAX_EXP { 128a7eb62a4Shoumkh kdebug!("query_addr_region: exp wrong"); 129c2481452Shoumkh return Err(MmioResult::WRONGEXP); 130c2481452Shoumkh } 131c2481452Shoumkh // 没有恰好符合要求的内存块 132c2481452Shoumkh // 注意:exp对应的链表list_guard已上锁【注意避免死锁问题】 133c2481452Shoumkh if list_guard.num_free == 0 { 134c2481452Shoumkh // 找到最小符合申请范围的内存块 135c2481452Shoumkh // 将大的内存块依次分成小块内存,直到能够满足exp大小,即将exp+1分成两块exp 136c2481452Shoumkh for e in exp + 1..MMIO_BUDDY_MAX_EXP + 1 { 137ef9f9732Shoumkh let pop_list: &mut SpinLockGuard<MmioFreeRegionList> = 138ef9f9732Shoumkh &mut self.free_regions[exp2index(e) as usize].lock(); 139ef9f9732Shoumkh if pop_list.num_free == 0 { 140c2481452Shoumkh continue; 141c2481452Shoumkh } 142ef9f9732Shoumkh 143c2481452Shoumkh for e2 in (exp + 1..e + 1).rev() { 144ef9f9732Shoumkh if e2 == e { 145ef9f9732Shoumkh match self.pop_block(pop_list) { 146ef9f9732Shoumkh Ok(region) => { 147ef9f9732Shoumkh if e2 != exp + 1 { 148ef9f9732Shoumkh // 要将分裂后的内存块插入到更小的链表中 149ef9f9732Shoumkh let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> = 150ef9f9732Shoumkh &mut self.free_regions[exp2index(e2 - 1) as usize].lock(); 151ef9f9732Shoumkh self.split_block(region, e2, low_list_guard); 152ef9f9732Shoumkh } else { 153ef9f9732Shoumkh // 由于exp对应的链表list_guard已经被锁住了 不能再加锁 154ef9f9732Shoumkh // 所以直接将list_guard传入 155ef9f9732Shoumkh self.split_block(region, e2, list_guard); 156ef9f9732Shoumkh } 157ef9f9732Shoumkh } 158ef9f9732Shoumkh Err(err) => { 159ef9f9732Shoumkh kdebug!("buddy_pop_region get wrong"); 160ef9f9732Shoumkh return Err(err); 161ef9f9732Shoumkh } 162ef9f9732Shoumkh } 163ef9f9732Shoumkh } else { 164ef9f9732Shoumkh match self.pop_block(&mut self.free_regions[exp2index(e2) as usize].lock()) 165ef9f9732Shoumkh { 166c2481452Shoumkh Ok(region) => { 167c2481452Shoumkh if e2 != exp + 1 { 168c2481452Shoumkh // 要将分裂后的内存块插入到更小的链表中 169c2481452Shoumkh let low_list_guard: &mut SpinLockGuard<MmioFreeRegionList> = 170a7eb62a4Shoumkh &mut self.free_regions[exp2index(e2 - 1) as usize].lock(); 171a7eb62a4Shoumkh self.split_block(region, e2, low_list_guard); 172c2481452Shoumkh } else { 173c2481452Shoumkh // 由于exp对应的链表list_guard已经被锁住了 不能再加锁 174c2481452Shoumkh // 所以直接将list_guard传入 175a7eb62a4Shoumkh self.split_block(region, e2, list_guard); 176c2481452Shoumkh } 177c2481452Shoumkh } 178c2481452Shoumkh Err(err) => { 179c2481452Shoumkh kdebug!("buddy_pop_region get wrong"); 180c2481452Shoumkh return Err(err); 181c2481452Shoumkh } 182c2481452Shoumkh } 183c2481452Shoumkh } 184ef9f9732Shoumkh } 185c2481452Shoumkh break; 186c2481452Shoumkh } 187c2481452Shoumkh // 判断是否获得了exp大小的内存块 188c2481452Shoumkh if list_guard.num_free > 0 { 189ef9f9732Shoumkh match self.pop_block(list_guard) { 190ef9f9732Shoumkh Ok(ret) => return Ok(ret), 191ef9f9732Shoumkh Err(err) => return Err(err), 192ef9f9732Shoumkh } 193c2481452Shoumkh } 194c2481452Shoumkh // 拆分大内存块无法获得exp大小内存块 195c2481452Shoumkh // 尝试用小内存块合成 196c2481452Shoumkh // 即将两块exp合成一块exp+1 197ef9f9732Shoumkh 198ef9f9732Shoumkh // TODO:修改下一个循环的冗余代码,请不要删除此处的注释 199ef9f9732Shoumkh // let merge = |high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, exp: u32| { 200ef9f9732Shoumkh // if let Err(err) = self.merge_all_exp( 201ef9f9732Shoumkh // exp, 202ef9f9732Shoumkh // &mut self.free_regions[exp2index(exp) as usize].lock(), 203ef9f9732Shoumkh // high_list_guard, 204ef9f9732Shoumkh // ) { 205ef9f9732Shoumkh // return err; 206ef9f9732Shoumkh // } else { 207ef9f9732Shoumkh // return MmioResult::SUCCESS; 208ef9f9732Shoumkh // } 209ef9f9732Shoumkh // }; 210c2481452Shoumkh for e in MMIO_BUDDY_MIN_EXP..exp { 211c2481452Shoumkh if e != exp - 1 { 212a7eb62a4Shoumkh match self.merge_all_exp( 213ef9f9732Shoumkh exp, 214ef9f9732Shoumkh &mut self.free_regions[exp2index(exp) as usize].lock(), 215ef9f9732Shoumkh &mut self.free_regions[exp2index(exp + 1)].lock(), 216c2481452Shoumkh ) { 217c2481452Shoumkh Ok(_) => continue, 218c2481452Shoumkh Err(err) => { 219ef9f9732Shoumkh kdebug!("merge_all_exp get wrong"); 220c2481452Shoumkh return Err(err); 221c2481452Shoumkh } 222c2481452Shoumkh } 223c2481452Shoumkh } else { 224a7eb62a4Shoumkh match self.merge_all_exp( 225ef9f9732Shoumkh exp, 226ef9f9732Shoumkh &mut self.free_regions[exp2index(exp) as usize].lock(), 227c2481452Shoumkh list_guard, 228c2481452Shoumkh ) { 229c2481452Shoumkh Ok(_) => continue, 230c2481452Shoumkh Err(err) => { 231ef9f9732Shoumkh kdebug!("merge_all_exp get wrong"); 232c2481452Shoumkh return Err(err); 233c2481452Shoumkh } 234c2481452Shoumkh } 235c2481452Shoumkh } 236c2481452Shoumkh } 237c2481452Shoumkh 238c2481452Shoumkh //判断是否获得了exp大小的内存块 239c2481452Shoumkh if list_guard.num_free > 0 { 240ef9f9732Shoumkh match self.pop_block(list_guard) { 241ef9f9732Shoumkh Ok(ret) => return Ok(ret), 242ef9f9732Shoumkh Err(err) => return Err(err), 243ef9f9732Shoumkh } 244c2481452Shoumkh } 245c2481452Shoumkh return Err(MmioResult::ENOFOUND); 246c2481452Shoumkh } else { 247ef9f9732Shoumkh match self.pop_block(list_guard) { 248ef9f9732Shoumkh Ok(ret) => return Ok(ret), 249ef9f9732Shoumkh Err(err) => return Err(err), 250ef9f9732Shoumkh } 251c2481452Shoumkh } 252c2481452Shoumkh } 253c2481452Shoumkh 254c2481452Shoumkh /// @brief 对query_addr_region进行封装 255c2481452Shoumkh /// 256c2481452Shoumkh /// @param exp 内存区域的大小(2^exp) 257c2481452Shoumkh /// 258c2481452Shoumkh /// @return Ok(Box<MmioBuddyAddrRegion>)符合要求的内存块信息结构体。 259c2481452Shoumkh /// @return Err(MmioResult) 没有满足要求的内存块时,返回__query_addr_region的错误码。 260c2481452Shoumkh fn mmio_buddy_query_addr_region( 261c2481452Shoumkh &self, 262c2481452Shoumkh exp: u32, 263c2481452Shoumkh ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> { 264c2481452Shoumkh let list_guard: &mut SpinLockGuard<MmioFreeRegionList> = 265a7eb62a4Shoumkh &mut self.free_regions[exp2index(exp)].lock(); 266a7eb62a4Shoumkh match self.query_addr_region(exp, list_guard) { 267c2481452Shoumkh Ok(ret) => return Ok(ret), 268c2481452Shoumkh Err(err) => { 269c2481452Shoumkh kdebug!("mmio_buddy_query_addr_region failed"); 270c2481452Shoumkh return Err(err); 271c2481452Shoumkh } 272c2481452Shoumkh } 273c2481452Shoumkh } 274c2481452Shoumkh /// @brief 往指定的地址空间链表中添加一个地址区域 275c2481452Shoumkh /// 276c2481452Shoumkh /// @param region 要被添加的地址结构体 277c2481452Shoumkh /// 278c2481452Shoumkh /// @param list_guard 目标链表 279a7eb62a4Shoumkh fn push_block( 280c2481452Shoumkh &self, 281c2481452Shoumkh region: Box<MmioBuddyAddrRegion>, 282c2481452Shoumkh list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 283c2481452Shoumkh ) { 284c2481452Shoumkh list_guard.list.push_back(region); 285c2481452Shoumkh list_guard.num_free += 1; 286c2481452Shoumkh } 287c2481452Shoumkh 288c2481452Shoumkh /// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址 289c2481452Shoumkh #[inline(always)] 290a7eb62a4Shoumkh fn calculate_block_vaddr(&self, vaddr: u64, exp: u32) -> u64 { 291c2481452Shoumkh return vaddr ^ (1 << exp); 292c2481452Shoumkh } 293c2481452Shoumkh 294c2481452Shoumkh /// @brief 寻找并弹出指定内存块的伙伴块 295c2481452Shoumkh /// 296c2481452Shoumkh /// @param region 对应内存块的信息 297c2481452Shoumkh /// 298c2481452Shoumkh /// @param exp 内存块大小 299c2481452Shoumkh /// 300c2481452Shoumkh /// @param list_guard 【exp】对应的链表 301c2481452Shoumkh /// 302c2481452Shoumkh /// @return Ok(Box<MmioBuddyAddrRegion) 返回伙伴块的引用 303c2481452Shoumkh /// @return Err(MmioResult) 304c2481452Shoumkh /// - 当链表为空,返回ISEMPTY 305c2481452Shoumkh /// - 没有找到伙伴块,返回ENOFOUND 306a7eb62a4Shoumkh fn pop_buddy_block( 307c2481452Shoumkh &self, 308c2481452Shoumkh vaddr: u64, 309c2481452Shoumkh exp: u32, 310c2481452Shoumkh list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 311c2481452Shoumkh ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> { 312c2481452Shoumkh if list_guard.list.len() == 0 { 313c2481452Shoumkh return Err(MmioResult::ISEMPTY); 314c2481452Shoumkh } else { 315c2481452Shoumkh //计算伙伴块的地址 316a7eb62a4Shoumkh let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp); 317c2481452Shoumkh 318c2481452Shoumkh // element 只会有一个元素 319c2481452Shoumkh let mut element: Vec<Box<MmioBuddyAddrRegion>> = list_guard 320c2481452Shoumkh .list 321c2481452Shoumkh .drain_filter(|x| x.vaddr == buddy_vaddr) 322c2481452Shoumkh .collect(); 323c2481452Shoumkh if element.len() == 1 { 324c2481452Shoumkh list_guard.num_free -= 1; 325c2481452Shoumkh return Ok(element.pop().unwrap()); 326c2481452Shoumkh } 327c2481452Shoumkh 328c2481452Shoumkh //没有找到对应的伙伴块 329c2481452Shoumkh return Err(MmioResult::ENOFOUND); 330c2481452Shoumkh } 331c2481452Shoumkh } 332c2481452Shoumkh 333c2481452Shoumkh /// @brief 从指定空闲链表中取出内存区域 334c2481452Shoumkh /// 335c2481452Shoumkh /// @param list_guard 【exp】对应的链表 336c2481452Shoumkh /// 337c2481452Shoumkh /// @return Ok(Box<MmioBuddyAddrRegion>) 内存块信息结构体的引用。 338c2481452Shoumkh /// 339c2481452Shoumkh /// @return Err(MmioResult) 当链表为空,无法删除时,返回ISEMPTY 340a7eb62a4Shoumkh fn pop_block( 341c2481452Shoumkh &self, 342c2481452Shoumkh list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 343c2481452Shoumkh ) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> { 344c2481452Shoumkh if !list_guard.list.is_empty() { 345c2481452Shoumkh list_guard.num_free -= 1; 346c2481452Shoumkh return Ok(list_guard.list.pop_back().unwrap()); 347c2481452Shoumkh } 348c2481452Shoumkh return Err(MmioResult::ISEMPTY); 349c2481452Shoumkh } 350c2481452Shoumkh 351c2481452Shoumkh /// @brief 合并所有2^{exp}大小的内存块 352c2481452Shoumkh /// 353c2481452Shoumkh /// @param exp 内存块大小的幂(2^exp) 354c2481452Shoumkh /// 355c2481452Shoumkh /// @param list_guard exp对应的链表 356c2481452Shoumkh /// 357c2481452Shoumkh /// @param high_list_guard exp+1对应的链表 358c2481452Shoumkh /// 359c2481452Shoumkh /// @return Ok(MmioResult) 合并成功返回SUCCESS 360c2481452Shoumkh /// @return Err(MmioResult) 361c2481452Shoumkh /// - 内存块过少,无法合并,返回EINVAL 362a7eb62a4Shoumkh /// - pop_buddy_block调用出错,返回其错误码 363a7eb62a4Shoumkh /// - merge_blocks调用出错,返回其错误码 364a7eb62a4Shoumkh fn merge_all_exp( 365c2481452Shoumkh &self, 366c2481452Shoumkh exp: u32, 367c2481452Shoumkh list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 368c2481452Shoumkh high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 369c2481452Shoumkh ) -> Result<MmioResult, MmioResult> { 370c2481452Shoumkh // 至少要两个内存块才能合并 371c2481452Shoumkh if list_guard.num_free <= 1 { 372c2481452Shoumkh return Err(MmioResult::EINVAL); 373c2481452Shoumkh } 374c2481452Shoumkh loop { 375c2481452Shoumkh if list_guard.num_free <= 1 { 376c2481452Shoumkh break; 377c2481452Shoumkh } 378c2481452Shoumkh // 获取内存块 379c2481452Shoumkh let vaddr: u64 = list_guard.list.back().unwrap().vaddr; 380c2481452Shoumkh // 获取伙伴内存块 381a7eb62a4Shoumkh match self.pop_buddy_block(vaddr, exp, list_guard) { 382c2481452Shoumkh Err(err) => { 383c2481452Shoumkh return Err(err); 384c2481452Shoumkh } 385c2481452Shoumkh Ok(buddy_region) => { 386c2481452Shoumkh let region: Box<MmioBuddyAddrRegion> = list_guard.list.pop_back().unwrap(); 387c2481452Shoumkh let copy_region: Box<MmioBuddyAddrRegion> = Box::new(MmioBuddyAddrRegion { 388c2481452Shoumkh vaddr: region.vaddr, 389c2481452Shoumkh }); 390c2481452Shoumkh // 在两块内存都被取出之后才进行合并 391a7eb62a4Shoumkh match self.merge_blocks(region, buddy_region, exp, high_list_guard) { 392c2481452Shoumkh Err(err) => { 393c2481452Shoumkh // 如果合并失败了要将取出来的元素放回去 394a7eb62a4Shoumkh self.push_block(copy_region, list_guard); 395a7eb62a4Shoumkh kdebug!("merge_all_exp: merge_blocks failed"); 396c2481452Shoumkh return Err(err); 397c2481452Shoumkh } 398c2481452Shoumkh Ok(_) => continue, 399c2481452Shoumkh } 400c2481452Shoumkh } 401c2481452Shoumkh } 402c2481452Shoumkh } 403c2481452Shoumkh return Ok(MmioResult::SUCCESS); 404c2481452Shoumkh } 405c2481452Shoumkh 406c2481452Shoumkh /// @brief 合并两个【已经从链表中取出】的内存块 407c2481452Shoumkh /// 408c2481452Shoumkh /// @param region_1 第一个内存块 409c2481452Shoumkh /// 410c2481452Shoumkh /// @param region_2 第二个内存 411c2481452Shoumkh /// 412c2481452Shoumkh /// @return Ok(MmioResult) 成功返回SUCCESS 413c2481452Shoumkh /// 414c2481452Shoumkh /// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL 415a7eb62a4Shoumkh fn merge_blocks( 416c2481452Shoumkh &self, 417c2481452Shoumkh region_1: Box<MmioBuddyAddrRegion>, 418c2481452Shoumkh region_2: Box<MmioBuddyAddrRegion>, 419c2481452Shoumkh exp: u32, 420c2481452Shoumkh high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>, 421c2481452Shoumkh ) -> Result<MmioResult, MmioResult> { 422c2481452Shoumkh // 判断是否为伙伴块 423a7eb62a4Shoumkh if region_1.vaddr != self.calculate_block_vaddr(region_2.vaddr, exp) { 424c2481452Shoumkh return Err(MmioResult::EINVAL); 425c2481452Shoumkh } 426c2481452Shoumkh // 将大的块放进下一级链表 427a7eb62a4Shoumkh self.push_block(region_1, high_list_guard); 428c2481452Shoumkh return Ok(MmioResult::SUCCESS); 429c2481452Shoumkh } 430c2481452Shoumkh 431c2481452Shoumkh /// @brief 创建一块mmio区域,并将vma绑定到initial_mm 432c2481452Shoumkh /// 433c2481452Shoumkh /// @param size mmio区域的大小(字节) 434c2481452Shoumkh /// 435c2481452Shoumkh /// @param vm_flags 要把vma设置成的标志 436c2481452Shoumkh /// 437c2481452Shoumkh /// @param res_vaddr 返回值-分配得到的虚拟地址 438c2481452Shoumkh /// 439c2481452Shoumkh /// @param res_length 返回值-分配的虚拟地址空间长度 440c2481452Shoumkh /// 441a7eb62a4Shoumkh /// @return Ok(i32) 成功返回0 442a7eb62a4Shoumkh /// 443a7eb62a4Shoumkh /// @return Err(i32) 失败返回错误码 444ef9f9732Shoumkh pub fn create_mmio( 445a7eb62a4Shoumkh &self, 446c2481452Shoumkh size: u32, 447c2481452Shoumkh vm_flags: vm_flags_t, 448c2481452Shoumkh res_vaddr: *mut u64, 449c2481452Shoumkh res_length: *mut u64, 450a7eb62a4Shoumkh ) -> Result<i32, i32> { 451c2481452Shoumkh if size > PAGE_1G_SIZE || size == 0 { 452a7eb62a4Shoumkh return Err(-(EPERM as i32)); 453c2481452Shoumkh } 454c2481452Shoumkh let mut retval: i32 = 0; 455c2481452Shoumkh // 计算前导0 456c2481452Shoumkh let mut size_exp: u32 = 31 - size.leading_zeros(); 457c2481452Shoumkh // 记录最终申请的空间大小 458c2481452Shoumkh let mut new_size: u32 = size; 459c2481452Shoumkh // 对齐要申请的空间大小 460c2481452Shoumkh // 如果要申请的空间大小小于4k,则分配4k 461c2481452Shoumkh if size_exp < PAGE_4K_SHIFT { 462c2481452Shoumkh new_size = PAGE_4K_SIZE; 463c2481452Shoumkh size_exp = PAGE_4K_SHIFT; 464c2481452Shoumkh } else if (new_size & (!(1 << size_exp))) != 0 { 465c2481452Shoumkh // 向左对齐空间大小 466c2481452Shoumkh size_exp += 1; 467c2481452Shoumkh new_size = 1 << size_exp; 468c2481452Shoumkh } 469c2481452Shoumkh match MMIO_POOL.mmio_buddy_query_addr_region(size_exp) { 470c2481452Shoumkh Ok(region) => { 471c2481452Shoumkh unsafe { 472c2481452Shoumkh *res_vaddr = region.vaddr; 473c2481452Shoumkh *res_length = new_size as u64; 474c2481452Shoumkh } 475c2481452Shoumkh // 创建vma 476c2481452Shoumkh let flags: u64 = vm_flags | (VM_IO | VM_DONTCOPY) as u64; 477c2481452Shoumkh let len_4k: u64 = (new_size % PAGE_2M_SIZE) as u64; 478c2481452Shoumkh let len_2m: u64 = new_size as u64 - len_4k; 479c2481452Shoumkh let mut loop_i: u64 = 0; 480c2481452Shoumkh // 先分配2M的vma 481c2481452Shoumkh loop { 482c2481452Shoumkh if loop_i >= len_2m { 483c2481452Shoumkh break; 484c2481452Shoumkh } 485c2481452Shoumkh let vma: *mut *mut vm_area_struct = null_mut(); 486c2481452Shoumkh retval = unsafe { 487c2481452Shoumkh mm_create_vma( 488c2481452Shoumkh &mut initial_mm, 489c2481452Shoumkh region.vaddr + loop_i, 490c2481452Shoumkh PAGE_2M_SIZE.into(), 491c2481452Shoumkh flags, 492c2481452Shoumkh null_mut(), 493c2481452Shoumkh vma, 494c2481452Shoumkh ) 495c2481452Shoumkh }; 496c2481452Shoumkh if retval != 0 { 497c2481452Shoumkh kdebug!( 498c2481452Shoumkh "failed to create mmio 2m vma. pid = {:?}", 499c2481452Shoumkh current_pcb().pid 500c2481452Shoumkh ); 501c2481452Shoumkh unsafe { 502c2481452Shoumkh vm_area_del(*vma); 503c2481452Shoumkh vm_area_free(*vma); 504c2481452Shoumkh } 505a7eb62a4Shoumkh return Err(retval); 506c2481452Shoumkh } 507c2481452Shoumkh loop_i += PAGE_2M_SIZE as u64; 508c2481452Shoumkh } 509c2481452Shoumkh // 分配4K的vma 510c2481452Shoumkh loop_i = len_2m; 511c2481452Shoumkh loop { 512c2481452Shoumkh if loop_i >= size as u64 { 513c2481452Shoumkh break; 514c2481452Shoumkh } 515c2481452Shoumkh let vma: *mut *mut vm_area_struct = null_mut(); 516c2481452Shoumkh retval = unsafe { 517c2481452Shoumkh mm_create_vma( 518c2481452Shoumkh &mut initial_mm, 519c2481452Shoumkh region.vaddr + loop_i, 520c2481452Shoumkh PAGE_4K_SIZE.into(), 521c2481452Shoumkh flags, 522c2481452Shoumkh null_mut(), 523c2481452Shoumkh vma, 524c2481452Shoumkh ) 525c2481452Shoumkh }; 526c2481452Shoumkh if retval != 0 { 527c2481452Shoumkh kdebug!( 528c2481452Shoumkh "failed to create mmio 4k vma. pid = {:?}", 529c2481452Shoumkh current_pcb().pid 530c2481452Shoumkh ); 531c2481452Shoumkh unsafe { 532c2481452Shoumkh vm_area_del(*vma); 533c2481452Shoumkh vm_area_free(*vma); 534c2481452Shoumkh } 535a7eb62a4Shoumkh return Err(retval); 536c2481452Shoumkh } 537c2481452Shoumkh loop_i += PAGE_4K_SIZE as u64; 538c2481452Shoumkh } 539c2481452Shoumkh } 540c2481452Shoumkh Err(_) => { 541c2481452Shoumkh kdebug!("failed to create mmio vma.pid = {:?}", current_pcb().pid); 542a7eb62a4Shoumkh return Err(-(ENOMEM as i32)); 543c2481452Shoumkh } 544c2481452Shoumkh } 545a7eb62a4Shoumkh return Ok(retval); 546c2481452Shoumkh } 547c2481452Shoumkh 548c2481452Shoumkh /// @brief 取消mmio的映射并将地址空间归还到buddy中 549c2481452Shoumkh /// 550c2481452Shoumkh /// @param vaddr 起始的虚拟地址 551c2481452Shoumkh /// 552c2481452Shoumkh /// @param length 要归还的地址空间的长度 553c2481452Shoumkh /// 554c2481452Shoumkh /// @return Ok(i32) 成功返回0 555c2481452Shoumkh /// 556c2481452Shoumkh /// @return Err(i32) 失败返回错误码 557ef9f9732Shoumkh pub fn release_mmio(&self, vaddr: u64, length: u64) -> Result<i32, i32> { 558c2481452Shoumkh //先将要释放的空间取消映射 559c2481452Shoumkh unsafe { 560c2481452Shoumkh mm_unmap(&mut initial_mm, vaddr, length, false); 561c2481452Shoumkh } 562c2481452Shoumkh let mut loop_i: u64 = 0; 563c2481452Shoumkh loop { 564c2481452Shoumkh if loop_i >= length { 565c2481452Shoumkh break; 566c2481452Shoumkh } 567c2481452Shoumkh // 获取要释放的vma的结构体 568c2481452Shoumkh let vma: *mut vm_area_struct = unsafe { vma_find(&mut initial_mm, vaddr + loop_i) }; 569c2481452Shoumkh if vma == null_mut() { 570c2481452Shoumkh kdebug!( 571c2481452Shoumkh "mmio_release failed: vma not found. At address: {:?}, pid = {:?}", 572c2481452Shoumkh vaddr + loop_i, 573c2481452Shoumkh current_pcb().pid 574c2481452Shoumkh ); 575a7eb62a4Shoumkh return Err(-(EINVAL as i32)); 576c2481452Shoumkh } 577c2481452Shoumkh // 检查vma起始地址是否正确 578c2481452Shoumkh if unsafe { (*vma).vm_start != (vaddr + loop_i) } { 579c2481452Shoumkh kdebug!( 580c2481452Shoumkh "mmio_release failed: addr_start is not equal to current: {:?}. pid = {:?}", 581c2481452Shoumkh vaddr + loop_i, 582c2481452Shoumkh current_pcb().pid 583c2481452Shoumkh ); 584a7eb62a4Shoumkh return Err(-(EINVAL as i32)); 585c2481452Shoumkh } 586c2481452Shoumkh // 将vma对应空间归还 587a7eb62a4Shoumkh match MMIO_POOL.give_back_block(unsafe { (*vma).vm_start }, unsafe { 588c2481452Shoumkh 31 - ((*vma).vm_end - (*vma).vm_start).leading_zeros() 589c2481452Shoumkh }) { 590c2481452Shoumkh Ok(_) => { 591c2481452Shoumkh loop_i += unsafe { (*vma).vm_end - (*vma).vm_start }; 592c2481452Shoumkh unsafe { 593c2481452Shoumkh vm_area_del(vma); 594c2481452Shoumkh vm_area_free(vma); 595c2481452Shoumkh } 596c2481452Shoumkh } 597c2481452Shoumkh Err(err) => { 598c2481452Shoumkh // vma对应空间没有成功归还的话,就不删除vma 599c2481452Shoumkh kdebug!( 600c2481452Shoumkh "mmio_release give_back failed: pid = {:?}", 601c2481452Shoumkh current_pcb().pid 602c2481452Shoumkh ); 603a7eb62a4Shoumkh return Err(err); 604a7eb62a4Shoumkh } 605a7eb62a4Shoumkh } 606a7eb62a4Shoumkh } 607a7eb62a4Shoumkh return Ok(0); 608a7eb62a4Shoumkh } 609a7eb62a4Shoumkh } 610a7eb62a4Shoumkh 611a7eb62a4Shoumkh /// @brief mmio伙伴系统内部的地址区域结构体 612a7eb62a4Shoumkh pub struct MmioBuddyAddrRegion { 613a7eb62a4Shoumkh vaddr: u64, 614a7eb62a4Shoumkh } 615a7eb62a4Shoumkh impl MmioBuddyAddrRegion { 616a7eb62a4Shoumkh pub fn new() -> Self { 617a7eb62a4Shoumkh return MmioBuddyAddrRegion { 618a7eb62a4Shoumkh ..Default::default() 619a7eb62a4Shoumkh }; 620a7eb62a4Shoumkh } 621a7eb62a4Shoumkh } 622a7eb62a4Shoumkh impl Default for MmioBuddyAddrRegion { 623a7eb62a4Shoumkh fn default() -> Self { 624a7eb62a4Shoumkh MmioBuddyAddrRegion { 625a7eb62a4Shoumkh vaddr: Default::default(), 626a7eb62a4Shoumkh } 627a7eb62a4Shoumkh } 628a7eb62a4Shoumkh } 629a7eb62a4Shoumkh 630a7eb62a4Shoumkh /// @brief 空闲页数组结构体 631a7eb62a4Shoumkh pub struct MmioFreeRegionList { 632a7eb62a4Shoumkh /// 存储mmio_buddy的地址链表 633a7eb62a4Shoumkh list: LinkedList<Box<MmioBuddyAddrRegion>>, 634a7eb62a4Shoumkh /// 空闲块的数量 635a7eb62a4Shoumkh num_free: i64, 636a7eb62a4Shoumkh } 637a7eb62a4Shoumkh impl MmioFreeRegionList { 638*64aea4b3SGou Ngai #[allow(dead_code)] 639a7eb62a4Shoumkh fn new() -> Self { 640a7eb62a4Shoumkh return MmioFreeRegionList { 641a7eb62a4Shoumkh ..Default::default() 642a7eb62a4Shoumkh }; 643a7eb62a4Shoumkh } 644a7eb62a4Shoumkh } 645a7eb62a4Shoumkh impl Default for MmioFreeRegionList { 646a7eb62a4Shoumkh fn default() -> Self { 647a7eb62a4Shoumkh MmioFreeRegionList { 648a7eb62a4Shoumkh list: Default::default(), 649a7eb62a4Shoumkh num_free: 0, 650a7eb62a4Shoumkh } 651a7eb62a4Shoumkh } 652a7eb62a4Shoumkh } 653a7eb62a4Shoumkh 654a7eb62a4Shoumkh /// @brief 初始化mmio的伙伴系统 655a7eb62a4Shoumkh #[no_mangle] 656a7eb62a4Shoumkh pub extern "C" fn __mmio_buddy_init() { 657a7eb62a4Shoumkh // 创建一堆1GB的地址块 658a7eb62a4Shoumkh let cnt_1g_blocks: u32 = ((MMIO_TOP - MMIO_BASE) / PAGE_1G_SIZE as i64) as u32; 659a7eb62a4Shoumkh let mut vaddr_base: u64 = MMIO_BASE as u64; 660a7eb62a4Shoumkh for _ in 0..cnt_1g_blocks { 661a7eb62a4Shoumkh match MMIO_POOL.give_back_block(vaddr_base, PAGE_1G_SHIFT) { 662a7eb62a4Shoumkh Ok(_) => { 663a7eb62a4Shoumkh vaddr_base += PAGE_1G_SIZE as u64; 664a7eb62a4Shoumkh } 665a7eb62a4Shoumkh Err(_) => { 666a7eb62a4Shoumkh kerror!("__mmio_buddy_init failed"); 667a7eb62a4Shoumkh return; 668a7eb62a4Shoumkh } 669a7eb62a4Shoumkh } 670a7eb62a4Shoumkh } 671a7eb62a4Shoumkh } 672a7eb62a4Shoumkh 673a7eb62a4Shoumkh /// @brief 将内存对象大小的幂转换成内存池中的数组的下标 674a7eb62a4Shoumkh /// 675a7eb62a4Shoumkh /// @param exp内存大小 676a7eb62a4Shoumkh /// 677a7eb62a4Shoumkh /// @return 内存池数组下标 678a7eb62a4Shoumkh #[inline(always)] 679a7eb62a4Shoumkh fn exp2index(exp: u32) -> usize { 680a7eb62a4Shoumkh return (exp - 12) as usize; 681a7eb62a4Shoumkh } 682a7eb62a4Shoumkh 683a7eb62a4Shoumkh /// @brief 创建一块mmio区域,并将vma绑定到initial_mm 684a7eb62a4Shoumkh /// 685a7eb62a4Shoumkh /// @param size mmio区域的大小(字节) 686a7eb62a4Shoumkh /// 687a7eb62a4Shoumkh /// @param vm_flags 要把vma设置成的标志 688a7eb62a4Shoumkh /// 689a7eb62a4Shoumkh /// @param res_vaddr 返回值-分配得到的虚拟地址 690a7eb62a4Shoumkh /// 691a7eb62a4Shoumkh /// @param res_length 返回值-分配的虚拟地址空间长度 692a7eb62a4Shoumkh /// 693a7eb62a4Shoumkh /// @return int 错误码 694a7eb62a4Shoumkh #[no_mangle] 695a7eb62a4Shoumkh pub extern "C" fn mmio_create( 696a7eb62a4Shoumkh size: u32, 697a7eb62a4Shoumkh vm_flags: vm_flags_t, 698a7eb62a4Shoumkh res_vaddr: *mut u64, 699a7eb62a4Shoumkh res_length: *mut u64, 700a7eb62a4Shoumkh ) -> i32 { 701a7eb62a4Shoumkh if let Err(err) = MMIO_POOL.create_mmio(size, vm_flags, res_vaddr, res_length) { 702c2481452Shoumkh return err; 703a7eb62a4Shoumkh } else { 704c2481452Shoumkh return 0; 705c2481452Shoumkh } 706a7eb62a4Shoumkh } 707a7eb62a4Shoumkh 708a7eb62a4Shoumkh /// @brief 取消mmio的映射并将地址空间归还到buddy中 709a7eb62a4Shoumkh /// 710a7eb62a4Shoumkh /// @param vaddr 起始的虚拟地址 711a7eb62a4Shoumkh /// 712a7eb62a4Shoumkh /// @param length 要归还的地址空间的长度 713a7eb62a4Shoumkh /// 714a7eb62a4Shoumkh /// @return Ok(i32) 成功返回0 715a7eb62a4Shoumkh /// 716a7eb62a4Shoumkh /// @return Err(i32) 失败返回错误码 717a7eb62a4Shoumkh #[no_mangle] 718a7eb62a4Shoumkh pub extern "C" fn mmio_release(vaddr: u64, length: u64) -> i32 { 719a7eb62a4Shoumkh if let Err(err) = MMIO_POOL.release_mmio(vaddr, length) { 720a7eb62a4Shoumkh return err; 721a7eb62a4Shoumkh } else { 722a7eb62a4Shoumkh return 0; 723a7eb62a4Shoumkh } 724a7eb62a4Shoumkh } 725