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