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